-- Petstore Phase 0:门店开通状态、一次性员工邀请与不可变操作审计 -- 前置:20260801_create_report_send_status.sql 已执行。 -- 语义:历史门店开通状态不可推断,统一为 unknown;新门店由应用写 in_progress。 ALTER TABLE t_store ADD COLUMN onboarding_status VARCHAR(16) NULL COMMENT 'unknown | in_progress | completed'; ALTER TABLE t_store ADD COLUMN onboarding_completed_at DATETIME NULL COMMENT '老板显式完成开通时间'; ALTER TABLE t_store ADD COLUMN onboarding_completed_by_user_id BIGINT NULL COMMENT '显式完成开通的老板用户'; UPDATE t_store SET onboarding_status = 'unknown'; ALTER TABLE t_store MODIFY COLUMN onboarding_status VARCHAR(16) NOT NULL DEFAULT 'in_progress' COMMENT 'unknown | in_progress | completed'; CREATE TABLE t_staff_invitation ( id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, invitation_id VARCHAR(36) NOT NULL, token_hash VARCHAR(64) NOT NULL COMMENT '原始 token 的 SHA-256;原始 token 不落库', store_id BIGINT NOT NULL, invited_name VARCHAR(64) NOT NULL, invited_phone VARCHAR(20) NOT NULL COMMENT '仅服务端用于微信核验匹配;客户端只返回脱敏值', status VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT 'pending | accepted | revoked | expired', expires_at DATETIME NOT NULL, created_by_user_id BIGINT NOT NULL, accepted_by_user_id BIGINT NULL, accepted_at DATETIME NULL, revoked_by_user_id BIGINT NULL, revoked_at DATETIME NULL, create_time DATETIME NOT NULL, update_time DATETIME NOT NULL, CONSTRAINT uk_staff_invitation_public_id UNIQUE (invitation_id), CONSTRAINT uk_staff_invitation_token_hash UNIQUE (token_hash), INDEX idx_staff_invite_store_status (store_id, status, expires_at), INDEX idx_staff_invite_phone (store_id, invited_phone, status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='限时、一次性员工邀请'; CREATE TABLE t_audit_log ( id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, audit_id VARCHAR(36) NOT NULL, store_id BIGINT NOT NULL, actor_user_id BIGINT NULL, actor_role VARCHAR(16) NULL, action VARCHAR(64) NOT NULL, target_type VARCHAR(32) NOT NULL, target_id VARCHAR(64) NULL, outcome VARCHAR(16) NOT NULL, metadata_json TEXT NOT NULL COMMENT '服务端白名单低敏标量 JSON', occurred_at DATETIME NOT NULL, create_time DATETIME NOT NULL, CONSTRAINT uk_audit_log_audit_id UNIQUE (audit_id), INDEX idx_audit_store_time (store_id, occurred_at), INDEX idx_audit_action_time (action, occurred_at), INDEX idx_audit_target (target_type, target_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='不可变操作审计'; -- 验证:以下六项必须全部为 0。 SELECT COUNT(*) AS invalid_store_onboarding_status_count FROM t_store WHERE onboarding_status NOT IN ('unknown', 'in_progress', 'completed'); SELECT COUNT(*) AS completed_onboarding_without_receipt_count FROM t_store WHERE onboarding_status = 'completed' AND (onboarding_completed_at IS NULL OR onboarding_completed_by_user_id IS NULL); SELECT COUNT(*) AS incomplete_onboarding_with_receipt_count FROM t_store WHERE onboarding_status IN ('unknown', 'in_progress') AND (onboarding_completed_at IS NOT NULL OR onboarding_completed_by_user_id IS NOT NULL); SELECT COUNT(*) AS invalid_staff_invitation_status_count FROM t_staff_invitation WHERE status NOT IN ('pending', 'accepted', 'revoked', 'expired'); SELECT COUNT(*) AS inconsistent_staff_invitation_acceptance_count FROM t_staff_invitation WHERE (status = 'accepted' AND (accepted_by_user_id IS NULL OR accepted_at IS NULL)) OR (status <> 'accepted' AND (accepted_by_user_id IS NOT NULL OR accepted_at IS NOT NULL)); SELECT COUNT(*) AS inconsistent_staff_invitation_revocation_count FROM t_staff_invitation WHERE (status = 'revoked' AND (revoked_by_user_id IS NULL OR revoked_at IS NULL)) OR (status <> 'revoked' AND (revoked_by_user_id IS NOT NULL OR revoked_at IS NOT NULL));