Reglow 基础库改造与集成 —— 小白实操手册

将 ReglowAdmin 通用后台拆解为基础库(pip/npm 包),供像匠项目直接复用,零重复开发。V0.3.1 版本。

版本:V0.3.1
更新日期:2026-06-29
适用场景:将 ReglowAdmin 通用后台拆解为基础库(pip/npm 包),供像匠(xiangjiang_project)直接复用,零重复开发。

V0.3.1 修正:对齐 Reglow 实际代码(coding/backend-python/main.py 与各模块 router.py),更正虚构的「三端 Router」约定为实际的「单 router + 可选 client_router」模式;用户端路由前缀更正为 /api/v1(非 /app/api/v1);store 模块示例改为 Controller 显式构造 Service 的依赖注入风格;补 dependencies_client.pysvg.path>=7.0、菜单 icon 用 @radix-icons/vue 组件引用等遗漏点。


写在前面:一个大白话故事

┌──────────────────────────────────────────────────────┐
│                                                      │
│  就像麦当劳开分店:                                    │
│                                                      │
│  总部研发了炸鸡配方、收银系统、排班制度……                │
│  (这些 = Reglow 基础库:登录、权限、菜单、日志、素材)   │
│                                                      │
│  每家分店不用重新发明炸鸡,直接拿总部配方用。              │
│  分店自己只需要操心——当地特色菜、促销活动、装修风格。      │
│  (这些 = 像匠独有业务:门店管理、订单系统、修图工作台)    │
│                                                      │
│  总部升级配方 → 所有分店自动受用,炸鸡口味保持一致。       │
│                                                      │
└──────────────────────────────────────────────────────┘

核心思想就一句话:

Reglow 基础库 = 麦当劳总部配方和运营系统。像匠后台 = 一家照相馆主题的麦当劳。系统直接复用,只建照相馆业务页面。

像匠不需要从零搭建后台界面。ReglowAdmin 的布局框架、组件库、登录页、用户管理页等全部可以直接复用。


目录

  1. 理解 ReglowAdmin:它到底提供了什么
  2. 改造总览:一张图看懂拆与合
  3. Backend:后端改造手把手
  4. Frontend:前端改造手把手
  5. 像匠开发实战:怎么最快上手
  6. 像匠后台需要写什么、不用写什么
  7. 对 Reglow 自身的影响
  8. 版本升级:怎么升得科学又不踩坑
  9. 日常开发工作流
  10. 十条铁律:记住了就不会走偏

一、理解 ReglowAdmin:它到底提供了什么

1.1 产品定位

ReglowAdmin 是一个架构先行的通用后台基座,不是简单的 CRUD 生成器。它遵循 5 条设计心法(来自 likeadmin 经验总结):

心法要义大白话
心法① 目录按模块分高内聚低耦合一个功能的所有代码放一个文件夹,别撒得到处都是
心法② 每层只做自己的事单一职责Controller 不写业务,Service 不写 SQL,Model 纯定义
心法③ 依赖注入替代 new控制反转不用自己 new 对象,框架自动给你组装好,测试时轻松换假数据
心法④ 声明式验证类型即文档Schema 定义好字段类型和规则,数据自动校验,Swagger 自动生成
心法⑤ 横切关注点下沉业务代码零污染租户/日志/权限交给中间件,业务代码只管写业务

1.2 架构分层:五层分工

请求进来
    ↓
┌──────────────────────────────┐
│  Controller(前台接待)        │  ← 只做三件事:接参数 → 调 Service → 返回响应
│  薄得像纸,零业务逻辑           │
├──────────────────────────────┤
│  Schema(安检门)              │  ← 声明输入输出的形状,脏数据止于此
│  类型即验证,类型即文档         │
├──────────────────────────────┤
│  Service(掌勺大厨)           │  ← 业务规则、流程编排、事务管理(核心大脑)
│  只管 raise 异常,不管怎么返回  │
├──────────────────────────────┤
│  Repository(仓库管理员)       │  ← 数据存取、查询封装、分页、数据权限
│  只跟数据库打交道,不碰业务      │
├──────────────────────────────┤
│  Model(食材规格书)            │  ← 纯表结构定义,零逻辑,10~20 行
│  换数据库只改 Repository       │
└──────────────────────────────┘

类比奶茶店:

  • Controller = 收银员(接单、传单、出餐)
  • Schema = 菜单模板(顾客只能点菜单上有的)
  • Service = 掌勺大厨(决定奶茶怎么做,配方在这)
  • Repository = 仓库管理员(管茶叶、奶精、珍珠,只负责取放)
  • Model = 食材规格书(珍珠直径 8mm,奶精保质期 7 天)

1.3 多端入口分离:管理端与用户端物理隔离

ReglowAdmin 采用 Router 分包 策略,两端独立路由树、独立鉴权链(基于实际 main.py 实现):

ReglowAdmin FastAPI App
│
├── /admin/api/v1/    ← 管理后台端(Web 后台)
│   └── 完整 CRUD + RBAC 权限 + 全字段
│   └── 鉴权:get_current_employee + PermissionChecker
│
├── /api/v1/          ← 用户端(App / 小程序 / H5 / 客服端)
│   └── 只读为主 + 微信/手机号登录 + 脱敏字段
│   └── 鉴权:get_current_client_user(在 core/dependencies_client.py)
│
└── /health           ← 健康检查(无需认证)

关于「开放接口端(Open API)」:当前 ReglowAdmin 尚未实现 /open/api/v1 第三方对接端。若像匠需要对接外部系统,作为 P3 阶段扩展,在 main.py 中追加 open_api = APIRouter(prefix="/open/api/v1") 即可,参考下方对比表预留设计。

两端隔离对比(含 Open API 预留设计):

维度Admin APIClient API(实际)Open API(预留)
路由前缀/admin/api/v1/api/v1/open/api/v1
认证方式JWT(账号密码)JWT(手机号/微信)API Key / OAuth2
权限RBAC(菜单+按钮+数据)本人数据ACL 按 Key 授权
限流600次/分钟120次/分钟60次/分钟
敏感字段全返回脱敏掩码 138****1234
内容过滤全状态仅已发布仅已发布
Token 有效期2h + 7d7d + 30d永久(可吊销)
依赖文件core/dependencies.pycore/dependencies_client.py待新建

1.4 权限体系:三维一体

┌──────────────────────────────────────────┐
│  操作权限(RBAC)                          │
│  用户 → 角色 → 菜单/按钮权限               │
│  声明式:@router.get(...,                   │
│    dependencies=[PermissionChecker(         │
│      "admin:list")])                        │
├──────────────────────────────────────────┤
│  数据权限(行级过滤)                       │
│  全部/本部门及以下/本部门/本人/自定义         │
│  Repository 层自动加 WHERE 过滤             │
├──────────────────────────────────────────┤
│  多租户(P3 扩展)                          │
│  中间件自动提取 tenant_id                    │
│  Repository 自动加 WHERE tenant_id = ?      │
│  Service 层完全无感                         │
└──────────────────────────────────────────┘

