90 lines
3.9 KiB
SQL
90 lines
3.9 KiB
SQL
-- 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));
|