# Actions(动作) > 读写实体的命令/用例。每个动作标注入口(controller/service 方法)、输入输出实体、适用规则。 ## Store 相关 ### action:register_boss 老板入驻:创建 `Store` + `boss` `User`,签发 `session_token`。 - **入口**:`POST /api/user/register-boss` → `UserService#registerBoss`(公开,在 AuthInterceptor allowlist) - **输入**:`storeName`、`bossName`、`phone`、`password` - **输出**:`entity:store`、`entity:user`、`session_token` - **适用规则**:`rule:BR-AUTH-001`(session token 签发) - **代码**:`backend/src/main/java/com/petstore/service/UserService.java#registerBoss` - **证据**:`anchored` ### action:update_store 更新店铺信息:仅 boss 且只能改自己所属门店。 - **入口**:`PUT /api/store/update` → `StoreController#update` → `StoreService#update` - **输入**:`entity:store`(id 必须等于 `current.storeId`) - **输出**:`entity:store` - **适用规则**:`rule:BR-STORE-001`(仅 boss + 同店) - **代码**:`backend/src/main/java/com/petstore/controller/StoreController.java#update` - **测试**:`StoreControllerTest` - **证据**:`anchored` ### action:delete_store 删除店铺:仅 boss 且只能删自己所属门店(软删)。 - **入口**:`DELETE /api/store/delete` → `StoreController#delete` - **适用规则**:`rule:BR-STORE-001` - **代码**:`backend/src/main/java/com/petstore/controller/StoreController.java#delete` - **测试**:`StoreControllerTest` - **证据**:`anchored` ### action:get_store_by_invite_code 按邀请码查门店:仅 boss/staff 且邀请码对应门店必须为当前用户所属门店。 - **入口**:`GET /api/store/invite-code` → `StoreController#getByInviteCode` - **适用规则**:`rule:BR-STORE-002`(邀请码同店校验) - **代码**:`backend/src/main/java/com/petstore/controller/StoreController.java#getByInviteCode` - **测试**:`StoreControllerTest` - **证据**:`anchored` ## User / 鉴权相关 ### action:login 手机号 + 短信验证码登录。**生产禁用**,仅 dev 模式(万能验证码 123456)可用。 - **入口**:`POST /api/user/login` → `UserService#login`(公开) - **输入**:`phone`、`code` - **输出**:`entity:user`、`entity:store`、`session_token` - **适用规则**:`rule:BR-AUTH-001`、`rule:BR-AUTH-002`(生产 SMS 禁用) - **代码**:`backend/src/main/java/com/petstore/service/UserService.java#login` - **测试**:`UserServiceLoginStrategyTest` - **证据**:`anchored` ### action:wx_phone_login 微信小程序手机号授权登录:`getPhoneNumber` 的 phoneCode + `uni.login` 的 loginCode 换手机号并沉淀 openid。 - **入口**:`POST /api/user/wx-phone-login` → `UserController#wxPhoneLogin` → `UserService#loginByVerifiedPhone`(公开) - **输出**:`entity:user`、`entity:store`、`session_token`、可能绑定 `wechat_openid`/`wechat_unionid` - **适用规则**:`rule:BR-AUTH-001` - **代码**:`backend/src/main/java/com/petstore/controller/UserController.java#wxPhoneLogin` - **证据**:`anchored`(生产登录主路径) ### action:bind_wechat 绑定小程序 openid/unionid;若标识曾绑定其他账号则先解绑。 - **入口**:`UserController#wxPhoneLogin` 内调用 `UserService#bindWechatMiniIdentity` - **适用规则**:— - **代码**:`backend/src/main/java/com/petstore/service/UserService.java#bindWechatMiniIdentity` - **证据**:`anchored` ## Appointment 相关 ### action:create_appointment 创建预约:按服务时长跨半小时容量桶占号,并保存时长快照;取消不占号;客户与创建人分开记录。 - **入口**:`POST /api/appointment/create` → `AppointmentController#create` → `AppointmentService#createBooking` - **输入**:`petName`、`petType`、`serviceType`、`appointmentTime`、`storeId`、`remark?`、`petId?`;门店代客预约另需 `customerUserId` 或 `customerPhone` - **输出**:`entity:appointment` - **身份口径**:customer 自约时客户=创建人=current.userId;boss/staff 代约时创建人=current.userId,客户按请求解析,legacy userId 镜像客户 - **适用规则**:`rule:BR-APPT-001`(状态机)、`rule:BR-APPT-003`(客户归属)、`rule:BR-APPT-004`(服务时长 + 门店容量 + 并发锁)、`rule:BR-SC-001`(门店客户建档) - **代码**:`backend/src/main/java/com/petstore/controller/AppointmentController.java#create` - **证据**:`anchored` ### action:start_service 开始服务:仅 `new → doing`,指定技师(谁点谁服务);仅 boss/staff 且同店。 - **入口**:`POST /api/appointment/start` → `AppointmentController#start` → `AppointmentService#startService` - **适用规则**:`rule:BR-APPT-001`、`rule:BR-APPT-002`(仅 boss/staff + 同店) - **代码**:`backend/src/main/java/com/petstore/controller/AppointmentController.java#start` - **测试**:`AppointmentServiceTest` - **证据**:`anchored` ### action:transition_appointment_status 更新预约状态:合法迁移见 `AppointmentService#transitionStatus`;customer 仅可取消自己的。 - **入口**:`PUT /api/appointment/status` → `AppointmentController#updateStatus` - **适用规则**:`rule:BR-APPT-001`、`rule:BR-APPT-003`(customer 仅取消自己的) - **代码**:`backend/src/main/java/com/petstore/controller/AppointmentController.java#updateStatus` - **测试**:`AppointmentServiceTest` - **证据**:`anchored` ### action:get_appointment_detail 预约详情:customer 仅本人,boss/staff 仅同店。 - **入口**:`GET /api/appointment/detail` → `AppointmentController#detail` - **适用规则**:`rule:BR-APPT-002`、`rule:BR-APPT-003` - **代码**:`backend/src/main/java/com/petstore/controller/AppointmentController.java#detail` - **测试**:`AppointmentControllerDetailTest` - **证据**:`anchored` ### action:list_appointments 预约列表:身份从上下文派生,customer 看自己,boss/staff 看本店。 - **入口**:`GET /api/appointment/list` → `AppointmentController#list` - **适用规则**:`rule:BR-APPT-002`、`rule:BR-APPT-003` - **代码**:`backend/src/main/java/com/petstore/controller/AppointmentController.java#list` - **证据**:`anchored` ## Report 相关 ### action:submit_report 提交报告:仅 boss/staff;`authorStaffId` 从上下文派生,`customerUserId` 从预约派生;报告所属门店必须等于当前用户门店。 - **入口**:`POST /api/report/create` → `ReportController#create` → `ReportService#create` - **输入**:`appointmentId`、`remark?`、`images`;身份字段不从请求体采信 - **输出**:`reportToken`、`reportId` - **适用规则**:`rule:BR-RPT-001`(必须绑定预约)、`rule:BR-RPT-002`(一约一份)、`rule:BR-RPT-003`(前后照片必填)、`rule:BR-RPT-004`(仅 doing 预约)、`rule:BR-RPT-005`(跨店 403) - **代码**:`backend/src/main/java/com/petstore/controller/ReportController.java#create` - **测试**:`ReportControllerTest`、`ReportServiceTest` - **证据**:`anchored` ### action:get_report_by_token 公开报告查询:凭 token 匿名访问,字段裁剪不返回 top-level `userId/storeId/reportToken`。 - **入口**:`GET /api/report/get?token=` → `ReportController#getByAppointmentId`(公开) - **适用规则**:`rule:BR-RPT-006`(公开字段裁剪) - **代码**:`backend/src/main/java/com/petstore/controller/ReportController.java#getByAppointmentId` - **测试**:`ReportControllerTest#publicTokenQueryHidesInternalFields` - **证据**:`anchored` ### action:confirm_report_sent 门店员工在宠主实际收到报告后显式确认发送。复制链接、生成/展示二维码、打开 H5 或预览报告都不自动计为发送;首次确认写入不可覆盖的回执,重复确认幂等成功。 - **入口**:`POST /api/report/confirm-sent` → `ReportController#confirmSent` → `ReportService#confirmSent` - **输入**:`reportId`、`channel=wechat|qr|other`;门店、员工与角色均从会话派生 - **输出**:`sendStatus`、`sentAt`、`sendChannel`、`alreadyConfirmed` - **适用规则**:`rule:BR-RPT-005`、`rule:BR-RPT-008`、`rule:BR-BE-001` - **触发事件**:`event:report_sent`(仅首次确认) - **代码**:`ReportController#confirmSent`、`ReportService#confirmSent`、`BusinessEventService#recordReportSent` - **测试**:`ReportControllerTest`、`ReportServiceTest`、`BusinessEventServiceTest` - **证据**:`anchored` ### action:track_report_open 报告打开埋点:服务端用 token 定位 Report 后写入低敏 BusinessEvent;事件表不保存 token/hash,日志只记 SHA-256 前 8 位 hash。 - **入口**:`POST /api/report/open-track` → `ReportController#trackReportOpen`(公开) - **适用规则**:`rule:BR-RPT-007`(token hash 日志)、`rule:BR-BE-001`(不可变与低敏事件) - **代码**:`ReportController#trackReportOpen`、`BusinessEventService#recordReportOpenByToken` - **测试**:`ReportControllerTest`、`BusinessEventServiceTest` - **证据**:`anchored` ### action:delete_report 删除报告:仅 boss/staff 且同店。 - **入口**:`DELETE /api/report/delete` → `ReportController#delete` - **适用规则**:`rule:BR-RPT-005` - **代码**:`backend/src/main/java/com/petstore/controller/ReportController.java#delete` - **证据**:`anchored`(同店校验用 `reportService.list(storeId,null)` 遍历,性能非最优,列为已知 gap) ## ReportLead 相关 ### action:submit_lead 宠主留资:凭 `reportToken` 匿名提交手机号,同报告同手机号去重。 - **入口**:`POST /api/report/{token}/reminder` → `ReportLeadController#submitReminder` → `ReportLeadService#submit`(公开) - **输入**:`phone`、`consent`、`loginCode?` - **输出**:`leadId`、`remindDate`、`unsubscribeToken`、`wechatBound` - **适用规则**:`rule:BR-LEAD-001`(去重)、`rule:BR-SC-001`(门店客户建档/绑定)、`rule:BR-BE-001`(低敏事件) - **代码**:`backend/src/main/java/com/petstore/controller/ReportLeadController.java#submitReminder` - **测试**:`ReportLeadControllerTest`、`ReportLeadServiceStoreCustomerTest` - **证据**:`anchored` ### action:unsubscribe 一键退订:凭 `unsubscribeToken`。 - **入口**:`POST /api/report/unsubscribe` → `ReportLeadController#unsubscribe`(公开) - **适用规则**:`rule:BR-UNSUB-001` - **代码**:`backend/src/main/java/com/petstore/controller/ReportLeadController.java#unsubscribe` - **测试**:`ReportLeadControllerTest` - **证据**:`anchored` ### action:list_leads 回访池列表:仅 boss/staff,`storeId` 从上下文派生;返回脱敏 openid/unionid。 - **入口**:`GET /api/report/leads` → `ReportLeadController#leads` - **适用规则**:`rule:BR-LEAD-002`(标识脱敏)、`rule:BR-LEAD-003`(跨店 403) - **代码**:`backend/src/main/java/com/petstore/controller/ReportLeadController.java#leads` - **证据**:`anchored` --- ## Batch 2 录入动作 ## Pet 相关 ### action:list_pets 宠物列表:customer 查自己宠物(`ownerUserId=current.userId`);boss/staff 查本店服务过的宠物(`storeId=current.storeId`)。 - **入口**:`GET /api/pet/list` → `PetController#list` - **适用规则**:`rule:BR-PET-001`(跨用户/跨店) - **代码**:`backend/src/main/java/com/petstore/controller/PetController.java#list` - **证据**:`anchored` ### action:create_pet 创建宠物档案:customer 强制 `ownerUserId=current.userId`;boss/staff 用 body.ownerUserId(代客建档)。 - **入口**:`POST /api/pet/create` → `PetController#create` → `PetService#create` - **适用规则**:`rule:BR-PET-001` - **代码**:`backend/src/main/java/com/petstore/controller/PetController.java#create` - **证据**:`anchored` ### action:update_pet 更新宠物:`operatorUserId`/`role` 从上下文派生。 - **入口**:`PUT /api/pet/update` → `PetController#update` → `PetService#update` - **适用规则**:`rule:BR-PET-001` - **代码**:`backend/src/main/java/com/petstore/controller/PetController.java#update` - **证据**:`anchored` ### action:delete_pet 删除宠物:`operatorUserId`/`role` 从上下文派生。 - **入口**:`DELETE /api/pet/delete` → `PetController#delete` → `PetService#delete` - **适用规则**:`rule:BR-PET-001` - **代码**:`backend/src/main/java/com/petstore/controller/PetController.java#delete` - **证据**:`anchored` ### action:get_pet_history 宠物服务时间线:宠主本人或本店员工/老板可查。 - **入口**:`GET /api/pet/history` → `PetController#history` → `PetService#getServiceHistory` - **适用规则**:`rule:BR-PET-001` - **代码**:`backend/src/main/java/com/petstore/controller/PetController.java#history` - **证据**:`anchored` ## ServiceType 相关 ### action:list_service_types 服务类型列表:公开接口,不传 storeId 返回系统默认;传 storeId 返回系统默认 + 该店自定义,同名时本店定义优先;每项返回预计服务时长。 - **入口**:`GET /api/service-type/list` → `ServiceTypeController#list`(公开,在 AuthInterceptor allowlist) - **代码**:`backend/src/main/java/com/petstore/controller/ServiceTypeController.java#list` - **证据**:`anchored` ### action:create_service_type 新增服务类型:仅 boss;`storeId=current.storeId`;必须填写 30 分钟粒度的预计时长。 - **入口**:`POST /api/service-type/create` → `ServiceTypeController#create` → `ServiceTypeService#create` - **适用规则**:`rule:BR-ST-001`(仅 boss + 同店) - **代码**:`backend/src/main/java/com/petstore/controller/ServiceTypeController.java#create` - **测试**:`ServiceTypeControllerTest` - **证据**:`anchored` ### action:update_service_type 编辑服务类型:仅 boss;必须为本店自定义(系统默认 `storeId` 为空不可改、他店不可改);名称和预计时长一起更新。 - **入口**:`PUT /api/service-type/update` → `ServiceTypeController#update` - **适用规则**:`rule:BR-ST-001` - **代码**:`backend/src/main/java/com/petstore/controller/ServiceTypeController.java#update` - **测试**:`ServiceTypeControllerTest` - **证据**:`anchored` ### action:delete_service_type 删除服务类型:仅 boss;必须为本店自定义(系统默认不可删、他店不可删)。 - **入口**:`DELETE /api/service-type/delete` → `ServiceTypeController#delete` - **适用规则**:`rule:BR-ST-001` - **代码**:`backend/src/main/java/com/petstore/controller/ServiceTypeController.java#delete` - **测试**:`ServiceTypeControllerTest` - **证据**:`anchored` ### action:init_service_types 初始化系统默认服务类型:仅 boss/staff(启动期已自动初始化)。 - **入口**:`POST /api/service-type/init` → `ServiceTypeController#init` - **代码**:`backend/src/main/java/com/petstore/controller/ServiceTypeController.java#init` - **测试**:`ServiceTypeControllerTest` - **证据**:`anchored` ## Schedule 相关 ### action:day_agenda 门店某日日程:仅 boss/staff;`storeId=current.storeId`;每个半小时桶返回预约/手动占用列表及已用、总计、剩余容量。 - **入口**:`GET /api/schedule/day` → `ScheduleController#day` → `ScheduleService#dayAgenda` - **适用规则**:`rule:BR-SCH-001`(仅 boss/staff + 跨店 403) - **代码**:`backend/src/main/java/com/petstore/controller/ScheduleController.java#day` - **测试**:`ScheduleControllerTest` - **证据**:`anchored` ### action:create_schedule_block 手动占用连续半小时档:仅 boss/staff;`storeId=current.storeId`、`createdByUserId=current.userId`;`walk_in` 消耗一个并发名额,`blocked` 关闭全部名额。 - **入口**:`POST /api/schedule/block` → `ScheduleController#createBlock` → `ScheduleService#createBlock` - **适用规则**:`rule:BR-SCH-001`、`rule:BR-SCH-002`、`rule:BR-APPT-004` - **代码**:`backend/src/main/java/com/petstore/controller/ScheduleController.java#createBlock` - **测试**:`ScheduleControllerTest` - **证据**:`anchored` ### action:delete_schedule_block 取消手动占用:仅 boss/staff;service 层做同店校验(`operatorStoreId`)。 - **入口**:`DELETE /api/schedule/block` → `ScheduleController#deleteBlock` → `ScheduleService#deleteBlock` - **适用规则**:`rule:BR-SCH-001` - **代码**:`backend/src/main/java/com/petstore/controller/ScheduleController.java#deleteBlock`、`service/ScheduleService.java#deleteBlock` - **测试**:`ScheduleControllerTest` - **证据**:`anchored` ## Upload / Highlight 相关 ### action:upload_image 上传图片/视频:扩展名/MIME 校验 + 路径归一化防逃逸;需登录。 - **入口**:`POST /api/upload/image` → `FileController#uploadImage` - **适用规则**:`rule:BR-UPLOAD-001`(路径归一化)、`rule:BR-UPLOAD-002`(扩展名/MIME 校验) - **代码**:`backend/src/main/java/com/petstore/controller/FileController.java#uploadImage` - **证据**:`anchored` ### action:get_upload_image 读取上传资源:公开(在 AuthInterceptor allowlist `GET /api/upload/image/**`);路径归一化防逃逸。 - **入口**:`GET /api/upload/image/**` → `FileController#getImage` - **适用规则**:`rule:BR-UPLOAD-001` - **代码**:`backend/src/main/java/com/petstore/controller/FileController.java#getImage` - **证据**:`anchored` ### action:generate_highlight 触发服务回顾短片生成:仅 boss/staff;`operatorUserId`/`role` 从上下文派生;异步 FFmpeg 拼接。 - **入口**:`POST /api/report/highlight/start` → `ReportController#startHighlight` → `ReportHighlightVideoService#requestGenerate` - **适用规则**:`rule:BR-HL-001`(仅 boss/staff)、`rule:BR-HL-002`(三态 + composeMode) - **代码**:`backend/src/main/java/com/petstore/controller/ReportController.java#startHighlight`、`service/ReportHighlightVideoService.java#requestGenerate` - **文档**:`docs/洗美报告短视频成片方案.md` - **证据**:`anchored`(接口与上下文派生已实现;FFmpeg 集成测试 `gap`) ## User 管理相关 ### action:create_staff 老板创建员工:仅 boss;`storeId=current.storeId`。 - **入口**:`POST /api/user/create-staff` → `UserController#createStaff` → `UserService#createStaff` - **适用规则**:`rule:BR-USER-001`(仅 boss) - **代码**:`backend/src/main/java/com/petstore/controller/UserController.java#createStaff` - **证据**:`anchored` ### action:list_staff 员工列表:仅 boss/staff;`storeId=current.storeId`。 - **入口**:`GET /api/user/staff-list` → `UserController#staffList` - **适用规则**:`rule:BR-USER-001` - **代码**:`backend/src/main/java/com/petstore/controller/UserController.java#staffList` - **证据**:`anchored` ### action:delete_staff 删除员工:仅 boss;目标员工必须属于本店。 - **入口**:`DELETE /api/user/staff` → `UserController#deleteStaff` - **适用规则**:`rule:BR-USER-001` - **代码**:`backend/src/main/java/com/petstore/controller/UserController.java#deleteStaff` - **证据**:`anchored` ### action:update_user 更新当前登录用户信息(头像/姓名/手机号):`id=current.userId`(覆盖请求体);手机号变更需 SMS 验证码(生产禁用)。 - **入口**:`PUT /api/user/update` → `UserController#updateUser` → `UserService#updateUser` - **适用规则**:`rule:BR-USER-002`(仅本人)、`rule:BR-AUTH-002`(生产手机号变更禁用) - **代码**:`backend/src/main/java/com/petstore/controller/UserController.java#updateUser` - **证据**:`anchored` --- ## Batch 2.1 补录动作(audit_drift 发现的遗漏) ## 公开查询类(在 AuthInterceptor allowlist) ### action:list_stores 门店列表:公开接口,经 `toPublicStoreView` 裁剪(不含 ownerId/inviteCode)。 - **入口**:`GET /api/store/list` → `StoreController#list`(公开) - **适用规则**:`rule:BR-STORE-003` - **代码**:`backend/src/main/java/com/petstore/controller/StoreController.java#list` - **测试**:`StoreControllerTest#publicListHidesOwnerIdAndInviteCode` - **证据**:`anchored` ### action:get_store 门店详情:公开接口,经 `toPublicStoreView` 裁剪(含 intro/营业时段,不含 ownerId/inviteCode/deleted)。 - **入口**:`GET /api/store/get` → `StoreController#get`(公开) - **适用规则**:`rule:BR-STORE-003` - **代码**:`backend/src/main/java/com/petstore/controller/StoreController.java#get` - **测试**:`StoreControllerTest#publicGetHidesOwnerIdAndInviteCode` - **证据**:`anchored` ### action:get_available_slots 门店某日可预约开始时段:公开接口,接收可选 `serviceType`,按服务时长检查覆盖的所有容量桶,返回开始/结束时间、容量与不可约原因。 - **入口**:`GET /api/appointment/available-slots` → `AppointmentController#availableSlots`(公开) - **适用规则**:`rule:BR-APPT-004`(时段校验) - **代码**:`backend/src/main/java/com/petstore/controller/AppointmentController.java#availableSlots` - **证据**:`anchored` ### action:get_report_suggestion 报告下次建议日期:公开接口,凭 token 查询(读取 `entity:service_interval` 推算)。 - **入口**:`GET /api/report/{token}/suggestion` → `ReportLeadController#suggestion`(公开) - **适用规则**:`rule:BR-INT-001` - **代码**:`backend/src/main/java/com/petstore/controller/ReportLeadController.java#suggestion` - **证据**:`anchored` ### action:submit_testimonial 宠主寄语提交:公开接口,凭 token 提交;同一报告保留一条,重复提交更新。 - **入口**:`POST /api/report/{token}/testimonial` → `ReportController#submitTestimonial`(公开) - **输出**:`entity:report_testimonial` - **适用规则**:`rule:BR-TST-001` - **触发事件**:`event:testimonial_saved` - **代码**:`backend/src/main/java/com/petstore/controller/ReportController.java#submitTestimonial` - **证据**:`anchored` ### action:get_legacy_upload 兼容旧路径读取上传资源:公开接口,路径归一化防逃逸。 - **入口**:`GET /api/upload/legacy/**` → `FileController#getLegacyImage`(公开) - **适用规则**:`rule:BR-UPLOAD-001` - **代码**:`backend/src/main/java/com/petstore/controller/FileController.java#getLegacyImage` - **证据**:`anchored` ## 注册/短信类(公开) ### action:register_staff 员工注册(邀请码方式):公开接口,凭邀请码加入对应门店。 - **入口**:`POST /api/user/register-staff` → `UserController#registerStaff` → `UserService#registerStaff`(公开) - **输出**:`entity:user`(staff)、`entity:store`、`session_token` - **适用规则**:`rule:BR-AUTH-001` - **代码**:`backend/src/main/java/com/petstore/controller/UserController.java#registerStaff` - **证据**:`anchored` ### action:send_sms 发送短信验证码:公开接口;**生产禁用**(`universalSmsCode` 为空时返回 403 `SMS_LOGIN_DISABLED`)。 - **入口**:`POST /api/sms/send` → `SmsController#send`(公开) - **适用规则**:`rule:BR-AUTH-002` - **代码**:`backend/src/main/java/com/petstore/controller/SmsController.java#send` - **证据**:`anchored` ### action:register_store 店铺注册(旧入口):公开接口,创建 Store。**deprecated**:与 `action:register_boss` 重复,勿作为新集成入口。 - **入口**:`POST /api/store/register` → `StoreController#register` → `StoreService#create` - **输出**:`entity:store` - **状态**:`deprecated` - **代码**:`backend/src/main/java/com/petstore/controller/StoreController.java#register` - **证据**:`gap`(与 `register_boss` 重复,建议废弃或合并) ## 删除/列表类(protected) ### action:delete_appointment 删除预约:仅 boss/staff 且同店。 - **入口**:`DELETE /api/appointment/delete` → `AppointmentController#delete` - **适用规则**:`rule:BR-APPT-002` - **代码**:`backend/src/main/java/com/petstore/controller/AppointmentController.java#delete` - **证据**:`anchored` ### action:list_reports 报告列表:boss/staff 查本店,customer 查自己相关报告;身份从上下文派生。 - **入口**:`GET /api/report/list` → `ReportController#list` - **适用规则**:`rule:BR-RPT-005`(跨店 403) - **代码**:`backend/src/main/java/com/petstore/controller/ReportController.java#list` - **证据**:`anchored` ## 微信 OAuth(TODO demo,deprecated) ### action:wechat_authorize 获取微信授权跳转 URL:公开接口(TODO demo,真实微信登录走 `action:wx_phone_login`)。**deprecated**。 - **入口**:`GET /api/wechat/authorize` → `WechatController#getAuthorizeUrl`(公开) - **状态**:`deprecated` - **代码**:`backend/src/main/java/com/petstore/controller/WechatController.java#getAuthorizeUrl` - **证据**:`gap`(TODO demo,未真实实现) ### action:wechat_callback 微信授权回调:公开接口(TODO demo,返回 `demo_openid_` + code,未真实换取 access_token)。**deprecated**。 - **入口**:`GET /api/wechat/callback` → `WechatController#callback`(公开) - **状态**:`deprecated` - **代码**:`backend/src/main/java/com/petstore/controller/WechatController.java#callback` - **证据**:`gap`(TODO demo,未真实实现;真实微信登录走 `action:wx_phone_login`) ## 客户端埋点 / 会话生命周期 ### action:track_video_play 成片点击播放埋点(前端客户端事件)。 - **入口**:frontend `reportView` / `videoPlayer`(client-emitted) - **触发事件**:`event:video_play` - **证据**:`documented`(schema 已冻结;上报与统计落地 `gap`) ### action:track_video_save 成片保存到相册埋点(前端客户端事件)。 - **入口**:frontend `reportView` / `videoPlayer`(client-emitted) - **触发事件**:`event:video_save` - **证据**:`documented`(schema 已冻结;上报与统计落地 `gap`) ### action:logout 退出登录 / 吊销会话:当前仅前端清本地 token,**无服务端吊销**。 - **入口**:—(未实现) - **触发事件**:`event:session_revoked` - **适用规则**:`rule:BR-AUTH-001` - **证据**:`gap` ### action:get_user_info 获取当前登录用户信息:`userId=current.userId`。 - **入口**:`GET /api/user/info` → `UserController#info` - **适用规则**:`rule:BR-USER-002`、`rule:BR-USER-003` - **代码**:`backend/src/main/java/com/petstore/controller/UserController.java#info` - **证据**:`anchored` --- ## 门店 Web 后台(Phase A) > 产品:`docs/门店管理后台升级方案-对标宠老板.md`。优先复用现有 `/api/**`,不另造状态机。 ### action:view_workbench 查看今日行动工作台(登录落点)。服务端按完整本店数据聚合逾期预约、服务中、今日待开始、成片异常、新报告待发送和到期回访,返回准确总数与低敏预览;报告提交、显式确认发送、打开与留资通过 BusinessEvent 汇总,仅未建模的转预约保持未知。 - **入口**:Admin UI `/workbench`;`GET /api/admin/workbench/actions`;兼容 `GET /api/admin/workbench/report-funnel?date=yyyy-MM-dd` - **输出**:`entity:workbench`、`entity:workbench_todo_item` - **适用规则**:`rule:BR-ADMIN-001`、`rule:BR-ADMIN-002`、`rule:BR-ADMIN-004`、`rule:BR-BE-001` - **触发事件**:`event:workbench_viewed`(可选,gap) - **代码**:`AdminBusinessEventController`、`AdminWorkbenchService`、`AdminBusinessEventService`、`admin/src/views/WorkbenchView.vue` - **测试**:`AdminBusinessEventControllerTest`、`AdminWorkbenchServiceTest`、`AdminBusinessEventServiceTest` - **证据**:`anchored` ### action:drilldown_workbench_todo 工作台行动组或具体预览下钻到对应列表并带筛选;预约预览可按 ID 直接打开受保护详情。 - **入口**:Admin UI workbench action click - **适用规则**:`rule:BR-ADMIN-001`、`rule:BR-ADMIN-002` - **代码**:`admin/src/views/WorkbenchView.vue`、`AppointmentsView.vue` - **证据**:`anchored` ### action:admin_list_appointments 后台预约列表(增强筛选;规则复用 Appointment*)。 - **入口**:Admin UI `/appointments`(planned);数据复用 `GET /api/appointment/list` - **适用规则**:`rule:BR-ADMIN-001`、`rule:BR-ADMIN-002`、`rule:BR-APPT-001`、`rule:BR-APPT-002` - **证据**:`documented` ### action:admin_list_reports 后台报告列表(成片三态、发送三态、复制公开链接、显式确认发送、触发重生成)。 - **入口**:Admin UI `/reports`;复用 `GET /api/report/list` + `action:confirm_report_sent` + `action:generate_highlight` - **适用规则**:`rule:BR-ADMIN-001`、`rule:BR-ADMIN-002`、`rule:BR-ADMIN-003`、`rule:BR-RPT-005`、`rule:BR-RPT-008` - **证据**:`anchored` ### action:admin_list_leads 后台回访线索列表。 - **入口**:Admin UI `/leads`(planned);复用 `GET /api/report/leads` - **适用规则**:`rule:BR-ADMIN-001`、`rule:BR-ADMIN-002`、`rule:BR-LEAD-002`、`rule:BR-LEAD-003` - **证据**:`documented` ### action:admin_list_service_customers 后台服务客户列表(瘦身主档;姓名/手机/宠物名搜索)。 - **入口**:`GET /api/admin/service-customers` → `AdminServiceCustomerController#listServiceCustomers` → Admin UI `/customers` - **输出**:`entity:store_customer` - **适用规则**:`rule:BR-ADMIN-001` … `BR-ADMIN-004`、`rule:BR-SC-001` - **证据**:`anchored` - **代码**:`backend/src/main/java/com/petstore/controller/AdminServiceCustomerController.java`、`AdminServiceCustomerService` - **产品决策**:以 `t_store_customer` 稳定主档为入口聚合,返回 `storeCustomerId`;不做余额/次卡列、持卡会员导入 - **文档**:`docs/门店管理后台-PhaseA-页面清单PRD.md §7.6` ### action:admin_update_settings 后台门店设置(资料、营业时段、服务类型瘦身表单、员工)。 - **入口**:`GET /api/admin/store` → `AdminStoreController#currentStore`;Admin UI `/settings`;写资料 `PUT /api/store/update` - **适用规则**:`rule:BR-ADMIN-001`、`rule:BR-ADMIN-002`、`rule:BR-ADMIN-003`、`rule:BR-STORE-001`、`rule:BR-ST-001`、`rule:BR-USER-001` - **证据**:`anchored` - **代码**:`AdminStoreController`、`StoreController#update`;服务类型/员工复用既有 API ### action:admin_manage_schedule 后台排班与手动占用(日视图)。 - **入口**:Admin UI `/schedule`;`GET /api/schedule/day`;`POST/DELETE /api/schedule/block` - **适用规则**:`rule:BR-ADMIN-001`、`rule:BR-ADMIN-002`、`rule:BR-SCH-001` - **证据**:`anchored`