Files
hunjing/backend/app/main.py
T
chenxin 34c481ab9e ✨ feat: WP-13 市场与交易——不可变账本、退款、Webhook 与保全态(ADR-009/021)
- 迁移 11:listing、order(六态 + 幂等唯一约束)、order_item(价格快照,客户端金额不可信)、ledger_entry(不可变 8 类型带符号分录)、webhook_event(Provider 事件 ID 幂等)、personal_domain.billing_status(保全态)
- 购买闭环:下单冻结价格快照 → 支付确认同事务写三分录(charge = platform_fee 10% + creator_payable,双录平衡校验拒绝不平衡提交)
- 退款:反向三条分录修正账本(Ledger 不删不改,ADR-009);重复退款幂等;汇总端点对账 balanced=true
- Webhook:HMAC-SHA256 验签(密钥经环境变量,错签 401)→ 按 Provider 事件 ID 幂等(重复投递 duplicate 不重复入账)→ 买方从订单反查(不信任 payload)
- 保全态:欠费只读保全(全部状态变更 403 且明示不删数据;解除端点不被保全自锁);读取不受影响,恢复即解锁——ADR-021 落地
- 测试 72 项全绿(+5):双录平衡、订单幂等、退款反向与对账、验签/幂等、保全只读与恢复
2026-09-11 11:37:45 +08:00

54 lines
1.9 KiB
Python

"""FastAPI 应用工厂。"""
from fastapi import FastAPI
from app.auth.routes import router as auth_router
from app.characters.routes import router as characters_router
from app.conversations.routes import message_router, run_router
from app.conversations.routes import router as conversations_router
from app.core.config import get_settings
from app.core.errors import install_error_handlers
from app.core.middleware import RequestContextMiddleware, configure_logging
from app.db.session import init_engine
from app.marketplace.routes import finance_router, webhook_router
from app.marketplace.routes import router as marketplace_router
from app.memories.routes import cycle_router
from app.memories.routes import router as memories_router
from app.tools.routes import calls_router, tools_router
def create_app() -> FastAPI:
settings = get_settings()
configure_logging(settings.log_level)
app = FastAPI(
title="Hunjing API",
version="0.1.0",
# 公共契约位于 docs/contracts 与 openapi/;本服务 docs 仅供开发调试。
docs_url="/_dev/docs",
openapi_url="/_dev/openapi.json",
)
install_error_handlers(app)
init_engine(app)
app.add_middleware(RequestContextMiddleware)
app.include_router(auth_router)
app.include_router(conversations_router)
app.include_router(run_router)
app.include_router(message_router)
app.include_router(cycle_router) # 先于 characters:避免通配生命周期路由拦截
app.include_router(characters_router)
app.include_router(memories_router)
app.include_router(tools_router)
app.include_router(calls_router)
app.include_router(marketplace_router)
app.include_router(finance_router)
app.include_router(webhook_router)
@app.get("/healthz", tags=["ops"])
async def healthz() -> dict[str, str]:
return {"status": "ok", "env": settings.env}
return app
app = create_app()