feat(matchmaker,contactauth): 受控联系授权机制立项落地(OQ-MATCHMAKER-003 / DEC-MATCHMAKER-003 B1 例外通道)
后端: - V056 matchmaker_contact_authorizations 表:channel CHECK(phone/offline_meeting/full_contact)、六态状态机(pending_approval→pending_consent→active→expired/revoked, →rejected)、部分唯一索引 uq_mm_contact_auth_active 防同红娘-同用户-同渠道多 ACTIVE、双态惰性收敛(active 过期 + pending_consent 超同意窗口) - ContactAuthorizationConfig 五 canonical key(matchmaker.contact.*):enabled 代码缺省 false fail-safe(yml 显式 true)/approver-authorities 双岗并列/consent-deadline-hours 72/default-validity-days 7/retention-days 365,全部 DEFAULT+CONFIG 待产品+法务终审 - ContactAuthorizationPolicy.assertContactAllowed(404 化 deny 先审计后 404) + canContact 徽标查询 - ContactAuthorizationService:request(须有效分配+purpose 必填)/approve(权限码动态判定∈配置+组长组织范围)/consent(用户本人,仅 pending_consent)/decline/revoke(reason 必填)/disclose(唯一披露出口:enabled fail-safe→assertActiveAssignment→assertContactAllowed→仅返回 phone/disclosedAt/authorizationId 三键,每次落 SensitiveAccessLog user_phone_disclosure,phone 不落应用日志) - 双控制器:运营端 /operator/matchmaker/contact-authorizations + C 端 /contact-authorizations(UserPrincipal 归属校验,独立端点无预同意参数),不碰 SecurityConfig 守卫翻转(机械锁强制复审机制按设计生效): - MatchmakerContactGuardTest 由「锁不存在」翻转为「锁新契约」五条:回显白名单类收敛/端点前缀收敛(受治理三包)/到期语义/consent 独立性三端扫描(后端+miniapp+admin-web,修复原只扫后端的预同意参数逃逸缺口)/ReferralService 白名单与无 @Scheduled 保留 - run-backend-contracts CURATED 18→20 前端: - miniapp 新页 pages/contact-consent(目的/渠道/窗口明示+独立同意拒绝按钮无预勾选,app.json 第 64 页) + 红娘工作台申请/列表/撤销 - admin-web「联系授权审批」tab(审批岗队列+本人授权撤销,枚举码中文映射) 验证:mvn verify 895/895(3 skip)、UI 契约 24/24(64 页)、后端契约门禁 228/CURATED 20、小程序真编译 87 WXML 0 失败;负向注入 5(工程师)+2(QA 不同落点)判红→还原复绿;QA 抓 disclose 键数收敛断言缺口已补并回归;QA fresh eyes PASS 0 P0/P1
This commit is contained in:
+50
@@ -0,0 +1,50 @@
|
||||
-- ============================================================
|
||||
-- V056: 受控联系授权表 matchmaker_contact_authorizations
|
||||
-- (ZC-MM-003 / B1 例外通道立项,架构师设计 H4/G4)
|
||||
--
|
||||
-- 语义:红娘对分配对象发起联系方式/线下见面授权申请,经审批岗批准、
|
||||
-- 用户单独明示同意(独立端点,无预同意参数)后方可生效;
|
||||
-- 唯一披露出口为 ContactAuthorizationService.disclose(每次落敏感访问审计)。
|
||||
--
|
||||
-- 状态机(六态):
|
||||
-- pending_approval → pending_consent(审批岗批准)
|
||||
-- pending_consent → active(用户单独同意)/ rejected(用户拒绝)
|
||||
-- active / pending_consent → expired(双态惰性收敛:有效期/同意窗口届满)
|
||||
-- active → revoked(申请人或审批人撤销)
|
||||
--
|
||||
-- 幂等:CREATE TABLE / INDEX 全部 IF NOT EXISTS,可重放。
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS matchmaker_contact_authorizations (
|
||||
id UUID PRIMARY KEY,
|
||||
operator_id UUID NOT NULL REFERENCES operators(id),
|
||||
user_id UUID NOT NULL REFERENCES users(id),
|
||||
channel VARCHAR(32) NOT NULL,
|
||||
purpose VARCHAR(200) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'pending_approval',
|
||||
approved_by UUID,
|
||||
approved_at TIMESTAMPTZ,
|
||||
user_consented_at TIMESTAMPTZ,
|
||||
expires_at TIMESTAMPTZ NOT NULL,
|
||||
revoked_at TIMESTAMPTZ,
|
||||
revoked_by UUID,
|
||||
revoke_reason VARCHAR(500),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ,
|
||||
CONSTRAINT chk_contact_auth_channel CHECK (channel IN ('phone', 'offline_meeting', 'full_contact')),
|
||||
CONSTRAINT chk_contact_auth_status CHECK (status IN (
|
||||
'pending_approval', 'pending_consent', 'active', 'rejected', 'expired', 'revoked'
|
||||
))
|
||||
);
|
||||
|
||||
-- 同一 (红娘, 用户, 渠道) 同时最多一条 active(防重复生效授权)
|
||||
-- H2 测试库以生成列 + 唯一索引等价实现(见 schema-h2.sql 注释)。
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_mm_contact_auth_active
|
||||
ON matchmaker_contact_authorizations(operator_id, user_id, channel)
|
||||
WHERE status = 'active';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_contact_auth_operator_status
|
||||
ON matchmaker_contact_authorizations(operator_id, status);
|
||||
CREATE INDEX IF NOT EXISTS idx_contact_auth_user_status
|
||||
ON matchmaker_contact_authorizations(user_id, status);
|
||||
Reference in New Issue
Block a user