1.5 ReglowAdmin 现有功能模块一览

┌──────────────────────────────────────────────┐
│              ReglowAdmin 通用后台             │
├──────────────────────────────────────────────┤
│                                              │
│  P0 核心必做                                  │
│  ├── 认证登录(账号密码 + 验证码 + 短信登录)    │
│  ├── 管理员管理(CRUD + 部门 + 岗位 + 工号)    │
│  ├── 角色管理(CRUD + 权限分配)               │
│  ├── 菜单管理(树形结构 + 按钮权限)            │
│  ├── 部门管理(树形组织架构)                   │
│  ├── 字典管理(枚举/下拉统一维护)              │
│  ├── 系统设置(短信/存储/备案信息)             │
│  └── 操作日志(变更前后快照)                   │
│                                              │
│  P1 重要                                      │
│  ├── 岗位管理                                 │
│  ├── 素材中心(图片/视频上传 + 生命周期清理)     │
│  ├── 数据权限(行级过滤)                       │
│  └── 代码生成器(一键生成模块)                 │
│                                              │
│  P2-P3 增强                                   │
│  ├── 通知公告                                 │
│  ├── 文章管理                                 │
│  ├── 照片/视频/相册管理                        │
│  ├── AI 生成(图片+视频)                       │
│  ├── 智能客服                                 │
│  ├── 消息模板                                 │
│  └── 多租户                                   │
│                                              │
└──────────────────────────────────────────────┘

二、改造总览:一张图看懂拆与合

改造前(现在):                      改造后(目标):

reglow_project/                     reglow_project/
├── coding/                         ├── reglow/          ← 📦 Python 基础库
│   ├── backend-python/             │   ├── core/              pip install reglow
│   │   ├── core/                   │   ├── common/
│   │   ├── common/                 │   └── modules/
│   │   ├── modules/                │       ├── auth/     # 认证(三端 Router)
│   │   └── main.py                 │       ├── employee/ # 管理员
│   └── frontend-admin/             │       ├── user/     # C端用户
│       └── src/                    │       ├── role/     # 角色
│                                   │       ├── menu/     # 菜单
│                                   │       ├── dept/     # 部门
│                                   │       ├── dict/     # 字典
│                                   │       ├── log/      # 日志
│                                   │       ├── config/   # 系统设置
│                                   │       ├── material/ # 素材
│                                   │       ├── notice/   # 通知
│                                   │       └── ...       # 更多
│                                   │
│                                   ├── frontend-reglow/  ← 📦 NPM 基础库
│                                   │   └── src/               @reglow/ui
│                                   │       ├── api/           API 客户端
│                                   │       ├── components/    组件库 reui
│                                   │       └── index.ts       统一导出
│                                   │
│                                   ├── reglow-app/      ← 🚀 Reglow 自己的后台
│                                   │   ├── backend/           from reglow import...
│                                   │   └── frontend/          import from @reglow/ui
│                                   │
│                                   └── pyproject.toml   # 包元信息
│
xiangjiang_project/                xiangjiang_project/
├── PRD/                           ├── PRD/
├── design/                        ├── design/
│                                   │
│                                   ├── backend/          ← 🚀 像匠后端
│                                   │   ├── main.py            from reglow import...
│                                   │   ├── requirements.txt   reglow==0.2.0
│                                   │   └── app/               每个模块自包含(store/, order/...)
│                                   │       ├── store/         门店模块(五层文件)
│                                   │       ├── order/         订单模块(五层文件)
│                                   │       └── ...            更多模块
│                                   │
│                                   └── admin/            ← 🚀 像匠 Web 后台
│                                       ├── package.json       "@reglow/ui": "^0.2.0"
│                                       └── src/pages/         照相馆业务页面

关键关系

@reglow/ui(前端壳+组件)          reglow(后端地基)
        │                              │
        ├── ReglowAdmin 也用它         ├── ReglowAdmin 也用它
        ├── 像匠也用它                  ├── 像匠也用它
        └── 下贤趣也用它                └── 下贤趣也用它

                    ↓
        各自独立部署、独立域名、独立数据库
        但共享同一套代码(基础库)

三、Backend:后端改造手把手

3.1 第一步:创建 pyproject.toml

reglow_project/ 根目录创建:

