# 宠小它 - 产品设计文档

> **本体对齐**：本文档与 [`ontology/objects.md`](./ontology/objects.md) 对齐（`entity:store`/`entity:user`/`entity:appointment`/`entity:report`），规则见 [`ontology/rules.md`](./ontology/rules.md)。冲突以本体为准。
>
> 版本：v2.1
> 日期：2026-08-02（v2.1：补齐可执行回访任务状态机与真实再次预约归因）

> **品牌**：宠小它 · **主 Slogan**：用心宠小它，温暖伴一生 · **副 Slogan**：智慧宠物门店服务系统  
> **Logo / VI**：[《宠小它-Logo与品牌识别说明》](./宠小它-Logo与品牌识别说明.md)（含概念草案图）
> 状态：产品设计确认中；**本期迭代重点：洗美过程短视频自动成片（竖屏、可变时长、双编排）**

**相关子文档：**

- [洗美报告短视频成片方案](./洗美报告短视频成片方案.md) — **本期迭代主方案**：过程短视频与自动成片（与 §5.3 服务报告延伸能力对应；时长与编排以专文「与工程实现同步」为准）
- [产品改进建议](./产品改进建议.md) — 中长期方向库；**§〇** 为本期重点说明
- [产品全方位优化说明 v1](./产品全方位优化说明-v1.md) — 定位/IA/交互/UI/商业化/小程序体验汇总与排期切片（**与专文互补**，冲突以评审更新为准）
- [智能预约助手产品与技术方案 v0.1](./宠小它智能预约助手-产品与技术方案-v0.1.md) — **待评审、未实现**：宠主通过文字/语音生成受控预约草稿，分 M0 表单回填与 M1 明确确认创建
- [**P0 研发落地清单**](./P0-研发落地清单.md) — **本期必做**：后端状态机、Tab 筛选、发送报告话术、H5 隐私提示、宠主路径、埋点最小集等（**可直接拆 issue**）

---

## 一、产品定位

**平台定位：** 面向独立宠物洗护单店的服务管理 SaaS；平台可承载多家独立试点门店，但本期不做连锁多门店组织。

**目标用户（v1）：**
- 宠物店老板 / 员工（管理预约 + 填写报告 + 发送报告 + 回访池）
- 宠主（在线预约、查看公开报告、留资回访、报告分享）

> **本期 P0 范围（冻结口径）：**
> - 门店端：预约列表、开始服务、填写报告、发送报告、回访池。
> - 宠主端：预约填单、公开报告页、下次服务提醒留资、报告打开基础埋点。
> - 报告能力：服务前/服务后照片、服务过程素材、短片生成与下载、分享链接/二维码/话术。
>
> **不进入 P0：**
> - 会员、储值、套餐、复杂 CRM。
> - 宠主账号内历史报告汇总。
> - 完整经营分析看板。

**登录方式：**
- 生产：微信手机号授权登录；老板入驻和员工接受邀请均必须经微信核验手机号。
- 开发：手机号+演示短信验证码；production profile 默认关闭，不作为生产备用通道。

**门店开通流程：**

```text
老板微信核验手机号创建门店
→ 补全门店名称/电话/地址
→ 确认预约首末时段与并发容量
→ 确认至少一个服务项目
→ 显式完成开通（邀请员工为选填，支持单人门店）
```

---

## 二、核心功能闭环（v1）

```
预约创建（宠主/老板/员工，下单即生效）→ 待开始(new) → 开始服务（剪毛/正式开做时点击，谁点谁技师）→ 进行中(doing) → 提交报告并完成(done) → 发送给宠主 → 显式确认发送
                                                                                              ↘ 已取消(cancel) → 在「已完成」Tab 与完成单并列展示
```

**报告分享流程（v1 重点）：**
```
填写并提交报告（照片+备注）→ 选择传播方式 → 宠主实际收到 → 员工「确认已发送」
                                      ├── 复制链接/话术（发给宠主微信）
                                      ├── 当面展示二维码（现场扫码）
                                      └── 其他可核实方式
```

