Files
writer-work-flow/apps/api/ww_api/main.py
Yaojia Wang d3dc620a71 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
2026-06-18 11:38:28 +02:00

56 lines
1.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""FastAPI 应用入口ARCH §7"""
from __future__ import annotations
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from ww_db import get_sessionmaker
from ww_shared import AppError, ErrorBody, ErrorEnvelope
from ww_api.logging_config import configure_logging, get_logger
from ww_api.middleware import request_id_middleware
from ww_api.routers import health, jobs, projects, settings_providers
from ww_api.services.project_deps import seed_stub_user
configure_logging()
log = get_logger("ww.api")
@asynccontextmanager
async def _lifespan(app: FastAPI) -> AsyncIterator[None]:
# 幂等 seed 单用户 stub——所有 owner_id FK 依赖它(见 memory/gotchas
async with get_sessionmaker()() as session:
await seed_stub_user(session)
yield
def create_app() -> FastAPI:
app = FastAPI(title="网文创作工作流 API", version="0.0.0", lifespan=_lifespan)
app.middleware("http")(request_id_middleware)
@app.exception_handler(AppError)
async def _app_error_handler(request: Request, exc: AppError) -> JSONResponse:
request_id = getattr(request.state, "request_id", None)
log.warning("app_error", code=exc.code, message=exc.message)
envelope = ErrorEnvelope(
error=ErrorBody(
code=exc.code,
message=exc.message,
details=exc.details,
request_id=request_id,
)
)
return JSONResponse(status_code=exc.http_status, content=envelope.model_dump())
app.include_router(health.router)
app.include_router(jobs.router)
app.include_router(projects.router)
app.include_router(settings_providers.router)
return app
app = create_app()