Files
meida_backend/apps/admin/app.py
T

83 lines
3.1 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.
"""admin 应用工厂(T-P2-09):极简运营后台的装配层。
与客户端 API 的装配差异只有三点:路由前缀 ``/admin/api/v1``(区分流量)、
鉴权换成 ``X-Admin-Token``、**空令牌时一个业务路由都不注册**——「未部署」
的语义用装配期决定,而不是每个请求里判空(404 更干净,扫描器也探不到面)。
"""
from __future__ import annotations
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from fastapi import FastAPI
from apps.admin.routers import assets, gaps, kb, rules, stats, users
from packages.shared.config import Settings, get_settings
from packages.shared.db import dispose_engine, get_session_factory
from packages.shared.handlers import install_exception_handlers
from packages.shared.logging import configure_logging, get_logger
from packages.shared.middleware import RequestContextMiddleware
from packages.shared.observability import setup_tracing
logger = get_logger(__name__)
#: 与客户端 API(/api/v1)区分的固定前缀;不提供 /v1 别名(后台没有历史包袱)。
ADMIN_API_PREFIX = "/admin/api/v1"
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
settings: Settings = app.state.admin_settings
# 启动即触碰共享 engine(懒加载单例,复用 packages.shared.db):
# 连接配置有问题应该在部署的那一刻暴露,而不是等顾问点第一个按钮。
get_session_factory()
logger.info(
"admin_started",
env=settings.app_env,
routes_registered=bool(settings.admin_token),
)
try:
yield
finally:
await dispose_engine()
logger.info("admin_stopped")
def create_admin_app(settings: Settings | None = None) -> FastAPI:
cfg = settings or get_settings()
configure_logging(
level=cfg.log_level, json_output=cfg.log_json, extra_redact_keys=cfg.extra_redact_keys
)
# 空令牌 = 等价未部署:业务路由、openapi、docs 全部不装配。
deployed = bool(cfg.admin_token)
app = FastAPI(
title="美搭运营后台",
version="0.1.0",
description=(
"极简运营后台:知识实体/规则维护、素材登记审核、发布编排与缺口看板"
"(T-P2-09)。鉴权:请求头 X-Admin-Token。"
),
lifespan=lifespan,
openapi_url=f"{ADMIN_API_PREFIX}/openapi.json" if deployed else None,
docs_url=f"{ADMIN_API_PREFIX}/docs" if deployed and cfg.is_local else None,
redoc_url=None,
)
app.state.admin_settings = cfg
app.add_middleware(RequestContextMiddleware)
install_exception_handlers(app)
setup_tracing(app, cfg)
if deployed:
routers = (kb.router, rules.router, assets.router, gaps.router, users.router, stats.router)
for router in routers:
app.include_router(router, prefix=ADMIN_API_PREFIX)
else:
logger.warning(
"admin_routes_disabled",
reason="ADMIN_TOKEN 为空:全部 admin 端点不注册(等价未部署)",
)
return app