---

## 三、数据模型

### t_store（店铺表）
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| name | VARCHAR | 店铺名称 |
| logo | VARCHAR | 店铺Logo |
| phone | VARCHAR | 联系电话 |
| address | VARCHAR | 地址 |
| intro | TEXT | 简介 |
| owner_id | BIGINT | 老板用户ID |
| invite_code | VARCHAR | legacy 兼容字段；不返回客户端、不再作为注册凭证 |
| booking_day_start | TIME | 每日首个容量桶开始时间 |
| booking_last_slot_start | TIME | 每日最后一个容量桶开始时间 |
| booking_capacity | INT | 门店并发接待数（1～10） |
| onboarding_status | VARCHAR | unknown / in_progress / completed |
| onboarding_completed_at | DATETIME | 老板显式完成开通时间 |
| onboarding_completed_by_user_id | BIGINT | 完成开通的老板用户 |
| create_time | DATETIME | 创建时间 |
| update_time | DATETIME | 更新时间 |

### t_user（用户表）
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| username | VARCHAR | 用户名 |
| password | VARCHAR | legacy 服务端兼容字段；生产微信注册只写不可登录哨兵值，不接收或下发密码 |
| name | VARCHAR | 姓名/技师名 |
| phone | VARCHAR | 手机号 |
| avatar | VARCHAR | 头像 |
| store_id | BIGINT | 所属店铺 |
| role | VARCHAR | boss / staff / customer |
| create_time | DATETIME | 创建时间 |
| update_time | DATETIME | 更新时间 |

### t_staff_invitation（员工邀请）

| 字段 | 类型 | 说明 |
|------|------|------|
| invitation_id | VARCHAR(36) | 对外随机 ID |
| token_hash | VARCHAR(64) | 原始 256-bit token 的 SHA-256；原文不落库 |
| store_id | BIGINT | 门店 |
| invited_name / invited_phone | VARCHAR | 受邀姓名 / 服务端核验手机号 |
| status | VARCHAR | pending / accepted / revoked / expired |
| expires_at | DATETIME | 1～30 天有效期 |
| accepted_by_user_id / accepted_at | BIGINT / DATETIME | 接受回执 |
| revoked_by_user_id / revoked_at | BIGINT / DATETIME | 撤销回执 |

### t_audit_log（不可变操作审计）

记录门店入驻/开通/设置与员工邀请/删除等操作。metadata 仅允许服务端白名单低敏标量，禁止手机号、token、微信标识、密码/密钥、IP、地址坐标和原始请求体。

### t_store_customer（门店客户主档）
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 本店客户稳定主键 |
| store_id | BIGINT | 门店 ID |
| customer_user_id | BIGINT | 全局 customer 账号，留资客户可空 |
| phone | VARCHAR(20) | 本店最后确认手机号，API 默认脱敏 |
| display_name | VARCHAR(64) | 门店视角客户称呼 |
| source | VARCHAR(32) | customer_booking / assisted_booking / report_lead |
| first_contact_at / last_contact_at | DATETIME | 首次/最近接触时间 |
| merged_into_store_customer_id | BIGINT | 软删除投影并入的同店 canonical 主档；用于保持不可变事件时间线连续 |
| create_time / update_time | DATETIME | 创建/更新时间 |
| deleted | TINYINT | 软删除标记 |

### t_business_event（不可变业务事件）
| 字段 | 类型 | 说明 |
|------|------|------|
| id / event_id | BIGINT / VARCHAR(36) | 内部主键 / 随机事件 ID |
| event_type / event_version | VARCHAR(64) / INT | 过去时事件类型 / schema 版本 |
| store_id / store_customer_id | BIGINT | 门店范围 / 可选客户关系 |
| aggregate_type / aggregate_id | VARCHAR(32) / BIGINT | 关联预约、报告或留资 |
| actor_user_id / actor_role | BIGINT / VARCHAR(16) | 操作人快照，匿名事件可空 |
| source | VARCHAR(32) | customer / admin / public_report / system / migration |
| occurred_at / create_time | DATETIME(3) | 业务发生 / 入库时间 |
| metadata_json | TEXT | 服务端白名单低敏维度，不存原始请求 |
| idempotency_key | VARCHAR(128) | 可选稳定幂等键 |