[build-system]
requires = ["setuptools>=75", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "reglow"
version = "0.2.1"
description = "ReglowAdmin 通用后台管理系统基础库 —— 五层架构 + 三端分离 + 三维权限"
readme = "README.md"
license = {file = "LICENSE"}
requires-python = ">=3.12"
keywords = ["fastapi", "admin", "backend", "rbac", "multi-tenant"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Framework :: FastAPI",
    "Programming Language :: Python :: 3.12",
]

dependencies = [
    "fastapi>=0.115.12",
    "uvicorn[standard]>=0.34.2",
    "sqlalchemy[asyncio]>=2.0.41",
    "aiomysql>=0.2.0",
    "pymysql>=1.1.1",
    "aiosqlite>=0.20.0",
    "email-validator>=2.3.0",
    "pydantic>=2.11.4",
    "pydantic-settings>=2.9.1",
    "python-jose[cryptography]>=3.4.0",
    "bcrypt>=4.3.0",
    "python-multipart>=0.0.20",
    "redis>=5.3.0",
    "alembic>=1.16.1",
    "httpx>=0.28.1",
    "captcha>=0.6.0",
    "pillow>=11.2.1",
    "svg.path>=7.0",
    "boto3>=1.38.8",
    "python-dotenv>=1.1.0",
]

[project.optional-dependencies]
ai = [
    "opencv-python>=4.11.0.86",
    "moviepy>=2.1.2",
    "edge-tts>=6.1.19",
    "pysrt>=1.1.2",
]
dev = [
    "coverage>=7.8.0",
]

[tool.setuptools.packages.find]
include = ["reglow*"]

3.2 第二步:移动目录结构

# 在 reglow_project 根目录执行(PowerShell)

# 创建 reglow 包目录
mkdir reglow\core
mkdir reglow\common
mkdir reglow\common\utils
mkdir reglow\modules

# 用 git mv 移动(保留历史)
git mv coding/backend-python/core/config.py              reglow/core/config.py
git mv coding/backend-python/core/database.py            reglow/core/database.py
git mv coding/backend-python/core/security.py            reglow/core/security.py
git mv coding/backend-python/core/dependencies.py        reglow/core/dependencies.py
git mv coding/backend-python/core/dependencies_client.py reglow/core/dependencies_client.py
git mv coding/backend-python/core/cache.py               reglow/core/cache.py
git mv coding/backend-python/core/redis_client.py        reglow/core/redis_client.py
git mv coding/backend-python/core/redis_keys.py          reglow/core/redis_keys.py
git mv coding/backend-python/core/rate_limit.py          reglow/core/rate_limit.py
git mv coding/backend-python/core/logging_config.py     reglow/core/logging_config.py
git mv coding/backend-python/core/observability.py       reglow/core/observability.py
git mv coding/backend-python/core/sms.py                 reglow/core/sms.py
git mv coding/backend-python/core/__init__.py            reglow/core/__init__.py

git mv coding/backend-python/common/response.py          reglow/common/response.py
git mv coding/backend-python/common/exceptions.py        reglow/common/exceptions.py
git mv coding/backend-python/common/exception_handler.py reglow/common/exception_handler.py
git mv coding/backend-python/common/middleware.py        reglow/common/middleware.py
git mv coding/backend-python/common/i18n.py              reglow/common/i18n.py
git mv coding/backend-python/common/utils/               reglow/common/utils/
git mv coding/backend-python/common/__init__.py          reglow/common/__init__.py

# 逐个模块移动
git mv coding/backend-python/modules/auth             reglow/modules/auth
git mv coding/backend-python/modules/user             reglow/modules/user
git mv coding/backend-python/modules/employee         reglow/modules/employee
git mv coding/backend-python/modules/role             reglow/modules/role
git mv coding/backend-python/modules/menu             reglow/modules/menu
git mv coding/backend-python/modules/dept             reglow/modules/dept
git mv coding/backend-python/modules/post             reglow/modules/post
git mv coding/backend-python/modules/dict             reglow/modules/dict
git mv coding/backend-python/modules/config           reglow/modules/config
git mv coding/backend-python/modules/log              reglow/modules/log
git mv coding/backend-python/modules/material         reglow/modules/material
git mv coding/backend-python/modules/notice           reglow/modules/notice
git mv coding/backend-python/modules/message          reglow/modules/message
git mv coding/backend-python/modules/article          reglow/modules/article
git mv coding/backend-python/modules/photo            reglow/modules/photo
git mv coding/backend-python/modules/video            reglow/modules/video
git mv coding/backend-python/modules/album            reglow/modules/album
git mv coding/backend-python/modules/ai               reglow/modules/ai
git mv coding/backend-python/modules/agreement        reglow/modules/agreement
git mv coding/backend-python/modules/customer_service reglow/modules/customer_service
git mv coding/backend-python/modules/__init__.py      reglow/modules/__init__.py

3.3 第三步:批量修正内部 import

改造后,reglow 包内部代码的 import 全部从 from core.xxx 改成 from reglow.core.xxx

旧写法新写法
from core.config import get_settingsfrom reglow.core.config import get_settings
from core.database import get_db, Basefrom reglow.core.database import get_db, Base
from core.security import verify_tokenfrom reglow.core.security import verify_token
from core.dependencies import get_current_employeefrom reglow.core.dependencies import get_current_employee
from core.dependencies_client import get_current_client_userfrom reglow.core.dependencies_client import get_current_client_user
from common.response import ApiResponsefrom reglow.common.response import ApiResponse
from common.exceptions import AppExceptionfrom reglow.common.exceptions import AppException
from modules.xxx.model import ...from reglow.modules.xxx.model import ...

操作技巧:在 VS Code 中,用「全局搜索替换」(Ctrl+Shift+H),正则模式:

  • from core\.from reglow.core.
  • from common\.from reglow.common.
  • from modules\.from reglow.modules.

只替换 reglow/ 目录下的文件。

注意core/dependencies_client.py 是用户端鉴权入口(导出 get_current_client_user),不要漏移;否则 modules/*/controller_client.py 会全部 import 报错。

3.4 第四步:模块 Router 的真实约定

改造后每个模块的 router.py 只导出一个主 router(管理端用),如需用户端再追加 client_router。命名遵循实际代码约定,不要臆造 admin_router / app_router / open_router 三件套。

# reglow/modules/article/router.py(实际代码)
from .controller import router
__all__ = ["router"]
# reglow/modules/user/router.py(同时有管理端 + 用户端的模块)
from .controller import router
from .controller_client import client_router
__all__ = ["router", "client_router"]
# reglow/modules/material/router.py(一个模块拆出多个 router)
from .controller import router, group_router
__all__ = ["router", "group_router"]

Controller 内部怎么写(以 Article 为例,对齐真实代码)

# reglow/modules/article/controller.py
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession

from .model import Article, ArticleCollection
from .schema import CreateArticleRequest, UpdateArticleRequest, ArticleResponse, ...
from .service import ArticleService
from common.response import ApiResponse, PageData
from core.database import get_db
from core.dependencies import PermissionChecker, get_current_employee

# 关键:模块自己在 APIRouter 上声明 prefix + tags
# 不要靠 main.py 的 include_router(..., prefix=...) 补,否则路径散落两处
router = APIRouter(prefix="/articles", tags=["文章管理"])

@router.get(
    "/",
    response_model=ApiResponse[PageData[ArticleResponse]],
    dependencies=[Depends(PermissionChecker("content:article:list"))],
)
async def list_articles(
    page: int = Query(1, ge=1),
    size: int = Query(10, ge=1, le=100),
    keyword: str | None = Query(None),
    db: AsyncSession = Depends(get_db),
):
    service = ArticleService(db)              # Service 显式接收 db
    items, total = await service.list_articles(page, size, keyword)
    return ApiResponse.success(PageData(items=items, total=total, page=page, size=size))

用户端怎么挂(参考 modules/user/controller_client.py 模式)

# reglow/modules/article/controller_client.py(像匠需要时新建)
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from .schema import ArticleResponse
from .service import ArticleService
from common.response import ApiResponse, PageData
from core.database import get_db
from core.dependencies_client import get_current_client_user   # 用户端鉴权

client_router = APIRouter(prefix="/articles", tags=["文章-用户端"])

@client_router.get("/", response_model=ApiResponse[PageData[ArticleResponse]])
async def list_published_articles(
    page: int = Query(1, ge=1),
    size: int = Query(10, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    _user=Depends(get_current_client_user),
):
    service = ArticleService(db)
    # Service 内部强制过滤 status=published,只返回已发布
    items, total = await service.list_published(page, size)
    return ApiResponse.success(PageData(items=items, total=total, page=page, size=size))

重要约定

  1. 管理端主 Router 变量名固定为 router(不要叫 admin_router)。
  2. 用户端 Router 变量名固定为 client_router(不要叫 app_router)。
  3. prefix 在模块内部 APIRouter(...) 上声明,不靠 main.pyinclude_router(prefix=...) 补,避免路径散落两处。
  4. 额外子 Router(如 material.group_routermessage.inbox_router)按需追加,命名见仁见智但要在 router.py 中显式 __all__ 暴露。

3.5 本地开发安装方式

# 在像匠项目的虚拟环境中(开发期)
cd d:\Huolidev\xiangjiang_project\backend
.venv\Scripts\activate

# 方式一:本地可编辑安装(推荐,改 reglow 代码即时生效)
pip install -e "d:\Huolidev\reglow_project"

# 方式二:从 Git 安装(正式版本)
pip install "git+https://git.xxx.com/reglow_project.git@v0.2.1"

# 带 AI 模块一起装
pip install -e "d:\Huolidev\reglow_project[ai]"

四、Frontend:前端改造手把手

4.1 建立 @reglow/ui npm 包

reglow_project/coding/frontend-admin/ 下改造:

// reglow_project/frontend-reglow/package.json
{
  "name": "@reglow/ui",
  "version": "0.2.1",
  "description": "ReglowAdmin 通用后台管理系统前端组件库 —— 布局框架 + reui 组件 + 通用页面",
  "type": "module",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "files": ["dist"],
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  },
  "peerDependencies": {
    "vue": "^3.5",
    "@radix-icons/vue": "^1.0",
    "@tanstack/vue-table": "^8.0"
  },
  "scripts": {
    "build": "vite build",
    "dev": "vite build --watch"
  }
}

4.2 统一导出入口

// frontend-reglow/src/index.ts —— 统一导出,一个 import 拿全部

// ─── API 客户端 ───
export { apiClient, setAuthToken, clearAuthToken } from "./api/client";
export * from "./api/index";

// ─── 布局框架(壳) ───
export { default as AdminLayout } from "./components/layout/AdminLayout.vue";
export { SidebarTree } from "./components/layout/SidebarTree.vue";
export { HeaderActions } from "./components/layout/HeaderActions.vue";
export { BreadcrumbNav } from "./components/layout/BreadcrumbNav.vue";
export { TabBar } from "./components/layout/TabBar.vue";
export { NoticeBell } from "./components/layout/NoticeBell.vue";
export { GlobalAiSidebar } from "./components/layout/GlobalAiSidebar.vue";

// ─── 通用页面(直接拿来用) ───
export { default as LoginPage } from "./pages/auth/LoginPage.vue";
export { default as RegisterPage } from "./pages/auth/RegisterPage.vue";
export { default as UserManagePage } from "./pages/user/UserManagePage.vue";
export { default as RoleManagePage } from "./pages/role/RoleManagePage.vue";
export { default as MenuManagePage } from "./pages/menu/MenuManagePage.vue";
export { default as DeptManagePage } from "./pages/dept/DeptManagePage.vue";
export { default as DictManagePage } from "./pages/dict/DictManagePage.vue";
export { default as SystemSettingsPage } from "./pages/config/SystemSettingsPage.vue";
export { default as OperationLogPage } from "./pages/log/OperationLogPage.vue";
export { default as MaterialCenterPage } from "./pages/material/MaterialCenterPage.vue";
export { default as NoticeManagePage } from "./pages/notice/NoticeManagePage.vue";

// ─── reui 组件库(表格/表单/弹窗/上传/编辑器...) ───
export * from "./components/reui/table";
export * from "./components/reui/form";
export * from "./components/reui/dialog";
export * from "./components/reui/drawer";
export * from "./components/reui/editor";
export * from "./components/reui/image-viewer";
export * from "./components/reui/date-picker";
export * from "./components/reui/notification";
export { default as ImageUploader } from "./components/common/ImageUploader.vue";
export { default as AvatarUploader } from "./components/common/AvatarUploader.vue";

// ─── 通用工具 ───
export { usePermission } from "./composables/usePermission";
export { useAuth } from "./composables/useAuth";

4.3 像匠前端如何安装

# 在像匠 Web 后台项目
cd d:\Huolidev\xiangjiang_project\admin
npm install "git+https://git.xxx.com/reglow_project.git#v0.2.1"

# 或本地开发联调
npm install "d:\Huolidev\reglow_project\frontend-reglow"

五、像匠开发实战:怎么最快上手

5.1 Backend:像匠的 main.py

对齐 Reglow 实际 main.py 风格:所有 Router 用 APIRouter(prefix=...) 在各自模块内声明 prefix,main.py 只负责挂载和组装,不重复声明 prefix

"""
像匠(XiangJiang)O2O 影像服务平台
基于 Reglow 基础库,零重复开发通用后台功能
"""
from contextlib import asynccontextmanager
from fastapi import FastAPI, APIRouter
from sqlalchemy.ext.asyncio import AsyncSession

from reglow.common.middleware import register_middlewares
from reglow.common.exception_handler import register_exception_handlers
from reglow.core.logging_config import setup_logging
from reglow.core.config import get_settings
from reglow.core.database import get_db
from reglow.core.observability import register_observability_routes

settings = get_settings()


@asynccontextmanager
async def lifespan(app: FastAPI):
    # 启动:连接池预热、Redis 连接、定时任务等
    yield
    # 关闭:清理资源


# ─── 从 reglow 直接引入:不需要写一行代码 ───
# 每个模块都导出主 `router`(管理端),命名统一为 `router`
# 个别模块需要用户端时再追加 `client_router` / `public_router` / `inbox_router` / `group_router` 等
from reglow.modules.auth.router import router as auth_router
from reglow.modules.employee.router import router as employee_router
from reglow.modules.user.router import router as user_router
from reglow.modules.role.router import router as role_router
from reglow.modules.menu.router import router as menu_router
from reglow.modules.dept.router import router as dept_router
from reglow.modules.post.router import router as post_router
from reglow.modules.dict.router import router as dict_router
from reglow.modules.config.router import router as config_router, settings_router
from reglow.modules.log.router import router as log_router
from reglow.modules.material.router import router as material_router, group_router as material_group_router
from reglow.modules.agreement.router import router as agreement_router, public_router as agreement_public_router
from reglow.modules.notice.router import router as notice_router
from reglow.modules.message.router import router as message_router, inbox_router
from reglow.modules.article.router import router as article_router
from reglow.modules.ai.router import router as ai_router
from reglow.modules.photo.router import router as photo_router
from reglow.modules.video.router import router as video_router
from reglow.modules.customer_service.router import (
    admin_router as cs_admin_router,
    client_router as cs_client_router,
)

# ─── 像匠独有业务路由(每个模块自包含,从 controller.py 导入 router) ───
from app.store.controller import router as store_router
from app.order.controller import router as order_router
from app.retouch.controller import router as retouch_router
from app.product.controller import router as product_router
from app.reservation.controller import router as reservation_router
from app.finance.controller import router as finance_router
from app.marketing.controller import router as marketing_router


def create_app() -> FastAPI:
    app = FastAPI(
        title="像匠 API",
        version="0.1.0",
        lifespan=lifespan,
        docs_url="/docs" if settings.DEBUG else None,
        redoc_url="/redoc" if settings.DEBUG else None,
    )

    register_middlewares(app)
    register_exception_handlers(app)

    # ========================================
    # Admin API —— 管理后台端 /admin/api/v1
    # ========================================
    # 注意:所有 prefix 都在模块内部 APIRouter(...) 上声明
    # 这里只在 admin_api 上声明顶层前缀,include_router 不再传 prefix
    admin_api = APIRouter(prefix="/admin/api/v1")

    # ─── Reglow 通用模块(开箱即用,一行不写) ───
    admin_api.include_router(auth_router,             tags=["认证"])
    admin_api.include_router(employee_router,          tags=["管理员"])
    admin_api.include_router(user_router,              tags=["用户"])
    admin_api.include_router(role_router,             tags=["角色"])
    admin_api.include_router(menu_router,             tags=["菜单"])
    admin_api.include_router(dept_router,             tags=["部门"])
    admin_api.include_router(post_router,             tags=["岗位"])
    admin_api.include_router(dict_router,             tags=["字典"])
    admin_api.include_router(config_router,           tags=["参数配置"])
    admin_api.include_router(settings_router,         tags=["系统设置"])
    admin_api.include_router(log_router,              tags=["操作日志"])
    admin_api.include_router(material_router,         tags=["素材管理"])
    admin_api.include_router(material_group_router,   tags=["素材分组"])
    admin_api.include_router(agreement_router,        tags=["协议管理"])
    admin_api.include_router(agreement_public_router, tags=["协议(公开)"])
    admin_api.include_router(notice_router,            tags=["通知公告"])
    admin_api.include_router(message_router,           tags=["系统消息"])
    admin_api.include_router(inbox_router,             tags=["收件箱"])
    admin_api.include_router(article_router,          tags=["文章管理"])
    admin_api.include_router(ai_router,                tags=["AI"])
    admin_api.include_router(photo_router,            tags=["照片管理"])
    admin_api.include_router(video_router,            tags=["视频管理"])
    admin_api.include_router(cs_admin_router,        tags=["智能客服"])

    # ─── 像匠独有业务路由(你写的,同样在模块内声明 prefix) ───
    admin_api.include_router(store_router,       tags=["门店"])
    admin_api.include_router(order_router,       tags=["订单"])
    admin_api.include_router(retouch_router,     tags=["修图"])
    admin_api.include_router(product_router,      tags=["产品"])
    admin_api.include_router(reservation_router, tags=["预约"])
    admin_api.include_router(finance_router,     tags=["财务"])
    admin_api.include_router(marketing_router,   tags=["营销"])

    app.include_router(admin_api)

    # ========================================
    # Client API —— 用户端 /api/v1(C 端 App / 小程序 / H5)
    # ========================================
    client_api = APIRouter(prefix="/api/v1")
    client_api.include_router(cs_client_router)   # 客服端
    # 像匠自己有 C 端业务时(如门店预约、订单查询),在这里 include_router
    # 例如:client_api.include_router(xj_reservation_client_router)
    app.include_router(client_api)

    # 健康检查 + 观测
    @app.get("/health")
    async def health():
        return {"status": "ok", "service": "xiangjiang", "version": "0.1.0"}

    register_observability_routes(app)

    # 静态文件(上传目录)
    from fastapi.staticfiles import StaticFiles
    import os
    os.makedirs(settings.UPLOAD_DIR, exist_ok=True)
    app.mount("/uploads", StaticFiles(directory=settings.UPLOAD_DIR), name="uploads")

    return app


app = create_app()

关键差异 vs 改造前的旧写法

旧写法(错误的)新写法(对齐实际 reglow)
from reglow.modules.auth.router import admin_routerfrom reglow.modules.auth.router import router
admin_app.include_router(auth_router, prefix="/auth")admin_api.include_router(auth_router, tags=["认证"])
app.mount("/admin/api/v1", admin_app) 用 sub-app 挂载app.include_router(admin_api) 用 APIRouter 合并

include_router + 顶层 prefix 而非 app.mount,所有路由在同一个 FastAPI 实例下,OpenAPI 文档统一生成,CORS / 中间件只配置一次。

5.2 Backend:像匠的业务模块怎么写

以「门店管理」为例,完全遵循 Reglow 的五层架构。所有文件都在 app/store/ 一个目录内。

依赖注入模式(对齐 Reglow 实际代码)

  • Controller 层用 Depends(get_db) 注入 AsyncSession,再显式构造 Serviceservice = StoreService(db)
  • Service不依赖 FastAPI 的 Depends(),构造函数直接接收 db: AsyncSession(也可以接收 Repository)。
  • Repository 层同样接收 db: AsyncSession,由 Service 构造或 Service 内部使用。

这样 Service / Repository 是纯 Python 类,可以脱离 FastAPI 在单元测试里直接 StoreService(fake_db) 构造,符合心法③「依赖注入」。

# ============= app/store/model.py =============
# 食材规格书:纯表结构定义,零逻辑
from sqlalchemy import String, Integer, Float, Text
from sqlalchemy.orm import Mapped, mapped_column
from reglow.core.database import AutoBigInt, Base, TimestampMixin


class Store(Base, TimestampMixin):
    __tablename__ = "xj_store"

    id: Mapped[int] = mapped_column(AutoBigInt, primary_key=True, autoincrement=True)
    name: Mapped[str] = mapped_column(String(100), comment="门店名称")
    address: Mapped[str] = mapped_column(String(255), comment="详细地址")
    phone: Mapped[str | None] = mapped_column(String(20), comment="联系电话")
    lat: Mapped[float | None] = mapped_column(Float, comment="纬度")
    lng: Mapped[float | None] = mapped_column(Float, comment="经度")
    cover_url: Mapped[str | None] = mapped_column(String(512), comment="封面图")
    business_hours: Mapped[str | None] = mapped_column(String(200), comment="营业时间")
    description: Mapped[str | None] = mapped_column(Text, comment="门店介绍")
    status: Mapped[int] = mapped_column(Integer, default=1, comment="1营业 2休息 3关闭")
    sort: Mapped[int] = mapped_column(Integer, default=0, comment="排序")


# ============= app/store/schema.py =============
# 安检门:声明式验证,类型即文档
from pydantic import BaseModel, Field
from datetime import datetime


class CreateStoreRequest(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    address: str = Field(..., max_length=255)
    phone: str | None = Field(None, pattern=r'^1[3-9]\d{9}$')
    lat: float | None = None
    lng: float | None = None
    business_hours: str | None = None
    description: str | None = None


class UpdateStoreRequest(BaseModel):
    name: str | None = Field(None, min_length=1, max_length=100)
    address: str | None = None
    phone: str | None = None
    business_hours: str | None = None
    description: str | None = None
    status: int | None = None


class StoreResponse(BaseModel):
    id: int
    name: str
    address: str
    phone: str | None
    lat: float | None
    lng: float | None
    cover_url: str | None
    business_hours: str | None
    description: str | None
    status: int
    sort: int
    created_at: datetime

    model_config = {"from_attributes": True}


# ============= app/store/repository.py =============
# 仓库管理员:只跟数据库打交道(接收 db,不依赖 FastAPI Depends)
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from .model import Store


class StoreRepository:
    def __init__(self, db: AsyncSession):
        self.db = db

    async def find_all(self, page: int, size: int, keyword: str | None = None) -> tuple[list[Store], int]:
        query = select(Store)
        count_query = select(func.count()).select_from(Store)
        if keyword:
            query = query.where(Store.name.contains(keyword))
            count_query = count_query.where(Store.name.contains(keyword))
        query = query.order_by(Store.sort).offset((page - 1) * size).limit(size)
        items = (await self.db.execute(query)).scalars().all()
        total = (await self.db.execute(count_query)).scalar()
        return items, total

    async def find_by_id(self, store_id: int) -> Store | None:
        result = await self.db.execute(select(Store).where(Store.id == store_id))
        return result.scalar_one_or_none()

    async def create(self, **kwargs) -> Store:
        store = Store(**kwargs)
        self.db.add(store)
        await self.db.commit()
        await self.db.refresh(store)
        return store

    async def update(self, store: Store, data) -> Store:
        for k, v in data.model_dump(exclude_unset=True).items():
            setattr(store, k, v)
        await self.db.commit()
        await self.db.refresh(store)
        return store

    async def delete(self, store: Store) -> None:
        await self.db.delete(store)
        await self.db.commit()


# ============= app/store/service.py =============
# 掌勺大厨:业务逻辑的归属地(不依赖 FastAPI,便于单测)
from reglow.common.exceptions import AppException
from .repository import StoreRepository


class StoreService:
    def __init__(self, db: AsyncSession):
        # Service 持有 Repository;测试时可换 fake repo
        self.repo = StoreRepository(db)

    async def list_stores(self, page: int, size: int, keyword: str | None = None):
        return await self.repo.find_all(page, size, keyword)

    async def get_store(self, store_id: int) -> Store:
        store = await self.repo.find_by_id(store_id)
        if not store:
            raise AppException(4000, "门店不存在")
        return store

    async def create_store(self, data: CreateStoreRequest) -> Store:
        return await self.repo.create(**data.model_dump())

    async def update_store(self, store_id: int, data: UpdateStoreRequest) -> Store:
        store = await self.get_store(store_id)
        return await self.repo.update(store, data)

    async def delete_store(self, store_id: int) -> None:
        store = await self.get_store(store_id)
        await self.repo.delete(store)


# ============= app/store/controller.py =============
# 前台接待:薄得像纸,只做三件事(接参数 → 调 Service → 返回响应)
# 关键:模块内部声明 prefix + tags,main.py 不再补 prefix
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession

from reglow.core.database import get_db
from reglow.core.dependencies import get_current_employee, PermissionChecker
from reglow.common.response import ApiResponse, PageData
from .schema import CreateStoreRequest, UpdateStoreRequest, StoreResponse
from .service import StoreService

router = APIRouter(
    prefix="/stores",
    tags=["门店管理"],
    dependencies=[Depends(get_current_employee)],  # 整个模块都要求登录
)


@router.get(
    "/",
    response_model=ApiResponse[PageData[StoreResponse]],
    dependencies=[Depends(PermissionChecker("store:list"))],
)
async def list_stores(
    page: int = Query(1, ge=1),
    size: int = Query(10, ge=1, le=100),
    keyword: str | None = Query(None),
    db: AsyncSession = Depends(get_db),
):
    service = StoreService(db)
    items, total = await service.list_stores(page, size, keyword)
    return ApiResponse.success(PageData(items=items, total=total, page=page, size=size))


@router.post(
    "/",
    response_model=ApiResponse[StoreResponse],
    dependencies=[Depends(PermissionChecker("store:create"))],
)
async def create_store(
    data: CreateStoreRequest,
    db: AsyncSession = Depends(get_db),
):
    service = StoreService(db)
    store = await service.create_store(data)
    return ApiResponse.success(store, "门店创建成功")


@router.get("/{store_id}", response_model=ApiResponse[StoreResponse])
async def get_store(store_id: int, db: AsyncSession = Depends(get_db)):
    service = StoreService(db)
    return ApiResponse.success(await service.get_store(store_id))


@router.put(
    "/{store_id}",
    response_model=ApiResponse[StoreResponse],
    dependencies=[Depends(PermissionChecker("store:update"))],
)
async def update_store(
    store_id: int,
    data: UpdateStoreRequest,
    db: AsyncSession = Depends(get_db),
):
    service = StoreService(db)
    return ApiResponse.success(await service.update_store(store_id, data), "更新成功")


@router.delete(
    "/{store_id}",
    response_model=ApiResponse,
    dependencies=[Depends(PermissionChecker("store:delete"))],
)
async def delete_store(store_id: int, db: AsyncSession = Depends(get_db)):
    service = StoreService(db)
    await service.delete_store(store_id)
    return ApiResponse.success(msg="删除成功")

三个关键模式(与 reglow 实际代码一致)

  1. Controller 显式构造 Serviceservice = StoreService(db),而不是 service: StoreService = Depends()。后者也能跑,但 Service 类就被 FastAPI 接管,单测时需要 mock 容器,更复杂。Reglow 现网代码采用前一种简洁写法。
  2. Service 不导 Depends:构造函数 __init__(self, db: AsyncSession) 是纯 Python,不挂 FastAPI 装饰。单测可以直接 StoreService(fake_db)
  3. prefix 在模块内 APIRouter(...) 上声明main.pyinclude_router 不传 prefix,路径只在一处维护。

5.3 像匠项目目录结构总览

重要:业务代码同样遵循心法①「按模块分」。不能因为写的是业务代码就退回按层分。

xiangjiang_project/
├── backend/                             # 🚀 像匠后端
│   ├── .env                             # 环境变量
│   ├── main.py                          # 组装 FastAPI(见 5.1)
│   ├── requirements.txt                 # reglow==0.2.1
│   ├── alembic.ini
│   ├── alembic/versions/                # xj_store, xj_order...迁移脚本
│   └── app/                             # 像匠独有代码(按模块分!)
│       ├── store/                       # 门店模块(自包含)
│       │   ├── model.py                 # xj_store 表定义
│       │   ├── schema.py                # 门店请求/响应声明式验证
│       │   ├── repository.py            # 门店数据访问
│       │   ├── service.py               # 门店业务逻辑
│       │   └── controller.py            # 门店接口(薄薄一层)
│       ├── order/                       # 订单模块
│       │   ├── model.py                 # xj_order
│       │   ├── schema.py
│       │   ├── repository.py
│       │   ├── service.py
│       │   └── controller.py
│       ├── product/                     # 产品/团购模块
│       │   └── ...(同上五层)
│       ├── reservation/                 # 预约模块
│       │   └── ...
│       ├── retouch/                     # 修图模块
│       │   └── ...
│       ├── finance/                     # 财务模块
│       │   └── ...
│       └── marketing/                   # 营销模块
│           └── ...
│
├── admin/                               # 🚀 像匠 Web 后台
│   ├── package.json                     # "@reglow/ui": "^0.2.1"
│   └── src/
│       ├── App.vue                      # 用 @reglow/ui 的 AdminLayout 壳
│       └── pages/                       # 🆕 只有照相馆业务页面
│           ├── store/                   # 门店列表
│           ├── order/                   # 订单管理
│           ├── retouch/                 # 修图工作台
│           ├── product/                 # 产品/团购
│           ├── reservation/             # 预约管理
│           ├── finance/                 # 财务报表
│           └── marketing/               # 营销活动
│
├── PRD/
└── design/

为什么业务代码也要按模块分?

心法①「目录按模块分」是一条通用原则,不看代码是「框架」还是「业务」。只因为它是业务代码就退回按层分,等于前半程走高铁、后半程走土路——快不起来。

你:我要改「订单模块」的状态流转逻辑!

❌ 如果按层分(像匠退回按层):在 5 个目录间跳来跳去

   app/models/order.py
   │   └→ class Order(Base):
   │       __tablename__ = "xj_order"
   │       status = mapped_column(Integer)     ← 改表字段
   │
   app/schemas/order.py
   │   └→ class UpdateOrderStatusRequest       ← 改校验规则
   │
   app/repositories/order.py
   │   └→ class OrderRepository:
   │       async def update_status(...)        ← 改查询
   │
   app/services/order.py
   │   └→ class OrderService:
   │       async def transition_status(...)     ← 改核心逻辑
   │
   app/api/order.py
       └→ @router.put("/{id}/status")          ← 改接口

   5 个文件散落 5 个目录,大脑还得拼一张「订单全景图」
   漏改一个就 Bug — 而且 90% 会漏。
✅ 按模块分:所有订单代码一个目录,秒定位

   app/order/
   ├── model.py          ← 改表
   ├── schema.py         ← 改校验
   ├── repository.py     ← 改查询
   ├── service.py        ← 改核心逻辑(状态机在这!)
   └── controller.py     ← 改接口

   进一个目录,5 个文件一览无余。
   Ctrl+P 搜 "order/service" 直接跳业务核心。

深层原因:

维度按层分按模块分
心智负担5 个目录,脑中拼图1 个目录,所见即所得
改漏风险改 service 忘了改 schema → Bug同目录 5 文件一字排开,不会漏
删模块5 个目录各删 1 个,漏删报错app/order/ 整个文件夹
新人上手「订单代码在哪?」说不清app/order/
拆微服务5 个目录捞文件,拆不动拎出 order/ 一个目录

一句话:代码是给业务服务的,当然按业务组织。不管是框架还是业务,组织原则一视同仁。


六、像匠后台需要写什么、不用写什么

一张表看清

你需要写的 ✅你不需要写的 ❌(@reglow/ui 直接给)
门店管理页(列表/新增/编辑/上下架)登录页(账号密码 + 验证码 + 短信登录)
订单管理页(列表/详情/状态流转)注册页(选部门 + 填信息)
修图工作台(任务分配/处理/交付)管理员管理页(CRUD + 部门 + 岗位)
产品/团购管理页角色权限管理页
预约管理页(日历视图+列表)菜单管理页(树形结构)
财务报表页(营收/对账)部门管理页(组织架构)
营销活动页字典管理页
摄影师管理页(扩展信息)系统设置页(短信/存储/备案)

操作日志页

素材中心(图片/视频上传)

通知公告页
布局框架AdminLayout(侧边栏+顶栏+标签页+面包屑)
照相馆菜单配置reui 组件库(表格/表单/弹窗/上传/编辑器/日期选择器...)

API 客户端(认证拦截+错误处理+请求封装)

像匠 App.vue 示例

<script setup>
import { AdminLayout } from "@reglow/ui";
import {
  StoreIcon,
  ReceiptIcon,
  ImageIcon,
  PackageIcon,
  CalendarIcon,
  ChartBarIcon,
  MegaphoneIcon,
} from "@radix-icons/vue";
// AdminLayout 自带:侧边栏、顶栏、标签页、面包屑、通知铃铛、AI 侧边栏

// 菜单 icon 传组件而非字符串名,避免与 @reglow/ui peerDependencies 中的图标库不匹配
const menus = [
  { name: "门店管理", path: "/stores", icon: StoreIcon },
  { name: "订单管理", path: "/orders", icon: ReceiptIcon },
  { name: "修图工作台", path: "/retouch", icon: ImageIcon },
  { name: "产品管理", path: "/products", icon: PackageIcon },
  { name: "预约管理", path: "/reservations", icon: CalendarIcon },
  { name: "财务报表", path: "/finance", icon: ChartBarIcon },
  { name: "营销活动", path: "/marketing", icon: MegaphoneIcon },
  // ─── 以下是 @reglow/ui 自带的通用页面,直接配路由就行 ───
  { name: "用户管理", path: "/users" },
  { name: "角色权限", path: "/roles" },
  { name: "菜单管理", path: "/menus" },
  { name: "部门管理", path: "/depts" },
  { name: "素材中心", path: "/materials" },
  { name: "系统设置", path: "/settings" },
];
</script>

<template>
  <AdminLayout :menus="menus" app-name="像匠摄影">
    <router-view />
  </AdminLayout>
</template>

图标约定@reglow/uipeerDependencies@radix-icons/vue,所以菜单 icon 传组件引用而非字符串名(如 icon: StoreIcon,而不是 icon: "mdi-store")。否则在像匠项目里要额外安装 mdi 图标库,与基础库脱节。


七、对 Reglow 自身的影响

7.1 Reglow 自己也变成消费者

改造后,ReglowAdmin 自己的 main.py 变得和像匠一样:

# reglow-app/backend/main.py —— ReglowAdmin 也是基础库的使用者
from reglow.core.config import Settings
from reglow.modules.auth.router import admin_router as auth_router
from reglow.modules.employee.router import admin_router as employee_router
# ... 所有模块从 reglow 包导入

app = FastAPI(title="ReglowAdmin")
admin_app = FastAPI(title="ReglowAdmin - Admin API")

admin_app.include_router(auth_router, prefix="/auth")
admin_app.include_router(employee_router, prefix="/employees")
# ... 自己也是组装者
app.mount("/admin/api/v1", admin_app)

好处:Reglow 自己成为基础库的第一个用户。如果自己都用不顺,别人肯定也用不顺——倒逼基础库质量。

7.2 影响一览

维度改造前改造后影响程度
目录位置coding/backend-python/reglow/(核心) + reglow-app/(应用)🟡 中等
import 路径from core.xxxfrom reglow.core.xxx🟡 中等
启动方式python main.pypip install -e . 后同样 python main.py🟢 不变
开发体验改代码即生效-e 可编辑安装,同样即时生效🟢 不变
复用方式只能复制代码pip install reglow🟢 质的飞跃
版本管理没有版本语义化版本 0.2.10.3.01.0.0🟢 新增能力
代码质量耦合边界清晰,基础库修改更谨慎🟢 提升
Git 历史保留git mv,历史完整保留🟢 保留

八、版本升级:怎么升得科学又不踩坑

8.1 版本锁定策略

# ─── 生产环境(推荐) ───
reglow==0.2.1        # 精确锁定,手动升级,稳如泰山

# ─── 开发环境 ───
reglow~=0.2.1        # 允许 patch 升级:>=0.2.1, <0.3.0
                      # Bug 修复自动升,大功能不改

# ─── 不推荐 ───
reglow>=0.2.0        # 啥都自动升,容易炸

8.2 升级标准流程

步骤 1 ─→ 看 CHANGELOG
           └→ Reglow 发新版了,看变了啥
              ├── Bug 修复 → 放心升 ✅
              ├── 新功能 → 看用不用得上,放心升 ✅
              └── ⚠️ Breaking Change → 必须手动适配后再升

步骤 2 ─→ 锁版本升级
           └→ requirements.txt:reglow==0.2.1 → reglow==0.3.0
           └→ pip install -r requirements.txt

步骤 3 ─→ 跑全部测试
           └→ 红灯 = 不能上线,排查原因

步骤 4 ─→ 手动回归
           └→ 登录、增删改查走一遍

步骤 5 ─→ 提交
           └→ git commit -m "chore: 升级 reglow 到 v0.3.0"

8.3 Reglow CHANGELOG 示例

# CHANGELOG

## [0.3.0] - 2026-07-15

### 新增

- `reglow.core.sms` 短信服务模块,支持阿里云/腾讯云/华为云短信
- `material` 模块新增浏览器素材提取器

### 修改

- `get_current_employee` 新增 `require_verified` 参数
- 操作日志增加变更前后快照

### ⚠️ Breaking Changes

- `Employee.superior_id` 类型从 `int` 改为 `int | None`
  → 旧代码如果不处理 None 会报类型错误,请检查所有引用

九、日常开发工作流

9.1 「像匠需要某功能」时怎么做

像匠需要新功能
│
├→ 先看 reglow 有没有
│   ├→ 有 → 直接用 ✅
│   └→ 没有 → 问自己:换一个项目(下贤趣)也需要吗?
│       ├→ 是 → 去 reglow 仓库开发,发新版本
│       └→ 否 → 在像匠自己的 app/ 目录下开发

9.2 本地联调配置

# ============ 终端 1:Reglow 基础库 ============
cd d:\Huolidev\reglow_project
pip install -e .                    # 可编辑模式安装

# ============ 终端 2:像匠后端 ============
cd d:\Huolidev\xiangjiang_project\backend
pip install -r requirements.txt    # 从本地 .venv 读取 reglow
uvicorn main:app --reload

# 现在改 reglow/core/config.py → 像匠即时生效!

9.3 FAQ

Q:像匠的数据库表会跟 Reglow 冲突吗?

A:不会。Reglow 的表统一 sys_ 前缀(sys_employeesys_user...),像匠的业务表用 xj_ 前缀(xj_storexj_order...),泾渭分明。

Q:想改某 Reglow 模块的逻辑怎么办?

A:三种方法,按推荐序:

  1. 继承覆写class XiangJiangAuthService(reglow.modules.auth.AuthService),重写方法
  2. 向 reglow 提 PR:确实通用的改动,合入基础库,所有项目受益
  3. 完全自己写:改动太大,在像匠里独立实现,不用 reglow 的这个模块

Q:Reglow 删除了我依赖的函数?

A:这属于 Breaking Change,必须升 MAJOR 版本号。升级前看 CHANGELOG,适配完再升。

Q:升级后某些接口不通了?

A:先降回旧版本(pip install reglow==旧版本),然后对照 CHANGELOG 排查。不要硬升。


附:十条铁律记住了就不会走偏

#铁律一句话违反后果
1公共抽出来,独有留下来换个项目还要吗?要→放 reglow,不要→留像匠通用代码散落各处,Bug 修 N 遍
2依赖不改源码只在 reglow 仓库改基础代码,不在下游改一升级就覆盖,改动全丢
3版本锁死生产 ==0.2.1,开发 ~=0.2.1自动升到不兼容版本直接炸
4每次发版写 CHANGELOG写清楚:新功能 / 修复 / ⚠️ Breaking Change下游不知道变了啥,不敢升级
5升级先看日志再跑测试任何红灯不能上线带着 Bug 上线
6五层架构不跨层Controller→Schema→Service→Repository→Model绕开 Service 直接调 Repository,业务规则落空
7两端 Router 分清楚管理端导 router,用户端追加 client_router(不叫 admin_router/app_router权限串漏,用户端拿到管理后台数据
8声明式验证不进 ServiceSchema 层拦截脏数据手写 if 校验散落 Service,漏一个就出事
9表前缀隔离Reglow 用 sys_,像匠用 xj_表名冲突,数据错乱
10像匠自己也是组装者main.py 只做组装,不写业务启动入口越来越臃肿

最后记住:Reglow 基础库 = 麦当劳总部配方和运营系统。像匠 = 用这套系统开的照相馆。总部配方升级,全部分店自动受益。像匠只操心照相馆自己的菜品——门店、订单、修图。

不是"从零搭建",是"拿过来就用的壳 + 自己填的业务内容"。