docs: document server-side rendering pipeline, response timing middleware, and Telegram pairing API

- Add comprehensive documentation for backend content rendering in AGENTS.md, detailing the new `render_content` and `render_title` Jinja globals built on mistune with media processing, emoji shortcodes, and XSS protection
- Document the `X-Response-Time` header and bottom-left render time indicator in README.md
- Update bot token pricing documentation to clarify fallback vs gateway cost headers
- Add `email_accounts` to soft-delete tables and `idx_users_role` composite index in database schema
- Implement `telegram_pairings` and `telegram_links` table creation with column migration and indexes
- Add `/profile/{username}/telegram` endpoint to docs API with request/unpair actions
- Register `TelegramService` in main.py lifespan and add `response_timing` middleware emitting `X-Response-Time` header
- Introduce `TelegramPairForm` model and `guard_public_host_sync` synchronous host validation function
This commit is contained in:
2026-06-18 22:09:34 +00:00
parent 95dca73291
commit 6ceca3d0d4
146 changed files with 6079 additions and 392 deletions
+3 -2
View File
@@ -19,7 +19,7 @@ from devplacepy.utils import (
)
from devplacepy.seo import base_seo_context, site_url, website_schema
from devplacepy.responses import respond, action_result
from devplacepy.schemas import AdminUsersOut
from devplacepy.schemas import AdminUsersOut, UserAiUsageOut
from devplacepy.services.audit import record as audit
from devplacepy.services.manager import service_manager
from devplacepy.services.openai_gateway.analytics import build_user_usage
@@ -62,7 +62,8 @@ async def admin_user_ai_usage(request: Request, uid: str, hours: int = 24):
return JSONResponse({"error": "Admin access required"}, status_code=403)
service = service_manager.get_service("openai")
pricing = pricing_from_cfg(service.get_config()) if service is not None else None
return JSONResponse(build_user_usage(uid, hours=hours, pricing=pricing))
usage = build_user_usage(uid, hours=hours, pricing=pricing)
return JSONResponse(UserAiUsageOut(**usage).model_dump())
@router.get("/users", response_class=HTMLResponse)
async def admin_users(request: Request, page: int = 1):