docs: 更新项目文档与开发规范

修正 hotel_id→shop_id 错误引用,补充 dev.sh 脚本用法、
测试架构说明、种子数据规范,整理目录结构为当前实际状态。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-04-07 23:07:16 +08:00
parent 39fe1da800
commit 098fba38f2
3 changed files with 364 additions and 282 deletions
+147 -124
View File
@@ -1,11 +1,11 @@
# 酒店仓库管理系统 — 项目上下文
# 酒库管理系统 — 项目上下文
> 所有 Agent 在开始工作前必须读取此文件,了解项目全貌。
## 项目简介
面向酒水门店的仓库管理系统。核心特点:
- **多租户**个账号对应一个门店,数据完全隔离(通过 `shop_id` 字段)
- **多租户**个账号对应一个门店,数据通过 `shop_id` 完全隔离
- **付费授权**:许可证绑定设备 ID,支持试用/年付/买断
- **跨端客户端**:Flutter 单一代码库,支持 Windows / Web / macOS / iOS / Android
@@ -15,21 +15,21 @@
后端:
语言: Go 1.26
框架: GinHTTP+ GORMORM
数据库: MySQL 8.0
数据库: MySQL 8.0Docker 容器 jiu_mysql
认证: JWTHS256),Access Token 60分钟,Refresh Token 7天
模块路径: github.com/wangjia/jiu/backend
前端:
框架: Flutter 3.x
状态管理: Riverpod
HTTP客户端: Dio
路由: go_router
HTTP客户端: Dio(含 401 自动刷新 token 拦截器)
路由: go_router(含登录重定向)
目录: client/
数据库迁移:
工具: golang-migrate
迁移文件: backend/migrations/
完整schema: backend/schema/schema.sql
数据库管理:
Schema: backend/schema/schema.sql(完整建表 SQL,容器启动时自动执行)
ORM 迁移: GORM AutoMigrate(后端启动时自动同步)
种子数据: backend/seeds/<shop>.sql(通过 dev.sh seed 命令执行)
```
## 项目目录结构
@@ -37,162 +37,185 @@
```
jiu/
├── backend/
│ ├── main.go # 入口
│ ├── config/config.yaml # 配置(本地开发)
│ ├── main.go # 入口,启动时执行 AutoMigrate
│ ├── config/
│ │ ├── config.go # 配置结构体(含 mapstructure 标签)
│ │ └── config.yaml # 本地开发配置(不提交 git)
│ ├── internal/
│ │ ├── handler/ # HTTP 处理器(每模块一文件)
│ │ ├── service/ # 业务逻辑层
│ │ ├── model/ # GORM 数据模型
│ │ ├── middleware/auth.go # JWT 验证 + 租户注入
│ │ ── router/router.go # 路由注册
├── migrations/ # 版本迁移 SQL
└── schema/schema.sql # 完整建表 SQL
├── client/ # Flutter 跨端客户端
│ │ ├── handler/ # HTTP 处理器(每模块一文件)
│ │ │ └── *_test.go # Handler 集成测试(SQLite in-memory
│ │ ├── service/ # 业务逻辑层
│ │ │ └── *_test.go # Service 单元测试
│ │ ── model/ # GORM 数据模型
│ │ ├── base.go # Base/TenantBase/Date/JSON 公共类型
│ │ └── *.go # 各业务模型
│ │ ├── middleware/auth.go # JWT 验证 + shop_id 注入(GetShopID/GetUserID
│ │ └── router/router.go # 路由注册
│ ├── testutil/setup.go # 测试工具包(SQLite DB、CreateTestXxx、GetAuthToken
│ ├── cmd/seed/main.go # 数据库工具(--reset 删表重建,--clear 清空数据)
│ ├── seeds/
│ │ └── H001.sql # 门店 H001 测试种子数据(SQL 命令形式)
│ └── schema/schema.sql # 完整建表 SQLMySQL
├── client/ # Flutter 跨端客户端
├── deploy/
│ └── docker-compose.yml # 本地开发:MySQL + Adminer
│ └── docker-compose.yml # 本地开发:MySQL(3306) + Adminer(8888)
├── scripts/
│ └── dev.sh # 一站式开发脚本(见下方用法)
└── docs/
├── context/project.md # 本文件
├── requirements/ # 需求文档
├── architecture/ # 架构设计
├── api/ # API 接口规范
├── review/ # 代码审查报告 + bug 报告
├── security/ # 安全审计报告
── runbooks/ # 运维操作手册
├── context/project.md # 本文件(项目全貌)
├── dev-setup.md # 环境搭建指南
├── requirements/ # 需求文档
├── architecture/ # 架构设计
├── api/ # API 接口规范
├── review/ # 代码审查报告 + bug 报告
── security/ # 安全审计报告
└── runbooks/ # 运维操作手册
```
## 核心数据模型
```yaml
主要表:
shops: # 酒店(租户)
users: # 用户(含 shop_id
licenses: # 许可证(含 device_id 绑定)
products: # 商品(含 custom_fields JSON 动态扩展)
warehouses: # 仓库
partners: # 往来单位(supplier/customer
stock_in_orders: # 入库单(draft→pending→approved/rejected
stock_in_items: # 入库单明细
stock_out_orders: # 出库单
stock_out_items: # 出库单明细
inventory: # 实时库存(唯一键shop_id+warehouse_id+product_id
inventory_logs: # 库存流水(每次变动记录)
inventory_checks: # 盘点单
finance_records: # 财务流水
number_rules: # 单号生成规则
shops: # 门店(租户根节点)
users: # 用户(含 shop_idrole: admin/operator/readonly
licenses: # 许可证(含 device_id 绑定,type: trial/monthly/annual/lifetime
product_categories: # 商品分类
products: # 商品(含 custom_fields JSON 动态扩展)
warehouses: # 仓库
partners: # 往来单位(type: supplier/customer
stock_in_orders: # 入库单(status: draft→pending→approved/rejected
stock_in_items: # 入库单明细
stock_out_orders: # 出库单
stock_out_items: # 出库单明细
inventories: # 实时库存(唯一键: shop_id+warehouse_id+product_id
inventory_logs: # 库存流水(每次变动自动记录)
inventory_checks: # 盘点单
inventory_check_items: # 盘点明细
finance_records: # 财务流水(receivable/payable/receipt/payment
number_rules: # 单号生成规则(前缀+日期+6位序号)
```
## 关键业务规则
1. **多租户**所有查询必须带 `shop_id` 条件,`shop_id` 只从 JWT 获取,不信任请求参数
2. **库存变更**:入库/出库审核通过时,同一事务更新 `inventory` + 写 `inventory_logs`
3. **出库前检查**出库审核时必须校验库存充足,不足返回错误并回滚事务
4. **单号生成**:通过 `number_rules` 表事务安全生成,格式 `{前缀}{日期}{6位序号}`
5. **扩展字段**:所有业务主表含 `custom_fields JSON`,用于存储动态业务字段
1. **多租户隔离**`shop_id` 只从 JWT 提取(`middleware.GetShopID(c)`),绝不从请求参数读取
2. **库存变更事务**:入库/出库审核时,同一事务更新 `inventories` + 写 `inventory_logs`
3. **出库前校验**审核出库时校验库存充足,不足返回错误并回滚
4. **单号生成**:通过 `number_rules` 表事务安全生成,格式 `{前缀}{YYYYMMDD}{6位序号}`
5. **扩展字段**:所有业务主表含 `custom_fields JSON`,用于存储动态业务字段,避免频繁改表
## 开发脚本(scripts/dev.sh
所有常用操作都通过 `sh scripts/dev.sh <命令>` 执行:
```bash
# 启动
sh scripts/dev.sh run # 启动前后端(后端代码未变则跳过重启)
sh scripts/dev.sh run --force # 强制重启后端
sh scripts/dev.sh --backend-only # 仅启动后端
sh scripts/dev.sh --frontend-only # 仅启动前端
# 数据库
sh scripts/dev.sh seed H001 # 清空并写入 H001 测试数据(执行 seeds/H001.sql
sh scripts/dev.sh reset # 删表重建(AutoMigrate
sh scripts/dev.sh clear # 清空所有业务数据(保留表结构)
```
## 本地开发快速启动
```bash
# 1. 启动 MySQL 容器(首次或容器未运行时)
docker compose -f deploy/docker-compose.yml up -d
# 2. 一键启动前后端
sh scripts/dev.sh run
# 3. 写入测试数据(另开终端)
sh scripts/dev.sh seed H001
# 4. 数据库管理界面(可选)
# 浏览器打开 http://localhost:8888
# 服务器: mysql,用户: root,密码: password,数据库: jiu_db
```
## 已实现的 API 接口
```yaml
认证:
- POST /api/v1/auth/login
- POST /api/v1/auth/refresh
认证(无需 JWT:
POST /api/v1/auth/login
POST /api/v1/auth/refresh
许可证:
- POST /api/v1/license/activate
- GET /api/v1/license/verify
- POST /api/v1/license/deactivate
POST /api/v1/license/activate
GET /api/v1/license/verify
POST /api/v1/license/deactivate
商品:
- GET/POST /api/v1/products
- PUT/DELETE /api/v1/products/:id
GET/POST /api/v1/products
PUT/DELETE /api/v1/products/:id
仓库:
- GET/POST /api/v1/warehouses
- PUT/DELETE /api/v1/warehouses/:id
GET/POST /api/v1/warehouses
PUT/DELETE /api/v1/warehouses/:id
往来单位:
- GET/POST /api/v1/partners
- PUT/DELETE /api/v1/partners/:id
GET/POST /api/v1/partners
PUT/DELETE /api/v1/partners/:id
入库:
- GET/POST /api/v1/stock-in/orders
- GET /api/v1/stock-in/orders/:id
- PUT /api/v1/stock-in/orders/:id/submit
- PUT /api/v1/stock-in/orders/:id/approve
- PUT /api/v1/stock-in/orders/:id/reject
GET/POST /api/v1/stock-in/orders
GET /api/v1/stock-in/orders/:id
PUT /api/v1/stock-in/orders/:id/submit
PUT /api/v1/stock-in/orders/:id/approve
PUT /api/v1/stock-in/orders/:id/reject
出库:
- GET/POST /api/v1/stock-out/orders
- GET /api/v1/stock-out/orders/:id
- PUT /api/v1/stock-out/orders/:id/submit
- PUT /api/v1/stock-out/orders/:id/approve
- PUT /api/v1/stock-out/orders/:id/reject
GET/POST /api/v1/stock-out/orders
GET /api/v1/stock-out/orders/:id
PUT /api/v1/stock-out/orders/:id/submit
PUT /api/v1/stock-out/orders/:id/approve
PUT /api/v1/stock-out/orders/:id/reject
库存:
- GET /api/v1/inventory
- GET /api/v1/inventory/logs
- POST/GET /api/v1/inventory/checks
GET /api/v1/inventory
GET /api/v1/inventory/logs
POST/GET /api/v1/inventory/checks
数据导入:
- POST /api/v1/import/products (Excel/CSV)
- POST /api/v1/import/partners (Excel/CSV)
POST /api/v1/import/products (Excel/CSV)
POST /api/v1/import/partners (Excel/CSV)
```
## Flutter 客户端结构
```
client/
├── pubspec.yaml # 依赖:riverpod, go_router, dio, intl
├── lib/
│ ├── main.dart # 入口,ProviderScope + MaterialApp.router
│ ├── core/
│ ├── theme/app_theme.dart # 颜色常量 + ThemeData
│ ├── auth/auth_state.dart # AuthUser, AuthState, AuthNotifier
│ │ ├── api/api_client.dart # Dio 封装
│ └── router/app_router.dart # go_router 路由定义(含登录重定向)
│ ├── screens/
│ ├── auth/login_screen.dart # 登录页(蓝色背景 + 居中卡片)
│ ├── shell/app_shell.dart # 主框架(顶栏 + 侧边栏 + 状态栏)
│ ├── stock_in/ # 入库单列表 + 新建表单
│ ├── stock_out/ # 出库单列表
│ ├── inventory/ # 库存查询 + 盘点
│ ├── partners/ # 往来单位
│ ├── finance/ # 财务管理
│ │ ├── products/ # 商品管理
│ │ ── settings/ # 系统设置(用户/仓库/编号规则)
── widgets/
├── page_scaffold.dart # Tab 页面封装
── data_table_card.dart # 含工具栏+分页的数据表格
│ ├── status_badge.dart # 状态标签(草稿/待审/已审/拒绝)
│ └── form_dialog.dart # 弹窗表单封装
```
**启动 Flutter 客户端**(需先安装 Flutter):
```bash
cd client
flutter pub get
flutter run -d macos # macOS 桌面
flutter run -d chrome # Web
```
## 本地开发启动
```bash
# 1. 启动数据库
cd deploy && docker compose up -d
# 2. 启动后端(会自动 AutoMigrate
cd backend && export PATH="/opt/homebrew/bin:$PATH" && go run main.go
# 3. 运行测试
cd backend && go test ./... -cover
# 4. 数据库管理界面
# 打开 http://localhost:8888,服务器:mysql, 用户:root, 密码:password, 数据库:jiu_db
client/lib/
├── main.dart # 入口:ProviderScope + _AppBootstrapauth restore
├── core/
│ ├── theme/app_theme.dart # 颜色常量 + ThemeData
│ ├── auth/auth_state.dart # AuthUser, AuthState, AuthNotifiershared_preferences 持久化)
│ ├── api/api_client.dart # Dio 封装(401 自动刷新,_disposed 防悬空回调)
└── router/app_router.dart # go_router_RouterNotifier + refreshListenable
├── screens/
├── auth/login_screen.dart # 登录页
│ ├── shell/app_shell.dart # 主框架(顶栏 + 侧边栏 + 状态栏)
│ ├── stock_in/ # 入库管理
│ ├── stock_out/ # 出库管理
│ ├── inventory/ # 库存管理
│ ├── partners/ # 往来单位
│ ├── finance/ # 财务管理
│ ├── products/ # 商品管理(含分类)
└── settings/ # 系统设置(用户/仓库/编号规则)
└── widgets/
── page_scaffold.dart # Tab 页面封装
── data_table_card.dart # 含工具栏+分页的数据表格
├── status_badge.dart # 状态标签(草稿/待审/已审/拒绝)
── form_dialog.dart # 弹窗表单封装
```
## 文档索引
| 文档 | 路径 | 说明 |
|------|------|------|
| 本文件 | docs/context/project.md | 项目全貌,所有 Agent 必读 |
| 项目上下文 | docs/context/project.md | 本文件,所有 Agent 必读 |
| 环境搭建 | docs/dev-setup.md | 工具安装 + 开发脚本详解 + 测试架构 |
| Schema | backend/schema/schema.sql | 完整数据库建表 SQL |
| H001 种子 | backend/seeds/H001.sql | 门店 H001 测试数据 |