Files
jiu/docs/context/project.md
T
wangjia 14e285e756 feat(db): H001 改名 S001,新增 S002(空库存版)
S001: 含完整入库/出库/库存历史数据
S002: 基础数据相同(商品/供应商/仓库),入库/出库/库存均为空,模拟新门店

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 23:43:21 +08:00

227 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 酒库管理系统 — 项目上下文
> 所有 Agent 在开始工作前必须读取此文件,了解项目全貌。
## 项目简介
面向酒水门店的仓库管理系统。核心特点:
- **多租户**:每个账号对应一个门店,数据通过 `shop_id` 完全隔离
- **付费授权**:许可证绑定设备 ID,支持试用/年付/买断
- **跨端客户端**:Flutter 单一代码库,支持 Windows / Web / macOS / iOS / Android
## 技术栈
```yaml
后端:
语言: Go 1.26
框架: GinHTTP+ GORMORM
数据库: MySQL 8.0Docker 容器 jiu_mysql
认证: JWTHS256),Access Token 60分钟,Refresh Token 7天
模块路径: github.com/wangjia/jiu/backend
前端:
框架: Flutter 3.x
状态管理: Riverpod
HTTP客户端: Dio(含 401 自动刷新 token 拦截器)
路由: go_router(含登录重定向)
目录: client/
数据库管理:
Schema: backend/schema/schema.sql(完整建表 SQL,容器启动时自动执行)
ORM 迁移: GORM AutoMigrate(后端启动时自动同步)
种子数据: backend/seeds/<shop>.sql(通过 dev.sh seed 命令执行)
```
## 项目目录结构
```
jiu/
├── backend/
│ ├── main.go # 入口,启动时执行 AutoMigrate
│ ├── config/
│ │ ├── config.go # 配置结构体(含 mapstructure 标签)
│ │ └── config.yaml # 本地开发配置(不提交 git)
│ ├── internal/
│ │ ├── 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/
│ │ └── S001.sql # 门店 S001 测试种子数据(SQL 命令形式)
│ └── schema/schema.sql # 完整建表 SQLMySQL
├── client/ # Flutter 跨端客户端
├── deploy/
│ └── docker-compose.yml # 本地开发:MySQL(3306) + Adminer(8888)
├── scripts/
│ └── dev.sh # 一站式开发脚本(见下方用法)
└── docs/
├── context/project.md # 本文件(项目全貌)
├── dev-setup.md # 环境搭建指南
├── requirements/ # 需求文档
├── architecture/ # 架构设计
├── api/ # API 接口规范
├── review/ # 代码审查报告 + bug 报告
├── security/ # 安全审计报告
└── runbooks/ # 运维操作手册
```
## 核心数据模型
```yaml
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` 只从 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 S001 # 清空并写入 S001 测试数据(执行 seeds/S001.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 S001
# 写入后可用以下账号登录(门店编号 S001):
# admin / password123 管理员
# operator / password123 操作员
# test / password123 只读
# 4. 数据库管理界面(可选)
# 浏览器打开 http://localhost:8888
# 服务器: mysql,用户: root,密码: password,数据库: jiu_db
```
## 已实现的 API 接口
```yaml
认证(无需 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
商品:
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/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-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
数据导入:
POST /api/v1/import/products (Excel/CSV)
POST /api/v1/import/partners (Excel/CSV)
```
## Flutter 客户端结构
```
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/dev-setup.md | 工具安装 + 开发脚本详解 + 测试架构 |
| Schema | backend/schema/schema.sql | 完整数据库建表 SQL |
| S001 种子 | backend/seeds/S001.sql | 门店 S001 测试数据(含完整入库/出库/库存历史) |
| S002 种子 | backend/seeds/S002.sql | 门店 S002 测试数据(基础数据相同,无库存/单据,模拟新门店) |