Files
persionalBrand/docs/03-data-and-api-design.md

180 lines
4.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.
# 数据库与 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` 表示微信支付交易;三者必须独立建模。支付成功不能直接等价于预约完成,预约仍由业务流程决定。