### t_follow_up_task（回访执行任务）
| 字段 | 类型 | 说明 |
|------|------|------|
| id / task_id | BIGINT / VARCHAR(36) | 内部主键 / Admin 对外随机 ID |
| store_id / store_customer_id | BIGINT | 门店范围 / canonical 客户关系 |
| source_lead_id / source_report_id | BIGINT | 来源留资 / 来源报告 |
| status | VARCHAR(16) | pending / in_progress / completed / canceled |
| outcome | VARCHAR(24) | rebooked / not_interested / invalid_contact / unsubscribed；仅终态 |
| due_date / assigned_user_id | DATE / BIGINT | 下次回访日 / 当前领取人 |
| attempt_count | INT | 已形成回执的员工联系次数 |
| last_attempt_outcome | VARCHAR(24) | no_answer / follow_later；仅非终态联系结果 |
| last_contacted_at / last_contacted_by_user_id | DATETIME / BIGINT | 最近联系回执 |
| closed_at / closed_by_user_id | DATETIME / BIGINT | 终结回执；退订取消无员工关闭人 |
| rebooked_appointment_id | BIGINT | 仅真实预约保存成功后写入 |
| create_time / update_time / version | DATETIME / DATETIME / BIGINT | 时间戳与乐观锁版本 |

### t_appointment（预约表）
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| pet_name | VARCHAR | 宠物名称 |
| pet_type | VARCHAR | 宠物类型（猫/狗/其他） |
| service_type | VARCHAR | 服务类型 |
| appointment_time | DATETIME | 预约开始时间（半小时粒度） |
| duration_minutes | INT | 下单时服务时长快照；修改服务项目不影响历史预约 |
| status | VARCHAR | new（待开始）/ doing（服务中）/ done（已完成）/ cancel（已取消） |
| store_id | BIGINT | 店铺ID |
| customer_user_id | BIGINT | 被服务客户账号 |
| created_by_user_id | BIGINT | 实际创建预约的账号 |
| user_id | BIGINT | legacy 兼容，新数据镜像 customer_user_id |
| assigned_user_id | BIGINT | 服务技师ID（开始服务时赋值，API 别名 assignedStaffId） |
| remark | TEXT | 备注 |
| create_time | DATETIME | 创建时间 |
| update_time | DATETIME | 更新时间 |

### t_report（报告表）
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| appointment_id | BIGINT | 预约ID |
| remark | TEXT | 备注 |
| customer_user_id | BIGINT | 报告归属客户，从预约派生 |
| author_staff_id | BIGINT | 实际提交报告的门店账号 |
| user_id | BIGINT | legacy 兼容，新数据镜像 author_staff_id |
| store_id | BIGINT | 店铺ID |
| report_token | VARCHAR | 报告访问令牌（UUID，永久有效） |
| pet_name | VARCHAR | 宠物名（冗余） |
| service_type | VARCHAR | 服务类型（冗余） |
| appointment_time | DATETIME | 服务时间（冗余） |
| staff_name | VARCHAR | 服务技师名快照（冗余） |
| send_status | VARCHAR(16) | unknown（历史不可确认）/ unsent（新报告待发送）/ sent（已显式确认） |
| sent_at | DATETIME | 首次显式确认发送时间 |
| sent_by_user_id | BIGINT | 首次确认发送员工 |
| send_channel | VARCHAR(16) | wechat / qr / other；首次确认后不可覆盖 |
| create_time | DATETIME | 创建时间 |
| update_time | DATETIME | 更新时间 |

