上线版: 产品表单统一+form嵌套修复+用户管理+部署+三套叙事

- 产品编辑入口统一走 ProductFormFull(卖点/风格/人群/品牌词全字段);
  修复开任务页 <form> 套 <form> 致"编辑产品"报错、改不了、跳回首个产品
- dashboard 入口卡片对齐实际路由: 系统管理(/config) 与 工作配置(/settings) 分开;
  settings ?tab=products 直达改用挂载后读 URL, 消除 hydration mismatch
- 新增用户管理(users API/admin service/改密页) + alembic 022/023/024
- 上线部署: Dockerfile / docker-compose.prod+https / nginx https / .env.example
- A8 三套正交叙事(痛点/场景/成分背书) + beige 调色去AI化 + 飞轮 text_import 高权重信号

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
yangqianqian
2026-06-30 18:08:13 +08:00
parent a77212781c
commit df1856d793
150 changed files with 8616 additions and 1765 deletions

View File

@@ -18,6 +18,22 @@ logger = logging.getLogger(__name__)
settings = get_settings()
def _cors_origins() -> list[str]:
origins = [
item.strip()
for item in (settings.CORS_ALLOW_ORIGINS or "").split(",")
if item.strip()
]
if settings.APP_ENV == "production":
return [origin for origin in origins if origin != "*"]
dev_origins = set(origins or ["http://localhost:3000"])
if "http://localhost:3000" in dev_origins:
dev_origins.add("http://127.0.0.1:3000")
if "http://127.0.0.1:3000" in dev_origins:
dev_origins.add("http://localhost:3000")
return sorted(dev_origins)
def create_app() -> FastAPI:
app = FastAPI(
title="Clover API",
@@ -29,7 +45,7 @@ def create_app() -> FastAPI:
# ── CORS ──────────────────────────────────────────
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 生产环境收窄到前端域名
allow_origins=_cors_origins(),
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
@@ -60,7 +76,7 @@ def create_app() -> FastAPI:
_register_routers(app)
# ── 静态文件G4坑修复图片 /uploads 路由)──────
uploads_dir = os.path.join(os.path.dirname(__file__), "uploads")
uploads_dir = settings.UPLOAD_ABS_ROOT
os.makedirs(uploads_dir, exist_ok=True)
app.mount("/uploads", StaticFiles(directory=uploads_dir), name="uploads")
@@ -69,6 +85,7 @@ def create_app() -> FastAPI:
def _register_routers(app: FastAPI) -> None:
from app.api.v1.auth import router as auth_router
from app.api.v1.users import router as users_router
from app.api.v1.api_keys import router as api_keys_router
from app.api.v1.products import router as products_router
from app.api.v1.product_images import router as product_images_router
@@ -84,6 +101,7 @@ def _register_routers(app: FastAPI) -> None:
prefix = "/api/v1"
app.include_router(auth_router, prefix=prefix)
app.include_router(users_router, prefix=prefix)
app.include_router(api_keys_router, prefix=prefix)
# 导出 router 必须在 products_router 之前:否则 /products/export 被 /products/{product_id} 吞掉
app.include_router(exports_router, prefix=prefix)