docs: define initial product requirements
This commit is contained in:
179
docs/03-data-and-api-design.md
Normal file
179
docs/03-data-and-api-design.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# 数据库与 API 设计
|
||||
|
||||
## 1. 关系概览
|
||||
|
||||
订单模型和接口的最新增量见 [首轮需求访谈决策](./07-requirements-interview-decisions.md)。实现时必须包含客户微信身份、套餐价格快照、标签、未读状态和客户订单查询;与本文早期枚举冲突时,以该文档为准。
|
||||
|
||||
```text
|
||||
BrandProfile 1
|
||||
├── Services 1..n
|
||||
└── PortfolioItems 1..n
|
||||
|
||||
Service 1 ── n Booking
|
||||
Booking 1 ── 0..n Feedback
|
||||
AdminUser 1 ── n AuditLog
|
||||
```
|
||||
|
||||
第一版数据库只有一个品牌记录,但所有内容表仍通过 `brand_id` 关联,便于后续扩展。
|
||||
|
||||
## 2. 表与约束
|
||||
|
||||
### brand_profiles
|
||||
|
||||
- `id` UUID 主键
|
||||
- `name` 必填
|
||||
- `is_published` 默认 true
|
||||
- `created_at`、`updated_at` 必填
|
||||
|
||||
### services
|
||||
|
||||
- `id` UUID 主键
|
||||
- `brand_id` 外键
|
||||
- `name` 必填
|
||||
- `price_text` 可空
|
||||
- `price_amount` 可空,单位为分,第一版不用于支付
|
||||
- `booking_enabled` 默认 true
|
||||
- `is_enabled` 默认 true
|
||||
- `sort_order` 默认 0
|
||||
- 对 `(brand_id, sort_order)` 建索引
|
||||
|
||||
### portfolio_items
|
||||
|
||||
- `id` UUID 主键
|
||||
- `brand_id` 外键
|
||||
- `image_urls` 可使用 JSON 数组,或拆分为 media_assets 表
|
||||
- `is_visible` 默认 true
|
||||
- `sort_order` 默认 0
|
||||
|
||||
### bookings
|
||||
|
||||
- `id` UUID 主键
|
||||
- `booking_no` 唯一
|
||||
- `brand_id` 外键
|
||||
- `service_id` 可空,防止服务删除后历史预约无法读取
|
||||
- `status` 枚举:`pending/contacted/completed/cancelled`
|
||||
- `extra_data` JSON,可存储受控的行业扩展字段
|
||||
- 对 `(brand_id, status, created_at)` 建索引
|
||||
- 不存支付状态
|
||||
|
||||
`extra_data` 不是任意键值存储。字段定义必须由品牌行业配置决定,API 需要校验键名、类型和必填规则;通用字段仍保持结构化。
|
||||
|
||||
### feedbacks
|
||||
|
||||
- `id` UUID 主键
|
||||
- `brand_id` 外键
|
||||
- `booking_id` 可空
|
||||
- `status` 枚举:`pending/approved/hidden`
|
||||
- 对 `(brand_id, status, created_at)` 建索引
|
||||
|
||||
### admin_users
|
||||
|
||||
- `id` UUID 主键
|
||||
- `username` 唯一
|
||||
- `password_hash` 必填
|
||||
- `role` 枚举:`admin/operator`
|
||||
- `is_enabled` 默认 true
|
||||
|
||||
### audit_logs
|
||||
|
||||
- `id` UUID 主键
|
||||
- `admin_user_id` 外键
|
||||
- `action`、`resource_type`、`resource_id` 必填
|
||||
- `metadata` JSON,可记录变更摘要,不记录密码和完整联系方式
|
||||
|
||||
## 3. API 约定
|
||||
|
||||
### 响应格式
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {},
|
||||
"error": null,
|
||||
"requestId": "..."
|
||||
}
|
||||
```
|
||||
|
||||
失败时:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": null,
|
||||
"error": {
|
||||
"code": "VALIDATION_ERROR",
|
||||
"message": "请填写有效的联系方式",
|
||||
"fields": {"phone": "格式不正确"}
|
||||
},
|
||||
"requestId": "..."
|
||||
}
|
||||
```
|
||||
|
||||
### 公开接口
|
||||
|
||||
```text
|
||||
GET /api/public/brand
|
||||
GET /api/public/services
|
||||
GET /api/public/services/:id
|
||||
GET /api/public/portfolio
|
||||
GET /api/public/portfolio/:id
|
||||
GET /api/public/feedbacks
|
||||
POST /api/public/bookings
|
||||
POST /api/public/feedbacks
|
||||
```
|
||||
|
||||
公开接口只能返回启用、可见和已审核数据。
|
||||
|
||||
### 管理接口
|
||||
|
||||
```text
|
||||
POST /api/auth/login
|
||||
POST /api/auth/logout
|
||||
GET /api/auth/me
|
||||
|
||||
GET /api/admin/brand
|
||||
PUT /api/admin/brand
|
||||
GET /api/admin/services
|
||||
POST /api/admin/services
|
||||
PUT /api/admin/services/:id
|
||||
DELETE /api/admin/services/:id
|
||||
GET /api/admin/portfolio
|
||||
POST /api/admin/portfolio
|
||||
PUT /api/admin/portfolio/:id
|
||||
DELETE /api/admin/portfolio/:id
|
||||
GET /api/admin/bookings
|
||||
GET /api/admin/bookings/:id
|
||||
PATCH /api/admin/bookings/:id/status
|
||||
GET /api/admin/feedbacks
|
||||
PATCH /api/admin/feedbacks/:id/status
|
||||
POST /api/admin/uploads/presign
|
||||
```
|
||||
|
||||
## 4. 预约接口规则
|
||||
|
||||
- 服务不存在或已停用时拒绝提交。
|
||||
- 期望日期早于当天时拒绝提交。
|
||||
- 联系方式至少一项非空。
|
||||
- 服务端再次执行所有校验,不能只依赖小程序校验。
|
||||
- 使用请求幂等键或短时间重复检测避免重复预约。
|
||||
- 创建成功后返回 `booking_no`,不返回管理员数据。
|
||||
|
||||
## 5. 文件上传流程
|
||||
|
||||
1. 后台请求上传凭证。
|
||||
2. API 校验管理员权限和文件元数据。
|
||||
3. 前端直接上传对象存储。
|
||||
4. 上传完成后提交文件 URL 和元数据。
|
||||
5. 内容实体引用该资源。
|
||||
|
||||
不得让浏览器上传任意路径或任意 MIME 文件。图片最大尺寸和大小由环境变量配置。
|
||||
|
||||
## 6. 远期支付边界
|
||||
|
||||
未来新增:
|
||||
|
||||
```text
|
||||
orders
|
||||
payments
|
||||
refunds
|
||||
```
|
||||
|
||||
`Booking` 表示客户意向或服务预约;`Order` 表示应收业务;`Payment` 表示微信支付交易;三者必须独立建模。支付成功不能直接等价于预约完成,预约仍由业务流程决定。
|
||||
Reference in New Issue
Block a user