### t_report_image（报告媒体表）
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| report_id | BIGINT | 关联报告ID |
| photo_url | VARCHAR(500) | 媒体URL |
| photo_type | VARCHAR(20) | before / after / during |
| sort_order | INT | 同类型内排序序号 |
| create_time | DATETIME | 创建时间 |

> 说明：当前后端已按 `photo_type` 存储前后图与过程素材；`media_type`（photo/video）为前端语义，后端字段化会在后续迭代补齐。

### t_service_type（服务类型表）
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| store_id | BIGINT | 店铺ID（NULL表示系统默认） |
| name | VARCHAR | 服务名称 |
| duration_minutes | INT | 预计服务时长（30～480，30 分钟粒度） |
| create_time | DATETIME | 创建时间 |

---

## 四、角色权限

| 功能 | 老板（boss） | 员工（staff） |
|------|-------------|---------------|
| 预约列表 | ✅ | ✅ |
| 新建预约 / 回访后代客预约 | ✅ | ✅ |
| 开始服务/填写报告 | ✅ | ✅ |
| 发送报告 | ✅ | ✅ |
| 员工管理 | ✅ | ❌ |
| 邀请码 | ✅ | ❌ |
| 店铺设置 | ✅ | ❌ |
| 服务类型管理 | ✅ | ❌ |
| 领取、改期、关闭本店回访任务 | ✅ | ✅ |

### 页面入口
- **index.html（统一入口）**：老板/员工同一套页面，通过「我的」页面区分功能
  - 老板「我的」：员工管理 / 服务类型 / 店铺设置 / 我的订单
  - 员工「我的」：我的订单

---

## 五、核心功能详解

### 5.1 登录体系

**微信授权登录**（主）
- 老板/员工均可使用微信授权登录

**手机号+短信验证码登录**（备用）

**员工入职流程：**
- 老板按员工本人手机号创建 1～30 天有效的一次性邀请；原始 token 仅创建响应显示一次，数据库只保存 hash
- 员工从小程序卡片进入，核对门店、姓名与脱敏手机号，再用微信核验的同一手机号接受邀请并自动关联门店
- 邀请可在接受前撤销，过期或已使用后不可再次创建账号；不支持永久邀请码、直接建号或随机密码登录

### 5.2 预约管理

**创建预约：**
- 老板/员工均可手动创建
- 字段：宠物名字、宠物类型（猫/狗/其他）、服务类型、预约时间、备注
- 建档人 = 当前登录用户
- 号源以服务项目预计时长、门店营业容量时段、门店并发接待数、线上预约与手动占用共同计算；创建时检查服务覆盖的每个半小时桶，并串行化同店容量判定避免超卖
- 线上预约当前不预选技师，容量是门店对外承诺的并发接待数；个人技师日历在具备预约前分配技师能力后再引入
- 从回访任务发起时携带 `followUpTaskId`；仅在同店、同 canonical 客户、当前员工已领取且预约真实保存成功后，任务才能以 `rebooked` 完成

**服务类型：**
- 系统默认：洗澡、美容、洗澡+美容、剪指甲、驱虫
- 老板可在默认基础上新增/编辑/删除自定义服务类型，并配置 30～480 分钟的预计时长
- 员工只能使用，不能管理

**预约状态语义（与界面文案对齐）：**
- **new = 待开始**：下单即占号生效，**无**门店单独「确认接单」环节；到店、洗吹等若尚未到「开剪/正式开做」，仍属待开始。
- **doing = 服务中**：店员在**剪毛/正式开做**时点击「开始服务」进入本状态。
- **done = 已完成**：提交服务报告时，后端将关联预约置为已完成（见 ReportService）。
- **cancel = 已取消**：取消后在前端「已完成」Tab 中与完成单并列展示（含历史取消）。

