feat: Phase 0 — monorepo 骨架 + 全表迁移 + FastAPI/Next 骨架 + CI
- uv(workspace) + pnpm monorepo;docker-compose(pg+api+web) - SQLAlchemy 16 MVP 表 + Alembic 初版迁移(无漂移,users stub) - FastAPI 骨架:统一错误信封(带 request_id) + structlog + /jobs/:id + OpenAPI - Next.js 骨架:纸感主题 token + OpenAPI→TS 客户端代码生成(gen:api) - CI(ruff/mypy/pytest + pg service + alembic 漂移校验) - 四份设计规格(PRODUCT/UX/ARCHITECTURE/DEV_PLAN) + CLAUDE.md
This commit is contained in:
28
apps/api/ww_api/middleware.py
Normal file
28
apps/api/ww_api/middleware.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""request_id 关联中间件(ARCH §9.3 / CLAUDE.md)。
|
||||
|
||||
每请求生成/透传 request_id,绑入 structlog contextvars,并回写响应头,
|
||||
错误信封也带上同一 id,便于端到端 grep。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from collections.abc import Awaitable, Callable
|
||||
|
||||
import structlog
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import Response
|
||||
|
||||
REQUEST_ID_HEADER = "x-request-id"
|
||||
|
||||
|
||||
async def request_id_middleware(
|
||||
request: Request, call_next: Callable[[Request], Awaitable[Response]]
|
||||
) -> Response:
|
||||
request_id = request.headers.get(REQUEST_ID_HEADER) or uuid.uuid4().hex
|
||||
structlog.contextvars.clear_contextvars()
|
||||
structlog.contextvars.bind_contextvars(request_id=request_id)
|
||||
request.state.request_id = request_id
|
||||
response = await call_next(request)
|
||||
response.headers[REQUEST_ID_HEADER] = request_id
|
||||
return response
|
||||
Reference in New Issue
Block a user