From 8303a4fac2f4482b928ab772c973d4689cbe3dcf Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 27 May 2026 11:04:51 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=90=8E=E7=AB=AF=E5=88=86?= =?UTF-8?q?=E5=B1=82=E8=B0=83=E6=95=B4(=E9=9B=86=E6=88=90=E5=B1=82?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E3=80=81crud=20=E6=94=B9=E5=90=8D)=20+=20?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E5=90=AF=E5=8A=A8=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - core 拆分: 极光/美团/短信三个外部集成从 core/ 迁出到新建的 integrations/, core/ 仅保留 config/security/logging 等基础设施 - crud/ 改名 repositories/; auth.py 中模块别名 crud_user -> user_repo - 同步更新 app/api/v1/{auth,meituan}.py 的 import 路径 - 新增 run.sh: 本地开发启动脚本(校验 .env、alembic upgrade 建表、uvicorn 监听 0.0.0.0:8770) - .gitignore 忽略 *.log, 避免 run.sh 运行日志入库 Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 3 +++ app/api/v1/auth.py | 12 ++++++------ app/api/v1/meituan.py | 2 +- app/{crud => integrations}/__init__.py | 0 app/{core => integrations}/jiguang.py | 0 app/{core => integrations}/meituan.py | 0 app/{core => integrations}/sms.py | 0 app/repositories/__init__.py | 0 app/{crud => repositories}/user.py | 0 run.sh | 18 ++++++++++++++++++ 10 files changed, 28 insertions(+), 7 deletions(-) rename app/{crud => integrations}/__init__.py (100%) rename app/{core => integrations}/jiguang.py (100%) rename app/{core => integrations}/meituan.py (100%) rename app/{core => integrations}/sms.py (100%) create mode 100644 app/repositories/__init__.py rename app/{crud => repositories}/user.py (100%) create mode 100755 run.sh diff --git a/.gitignore b/.gitignore index 4285625..eaf4bc3 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ secrets/* .idea/ .vscode/ *.swp + +# 运行日志(run.sh 输出, 不入库) +*.log diff --git a/app/api/v1/auth.py b/app/api/v1/auth.py index 294ca77..ed7e4b6 100644 --- a/app/api/v1/auth.py +++ b/app/api/v1/auth.py @@ -15,10 +15,10 @@ import logging from fastapi import APIRouter, HTTPException, status from app.api.deps import CurrentUser, DbSession -from app.core.jiguang import JiguangError, mask_phone, verify_and_get_phone from app.core.security import TokenError, decode_token, issue_token_pair -from app.core.sms import SmsError, send_code, verify_code -from app.crud import user as crud_user +from app.integrations.jiguang import JiguangError, mask_phone, verify_and_get_phone +from app.integrations.sms import SmsError, send_code, verify_code +from app.repositories import user as user_repo from app.schemas.auth import ( JverifyLoginRequest, LogoutResponse, @@ -61,7 +61,7 @@ def jverify_login(req: JverifyLoginRequest, db: DbSession) -> TokenWithUser: logger.error("[JG] verify+decrypt failed: %s", e, exc_info=True) raise HTTPException(status_code=502, detail=f"jiguang verify failed: {e}") from e - user = crud_user.upsert_user_for_login(db, phone=phone, register_channel="jverify") + user = user_repo.upsert_user_for_login(db, phone=phone, register_channel="jverify") if user.status != "active": raise HTTPException(status_code=403, detail="account disabled") @@ -88,7 +88,7 @@ def sms_login(req: SmsLoginRequest, db: DbSession) -> TokenWithUser: if not verify_code(req.phone, req.code): raise HTTPException(status_code=400, detail="invalid sms code") - user = crud_user.upsert_user_for_login(db, phone=req.phone, register_channel="sms") + user = user_repo.upsert_user_for_login(db, phone=req.phone, register_channel="sms") if user.status != "active": raise HTTPException(status_code=403, detail="account disabled") @@ -106,7 +106,7 @@ def refresh(req: RefreshRequest, db: DbSession) -> TokenPair: raise HTTPException(status_code=401, detail=str(e)) from e user_id = int(payload["sub"]) - user = crud_user.get_user_by_id(db, user_id) + user = user_repo.get_user_by_id(db, user_id) if user is None or user.status != "active": raise HTTPException(status_code=401, detail="user not found or disabled") diff --git a/app/api/v1/meituan.py b/app/api/v1/meituan.py index a24364a..4d56b73 100644 --- a/app/api/v1/meituan.py +++ b/app/api/v1/meituan.py @@ -9,7 +9,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed from fastapi import APIRouter, HTTPException -from app.core.meituan import MeituanCpsError, get_referral_link, query_coupon +from app.integrations.meituan import MeituanCpsError, get_referral_link, query_coupon from app.schemas.meituan import ( CouponCard, CouponListRequest, diff --git a/app/crud/__init__.py b/app/integrations/__init__.py similarity index 100% rename from app/crud/__init__.py rename to app/integrations/__init__.py diff --git a/app/core/jiguang.py b/app/integrations/jiguang.py similarity index 100% rename from app/core/jiguang.py rename to app/integrations/jiguang.py diff --git a/app/core/meituan.py b/app/integrations/meituan.py similarity index 100% rename from app/core/meituan.py rename to app/integrations/meituan.py diff --git a/app/core/sms.py b/app/integrations/sms.py similarity index 100% rename from app/core/sms.py rename to app/integrations/sms.py diff --git a/app/repositories/__init__.py b/app/repositories/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/crud/user.py b/app/repositories/user.py similarity index 100% rename from app/crud/user.py rename to app/repositories/user.py diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..bc00fe8 --- /dev/null +++ b/run.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# 本地开发启动脚本:监听 0.0.0.0(真机局域网 / adb reverse 都能连),改代码自动重启。 +# +# 前置(首次):先激活装好依赖的环境,例如: +# conda activate price && pip install -e . +# 真机联调流程见前台 local.properties 的 debug.api.host。 +set -e +cd "$(dirname "$0")" + +if [ ! -f .env ]; then + echo "❌ 缺 .env:先 cp .env.example .env 并填值(至少 JWT_SECRET_KEY;测美团再填 MT_CPS_*)" + exit 1 +fi + +mkdir -p data # sqlite 文件所在目录 +alembic upgrade head # 确保表已建(幂等,已是最新则 no-op) + +exec uvicorn app.main:app --host 0.0.0.0 --port 8770 --reload