**开始服务：**
- 点击「开始服务」→ 状态变为「进行中」
- assigned_user_id = 当前登录用户（谁点谁服务）

#### 预约状态迁移矩阵（产品规则 · 供开发/测试验收）

| 当前状态 | 目标状态 | 触发 | 操作角色 | 备注 |
|----------|----------|------|----------|------|
| （创建） | new | 成功创建预约 | 宠主/老板/员工 | 下单即生效，占号 |
| new | doing | 点击「开始服务」 | boss / staff | 建议在剪毛/正式开做时点击 |
| new | cancel | 取消预约 | 宠主（C 端）/ 门店侧 | 业务可约定开始前可取消 |
| doing | done | 提交服务报告（创建 Report） | boss / staff | 后端 `ReportService.create` 内将预约置 done |
| doing | cancel | 取消（若允许） | 视业务 | **建议**：仅允许店长或限定条件，当前接口需防滥用 |
| done | — | 终态 | — | 不回退 |
| cancel | — | 终态 | — | 不回退 |

**期望约束（建议在接口层逐步收紧）：** `new → doing` 仅当当前为 `new`；`doing → done` 由报告提交触发；取消仅允许自 `new` / `doing`（按产品最终规则）。当前部分接口未校验前置状态，以实际上线前补校验为准。

### 5.3 服务报告

**填写报告（进行中状态可操作）：**

**报告提交必填项：**
- 宠物名称
- 服务类型
- 服务时间
- 服务前照片至少 1 张
- 服务后照片至少 1 张

服务过程中照片/视频、备注为选填。

- 技师 = 开始服务时分配的用户
- 提交后锁死，不可再修改
- 一约一份报告（同一 `appointmentId` 第二次提交返回 `REPORT_ALREADY_EXISTS`）
- 报告必须绑定预约 `appointmentId`；无预约报告不作为本期主路径

> **本期迭代重点：** 洗美报告「过程短视频 + 自动生成 **竖屏成片（9:16）**」，**成片时长随素材量变化**（配置级总时长上限），支持 **预设顺序 / 穿插** 两种编排（`highlight_compose_mode`）。产品边界、参考分镜、成本与工程机制见子文档 [《洗美报告短视频成片方案》](./洗美报告短视频成片方案.md)。成片以服务端模板化拼接（如 FFmpeg）为主，成片可在报告页/H5 播放与分享。
>
> **实现对齐备注（2026-04）**：服务端已落库过程素材，报告查询接口对 `duringMedia` 的回传需与成片任务对齐；`highlight_video_*`、`highlight_duration_sec`、`highlight_compose_mode` 等字段承载成片 URL、时长、编排方式与任务状态，本期需完成**发起 → 异步生成 → 成功播放 / 失败提示**闭环。

### 5.4 发送报告（v1 核心功能）

**操作入口：** 报告提交成功后进入「发送给宠主」弹层；后台报告列表也可继续处理待发送报告。

**发送方式：**
1. **复制链接** — 生成报告链接，一键复制到剪贴板，可发给宠主微信
2. **当面扫码** — 展示报告二维码，宠主现场扫码打开
3. **其他方式** — 仅在员工能够确认宠主实际收到时使用

**确认口径：**
- 复制链接、复制话术、生成/展示二维码、预览或打开报告，**都不自动等于已发送**。
- 宠主实际收到后，由本店 boss/staff 选择真实渠道并点击「确认已发送」。
- 首次确认写入 `sent_at/sent_by_user_id/send_channel` 和 `report_sent` 事件；重复点击幂等成功，不覆盖首次回执。
- 历史报告没有可靠发送证据，迁移后统一为 `unknown`；只有迁移后新报告默认 `unsent` 并进入工作台待办。

**报告链接：**
- URL：`https://域名/report.html?token=xxx`
- Token = UUID，永久有效
- 宠主打开无需登录（v1 免登录）

**报告二维码：**
- 扫码直接打开报告页
- 打印出来可贴在墙上/前台，方便宠主扫码

