{"id":"entity:store","type":"Entity","name":"Store","nameZh":"门店","domain":"store","fields":["id","name","logo","phone","address","latitude","longitude","intro","owner_id","invite_code","booking_day_start","booking_last_slot_start","booking_capacity","create_time","update_time","deleted"],"systems":["Backend Core"],"code":"backend/src/main/java/com/petstore/entity/Store.java","doc":"docs/产品设计文档.md §三 t_store","test":"StoreControllerTest","evidence":"anchored"} {"id":"entity:user","type":"Entity","name":"User","nameZh":"用户","domain":"user","fields":["id","username","password","name","phone","avatar","store_id","role","wechat_openid","wechat_unionid","create_time","update_time","deleted"],"systems":["Backend Core"],"code":"backend/src/main/java/com/petstore/entity/User.java","doc":"docs/产品设计文档.md §三 t_user; docs/.agents/common-context.md 术语规则","test":"UserServiceLoginStrategyTest; UserJsonIgnoreTest","evidence":"anchored"} {"id":"entity:appointment","type":"Entity","name":"Appointment","nameZh":"预约","domain":"appointment","fields":["id","pet_name","pet_type","service_type","appointment_time","duration_minutes","status","store_id","user_id","customer_user_id","created_by_user_id","assigned_user_id","pet_id","remark","create_time","update_time","deleted"],"systems":["Backend Core"],"code":"backend/src/main/java/com/petstore/entity/Appointment.java; backend/src/main/java/com/petstore/service/AppointmentService.java","doc":"docs/产品设计文档.md §三 t_appointment §5.2; docs/架构决策-真实预约容量模型-2026-08-01.md","test":"AppointmentServiceTest; BookingCapacityServiceTest; AppointmentControllerDetailTest; AppointmentControllerIdentityTest; BookingCapacityMigrationTest","evidence":"anchored"} {"id":"entity:report","type":"Entity","name":"Report","nameZh":"服务报告","domain":"report","fields":["id","appointment_id","remark","user_id","customer_user_id","author_staff_id","store_id","report_token","pet_name","service_type","appointment_time","staff_name","highlight_video_url","highlight_video_status","highlight_video_error","highlight_duration_sec","highlight_compose_mode","highlight_fail_reason","highlight_share_cover_url","create_time","update_time","deleted"],"systems":["Report Media Backend"],"code":"backend/src/main/java/com/petstore/entity/Report.java; backend/src/main/java/com/petstore/service/ReportService.java","doc":"docs/产品设计文档.md §三 t_report §5.3; docs/API-报告成片字段契约.md","test":"ReportServiceTest; ReportControllerTest","evidence":"anchored"} {"id":"entity:report_lead","type":"Entity","name":"ReportLead","nameZh":"留资线索","domain":"lead","fields":["id","report_id","store_id","phone","pet_name","service_type","wechat_openid","wechat_unionid","reminder_type","remind_date","remind_status","unsubscribe_token","client_ip","create_time","update_time","deleted"],"systems":["Report Media Backend"],"code":"backend/src/main/java/com/petstore/controller/ReportLeadController.java; backend/src/main/java/com/petstore/entity/ReportLead.java","doc":"docs/本期主线-下一步产品优化点.md §C 留资","test":"ReportLeadControllerTest","evidence":"anchored"} {"id":"entity:business_event","type":"Entity","name":"BusinessEvent","nameZh":"不可变业务事件","domain":"platform","jpa":true,"fields":["id","event_id","event_type","event_version","store_id","store_customer_id","aggregate_type","aggregate_id","actor_user_id","actor_role","source","occurred_at","metadata_json","idempotency_key","create_time"],"systems":["Backend Core","Report Media Backend","Store Admin FE"],"code":"backend/src/main/java/com/petstore/entity/BusinessEvent.java; backend/src/main/java/com/petstore/service/BusinessEventService.java","doc":"docs/ontology/objects.md#entity:business_event; docs/架构决策-业务事件落库-2026-08-01.md","test":"BusinessEventServiceTest; BusinessEventMigrationTest","evidence":"anchored"} {"id":"action:register_boss","type":"Action","name":"registerBoss","nameZh":"老板入驻","inputs":["storeName","bossName","phone","password"],"outputs":["entity:store","entity:user","session_token"],"entrypoints":["POST /api/user/register-boss","UserService#registerBoss"],"appliesRules":["rule:BR-AUTH-001"],"code":"backend/src/main/java/com/petstore/service/UserService.java#registerBoss","evidence":"anchored","domain":"user"} {"id":"action:update_store","type":"Action","name":"updateStore","nameZh":"更新店铺","inputs":["entity:store"],"outputs":["entity:store"],"entrypoints":["PUT /api/store/update","StoreController#update","StoreService#update"],"appliesRules":["rule:BR-STORE-001"],"code":"backend/src/main/java/com/petstore/controller/StoreController.java#update","test":"StoreControllerTest","evidence":"anchored","domain":"store"} {"id":"action:delete_store","type":"Action","name":"deleteStore","nameZh":"删除店铺","inputs":["id"],"outputs":[],"entrypoints":["DELETE /api/store/delete","StoreController#delete"],"appliesRules":["rule:BR-STORE-001"],"code":"backend/src/main/java/com/petstore/controller/StoreController.java#delete","test":"StoreControllerTest","evidence":"anchored","domain":"store"} {"id":"action:get_store_by_invite_code","type":"Action","name":"getStoreByInviteCode","nameZh":"按邀请码查门店","inputs":["code"],"outputs":["entity:store"],"entrypoints":["GET /api/store/invite-code","StoreController#getByInviteCode"],"appliesRules":["rule:BR-STORE-002"],"code":"backend/src/main/java/com/petstore/controller/StoreController.java#getByInviteCode","test":"StoreControllerTest","evidence":"anchored","domain":"store"} {"id":"action:login","type":"Action","name":"login","nameZh":"手机号验证码登录","inputs":["phone","code"],"outputs":["entity:user","entity:store","session_token"],"entrypoints":["POST /api/user/login","UserService#login"],"appliesRules":["rule:BR-AUTH-001","rule:BR-AUTH-002"],"code":"backend/src/main/java/com/petstore/service/UserService.java#login","test":"UserServiceLoginStrategyTest","evidence":"anchored","domain":"auth"} {"id":"action:wx_phone_login","type":"Action","name":"wxPhoneLogin","nameZh":"微信手机号授权登录","inputs":["phoneCode","loginCode"],"outputs":["entity:user","entity:store","session_token"],"entrypoints":["POST /api/user/wx-phone-login","UserController#wxPhoneLogin","UserService#loginByVerifiedPhone"],"appliesRules":["rule:BR-AUTH-001"],"code":"backend/src/main/java/com/petstore/controller/UserController.java#wxPhoneLogin","evidence":"anchored","domain":"auth"} {"id":"action:bind_wechat","type":"Action","name":"bindWechat","nameZh":"绑定微信标识","inputs":["userId","openid","unionid"],"outputs":["entity:user"],"entrypoints":["UserService#bindWechatMiniIdentity"],"appliesRules":[],"code":"backend/src/main/java/com/petstore/service/UserService.java#bindWechatMiniIdentity","evidence":"anchored","domain":"auth"} {"id":"action:create_appointment","type":"Action","name":"createAppointment","nameZh":"创建预约","inputs":["petName","petType","serviceType","appointmentTime","storeId","remark","petId","customerUserId","customerPhone","customerName"],"outputs":["entity:appointment"],"entrypoints":["POST /api/appointment/create","AppointmentController#create","AppointmentService#createBooking"],"appliesRules":["rule:BR-APPT-001","rule:BR-APPT-003","rule:BR-APPT-004","rule:BR-SC-001","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/controller/AppointmentController.java#create; backend/src/main/java/com/petstore/service/AppointmentService.java#createBooking; backend/src/main/java/com/petstore/service/StoreCustomerService.java#touchBooking; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordAppointmentCreated","test":"AppointmentControllerIdentityTest; AppointmentServiceTest; StoreCustomerServiceTest; BusinessEventServiceTest","evidence":"anchored","domain":"appointment"} {"id":"action:start_service","type":"Action","name":"startService","nameZh":"开始服务","inputs":["appointmentId"],"outputs":["entity:appointment"],"entrypoints":["POST /api/appointment/start","AppointmentController#start","AppointmentService#startService"],"appliesRules":["rule:BR-APPT-001","rule:BR-APPT-002","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/controller/AppointmentController.java#start; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordAppointmentStatusChanged","test":"AppointmentServiceTest; BusinessEventServiceTest","evidence":"anchored","domain":"appointment"} {"id":"action:transition_appointment_status","type":"Action","name":"transitionAppointmentStatus","nameZh":"更新预约状态","inputs":["id","status"],"outputs":["entity:appointment"],"entrypoints":["PUT /api/appointment/status","AppointmentController#updateStatus","AppointmentService#transitionStatus"],"appliesRules":["rule:BR-APPT-001","rule:BR-APPT-002","rule:BR-APPT-003","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/controller/AppointmentController.java#updateStatus; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordAppointmentStatusChanged","test":"AppointmentServiceTest; BusinessEventServiceTest","evidence":"anchored","domain":"appointment"} {"id":"action:get_appointment_detail","type":"Action","name":"getAppointmentDetail","nameZh":"预约详情","inputs":["id"],"outputs":["entity:appointment"],"entrypoints":["GET /api/appointment/detail","AppointmentController#detail"],"appliesRules":["rule:BR-APPT-002","rule:BR-APPT-003"],"code":"backend/src/main/java/com/petstore/controller/AppointmentController.java#detail","test":"AppointmentControllerDetailTest","evidence":"anchored","domain":"appointment"} {"id":"action:list_appointments","type":"Action","name":"listAppointments","nameZh":"预约列表","inputs":["status","page","pageSize"],"outputs":["entity:appointment"],"entrypoints":["GET /api/appointment/list","AppointmentController#list"],"appliesRules":["rule:BR-APPT-002","rule:BR-APPT-003"],"code":"backend/src/main/java/com/petstore/controller/AppointmentController.java#list","evidence":"anchored","domain":"appointment"} {"id":"action:submit_report","type":"Action","name":"submitReport","nameZh":"提交报告","inputs":["appointmentId","remark","images"],"outputs":["reportToken","reportId"],"entrypoints":["POST /api/report/create","ReportController#create","ReportService#create"],"appliesRules":["rule:BR-RPT-001","rule:BR-RPT-002","rule:BR-RPT-003","rule:BR-RPT-004","rule:BR-RPT-005","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#create; backend/src/main/java/com/petstore/service/ReportService.java#create; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordReportSubmitted","test":"ReportControllerTest; ReportServiceTest; BusinessEventServiceTest","evidence":"anchored","domain":"report","note":"authorStaffId 从登录上下文派生,customerUserId 从预约派生;报告提交与事件同事务"} {"id":"action:get_report_by_token","type":"Action","name":"getReportByToken","nameZh":"公开报告查询","inputs":["token"],"outputs":["entity:report"],"entrypoints":["GET /api/report/get","ReportController#getByAppointmentId"],"appliesRules":["rule:BR-RPT-006"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#getByAppointmentId","test":"ReportControllerTest#publicTokenQueryHidesInternalFields","evidence":"anchored","domain":"report"} {"id":"action:track_report_open","type":"Action","name":"trackReportOpen","nameZh":"报告打开埋点","inputs":["token","visitType"],"outputs":["entity:business_event"],"entrypoints":["POST /api/report/open-track","ReportController#trackReportOpen"],"appliesRules":["rule:BR-RPT-007","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#trackReportOpen; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordReportOpenByToken","test":"ReportControllerTest; BusinessEventServiceTest","evidence":"anchored","domain":"report"} {"id":"action:delete_report","type":"Action","name":"deleteReport","nameZh":"删除报告","inputs":["id"],"outputs":[],"entrypoints":["DELETE /api/report/delete","ReportController#delete"],"appliesRules":["rule:BR-RPT-005"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#delete","evidence":"anchored","domain":"report"} {"id":"action:submit_lead","type":"Action","name":"submitLead","nameZh":"宠主留资","inputs":["token","phone","consent","loginCode"],"outputs":["leadId","remindDate","unsubscribeToken","wechatBound"],"entrypoints":["POST /api/report/{token}/reminder","ReportLeadController#submitReminder","ReportLeadService#submit"],"appliesRules":["rule:BR-LEAD-001","rule:BR-SC-001","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/controller/ReportLeadController.java#submitReminder; backend/src/main/java/com/petstore/service/ReportLeadService.java#submit; backend/src/main/java/com/petstore/service/StoreCustomerService.java#touchLead; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordLeadSubmitted","evidence":"anchored","test":"ReportLeadControllerTest; ReportLeadServiceStoreCustomerTest; StoreCustomerServiceTest; BusinessEventServiceTest","domain":"lead"} {"id":"action:unsubscribe","type":"Action","name":"unsubscribe","nameZh":"一键退订","inputs":["unsubscribeToken"],"outputs":[],"entrypoints":["POST /api/report/unsubscribe","ReportLeadController#unsubscribe"],"appliesRules":["rule:BR-UNSUB-001"],"code":"backend/src/main/java/com/petstore/controller/ReportLeadController.java#unsubscribe","evidence":"anchored","domain":"lead","test":"ReportLeadControllerTest"} {"id":"action:list_leads","type":"Action","name":"listLeads","nameZh":"回访池列表","inputs":["status"],"outputs":["entity:report_lead"],"entrypoints":["GET /api/report/leads","ReportLeadController#leads"],"appliesRules":["rule:BR-LEAD-002","rule:BR-LEAD-003"],"code":"backend/src/main/java/com/petstore/controller/ReportLeadController.java#leads","evidence":"anchored","test":"ReportLeadControllerTest","domain":"lead"} {"id":"event:store_registered","type":"Event","name":"StoreRegistered","nameZh":"门店入驻","domain":"store","payload":["storeId","bossUserId","inviteCode"],"emittedBy":["action:register_boss"],"evidence":"anchored"} {"id":"event:session_issued","type":"Event","name":"SessionIssued","nameZh":"签发会话令牌","domain":"auth","payload":["userId","storeId","role","exp"],"emittedBy":["action:register_boss","action:login","action:wx_phone_login"],"code":"backend/src/main/java/com/petstore/auth/SessionTokenService.java#issue","test":"SessionTokenServiceTest","evidence":"anchored"} {"id":"event:wx_bound","type":"Event","name":"WxBound","nameZh":"微信标识绑定","domain":"auth","payload":["userId","openid","unionid"],"emittedBy":["action:bind_wechat"],"code":"backend/src/main/java/com/petstore/service/UserService.java#bindWechatMiniIdentity","evidence":"anchored"} {"id":"event:appointment_created","type":"Event","name":"AppointmentCreated","nameZh":"预约创建","domain":"appointment","payload":["storeId","storeCustomerId","aggregateId","actorUserId","actorRole","bookingOrigin","durationMinutes","occurredAt"],"emittedBy":["action:create_appointment"],"appliesRules":["rule:BR-BE-001","rule:BR-APPT-004"],"code":"backend/src/main/java/com/petstore/service/AppointmentService.java#createBooking; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordAppointmentCreated","test":"AppointmentServiceTest; BusinessEventServiceTest","evidence":"anchored"} {"id":"event:appointment_status_changed","type":"Event","name":"AppointmentStatusChanged","nameZh":"预约状态迁移","domain":"appointment","payload":["storeId","storeCustomerId","aggregateId","fromStatus","toStatus","actorUserId","actorRole","occurredAt"],"emittedBy":["action:start_service","action:transition_appointment_status","action:submit_report"],"appliesRules":["rule:BR-APPT-001","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/service/AppointmentService.java#startService; #transitionStatus; backend/src/main/java/com/petstore/service/ReportService.java#create; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordAppointmentStatusChanged","test":"AppointmentServiceTest; ReportServiceTest#createDoingAppointmentMarksDone; BusinessEventServiceTest","evidence":"anchored"} {"id":"event:service_started","type":"Event","name":"ServiceStarted","nameZh":"服务开始","domain":"appointment","payload":["storeId","storeCustomerId","appointmentId","actorUserId","actorRole","occurredAt"],"emittedBy":["action:start_service"],"appliesRules":["rule:BR-APPT-001","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/service/BusinessEventService.java#recordAppointmentStatusChanged","test":"BusinessEventServiceTest#statusToDoingRecordsGenericAndServiceStartedFacts","evidence":"anchored"} {"id":"event:service_completed","type":"Event","name":"ServiceCompleted","nameZh":"服务完成","domain":"appointment","payload":["storeId","storeCustomerId","appointmentId","actorUserId","actorRole","occurredAt"],"emittedBy":["action:transition_appointment_status","action:submit_report"],"appliesRules":["rule:BR-APPT-001","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/service/BusinessEventService.java#recordAppointmentStatusChanged; backend/src/main/java/com/petstore/service/ReportService.java#create","test":"AppointmentServiceTest; ReportServiceTest","evidence":"anchored"} {"id":"event:report_submitted","type":"Event","name":"ReportSubmitted","nameZh":"报告提交","domain":"report","payload":["storeId","storeCustomerId","reportId","actorUserId","actorRole","occurredAt"],"emittedBy":["action:submit_report"],"appliesRules":["rule:BR-RPT-001","rule:BR-RPT-002","rule:BR-RPT-004","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/service/ReportService.java#create; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordReportSubmitted","test":"ReportServiceTest; BusinessEventServiceTest","evidence":"anchored"} {"id":"event:report_opened","type":"Event","name":"ReportOpened","nameZh":"报告首次打开","domain":"report","payload":["storeId","storeCustomerId","reportId","visitType","occurredAt"],"emittedBy":["action:track_report_open"],"appliesRules":["rule:BR-RPT-007","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#trackReportOpen; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordReportOpenByToken","doc":"docs/本期主线-下一步产品优化点.md 埋点事件 schema","test":"ReportControllerTest; BusinessEventServiceTest","evidence":"anchored"} {"id":"event:report_reopened","type":"Event","name":"ReportReopened","nameZh":"报告再次打开","domain":"report","payload":["storeId","storeCustomerId","reportId","visitType","occurredAt"],"emittedBy":["action:track_report_open"],"appliesRules":["rule:BR-RPT-007","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/service/BusinessEventService.java#recordReportOpenByToken","doc":"docs/本期主线-下一步产品优化点.md 埋点事件 schema","test":"BusinessEventServiceTest#reportOpenStoresReportIdButNeverToken","evidence":"anchored"} {"id":"event:lead_submitted","type":"Event","name":"LeadSubmitted","nameZh":"留资提交","domain":"lead","payload":["storeId","storeCustomerId","leadId","repeatSubmit","occurredAt"],"emittedBy":["action:submit_lead"],"appliesRules":["rule:BR-LEAD-001","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/service/ReportLeadService.java#submit; backend/src/main/java/com/petstore/service/BusinessEventService.java#recordLeadSubmitted","doc":"docs/本期主线-下一步产品优化点.md 埋点事件 schema","test":"ReportLeadServiceStoreCustomerTest; BusinessEventMigrationTest","evidence":"anchored"} {"id":"rule:BR-AUTH-001","type":"Rule","name":"HMAC session token 鉴权","domain":"auth","appliesTo":["action:register_boss","action:login","action:wx_phone_login","action:update_store","action:delete_store","action:get_store_by_invite_code","action:create_appointment","action:start_service","action:transition_appointment_status","action:get_appointment_detail","action:list_appointments","action:submit_report","action:get_report_by_token","action:track_report_open","action:delete_report","action:list_leads"],"code":"backend/src/main/java/com/petstore/auth/AuthInterceptor.java; SessionTokenService.java; CurrentUserContext.java","test":"SessionTokenServiceTest","evidence":"anchored"} {"id":"rule:BR-AUTH-002","type":"Rule","name":"生产登录策略:仅微信授权","domain":"auth","appliesTo":["action:login","action:wx_phone_login"],"code":"backend/src/main/java/com/petstore/service/UserService.java#login; SmsController.java","test":"UserServiceLoginStrategyTest","evidence":"anchored"} {"id":"rule:BR-STORE-001","type":"Rule","name":"店铺更新/删除仅 boss + 同店","domain":"store","appliesTo":["action:update_store","action:delete_store"],"code":"backend/src/main/java/com/petstore/controller/StoreController.java#update; #delete","test":"StoreControllerTest","evidence":"anchored"} {"id":"rule:BR-STORE-002","type":"Rule","name":"邀请码查询仅 boss/staff + 同店","domain":"store","appliesTo":["action:get_store_by_invite_code"],"code":"backend/src/main/java/com/petstore/controller/StoreController.java#getByInviteCode","test":"StoreControllerTest#inviteCodeCrossStoreForbidden","evidence":"anchored"} {"id":"rule:BR-APPT-001","type":"Rule","name":"预约状态机","domain":"appointment","appliesTo":["action:start_service","action:transition_appointment_status","action:submit_report"],"code":"backend/src/main/java/com/petstore/service/AppointmentService.java#startService; #transitionStatus","test":"AppointmentServiceTest","evidence":"anchored"} {"id":"rule:BR-APPT-002","type":"Rule","name":"预约跨店 403","domain":"appointment","appliesTo":["action:list_appointments","action:start_service","action:transition_appointment_status","action:get_appointment_detail"],"code":"backend/src/main/java/com/petstore/controller/AppointmentController.java","test":"AppointmentControllerDetailTest","evidence":"anchored"} {"id":"rule:BR-APPT-003","type":"Rule","name":"预约客户归属与跨用户 403","domain":"appointment","appliesTo":["action:create_appointment","action:get_appointment_detail","action:transition_appointment_status"],"code":"backend/src/main/java/com/petstore/controller/AppointmentController.java#create; #detail; #updateStatus; backend/src/main/java/com/petstore/service/AppointmentService.java#createBooking","test":"AppointmentControllerIdentityTest; AppointmentControllerDetailTest#customerCannotViewOthersAppointment","evidence":"anchored"} {"id":"rule:BR-APPT-004","type":"Rule","name":"真实预约容量:服务时长快照 + 跨桶容量 + 同店并发锁","domain":"appointment","appliesTo":["action:create_appointment","action:get_available_slots","action:create_schedule_block"],"code":"backend/src/main/java/com/petstore/service/AppointmentService.java#createBooking; backend/src/main/java/com/petstore/service/BookingCapacityService.java; backend/src/main/java/com/petstore/service/ScheduleService.java#createBlock","doc":"docs/产品设计文档.md §5.2; docs/架构决策-真实预约容量模型-2026-08-01.md","test":"BookingCapacityServiceTest; AppointmentServiceTest; BookingCapacityMigrationTest","evidence":"anchored"} {"id":"rule:BR-RPT-001","type":"Rule","name":"报告必须绑定预约","domain":"report","appliesTo":["action:submit_report"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#create; service/ReportService.java#create","test":"ReportControllerTest#createMissingAppointmentIdReturnsBizCode; ReportServiceTest#createWithNullAppointmentIdThrows","evidence":"anchored"} {"id":"rule:BR-RPT-002","type":"Rule","name":"一约一份报告","domain":"report","appliesTo":["action:submit_report"],"code":"backend/src/main/java/com/petstore/entity/Report.java; mapper/ReportMapper.java; service/ReportService.java#create; controller/ReportController.java#create","test":"ReportServiceTest#createDuplicateReportThrows; ReportControllerTest#createDuplicateReportReturnsAlreadyExists","evidence":"anchored"} {"id":"rule:BR-RPT-003","type":"Rule","name":"报告前后照片必填","domain":"report","appliesTo":["action:submit_report"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#hasPhotoType; frontend/src/pages/report/Report.vue#submitReport","test":"ReportControllerTest#createMissingBeforePhotoReturnsBizCode; createMissingAfterPhotoReturnsBizCode","doc":"docs/产品设计文档.md §5.3 报告提交必填项","evidence":"anchored"} {"id":"rule:BR-RPT-004","type":"Rule","name":"报告仅 doing 预约可提交","domain":"report","appliesTo":["action:submit_report"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#create; service/ReportService.java#create","test":"ReportServiceTest#createDoingAppointmentMarksDone","evidence":"anchored"} {"id":"rule:BR-RPT-005","type":"Rule","name":"报告跨店 403","domain":"report","appliesTo":["action:submit_report","action:delete_report"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#create; #delete","test":"ReportControllerTest#createCrossStoreReturnsForbidden; createNonStaffReturnsForbidden","evidence":"anchored"} {"id":"rule:BR-RPT-006","type":"Rule","name":"公开报告字段裁剪","domain":"report","appliesTo":["action:get_report_by_token"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#getByAppointmentId","test":"ReportControllerTest#publicTokenQueryHidesInternalFields","frontend":"frontend/src/pages/report-view/reportView.vue","evidence":"anchored"} {"id":"rule:BR-RPT-007","type":"Rule","name":"token hash 日志","domain":"report","appliesTo":["action:track_report_open"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#shortTokenHash; #trackReportOpen","evidence":"anchored"} {"id":"rule:BR-LEAD-001","type":"Rule","name":"留资去重","domain":"lead","appliesTo":["action:submit_lead"],"code":"backend/src/main/java/com/petstore/service/ReportLeadService.java#submit","evidence":"anchored","test":"ReportLeadControllerTest#submitLeadRepeatSubmitReturnsAlreadySubmitted"} {"id":"rule:BR-SC-001","type":"Rule","name":"门店客户主档唯一性与合并","domain":"admin","appliesTo":["action:create_appointment","action:submit_lead","action:admin_list_service_customers"],"code":"backend/src/main/java/com/petstore/service/StoreCustomerService.java","doc":"docs/ontology/rules.md#rule:BR-SC-001; docs/架构决策-门店客户主档-2026-08-01.md","test":"StoreCustomerServiceTest; ReportLeadServiceStoreCustomerTest; IdentityOwnershipQueryTest","evidence":"anchored"} {"id":"rule:BR-BE-001","type":"Rule","name":"业务事件不可变幂等与低敏","domain":"platform","appliesTo":["action:create_appointment","action:start_service","action:transition_appointment_status","action:submit_report","action:track_report_open","action:submit_lead","action:view_workbench"],"code":"backend/src/main/java/com/petstore/service/BusinessEventService.java; backend/src/main/java/com/petstore/service/AdminBusinessEventService.java","doc":"docs/ontology/rules.md#rule:BR-BE-001; docs/架构决策-业务事件落库-2026-08-01.md","test":"BusinessEventServiceTest; BusinessEventMigrationTest; AdminBusinessEventControllerTest","evidence":"anchored"} {"id":"rule:BR-LEAD-002","type":"Rule","name":"留资标识脱敏","domain":"lead","appliesTo":["action:list_leads"],"code":"backend/src/main/java/com/petstore/controller/ReportLeadController.java#maskIdentifier; #leads","frontend":"frontend/src/pages/mine/Leads.vue","evidence":"anchored"} {"id":"rule:BR-LEAD-003","type":"Rule","name":"回访池跨店 403","domain":"lead","appliesTo":["action:list_leads"],"code":"backend/src/main/java/com/petstore/controller/ReportLeadController.java#leads","evidence":"anchored"} {"id":"rel:store_has_users","type":"Relation","subject":"entity:store","predicate":"HAS","object":"entity:user","cardinality":"1—N","evidence":"anchored","doc":"User.store_id → Store.id","domain":"store"} {"id":"rel:user_belongs_to_store","type":"Relation","subject":"entity:user","predicate":"BELONGS_TO","object":"entity:store","cardinality":"N—1","evidence":"anchored","doc":"boss/staff 归属一个门店;customer 可无门店","domain":"user"} {"id":"rel:store_has_appointments","type":"Relation","subject":"entity:store","predicate":"HAS","object":"entity:appointment","cardinality":"1—N","evidence":"anchored","doc":"Appointment.store_id","domain":"store"} {"id":"rel:user_creates_appointments","type":"Relation","subject":"entity:user","predicate":"CREATES","object":"entity:appointment","cardinality":"1—N","evidence":"anchored","doc":"Appointment.created_by_user_id","domain":"user"} {"id":"rel:user_owns_appointments","type":"Relation","subject":"entity:user","predicate":"RECEIVES_SERVICE_IN","object":"entity:appointment","cardinality":"1—N","evidence":"anchored","doc":"Appointment.customer_user_id(客户归属)","domain":"user"} {"id":"rel:user_serves_appointments","type":"Relation","subject":"entity:user","predicate":"SERVES","object":"entity:appointment","cardinality":"1—N","evidence":"anchored","doc":"Appointment.assigned_user_id(谁点谁服务)","domain":"user"} {"id":"rel:appointment_has_report","type":"Relation","subject":"entity:appointment","predicate":"HAS","object":"entity:report","cardinality":"1—1","evidence":"anchored","doc":"Report.appointment_id(uk_report_appointment 唯一约束)","domain":"appointment"} {"id":"rel:report_belongs_to_store","type":"Relation","subject":"entity:report","predicate":"BELONGS_TO","object":"entity:store","cardinality":"N—1","evidence":"anchored","doc":"Report.store_id","domain":"report"} {"id":"rel:report_served_by_user","type":"Relation","subject":"entity:report","predicate":"SERVED_BY","object":"entity:user","cardinality":"N—1","evidence":"anchored","doc":"Report.appointment_id -> Appointment.assigned_user_id(服务技师)","domain":"report"} {"id":"rel:report_authored_by_user","type":"Relation","subject":"entity:report","predicate":"AUTHORED_BY","object":"entity:user","cardinality":"N—1","evidence":"anchored","doc":"Report.author_staff_id(报告作者)","domain":"report"} {"id":"rel:report_belongs_to_customer","type":"Relation","subject":"entity:report","predicate":"BELONGS_TO_CUSTOMER","object":"entity:user","cardinality":"N—1","evidence":"anchored","doc":"Report.customer_user_id(报告归属客户)","domain":"report"} {"id":"rel:report_has_leads","type":"Relation","subject":"entity:report","predicate":"HAS","object":"entity:report_lead","cardinality":"1—N","evidence":"anchored","doc":"ReportLead.report_id(同手机号去重)","domain":"report"} {"id":"rel:lead_belongs_to_store","type":"Relation","subject":"entity:report_lead","predicate":"BELONGS_TO","object":"entity:store","cardinality":"N—1","evidence":"anchored","doc":"ReportLead.store_id(回访池范围)","domain":"lead"} {"id":"rel:register_boss_emits_store_registered","type":"Relation","subject":"action:register_boss","predicate":"EMITS","object":"event:store_registered","evidence":"anchored","domain":"user"} {"id":"rel:register_boss_emits_session_issued","type":"Relation","subject":"action:register_boss","predicate":"EMITS","object":"event:session_issued","evidence":"anchored","domain":"user"} {"id":"rel:login_emits_session_issued","type":"Relation","subject":"action:login","predicate":"EMITS","object":"event:session_issued","evidence":"anchored","domain":"auth"} {"id":"rel:wx_phone_login_emits_session_issued","type":"Relation","subject":"action:wx_phone_login","predicate":"EMITS","object":"event:session_issued","evidence":"anchored","domain":"auth"} {"id":"rel:wx_phone_login_emits_wx_bound","type":"Relation","subject":"action:wx_phone_login","predicate":"EMITS","object":"event:wx_bound","evidence":"anchored","domain":"auth"} {"id":"rel:create_appointment_emits_appointment_created","type":"Relation","subject":"action:create_appointment","predicate":"EMITS","object":"event:appointment_created","evidence":"anchored","domain":"appointment"} {"id":"rel:start_service_emits_status_changed","type":"Relation","subject":"action:start_service","predicate":"EMITS","object":"event:appointment_status_changed","evidence":"anchored","domain":"appointment"} {"id":"rel:start_service_emits_service_started","type":"Relation","subject":"action:start_service","predicate":"EMITS","object":"event:service_started","evidence":"anchored","domain":"appointment"} {"id":"rel:transition_status_emits_status_changed","type":"Relation","subject":"action:transition_appointment_status","predicate":"EMITS","object":"event:appointment_status_changed","evidence":"anchored","domain":"appointment"} {"id":"rel:submit_report_emits_report_submitted","type":"Relation","subject":"action:submit_report","predicate":"EMITS","object":"event:report_submitted","evidence":"anchored","domain":"report"} {"id":"rel:submit_report_emits_status_changed","type":"Relation","subject":"action:submit_report","predicate":"EMITS","object":"event:appointment_status_changed","evidence":"anchored","doc":"doing→done","domain":"report"} {"id":"rel:submit_report_emits_service_completed","type":"Relation","subject":"action:submit_report","predicate":"EMITS","object":"event:service_completed","evidence":"anchored","domain":"report"} {"id":"rel:store_has_business_events","type":"Relation","subject":"entity:store","predicate":"HAS","object":"entity:business_event","evidence":"anchored","cardinality":"1—N","domain":"platform","doc":"BusinessEvent.store_id"} {"id":"rel:store_customer_has_business_events","type":"Relation","subject":"entity:store_customer","predicate":"HAS","object":"entity:business_event","evidence":"anchored","cardinality":"1—N","domain":"platform","doc":"BusinessEvent.store_customer_id 可空"} {"id":"rel:track_report_open_emits_report_opened","type":"Relation","subject":"action:track_report_open","predicate":"EMITS","object":"event:report_opened","evidence":"anchored","domain":"report"} {"id":"rel:track_report_open_emits_report_reopened","type":"Relation","subject":"action:track_report_open","predicate":"EMITS","object":"event:report_reopened","evidence":"documented","domain":"report"} {"id":"rel:submit_lead_emits_lead_submitted","type":"Relation","subject":"action:submit_lead","predicate":"EMITS","object":"event:lead_submitted","evidence":"documented","domain":"lead"} {"id":"entity:pet","type":"Entity","name":"Pet","nameZh":"宠物档案","domain":"pet","fields":["id","name","pet_type","breed","avatar","owner_user_id","remark","create_time","update_time","deleted"],"systems":["Backend Core"],"code":"backend/src/main/java/com/petstore/entity/Pet.java; controller/PetController.java; service/PetService.java","doc":"docs/产品设计文档.md §三 t_pet","test":"PetControllerTest","evidence":"anchored"} {"id":"entity:service_type","type":"Entity","name":"ServiceType","nameZh":"服务类型","domain":"service_type","fields":["id","store_id","name","duration_minutes","create_time"],"systems":["Backend Core"],"code":"backend/src/main/java/com/petstore/entity/ServiceType.java; controller/ServiceTypeController.java","doc":"docs/产品设计文档.md §三 t_service_type §5.2; docs/架构决策-真实预约容量模型-2026-08-01.md","test":"ServiceTypeControllerTest; BookingCapacityMigrationTest","evidence":"anchored"} {"id":"entity:schedule_block","type":"Entity","name":"ScheduleBlock","nameZh":"门店排班占用","domain":"schedule","fields":["id","store_id","slot_start","duration_minutes","block_type","note","created_by_user_id","create_time","update_time","deleted"],"systems":["Backend Core"],"code":"backend/src/main/java/com/petstore/entity/ScheduleBlock.java; controller/ScheduleController.java; service/ScheduleService.java","doc":"docs/产品设计文档.md §5.2 预约时段占用; docs/架构决策-真实预约容量模型-2026-08-01.md","test":"ScheduleControllerTest; BookingCapacityServiceTest; BookingCapacityMigrationTest","evidence":"anchored"} {"id":"entity:report_image","type":"Entity","name":"ReportImage","nameZh":"报告媒体","domain":"report","fields":["id","report_id","photo_url","photo_type","media_type","sort_order","create_time"],"systems":["Report Media Backend"],"code":"backend/src/main/java/com/petstore/entity/ReportImage.java; mapper/ReportImageMapper.java","doc":"docs/产品设计文档.md §三 t_report_image","test":"ReportServiceTest#createWithImagesSavesEachImage","evidence":"anchored"} {"id":"entity:highlight_video","type":"Entity","name":"HighlightVideo","nameZh":"服务回顾短片","domain":"report","fields":["report_id","highlight_video_url","highlight_video_status","highlight_video_error","highlight_duration_sec","highlight_compose_mode","highlight_fail_reason","highlight_share_cover_url"],"systems":["Report Media Backend"],"code":"backend/src/main/java/com/petstore/entity/Report.java; service/ReportHighlightVideoService.java","doc":"docs/API-报告成片字段契约.md; docs/洗美报告短视频成片方案.md","test":"ReportHighlightVideoServiceTest","evidence":"anchored","jpa":false} {"id":"entity:session_token","type":"Entity","name":"SessionToken","nameZh":"会话令牌","domain":"auth","fields":["userId","storeId","role","exp"],"systems":["Backend Core"],"code":"backend/src/main/java/com/petstore/auth/SessionTokenService.java; CurrentUser.java; CurrentUserContext.java; AuthInterceptor.java","doc":"docs/ontology/rules.md#rule:BR-AUTH-001","test":"SessionTokenServiceTest","evidence":"anchored","jpa":false} {"id":"action:list_pets","type":"Action","name":"listPets","nameZh":"宠物列表","inputs":[],"outputs":["entity:pet"],"entrypoints":["GET /api/pet/list","PetController#list"],"appliesRules":["rule:BR-PET-001"],"code":"backend/src/main/java/com/petstore/controller/PetController.java#list","evidence":"anchored","test":"PetControllerTest","domain":"pet"} {"id":"action:create_pet","type":"Action","name":"createPet","nameZh":"创建宠物","inputs":["entity:pet"],"outputs":["entity:pet"],"entrypoints":["POST /api/pet/create","PetController#create","PetService#create"],"appliesRules":["rule:BR-PET-001"],"code":"backend/src/main/java/com/petstore/controller/PetController.java#create","evidence":"anchored","test":"PetControllerTest","domain":"pet"} {"id":"action:update_pet","type":"Action","name":"updatePet","nameZh":"更新宠物","inputs":["id","name","petType","breed","avatar","remark"],"outputs":["entity:pet"],"entrypoints":["PUT /api/pet/update","PetController#update","PetService#update"],"appliesRules":["rule:BR-PET-001"],"code":"backend/src/main/java/com/petstore/controller/PetController.java#update","evidence":"anchored","test":"PetControllerTest","domain":"pet"} {"id":"action:delete_pet","type":"Action","name":"deletePet","nameZh":"删除宠物","inputs":["id"],"outputs":[],"entrypoints":["DELETE /api/pet/delete","PetController#delete","PetService#delete"],"appliesRules":["rule:BR-PET-001"],"code":"backend/src/main/java/com/petstore/controller/PetController.java#delete","evidence":"anchored","test":"PetControllerTest","domain":"pet"} {"id":"action:get_pet_history","type":"Action","name":"getPetHistory","nameZh":"宠物服务时间线","inputs":["petId"],"outputs":[],"entrypoints":["GET /api/pet/history","PetController#history","PetService#getServiceHistory"],"appliesRules":["rule:BR-PET-001"],"code":"backend/src/main/java/com/petstore/controller/PetController.java#history","evidence":"anchored","test":"PetControllerTest","domain":"pet"} {"id":"action:list_service_types","type":"Action","name":"listServiceTypes","nameZh":"服务类型列表","inputs":["storeId"],"outputs":["entity:service_type"],"entrypoints":["GET /api/service-type/list","ServiceTypeController#list"],"appliesRules":[],"code":"backend/src/main/java/com/petstore/controller/ServiceTypeController.java#list","evidence":"anchored","domain":"service_type"} {"id":"action:create_service_type","type":"Action","name":"createServiceType","nameZh":"新增服务类型","inputs":["name","durationMinutes"],"outputs":["entity:service_type"],"entrypoints":["POST /api/service-type/create","ServiceTypeController#create","ServiceTypeService#create"],"appliesRules":["rule:BR-ST-001"],"code":"backend/src/main/java/com/petstore/controller/ServiceTypeController.java#create","test":"ServiceTypeControllerTest","evidence":"anchored","domain":"service_type"} {"id":"action:update_service_type","type":"Action","name":"updateServiceType","nameZh":"编辑服务类型","inputs":["id","name","durationMinutes"],"outputs":["entity:service_type"],"entrypoints":["PUT /api/service-type/update","ServiceTypeController#update"],"appliesRules":["rule:BR-ST-001"],"code":"backend/src/main/java/com/petstore/controller/ServiceTypeController.java#update","test":"ServiceTypeControllerTest","evidence":"anchored","domain":"service_type"} {"id":"action:delete_service_type","type":"Action","name":"deleteServiceType","nameZh":"删除服务类型","inputs":["id"],"outputs":[],"entrypoints":["DELETE /api/service-type/delete","ServiceTypeController#delete"],"appliesRules":["rule:BR-ST-001"],"code":"backend/src/main/java/com/petstore/controller/ServiceTypeController.java#delete","test":"ServiceTypeControllerTest","evidence":"anchored","domain":"service_type"} {"id":"action:init_service_types","type":"Action","name":"initServiceTypes","nameZh":"初始化系统默认服务类型","inputs":[],"outputs":[],"entrypoints":["POST /api/service-type/init","ServiceTypeController#init"],"appliesRules":["rule:BR-ST-001"],"code":"backend/src/main/java/com/petstore/controller/ServiceTypeController.java#init","test":"ServiceTypeControllerTest","evidence":"anchored","domain":"service_type"} {"id":"action:day_agenda","type":"Action","name":"dayAgenda","nameZh":"门店某日日程","inputs":["date"],"outputs":["entity:appointment","entity:schedule_block"],"entrypoints":["GET /api/schedule/day","ScheduleController#day","ScheduleService#dayAgenda"],"appliesRules":["rule:BR-SCH-001","rule:BR-SCH-002"],"code":"backend/src/main/java/com/petstore/controller/ScheduleController.java#day","test":"ScheduleControllerTest; BookingCapacityServiceTest","evidence":"anchored","domain":"schedule"} {"id":"action:create_schedule_block","type":"Action","name":"createScheduleBlock","nameZh":"手动占用时段","inputs":["slotStart","durationMinutes","blockType","note"],"outputs":["entity:schedule_block"],"entrypoints":["POST /api/schedule/block","ScheduleController#createBlock","ScheduleService#createBlock"],"appliesRules":["rule:BR-SCH-001","rule:BR-SCH-002","rule:BR-APPT-004"],"code":"backend/src/main/java/com/petstore/controller/ScheduleController.java#createBlock","test":"ScheduleControllerTest; BookingCapacityServiceTest","evidence":"anchored","domain":"schedule"} {"id":"action:delete_schedule_block","type":"Action","name":"deleteScheduleBlock","nameZh":"取消手动占用","inputs":["id"],"outputs":[],"entrypoints":["DELETE /api/schedule/block","ScheduleController#deleteBlock","ScheduleService#deleteBlock"],"appliesRules":["rule:BR-SCH-001"],"code":"backend/src/main/java/com/petstore/controller/ScheduleController.java#deleteBlock; service/ScheduleService.java#deleteBlock","test":"ScheduleControllerTest","evidence":"anchored","domain":"schedule"} {"id":"action:upload_image","type":"Action","name":"uploadImage","nameZh":"上传图片/视频","inputs":["file"],"outputs":["url"],"entrypoints":["POST /api/upload/image","FileController#uploadImage"],"appliesRules":["rule:BR-UPLOAD-001","rule:BR-UPLOAD-002"],"code":"backend/src/main/java/com/petstore/controller/FileController.java#uploadImage","evidence":"anchored","domain":"upload"} {"id":"action:get_upload_image","type":"Action","name":"getUploadImage","nameZh":"读取上传资源","inputs":["path"],"outputs":[],"entrypoints":["GET /api/upload/image/**","FileController#getImage"],"appliesRules":["rule:BR-UPLOAD-001"],"code":"backend/src/main/java/com/petstore/controller/FileController.java#getImage","evidence":"anchored","domain":"upload"} {"id":"action:generate_highlight","type":"Action","name":"generateHighlight","nameZh":"触发成片生成","inputs":["reportId","composeMode"],"outputs":["entity:highlight_video"],"entrypoints":["POST /api/report/highlight/start","ReportController#startHighlight","ReportHighlightVideoService#requestGenerate"],"appliesRules":["rule:BR-HL-001","rule:BR-HL-002"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#startHighlight; service/ReportHighlightVideoService.java#requestGenerate","doc":"docs/洗美报告短视频成片方案.md","evidence":"anchored","domain":"report","test":"ReportHighlightVideoServiceTest"} {"id":"action:create_staff","type":"Action","name":"createStaff","nameZh":"老板创建员工","inputs":["name","phone"],"outputs":["entity:user"],"entrypoints":["POST /api/user/create-staff","UserController#createStaff","UserService#createStaff"],"appliesRules":["rule:BR-USER-001"],"code":"backend/src/main/java/com/petstore/controller/UserController.java#createStaff","evidence":"anchored","domain":"user"} {"id":"action:list_staff","type":"Action","name":"listStaff","nameZh":"员工列表","inputs":[],"outputs":["entity:user"],"entrypoints":["GET /api/user/staff-list","UserController#staffList"],"appliesRules":["rule:BR-USER-001"],"code":"backend/src/main/java/com/petstore/controller/UserController.java#staffList","evidence":"anchored","domain":"user"} {"id":"action:delete_staff","type":"Action","name":"deleteStaff","nameZh":"删除员工","inputs":["staffId"],"outputs":[],"entrypoints":["DELETE /api/user/staff","UserController#deleteStaff"],"appliesRules":["rule:BR-USER-001"],"code":"backend/src/main/java/com/petstore/controller/UserController.java#deleteStaff","evidence":"anchored","domain":"user"} {"id":"action:update_user","type":"Action","name":"updateUser","nameZh":"更新当前用户信息","inputs":["name","phone","avatar","code"],"outputs":["entity:user"],"entrypoints":["PUT /api/user/update","UserController#updateUser","UserService#updateUser"],"appliesRules":["rule:BR-USER-002","rule:BR-AUTH-002"],"code":"backend/src/main/java/com/petstore/controller/UserController.java#updateUser","evidence":"anchored","domain":"user"} {"id":"action:get_user_info","type":"Action","name":"getUserInfo","nameZh":"获取当前用户信息","inputs":[],"outputs":["entity:user"],"entrypoints":["GET /api/user/info","UserController#info"],"appliesRules":["rule:BR-USER-002","rule:BR-USER-003"],"code":"backend/src/main/java/com/petstore/controller/UserController.java#info","evidence":"anchored","domain":"user"} {"id":"event:highlight_succeeded","type":"Event","name":"HighlightSucceeded","nameZh":"成片生成成功","domain":"report","payload":["reportTokenHash","appointmentId","durationSec","composeMode","ts"],"emittedBy":["action:generate_highlight"],"appliesRules":["rule:BR-HL-002"],"code":"backend/src/main/java/com/petstore/service/ReportHighlightVideoService.java","doc":"docs/本期主线-下一步产品优化点.md 埋点事件 schema","evidence":"documented"} {"id":"event:highlight_failed","type":"Event","name":"HighlightFailed","nameZh":"成片生成失败","domain":"report","payload":["reportTokenHash","appointmentId","failReason","ts"],"emittedBy":["action:generate_highlight"],"appliesRules":["rule:BR-HL-002"],"code":"backend/src/main/java/com/petstore/service/ReportHighlightVideoService.java","doc":"docs/本期主线-下一步产品优化点.md 埋点事件 schema","evidence":"documented"} {"id":"event:video_play","type":"Event","name":"VideoPlay","nameZh":"成片点击播放","domain":"report","payload":["reportTokenHash","ts","source"],"emittedBy":["action:track_video_play"],"doc":"docs/本期主线-下一步产品优化点.md 埋点事件 schema","evidence":"documented"} {"id":"event:video_save","type":"Event","name":"VideoSave","nameZh":"成片保存到相册","domain":"report","payload":["reportTokenHash","ts"],"emittedBy":["action:track_video_save"],"doc":"docs/本期主线-下一步产品优化点.md 埋点事件 schema","evidence":"documented"} {"id":"event:upload_completed","type":"Event","name":"UploadCompleted","nameZh":"上传完成","domain":"upload","payload":["url","mediaType","size","ts"],"emittedBy":["action:upload_image"],"code":"backend/src/main/java/com/petstore/controller/FileController.java#uploadImage","evidence":"implemented"} {"id":"event:schedule_block_created","type":"Event","name":"ScheduleBlockCreated","nameZh":"排班占用创建","domain":"schedule","payload":["blockId","storeId","slotStart","blockType","createdByUserId"],"emittedBy":["action:create_schedule_block"],"code":"backend/src/main/java/com/petstore/service/ScheduleService.java#createBlock","evidence":"anchored"} {"id":"event:schedule_block_deleted","type":"Event","name":"ScheduleBlockDeleted","nameZh":"排班占用取消","domain":"schedule","payload":["blockId","storeId"],"emittedBy":["action:delete_schedule_block"],"code":"backend/src/main/java/com/petstore/service/ScheduleService.java#deleteBlock","evidence":"anchored"} {"id":"event:service_type_created","type":"Event","name":"ServiceTypeCreated","nameZh":"服务类型创建","domain":"service_type","payload":["serviceTypeId","storeId","name"],"emittedBy":["action:create_service_type"],"code":"backend/src/main/java/com/petstore/service/ServiceTypeService.java#create","evidence":"anchored"} {"id":"event:service_type_deleted","type":"Event","name":"ServiceTypeDeleted","nameZh":"服务类型删除","domain":"service_type","payload":["serviceTypeId","storeId"],"emittedBy":["action:delete_service_type"],"code":"backend/src/main/java/com/petstore/service/ServiceTypeService.java#delete","evidence":"anchored"} {"id":"event:pet_created","type":"Event","name":"PetCreated","nameZh":"宠物档案创建","domain":"pet","payload":["petId","ownerUserId","name","petType"],"emittedBy":["action:create_pet"],"code":"backend/src/main/java/com/petstore/service/PetService.java#create","evidence":"anchored"} {"id":"event:staff_created","type":"Event","name":"StaffCreated","nameZh":"员工创建","domain":"user","payload":["staffId","storeId","name","phone"],"emittedBy":["action:create_staff"],"code":"backend/src/main/java/com/petstore/service/UserService.java#createStaff","evidence":"anchored"} {"id":"event:user_updated","type":"Event","name":"UserUpdated","nameZh":"用户信息更新","domain":"user","payload":["userId","updatedFields"],"emittedBy":["action:update_user"],"code":"backend/src/main/java/com/petstore/service/UserService.java#updateUser","evidence":"anchored"} {"id":"rule:BR-UPLOAD-001","type":"Rule","name":"上传路径归一化","domain":"upload","appliesTo":["action:upload_image","action:get_upload_image"],"code":"backend/src/main/java/com/petstore/controller/FileController.java#resolveSafePath; #uploadRoot","evidence":"anchored"} {"id":"rule:BR-UPLOAD-002","type":"Rule","name":"上传扩展名/MIME 校验","domain":"upload","appliesTo":["action:upload_image"],"code":"backend/src/main/java/com/petstore/controller/FileController.java#isAllowedMediaType; #hasMediaExtension","evidence":"anchored"} {"id":"rule:BR-HL-001","type":"Rule","name":"成片仅 boss/staff 可触发","domain":"report","appliesTo":["action:generate_highlight"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#startHighlight","evidence":"anchored","test":"ReportHighlightVideoServiceTest#requestGenerateRejectsCustomerWithoutAppointmentOwnershipPath"} {"id":"rule:BR-HL-002","type":"Rule","name":"成片三态 + composeMode","domain":"report","appliesTo":["action:generate_highlight"],"code":"backend/src/main/java/com/petstore/entity/Report.java; service/ReportHighlightVideoService.java","doc":"docs/洗美报告短视频成片方案.md; docs/API-报告成片字段契约.md","evidence":"anchored","test":"ReportHighlightVideoServiceTest"} {"id":"rule:BR-SCH-001","type":"Rule","name":"排班仅 boss/staff + 跨店 403","domain":"schedule","appliesTo":["action:day_agenda","action:create_schedule_block","action:delete_schedule_block"],"code":"backend/src/main/java/com/petstore/controller/ScheduleController.java; service/ScheduleService.java#deleteBlock","test":"ScheduleControllerTest","evidence":"anchored"} {"id":"rule:BR-SCH-002","type":"Rule","name":"手动占用容量语义:walk_in 消耗一份,blocked 关闭全部","domain":"schedule","appliesTo":["action:day_agenda","action:create_schedule_block"],"code":"backend/src/main/java/com/petstore/service/ScheduleService.java; backend/src/main/java/com/petstore/service/BookingCapacityService.java","test":"BookingCapacityServiceTest; ScheduleControllerTest","evidence":"anchored"} {"id":"rule:BR-ST-001","type":"Rule","name":"服务类型仅 boss + 同店 + 系统默认不可改删","domain":"service_type","appliesTo":["action:create_service_type","action:update_service_type","action:delete_service_type","action:init_service_types"],"code":"backend/src/main/java/com/petstore/controller/ServiceTypeController.java","test":"ServiceTypeControllerTest","evidence":"anchored"} {"id":"rule:BR-PET-001","type":"Rule","name":"宠物跨用户/跨店","domain":"pet","appliesTo":["action:list_pets","action:create_pet","action:update_pet","action:delete_pet","action:get_pet_history"],"code":"backend/src/main/java/com/petstore/controller/PetController.java","evidence":"anchored","test":"PetControllerTest"} {"id":"rule:BR-USER-001","type":"Rule","name":"员工管理仅 boss + 同店","domain":"user","appliesTo":["action:create_staff","action:list_staff","action:delete_staff"],"code":"backend/src/main/java/com/petstore/controller/UserController.java","evidence":"anchored"} {"id":"rule:BR-USER-002","type":"Rule","name":"用户更新仅本人","domain":"user","appliesTo":["action:update_user","action:get_user_info"],"code":"backend/src/main/java/com/petstore/controller/UserController.java#updateUser; #info","evidence":"anchored"} {"id":"rule:BR-CONFIG-001","type":"Rule","name":"生产配置环境变量","domain":"config","appliesTo":[],"code":"backend/src/main/resources/application.yml; application-example.yml","doc":"backend/README.md 环境变量表","evidence":"anchored"} {"id":"rule:BR-CONFIG-002","type":"Rule","name":"production profile 强制只读 schema 安全配置","domain":"config","appliesTo":[],"code":"backend/src/main/resources/application.yml production profile; backend/src/main/java/com/petstore/config/ProductionConfigurationValidator.java; backend/src/main/java/com/petstore/PetstoreApplication.java","doc":"backend/README.md production profile","test":"ProductionConfigurationValidatorTest","evidence":"anchored","note":"生产禁用自动建表/show-sql/SMS 万能码/默认数据初始化,并拒绝弱密钥、占位域名和宽 CORS"} {"id":"rule:BR-CONFIG-003","type":"Rule","name":"生产发布只读门禁","domain":"config","appliesTo":[],"code":"backend/src/main/java/com/petstore/config/ProductionDatabasePreflightRunner.java; backend/src/main/java/com/petstore/config/PetstoreRuntimeHealthIndicator.java; backend/deploy/release-preflight.sh; backend/deploy/production-smoke.sh","doc":"docs/生产发布与回滚Runbook-2026-08-01.md; docs/生产监控与告警基线-2026-08-01.md","evidence":"anchored","note":"备份和四迁移后运行 schema validate + 15 项只读不变量;readiness 覆盖 DB/磁盘/上传/FFmpeg;自动 smoke 只读"} {"id":"rel:user_owns_pets","type":"Relation","subject":"entity:user","predicate":"OWNS","object":"entity:pet","cardinality":"1—N","evidence":"anchored","doc":"Pet.owner_user_id → User.id","domain":"user"} {"id":"rel:pet_has_appointments","type":"Relation","subject":"entity:pet","predicate":"HAS","object":"entity:appointment","cardinality":"1—N","evidence":"anchored","doc":"Appointment.pet_id(可空)","domain":"pet"} {"id":"rel:store_has_service_types","type":"Relation","subject":"entity:store","predicate":"HAS","object":"entity:service_type","cardinality":"1—N","evidence":"anchored","doc":"ServiceType.store_id(NULL=系统默认)","domain":"store"} {"id":"rel:store_has_schedule_blocks","type":"Relation","subject":"entity:store","predicate":"HAS","object":"entity:schedule_block","cardinality":"1—N","evidence":"anchored","doc":"ScheduleBlock.store_id","domain":"store"} {"id":"rel:user_creates_schedule_blocks","type":"Relation","subject":"entity:user","predicate":"CREATES","object":"entity:schedule_block","cardinality":"1—N","evidence":"anchored","doc":"ScheduleBlock.created_by_user_id","domain":"user"} {"id":"rel:report_has_highlight_video","type":"Relation","subject":"entity:report","predicate":"HAS","object":"entity:highlight_video","cardinality":"1—1","evidence":"anchored","doc":"Report.highlight_* 字段承载","domain":"report"} {"id":"rel:user_has_session_tokens","type":"Relation","subject":"entity:user","predicate":"HAS","object":"entity:session_token","cardinality":"1—N","evidence":"anchored","doc":"token payload userId","domain":"user"} {"id":"rel:report_has_images","type":"Relation","subject":"entity:report","predicate":"HAS","object":"entity:report_image","cardinality":"1—N","evidence":"anchored","doc":"ReportImage.report_id(before/after/during)","domain":"report"} {"id":"rel:generate_highlight_emits_succeeded","type":"Relation","subject":"action:generate_highlight","predicate":"EMITS","object":"event:highlight_succeeded","evidence":"documented","domain":"report"} {"id":"rel:generate_highlight_emits_failed","type":"Relation","subject":"action:generate_highlight","predicate":"EMITS","object":"event:highlight_failed","evidence":"documented","domain":"report"} {"id":"rel:upload_image_emits_upload_completed","type":"Relation","subject":"action:upload_image","predicate":"EMITS","object":"event:upload_completed","evidence":"implemented","domain":"upload"} {"id":"rel:create_schedule_block_emits_block_created","type":"Relation","subject":"action:create_schedule_block","predicate":"EMITS","object":"event:schedule_block_created","evidence":"anchored","domain":"schedule"} {"id":"rel:delete_schedule_block_emits_block_deleted","type":"Relation","subject":"action:delete_schedule_block","predicate":"EMITS","object":"event:schedule_block_deleted","evidence":"anchored","domain":"schedule"} {"id":"rel:create_service_type_emits_type_created","type":"Relation","subject":"action:create_service_type","predicate":"EMITS","object":"event:service_type_created","evidence":"anchored","domain":"service_type"} {"id":"rel:delete_service_type_emits_type_deleted","type":"Relation","subject":"action:delete_service_type","predicate":"EMITS","object":"event:service_type_deleted","evidence":"anchored","domain":"service_type"} {"id":"rel:create_pet_emits_pet_created","type":"Relation","subject":"action:create_pet","predicate":"EMITS","object":"event:pet_created","evidence":"anchored","domain":"pet"} {"id":"rel:create_staff_emits_staff_created","type":"Relation","subject":"action:create_staff","predicate":"EMITS","object":"event:staff_created","evidence":"anchored","domain":"user"} {"id":"rel:update_user_emits_user_updated","type":"Relation","subject":"action:update_user","predicate":"EMITS","object":"event:user_updated","evidence":"anchored","domain":"user"} {"id":"rel:bind_wechat_emits_wx_bound","type":"Relation","subject":"action:bind_wechat","predicate":"EMITS","object":"event:wx_bound","evidence":"anchored","domain":"auth"} {"id":"entity:report_testimonial","type":"Entity","name":"ReportTestimonial","nameZh":"宠主寄语","domain":"report","fields":["id","report_id","store_id","content","is_public","create_time","update_time"],"systems":["Report Media Backend"],"code":"backend/src/main/java/com/petstore/entity/ReportTestimonial.java; service/ReportTestimonialService.java","doc":"docs/ontology/objects.md#entity:report_testimonial","test":"ReportTestimonialServiceTest","evidence":"anchored"} {"id":"entity:service_interval","type":"Entity","name":"ServiceInterval","nameZh":"服务建议周期配置","domain":"service_type","fields":["id","store_id","service_name","pet_type","interval_days_min","interval_days_max","create_time"],"systems":["Report Media Backend"],"code":"backend/src/main/java/com/petstore/entity/ServiceInterval.java","doc":"docs/ontology/objects.md#entity:service_interval","test":"","evidence":"anchored"} {"id":"action:list_stores","type":"Action","name":"listStores","nameZh":"门店列表","inputs":[],"outputs":["entity:store"],"entrypoints":["GET /api/store/list","StoreController#list"],"appliesRules":["rule:BR-STORE-003"],"code":"backend/src/main/java/com/petstore/controller/StoreController.java#list","evidence":"anchored","domain":"store","test":"StoreControllerTest#publicListHidesOwnerIdAndInviteCode"} {"id":"action:get_store","type":"Action","name":"getStore","nameZh":"门店详情","inputs":["id"],"outputs":["entity:store"],"entrypoints":["GET /api/store/get","StoreController#get"],"appliesRules":["rule:BR-STORE-003"],"code":"backend/src/main/java/com/petstore/controller/StoreController.java#get","evidence":"anchored","domain":"store","test":"StoreControllerTest#publicGetHidesOwnerIdAndInviteCode"} {"id":"action:get_available_slots","type":"Action","name":"getAvailableSlots","nameZh":"可预约时段","inputs":["storeId","date","serviceType"],"outputs":[],"entrypoints":["GET /api/appointment/available-slots","AppointmentController#availableSlots"],"appliesRules":["rule:BR-APPT-004"],"code":"backend/src/main/java/com/petstore/controller/AppointmentController.java#availableSlots; backend/src/main/java/com/petstore/service/BookingCapacityService.java","test":"BookingCapacityServiceTest","evidence":"anchored","domain":"appointment"} {"id":"action:get_report_suggestion","type":"Action","name":"getReportSuggestion","nameZh":"报告下次建议日期","inputs":["token"],"outputs":[],"entrypoints":["GET /api/report/{token}/suggestion","ReportLeadController#suggestion"],"appliesRules":["rule:BR-INT-001"],"code":"backend/src/main/java/com/petstore/controller/ReportLeadController.java#suggestion","evidence":"anchored","domain":"lead"} {"id":"action:submit_testimonial","type":"Action","name":"submitTestimonial","nameZh":"宠主寄语提交","inputs":["token","content","isPublic"],"outputs":["entity:report_testimonial"],"entrypoints":["POST /api/report/{token}/testimonial","ReportController#submitTestimonial"],"appliesRules":["rule:BR-TST-001"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#submitTestimonial","evidence":"anchored","domain":"report","test":"ReportTestimonialServiceTest"} {"id":"action:get_legacy_upload","type":"Action","name":"getLegacyUpload","nameZh":"兼容旧路径读取上传资源","inputs":["path"],"outputs":[],"entrypoints":["GET /api/upload/legacy/**","FileController#getLegacyImage"],"appliesRules":["rule:BR-UPLOAD-001"],"code":"backend/src/main/java/com/petstore/controller/FileController.java#getLegacyImage","evidence":"anchored","domain":"upload"} {"id":"action:register_staff","type":"Action","name":"registerStaff","nameZh":"员工注册(邀请码)","inputs":["phone","password","name","inviteCode"],"outputs":["entity:user","entity:store","session_token"],"entrypoints":["POST /api/user/register-staff","UserController#registerStaff","UserService#registerStaff"],"appliesRules":["rule:BR-AUTH-001"],"code":"backend/src/main/java/com/petstore/controller/UserController.java#registerStaff","evidence":"anchored","domain":"user"} {"id":"action:send_sms","type":"Action","name":"sendSms","nameZh":"发送短信验证码","inputs":["phone"],"outputs":[],"entrypoints":["POST /api/sms/send","SmsController#send"],"appliesRules":["rule:BR-AUTH-002"],"code":"backend/src/main/java/com/petstore/controller/SmsController.java#send","evidence":"anchored","domain":"auth"} {"id":"action:register_store","type":"Action","name":"registerStore","nameZh":"店铺注册(旧入口)","inputs":["entity:store"],"outputs":["entity:store"],"entrypoints":["POST /api/store/register","StoreController#register","StoreService#create"],"appliesRules":[],"code":"backend/src/main/java/com/petstore/controller/StoreController.java#register","evidence":"gap","domain":"store","status":"deprecated","deprecated":true,"doc":"deprecated:勿作为新集成入口"} {"id":"action:delete_appointment","type":"Action","name":"deleteAppointment","nameZh":"删除预约","inputs":["id"],"outputs":[],"entrypoints":["DELETE /api/appointment/delete","AppointmentController#delete"],"appliesRules":["rule:BR-APPT-002"],"code":"backend/src/main/java/com/petstore/controller/AppointmentController.java#delete","evidence":"anchored","domain":"appointment"} {"id":"action:list_reports","type":"Action","name":"listReports","nameZh":"报告列表","inputs":["page","pageSize"],"outputs":["entity:report"],"entrypoints":["GET /api/report/list","ReportController#list"],"appliesRules":["rule:BR-RPT-005"],"code":"backend/src/main/java/com/petstore/controller/ReportController.java#list","evidence":"anchored","domain":"report"} {"id":"action:wechat_authorize","type":"Action","name":"wechatAuthorize","nameZh":"获取微信授权跳转URL","inputs":[],"outputs":[],"entrypoints":["GET /api/wechat/authorize","WechatController#getAuthorizeUrl"],"appliesRules":[],"code":"backend/src/main/java/com/petstore/controller/WechatController.java#getAuthorizeUrl","evidence":"gap","domain":"auth","status":"deprecated","deprecated":true,"doc":"deprecated:勿作为新集成入口"} {"id":"action:wechat_callback","type":"Action","name":"wechatCallback","nameZh":"微信授权回调","inputs":["code","state"],"outputs":[],"entrypoints":["GET /api/wechat/callback","WechatController#callback"],"appliesRules":[],"code":"backend/src/main/java/com/petstore/controller/WechatController.java#callback","evidence":"gap","domain":"auth","status":"deprecated","deprecated":true,"doc":"deprecated:勿作为新集成入口"} {"id":"rel:report_has_testimonial","type":"Relation","subject":"entity:report","predicate":"HAS","object":"entity:report_testimonial","cardinality":"1—1","evidence":"anchored","doc":"ReportTestimonial.report_id(唯一约束)","domain":"report"} {"id":"rel:testimonial_belongs_to_store","type":"Relation","subject":"entity:report_testimonial","predicate":"BELONGS_TO","object":"entity:store","cardinality":"N—1","evidence":"anchored","doc":"ReportTestimonial.store_id","domain":"report"} {"id":"rel:service_interval_belongs_to_store","type":"Relation","subject":"entity:service_interval","predicate":"BELONGS_TO","object":"entity:store","cardinality":"N—1","evidence":"anchored","doc":"ServiceInterval.store_id(NULL=系统默认)","domain":"service_type"} {"id":"rel:submit_testimonial_emits_testimonial_saved","type":"Relation","subject":"action:submit_testimonial","predicate":"EMITS","object":"event:testimonial_saved","evidence":"documented","doc":"寄语提交触发独立事件 event:testimonial_saved","domain":"report"} {"id":"entity:highlight_fail_reason","type":"Entity","name":"HighlightFailReason","nameZh":"成片失败原因归类","domain":"report","jpa":false,"fields":["MATERIAL","SERVICE","NETWORK","UNKNOWN"],"systems":["Report Media Backend"],"code":"backend/src/main/java/com/petstore/entity/HighlightFailReason.java","doc":"docs/ontology/objects.md#entity:highlight_fail_reason","test":"ReportHighlightVideoServiceTest#failReasonUserMessagesHaveNoTechJargon; #classifyFailureMapsReasons","evidence":"anchored"} {"id":"entity:current_user","type":"Entity","name":"CurrentUser","nameZh":"当前登录用户上下文","domain":"auth","jpa":false,"fields":["userId","storeId","role"],"systems":["Backend Core"],"code":"backend/src/main/java/com/petstore/auth/CurrentUser.java; CurrentUserContext.java; AuthInterceptor.java","doc":"docs/ontology/objects.md#entity:current_user","test":"SessionTokenServiceTest","evidence":"anchored"} {"id":"entity:membership","type":"Entity","name":"Membership","nameZh":"会员卡","domain":"growth","jpa":false,"fields":[],"systems":[],"code":"","doc":"docs/ontology/objects.md#待录入(P1/P2 方向,gap 证据)","test":"","evidence":"gap","status":"roadmap","note":"Phase A 门店后台明确不做;对标宠老板会员卡/升降级。仅 roadmap 占位。"} {"id":"entity:stored_value","type":"Entity","name":"StoredValue","nameZh":"储值","domain":"growth","jpa":false,"fields":[],"systems":[],"code":"","doc":"docs/ontology/objects.md#待录入(P1/P2 方向,gap 证据)","test":"","evidence":"gap","status":"roadmap","note":"Phase A 明确不做;依赖收银流水。"} {"id":"entity:service_package","type":"Entity","name":"ServicePackage","nameZh":"套餐","domain":"growth","jpa":false,"fields":[],"systems":[],"code":"","doc":"docs/ontology/objects.md#待录入(P1/P2 方向,gap 证据)","test":"","evidence":"gap","status":"roadmap","note":"Phase A 明确不做;次卡/套餐属 C 期。"} {"id":"entity:report_history","type":"Entity","name":"ReportHistory","nameZh":"宠主历史报告汇总","domain":"report","jpa":false,"fields":[],"systems":[],"code":"","doc":"docs/ontology/objects.md#待录入(P1/P2 方向,gap 证据)","test":"","evidence":"gap","status":"roadmap","note":"P2 方向库占位,不展开字段"} {"id":"entity:analytics_dashboard","type":"Entity","name":"AnalyticsDashboard","nameZh":"经营分析看板","domain":"analytics","jpa":false,"fields":[],"systems":[],"code":"","doc":"docs/ontology/objects.md#待录入(P1/P2 方向,gap 证据)","test":"","evidence":"gap","status":"roadmap","note":"B 期经营看板;A 期工作台仅轻量指标卡,不展开本实体。"} {"id":"rule:BR-USER-003","type":"Rule","name":"userSensitiveFieldsJsonIgnore","nameZh":"User 敏感字段不序列化","domain":"user","appliesTo":["action:login","action:wx_phone_login","action:get_user_info","action:update_user","action:register_boss","action:register_staff","action:list_staff"],"code":"backend/src/main/java/com/petstore/entity/User.java","doc":"docs/ontology/rules.md#rule:BR-USER-003","test":"UserJsonIgnoreTest","evidence":"anchored"} {"id":"rule:BR-STORE-003","type":"Rule","name":"publicStoreFieldTrim","nameZh":"公开门店字段裁剪","domain":"store","appliesTo":["action:get_store","action:list_stores"],"code":"backend/src/main/java/com/petstore/controller/StoreController.java#toPublicStoreView","doc":"docs/ontology/rules.md#rule:BR-STORE-003","test":"StoreControllerTest#publicGetHidesOwnerIdAndInviteCode; StoreControllerTest#publicListHidesOwnerIdAndInviteCode","evidence":"anchored","note":"公开 get/list 经 toPublicStoreView 裁剪,不含 ownerId/inviteCode/deleted"} {"id":"rule:BR-TST-001","type":"Rule","name":"oneReportOneTestimonial","nameZh":"一报告一寄语(重复提交更新)","domain":"report","appliesTo":["action:submit_testimonial"],"code":"backend/src/main/java/com/petstore/service/ReportTestimonialService.java","doc":"docs/ontology/rules.md#rule:BR-TST-001","test":"ReportTestimonialServiceTest","evidence":"anchored"} {"id":"rule:BR-UNSUB-001","type":"Rule","name":"unsubscribeByToken","nameZh":"凭 unsubscribeToken 一键退订","domain":"lead","appliesTo":["action:unsubscribe"],"code":"backend/src/main/java/com/petstore/controller/ReportLeadController.java#unsubscribe","doc":"docs/ontology/rules.md#rule:BR-UNSUB-001","test":"ReportLeadControllerTest","evidence":"anchored"} {"id":"rule:BR-INT-001","type":"Rule","name":"serviceIntervalSuggestion","nameZh":"服务建议周期推算下次日期","domain":"service_type","appliesTo":["action:get_report_suggestion"],"code":"backend/src/main/java/com/petstore/service/ReportLeadService.java#suggestNext","doc":"docs/ontology/rules.md#rule:BR-INT-001","test":"ReportLeadControllerTest","evidence":"anchored"} {"id":"action:track_video_play","type":"Action","name":"trackVideoPlay","nameZh":"成片点击播放埋点","domain":"report","inputs":["reportTokenHash","source"],"outputs":["event:video_play"],"entrypoints":["frontend reportView / videoPlayer (client-emitted)"],"appliesRules":[],"code":"","doc":"docs/本期主线-下一步产品优化点.md 埋点事件 schema","evidence":"documented","note":"前端客户端事件;上报与统计落地 gap"} {"id":"action:track_video_save","type":"Action","name":"trackVideoSave","nameZh":"成片保存相册埋点","domain":"report","inputs":["reportTokenHash"],"outputs":["event:video_save"],"entrypoints":["frontend reportView / videoPlayer (client-emitted)"],"appliesRules":[],"code":"","doc":"docs/本期主线-下一步产品优化点.md 埋点事件 schema","evidence":"documented","note":"前端客户端事件;上报与统计落地 gap"} {"id":"action:logout","type":"Action","name":"logout","nameZh":"退出登录 / 吊销会话","domain":"auth","inputs":["sessionToken"],"outputs":["event:session_revoked"],"entrypoints":[],"appliesRules":["rule:BR-AUTH-001"],"code":"","doc":"docs/ontology/actions.md#action:logout","evidence":"gap","note":"当前仅有签发无服务端吊销;前端清本地 token"} {"id":"event:testimonial_saved","type":"Event","name":"testimonialSaved","nameZh":"宠主寄语已保存","domain":"report","emittedBy":["action:submit_testimonial"],"payload":["reportTokenHash","testimonialId","isPublic","ts"],"code":"backend/src/main/java/com/petstore/service/ReportTestimonialService.java","doc":"docs/ontology/events.md#event:testimonial_saved","evidence":"documented","note":"代码已写库;独立事件上报/统计未落地"} {"id":"event:session_revoked","type":"Event","name":"sessionRevoked","nameZh":"会话吊销","domain":"auth","emittedBy":["action:logout"],"payload":["userId","ts"],"code":"","doc":"docs/ontology/events.md#event:session_revoked","evidence":"gap"} {"id":"rel:highlight_has_fail_reason","type":"Relation","subject":"entity:highlight_video","predicate":"HAS","object":"entity:highlight_fail_reason","cardinality":"0—1","domain":"report","evidence":"anchored","doc":"Report.highlight_fail_reason 使用 HighlightFailReason 归类"} {"id":"rel:session_token_resolves_to_current_user","type":"Relation","subject":"entity:session_token","predicate":"RESOLVES_TO","object":"entity:current_user","cardinality":"1—1","domain":"auth","evidence":"anchored","doc":"AuthInterceptor 解析 token → CurrentUserContext"} {"id":"rel:track_video_play_emits_video_play","type":"Relation","subject":"action:track_video_play","predicate":"EMITS","object":"event:video_play","domain":"report","evidence":"documented"} {"id":"rel:track_video_save_emits_video_save","type":"Relation","subject":"action:track_video_save","predicate":"EMITS","object":"event:video_save","domain":"report","evidence":"documented"} {"id":"rel:logout_emits_session_revoked","type":"Relation","subject":"action:logout","predicate":"EMITS","object":"event:session_revoked","domain":"auth","evidence":"gap"} {"id":"rel:br_user_003_applies","type":"Relation","subject":"rule:BR-USER-003","predicate":"APPLIES_TO","object":"action:get_user_info","domain":"user","evidence":"anchored","doc":"同样适用于 login/register/list_staff 等返回 User 的动作"} {"id":"rel:br_tst_001_applies","type":"Relation","subject":"rule:BR-TST-001","predicate":"APPLIES_TO","object":"action:submit_testimonial","domain":"report","evidence":"anchored"} {"id":"rel:br_unsub_001_applies","type":"Relation","subject":"rule:BR-UNSUB-001","predicate":"APPLIES_TO","object":"action:unsubscribe","domain":"lead","evidence":"anchored"} {"id":"rel:br_int_001_applies","type":"Relation","subject":"rule:BR-INT-001","predicate":"APPLIES_TO","object":"action:get_report_suggestion","domain":"service_type","evidence":"anchored"} {"id":"rel:br_store_003_applies","type":"Relation","subject":"rule:BR-STORE-003","predicate":"APPLIES_TO","object":"action:get_store","domain":"store","evidence":"anchored"} {"id":"entity:admin_console","type":"Entity","name":"AdminConsole","nameZh":"门店 Web 管理后台","domain":"admin","jpa":false,"fields":["surface","navModules","storeScope","roleGate"],"systems":["Store Admin FE","Backend Core"],"code":"","doc":"docs/ontology/objects.md#entity:admin_console","test":"","evidence":"documented","note":"Phase A 产品预录入;独立 Web 端,与 uni-app 小程序并存。对标宠老板「店铺概况」入口,不做收银/库存。详见 docs/门店管理后台升级方案-对标宠老板.md","status":"planned"} {"id":"entity:workbench","type":"Entity","name":"Workbench","nameZh":"今日行动工作台","domain":"admin","jpa":false,"fields":["todayAppointmentCount","todayDoneCount","overdueAppointmentCount","inServiceCount","upcomingTodayCount","highlightAnomalyCount","dueFollowUpCount","actionGroups","reportFunnel"],"systems":["Store Admin FE","Backend Core","Report Media Backend"],"code":"admin/src/views/WorkbenchView.vue; backend/src/main/java/com/petstore/service/AdminWorkbenchService.java; backend/src/main/java/com/petstore/service/AdminBusinessEventService.java","doc":"docs/ontology/objects.md#entity:workbench","test":"AdminWorkbenchServiceTest; AdminBusinessEventServiceTest","evidence":"anchored","note":"服务端按完整本店数据准确聚合行动;每组最多 3 条低敏预览;报告发送与转预约未跟踪时显示未知。","status":"implemented"} {"id":"entity:workbench_todo_item","type":"Entity","name":"WorkbenchTodoItem","nameZh":"工作台行动组","domain":"admin","jpa":false,"fields":["kind","urgency","count","items","drilldownAction","filter"],"systems":["Store Admin FE","Backend Core"],"code":"backend/src/main/java/com/petstore/service/AdminWorkbenchService.java; admin/src/views/WorkbenchView.vue","doc":"docs/ontology/objects.md#entity:workbench_todo_item","test":"AdminWorkbenchServiceTest","evidence":"anchored","note":"kind: overdue_appointment | in_service | upcoming_today | highlight_anomaly | follow_up_due;items 不含手机号/token/媒体 URL","status":"implemented"} {"id":"entity:store_customer","type":"Entity","name":"StoreCustomer","nameZh":"门店客户主档(瘦身)","domain":"admin","jpa":true,"fields":["id","store_id","customer_user_id","phone","display_name","source","first_contact_at","last_contact_at","create_time","update_time","deleted"],"systems":["Store Admin FE","Backend Core","Report Media Backend"],"code":"backend/src/main/java/com/petstore/entity/StoreCustomer.java; backend/src/main/java/com/petstore/service/StoreCustomerService.java; backend/src/main/java/com/petstore/service/AdminServiceCustomerService.java","doc":"docs/ontology/objects.md#entity:store_customer; docs/架构决策-门店客户主档-2026-08-01.md","test":"StoreCustomerServiceTest; AdminServiceCustomerServiceTest; IdentityOwnershipQueryTest","evidence":"anchored","note":"门店与客户的稳定关系实体;API 动态聚合宠物/到店/报告/留资,不含余额/次卡/积分。","status":"implemented"} {"id":"rule:BR-ADMIN-001","type":"Rule","name":"adminRoleGate","nameZh":"门店后台角色门禁(boss/staff 可读写)","domain":"admin","appliesTo":["action:view_workbench","action:admin_list_appointments","action:admin_list_reports","action:admin_list_leads","action:admin_list_service_customers","action:admin_update_settings"],"code":"","doc":"docs/ontology/rules.md#rule:BR-ADMIN-001; docs/门店管理后台-PhaseA-页面清单PRD.md","test":"","evidence":"documented","note":"boss 与 staff 均可进入 admin_console 并编辑本店数据;customer 禁止。删店/部分设置仍仅 boss(BR-STORE-001/BR-USER-001)。产品决策 2026-07-10。"} {"id":"rule:BR-ADMIN-002","type":"Rule","name":"adminStoreScope","nameZh":"后台数据仅本店 storeId","domain":"admin","appliesTo":["action:view_workbench","action:admin_list_appointments","action:admin_list_reports","action:admin_list_leads","action:admin_list_service_customers","action:admin_update_settings"],"code":"","doc":"docs/ontology/rules.md#rule:BR-ADMIN-002","test":"","evidence":"documented","note":"所有后台查询/写操作强制 current.storeId;忽略跨店请求参数。连锁同步不在 Phase A。"} {"id":"rule:BR-ADMIN-003","type":"Rule","name":"adminInternalFieldsAllowed","nameZh":"后台可看内部字段(与公开裁剪对称)","domain":"admin","appliesTo":["action:admin_list_reports","action:admin_update_settings","action:admin_list_service_customers"],"code":"","doc":"docs/ontology/rules.md#rule:BR-ADMIN-003","test":"","evidence":"documented","note":"经 BR-ADMIN-001 鉴权后,后台可返回 inviteCode、完整报告内部字段等;公开 API 仍受 BR-STORE-003/BR-RPT-006 约束。手机号默认仍脱敏,明文需更高权限(预留)。"} {"id":"rule:BR-ADMIN-004","type":"Rule","name":"adminPhaseAOutOfScope","nameZh":"Phase A 后台范围闸门","domain":"admin","appliesTo":["entity:admin_console","entity:workbench"],"code":"","doc":"docs/ontology/rules.md#rule:BR-ADMIN-004","test":"","evidence":"documented","note":"禁止将 membership/stored_value/service_package/收银/库存/寄养/押金/点餐/支付宝渠道 写入 Phase A 后台范围或设计稿。上述保持 evidence=gap。"} {"id":"action:view_workbench","type":"Action","name":"viewWorkbench","nameZh":"查看今日行动工作台","domain":"admin","inputs":["date","entity:current_user"],"outputs":["entity:workbench","entity:workbench_todo_item"],"entrypoints":["GET /api/admin/workbench/actions","GET /api/admin/workbench/report-funnel","Admin UI /workbench"],"appliesRules":["rule:BR-ADMIN-001","rule:BR-ADMIN-002","rule:BR-ADMIN-004","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/controller/AdminBusinessEventController.java#actions; #reportFunnel; backend/src/main/java/com/petstore/service/AdminWorkbenchService.java; backend/src/main/java/com/petstore/service/AdminBusinessEventService.java; admin/src/views/WorkbenchView.vue","doc":"docs/ontology/actions.md#action:view_workbench","test":"AdminBusinessEventControllerTest; AdminWorkbenchServiceTest; AdminBusinessEventServiceTest","evidence":"anchored","note":"按会话 storeId 聚合完整本店行动与低敏预览;事件漏斗按日期汇总。"} {"id":"action:drilldown_workbench_todo","type":"Action","name":"drilldownWorkbenchTodo","nameZh":"工作台行动下钻","domain":"admin","inputs":["entity:workbench_todo_item"],"outputs":[],"entrypoints":["Admin UI workbench action click"],"appliesRules":["rule:BR-ADMIN-001","rule:BR-ADMIN-002"],"code":"admin/src/views/WorkbenchView.vue; admin/src/views/AppointmentsView.vue","doc":"docs/ontology/actions.md#action:drilldown_workbench_todo","evidence":"anchored","note":"按 kind 跳转 appointments/reports/leads 并带筛选;预约预览可按受保护 ID 详情打开。"} {"id":"action:admin_list_appointments","type":"Action","name":"adminListAppointments","nameZh":"后台预约列表","domain":"admin","inputs":["status","dateFrom","dateTo","assignedUserId","page","pageSize"],"outputs":["entity:appointment"],"entrypoints":["Admin UI /appointments (planned)","reuses GET /api/appointment/list"],"appliesRules":["rule:BR-ADMIN-001","rule:BR-ADMIN-002","rule:BR-APPT-001","rule:BR-APPT-002"],"code":"backend/.../AppointmentController.java#list (reuse)","doc":"docs/ontology/actions.md#action:admin_list_appointments","evidence":"documented","note":"Web 列表增强筛选;业务规则复用现有 Appointment*,不另造状态机。;Web 允许调用 start_service(产品决策 2026-07-10)"} {"id":"action:admin_list_reports","type":"Action","name":"adminListReports","nameZh":"后台报告列表","domain":"admin","inputs":["dateFrom","dateTo","highlightStatus","page","pageSize"],"outputs":["entity:report","entity:highlight_video"],"entrypoints":["Admin UI /reports (planned)","reuses GET /api/report/list"],"appliesRules":["rule:BR-ADMIN-001","rule:BR-ADMIN-002","rule:BR-ADMIN-003","rule:BR-RPT-005"],"code":"backend/.../ReportController.java#list (reuse)","doc":"docs/ontology/actions.md#action:admin_list_reports","evidence":"documented","note":"含成片三态、复制公开链接、触发重生成(复用 generate_highlight)。"} {"id":"action:admin_list_leads","type":"Action","name":"adminListLeads","nameZh":"后台回访线索列表","domain":"admin","inputs":["remindStatus","remindDateTo","page","pageSize"],"outputs":["entity:report_lead"],"entrypoints":["Admin UI /leads (planned)","reuses GET /api/report/leads"],"appliesRules":["rule:BR-ADMIN-001","rule:BR-ADMIN-002","rule:BR-LEAD-002","rule:BR-LEAD-003"],"code":"backend/.../ReportLeadController.java#leads (reuse)","doc":"docs/ontology/actions.md#action:admin_list_leads","evidence":"documented"} {"id":"action:admin_list_service_customers","type":"Action","name":"adminListServiceCustomers","nameZh":"后台服务客户列表","domain":"admin","inputs":["source","hasPendingLead","lastVisitFrom","lastVisitTo","q","page","pageSize"],"outputs":["entity:store_customer"],"entrypoints":["GET /api/admin/service-customers","Admin UI /customers"],"appliesRules":["rule:BR-ADMIN-001","rule:BR-ADMIN-002","rule:BR-ADMIN-003","rule:BR-ADMIN-004","rule:BR-SC-001"],"code":"backend/src/main/java/com/petstore/controller/AdminServiceCustomerController.java#listServiceCustomers; backend/src/main/java/com/petstore/service/AdminServiceCustomerService.java","doc":"docs/ontology/actions.md#action:admin_list_service_customers; docs/门店管理后台-PhaseA-页面清单PRD.md §7.6","test":"AdminServiceCustomerControllerTest; AdminServiceCustomerServiceTest","evidence":"anchored","note":"以 t_store_customer 稳定主档为入口,动态聚合宠物/到店/报告/留资;返回 storeCustomerId 和脱敏手机号。"} {"id":"action:admin_update_settings","type":"Action","name":"adminUpdateSettings","nameZh":"后台门店设置读写","domain":"admin","inputs":["entity:store","entity:service_type","entity:user"],"outputs":["entity:store","entity:service_type","entity:user"],"entrypoints":["GET /api/admin/store","Admin UI /settings","PUT /api/store/update"],"appliesRules":["rule:BR-ADMIN-001","rule:BR-ADMIN-002","rule:BR-ADMIN-003","rule:BR-STORE-001","rule:BR-ST-001","rule:BR-USER-001"],"code":"","doc":"docs/ontology/actions.md#action:admin_update_settings","evidence":"anchored","note":"后台读本店含 inviteCode(GET /api/admin/store);写资料复用 PUT /api/store/update(仅 boss);服务类型/员工复用既有 API。","code_refs":["backend/src/main/java/com/petstore/controller/AdminStoreController.java#currentStore","backend/src/main/java/com/petstore/controller/StoreController.java#update"]} {"id":"action:admin_manage_schedule","type":"Action","name":"adminManageSchedule","nameZh":"后台排班与占用","domain":"admin","inputs":["date","entity:schedule_block"],"outputs":["entity:schedule_block","entity:appointment"],"entrypoints":["Admin UI /schedule","GET /api/schedule/day","POST /api/schedule/block","DELETE /api/schedule/block"],"appliesRules":["rule:BR-ADMIN-001","rule:BR-ADMIN-002","rule:BR-SCH-001","rule:BR-SCH-002","rule:BR-APPT-004"],"code":"","doc":"docs/ontology/actions.md#action:admin_manage_schedule","evidence":"anchored","note":"Web 排班日视图展示容量占用;增删带时长占用复用 ScheduleController。"} {"id":"event:workbench_viewed","type":"Event","name":"workbenchViewed","nameZh":"工作台已打开","domain":"admin","emittedBy":["action:view_workbench"],"payload":["storeId","userId","ts"],"code":"","doc":"docs/ontology/events.md#event:workbench_viewed","evidence":"gap","note":"可选埋点;A 期可不实现上报。"} {"id":"rel:admin_console_has_workbench","type":"Relation","subject":"entity:admin_console","predicate":"HAS","object":"entity:workbench","domain":"admin","evidence":"documented","cardinality":"1—1","doc":"登录默认工作台"} {"id":"rel:workbench_has_todo_items","type":"Relation","subject":"entity:workbench","predicate":"HAS","object":"entity:workbench_todo_item","domain":"admin","evidence":"anchored","cardinality":"1—N","doc":"按优先级排序的行动组"} {"id":"rel:workbench_reads_appointments","type":"Relation","subject":"entity:workbench","predicate":"AGGREGATES","object":"entity:appointment","domain":"admin","evidence":"documented","cardinality":"1—N","doc":"今日预约指标"} {"id":"rel:workbench_reads_reports","type":"Relation","subject":"entity:workbench","predicate":"AGGREGATES","object":"entity:report","domain":"admin","evidence":"documented","cardinality":"1—N","doc":"待出报告/成片异常"} {"id":"rel:workbench_reads_leads","type":"Relation","subject":"entity:workbench","predicate":"AGGREGATES","object":"entity:report_lead","domain":"admin","evidence":"documented","cardinality":"1—N","doc":"待回访"} {"id":"rel:workbench_reads_business_events","type":"Relation","subject":"entity:workbench","predicate":"AGGREGATES","object":"entity:business_event","domain":"admin","evidence":"anchored","cardinality":"1—N","doc":"报告提交/打开/留资去重漏斗"} {"id":"rel:store_has_service_customers","type":"Relation","subject":"entity:store","predicate":"HAS","object":"entity:store_customer","domain":"admin","evidence":"anchored","cardinality":"1—N","doc":"StoreCustomer.store_id"} {"id":"rel:service_customer_is_user","type":"Relation","subject":"entity:store_customer","predicate":"LINKS","object":"entity:user","domain":"admin","evidence":"anchored","cardinality":"N—0..1","doc":"StoreCustomer.customer_user_id;留资客户可先为空"} {"id":"rel:service_customer_has_pets","type":"Relation","subject":"entity:store_customer","predicate":"HAS","object":"entity:pet","domain":"admin","evidence":"anchored","cardinality":"1—N","doc":"customer_user_id -> Pet.owner_user_id(动态读模型)"} {"id":"rel:view_workbench_emits_viewed","type":"Relation","subject":"action:view_workbench","predicate":"EMITS","object":"event:workbench_viewed","domain":"admin","evidence":"documented"} {"id":"rel:br_admin_001_applies_workbench","type":"Relation","subject":"rule:BR-ADMIN-001","predicate":"APPLIES_TO","object":"action:view_workbench","domain":"admin","evidence":"documented"} {"id":"rel:br_admin_002_applies_workbench","type":"Relation","subject":"rule:BR-ADMIN-002","predicate":"APPLIES_TO","object":"action:view_workbench","domain":"admin","evidence":"documented"} {"id":"rel:br_admin_004_gates_console","type":"Relation","subject":"rule:BR-ADMIN-004","predicate":"CONSTRAINS","object":"entity:admin_console","domain":"admin","evidence":"documented","doc":"Phase A 范围闸门"} {"id":"rel:admin_list_appts_reads_appointment","type":"Relation","subject":"action:admin_list_appointments","predicate":"READS","object":"entity:appointment","domain":"admin","evidence":"documented"} {"id":"rel:admin_list_reports_reads_report","type":"Relation","subject":"action:admin_list_reports","predicate":"READS","object":"entity:report","domain":"admin","evidence":"documented"} {"id":"rel:admin_list_leads_reads_lead","type":"Relation","subject":"action:admin_list_leads","predicate":"READS","object":"entity:report_lead","domain":"admin","evidence":"documented"} {"id":"rel:admin_list_customers_reads_sc","type":"Relation","subject":"action:admin_list_service_customers","predicate":"READS","object":"entity:store_customer","domain":"admin","evidence":"anchored"} {"id":"rel:drilldown_todo_to_list_appts","type":"Relation","subject":"action:drilldown_workbench_todo","predicate":"ROUTES_TO","object":"action:admin_list_appointments","domain":"admin","evidence":"anchored","doc":"kind=overdue_appointment|in_service|upcoming_today;按 ID 或服务端口径筛选"}