### 5.5 H5 报告页

**访问方式：** 链接或二维码扫码，免登录

**报告页内容：**
- 品牌头部：店铺 Logo + 店铺名称 + 联系电话 + 地址
- 服务信息卡片：宠物名、服务项目、服务时间、技师名
- 前后对比照片（并排展示）
- 服务过程中素材区（照片/短视频）
- 技师备注
- 底部品牌信息（即使链接被转发，店铺信息持续透出）

**分享能力：**
- 长按图片可保存
- 链接可复制转发微信

### 5.6 老板后台（合并到「我的」页面）

**员工管理：**
- 老板按员工本人微信手机号创建 1～30 天有效的一次性邀请
- 小程序直接转发带受控 path 的邀请卡片；原始口令仅创建后显示一次
- 员工从卡片进入，查看门店/姓名/脱敏手机号，经微信核验后加入
- 老板查看邀请状态、撤销待接受邀请、删除已加入员工

**服务类型：**
- 新增服务类型
- 删除自定义服务类型（系统默认不可删）

**店铺设置：**
- 店铺名称
- 店铺Logo
- 联系电话
- 地址
- 简介

**服务客户时间线（Admin）：**
- 以 `StoreCustomer.id` 为稳定门店客户关系，不用手机号或临时列表行作为详情主键
- 客户详情按时间倒序展示预约创建/状态、开始与完成服务、报告提交/确认发送/打开、回访意向等已落库事实
- 每条事实可跳转对应预约、报告或回访池；不在时间线复制备注、媒体或联系方式原文
- 时间线只读且不承载会员、余额、次卡、积分或可编辑营销标签

**回访任务池（Admin）：**
- `ReportLead` 保存宠主同意和来源事实，`FollowUpTask` 保存员工协作状态；Admin 不再直接改留资状态
- 员工先领取任务，领取人才能登记未接通/稍后联系、关闭本轮或发起再次预约；他人已领取返回冲突
- 未接通/稍后联系会增加联系次数并回到待领取；暂无意向/联系方式无效为完成终态；退订为系统取消且不增加员工次数
- `rebooked` 不提供手工关闭选项，必须通过真实预约创建且容量校验成功；工作台漏斗只统计 `rebook_created`
- 同店已认证员工仅在开放任务中可见完整手机号用于实际联系；终态任务、工作台、时间线、事件和审计不复制手机号原文

---

## 六、技术方案

| 端 | 技术 |
|----|------|
| APP前端 | uniapp + Vue3 |
| H5报告页 | Vue3（独立部署） |
| 后端 | Spring Boot 3.2 + JPA |
| 数据库 | MySQL |
| 图片存储 | 本地存储（后续可平滑切换OSS） |

---

## 七、开发进度

| 优先级 | 功能 | 状态 |
|--------|------|------|
| P0 | 微信核验老板入驻 + 门店开通清单 | ✅ 代码完成，待生产迁移/真机验收 |
| P0 | 一次性员工邀请、微信核验接受、撤销与状态 | ✅ 代码完成，待生产迁移/真机验收 |
| P0 | 员工登录（微信+验证码） | ✅ |
| P0 | 预约列表 | ✅ |
| P0 | 预约创建 | ✅ |
| P0 | 服务时长 + 门店并发预约容量 + 连续占用 | ✅ |
| P0 | 开始服务（分配技师） | ✅ |
| P0 | 报告填写 | ✅ |
| P0 | 报告过程素材上传（照片/短视频） | ✅ 基础能力已接入 |
| P0 | 发送报告（复制链接+下载二维码） | 🔨 本次 |
| P0 | H5报告页（品牌信息强化） | 🔨 本次 |
| P0 | H5报告页（链接+二维码） | ✅ |
| P1 | 报告过程素材回传（duringMedia） | 🔨 进行中 |
| **P0** | **洗美过程短视频自动成片（可变时长、双编排、模板拼接）** | **🔨 本期迭代重点** |
| P0 | 老板后台（开通清单+员工邀请中心） | ✅ Admin 与小程序均已接入 |
| P0 | 服务客户事实时间线（Admin） | ✅ 代码完成，含 StoreCustomer 合并别名历史连续性，待生产迁移 |
| P0 | 可执行回访任务池 + 真实再次预约归因（Admin） | ✅ 代码完成，待生产迁移与三角色验收 |
| P0 | 老板后台（预约概览） | ✅ 已合并到index.html |
| P1 | 服务类型管理（老板后台） | ✅ |
| P1 | 店铺设置（老板后台） | ✅ |
| P1 | 本地文件上传（替代base64） | ✅ |
| P2 | 宠主端（历史报告汇总） | ⏳ P2（不进入本期 P0） |

---

## 八、数据库变更

```sql
-- 预约表新增技师字段
ALTER TABLE t_appointment ADD COLUMN assigned_user_id BIGINT COMMENT '技师ID';

-- 店铺表新增简介字段
ALTER TABLE t_store ADD COLUMN intro TEXT COMMENT '简介';

-- 服务类型表
CREATE TABLE t_service_type (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    store_id BIGINT COMMENT '店铺ID，NULL表示系统默认',
    name VARCHAR(50) NOT NULL,
    duration_minutes INT NOT NULL DEFAULT 60,
    create_time DATETIME
);

-- 系统默认服务类型
INSERT INTO t_service_type (store_id, name, duration_minutes, create_time) VALUES
(NULL, '洗澡', 60, NOW()),
(NULL, '美容', 120, NOW()),
(NULL, '洗澡+美容', 150, NOW()),
(NULL, '剪指甲', 30, NOW()),
(NULL, '驱虫', 30, NOW());

-- 真实预约容量字段（完整回填与验证见 backend/db/migrations/20260801_create_booking_capacity.sql）
ALTER TABLE t_appointment ADD COLUMN duration_minutes INT NOT NULL DEFAULT 60;
ALTER TABLE t_schedule_block ADD COLUMN duration_minutes INT NOT NULL DEFAULT 30;
ALTER TABLE t_store ADD COLUMN booking_capacity INT NOT NULL DEFAULT 1;

-- 报告显式确认发送字段（完整历史兼容与验证见 backend/db/migrations/20260801_create_report_send_status.sql）
ALTER TABLE t_report ADD COLUMN send_status VARCHAR(16) NOT NULL DEFAULT 'unsent';
ALTER TABLE t_report ADD COLUMN sent_at DATETIME NULL;
ALTER TABLE t_report ADD COLUMN sent_by_user_id BIGINT NULL;
ALTER TABLE t_report ADD COLUMN send_channel VARCHAR(16) NULL;

-- 报告媒体表（前后图 + 过程素材）
CREATE TABLE t_report_image (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    report_id BIGINT NOT NULL COMMENT '关联报告ID',
    photo_url VARCHAR(500) NOT NULL COMMENT '媒体URL',
    photo_type VARCHAR(20) NOT NULL COMMENT 'before/after/during',
    sort_order INT DEFAULT 0 COMMENT '同类型排序',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_report_image_report_id (report_id),
    INDEX idx_report_image_report_type_sort (report_id, photo_type, sort_order)
);

-- 回访任务完整建表、历史回填和五项验证见：
-- backend/db/migrations/20260802_create_follow_up_task.sql
```

---

## 九、后续事项（开放清单）

- [ ] 宠小它 Logo 素材
- [ ] 图片存储方案（本地 / OSS）
- [ ] 短信验证码服务商接入
- [ ] 微信授权登录 AppID/AppSecret
- [ ] H5页面域名及部署方案
- [ ] 宠主账号内历史报告汇总（P2，不进入本期 P0）
- [ ] 会员、储值、套餐、复杂 CRM（P1/P2，不进入本期 P0）
