From 8cc0cd9e7811a30281d633b729cce953818fa43b Mon Sep 17 00:00:00 2001 From: Albert Date: Sun, 26 Apr 2026 14:22:32 +0800 Subject: [PATCH] feat(account): map iteration review reminders --- frontend/src/api/accountSettings.ts | 20 ++++++++++++++----- .../account-settings/accountSettings.test.ts | 7 +++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/frontend/src/api/accountSettings.ts b/frontend/src/api/accountSettings.ts index 035df01a..eed4ef2d 100644 --- a/frontend/src/api/accountSettings.ts +++ b/frontend/src/api/accountSettings.ts @@ -10,7 +10,8 @@ export type AccountPostReleaseNotificationEvent = | "feedback_received" | "revenue_signal" | "compliance_blocked" - | "iteration_recommendation"; + | "iteration_recommendation" + | "next_change_review"; export type AccountReleaseNotificationEvent = | "release_gate_blocked" | "release_gate_ready" @@ -67,7 +68,7 @@ export interface AccountReleaseGateNotificationPreference { export interface AccountPostReleaseNotificationPreference { event: AccountPostReleaseNotificationEvent; notificationKey: AccountNotificationKey; - surface: "release_growth"; + surface: "release_growth" | "change_review"; spaceReadable: boolean; inAppEnabled: boolean; showInAppReminder: boolean; @@ -188,24 +189,33 @@ const releaseNotificationEventMeta: Record< const postReleaseNotificationEventMeta: Record< AccountPostReleaseNotificationEvent, - { notificationKey: AccountNotificationKey; reason: string } + { notificationKey: AccountNotificationKey; surface: "release_growth" | "change_review"; reason: string } > = { feedback_received: { notificationKey: "releaseGate", + surface: "release_growth", reason: "Release/Growth 收到发布后用户反馈时使用发布门禁偏好控制页面内提醒;反馈证据本身不受偏好隐藏。", }, revenue_signal: { notificationKey: "releaseGate", + surface: "release_growth", reason: "Release/Growth 收到收入、转化或增长信号时使用发布门禁偏好控制页面内提醒;收入证据本身不受偏好隐藏。", }, compliance_blocked: { notificationKey: "releaseGate", + surface: "release_growth", reason: "合规、风控或发布后审核阻塞下一步时使用发布门禁偏好控制页面内提醒;阻塞状态与证据仍必须展示在业务页面。", }, iteration_recommendation: { notificationKey: "pendingConfirmation", + surface: "change_review", reason: "AI 生成下一轮迭代建议、需要人类拍板时使用待确认偏好控制页面内提醒;建议对象和证据仍保留。", }, + next_change_review: { + notificationKey: "pendingConfirmation", + surface: "change_review", + reason: "下一轮 Change Review 或 ChangeSet 待审需要人类拍板时使用待确认偏好控制页面内提醒;ChangeSet 与 recommendation 不受偏好隐藏。", + }, }; export function createDefaultAccountSettings(seed: AccountSettingsSeed = {}): AccountSettings { @@ -357,7 +367,7 @@ export function getPostReleaseNotificationPreference( return { event, notificationKey: meta.notificationKey, - surface: "release_growth", + surface: meta.surface, spaceReadable: true, inAppEnabled: enabled, showInAppReminder: enabled, @@ -369,7 +379,7 @@ export function getPostReleaseNotificationPreference( reminderPolicy: "page_reminder_only", mutedDetail: enabled ? "Release/Growth 或 Space 可显示页面内提醒;桌面/邮件只记录偏好,不代表系统级推送已接入。" - : "仅静默页面内提醒;反馈、收入、合规、迭代建议及其证据仍必须按业务页面展示。", + : "仅静默页面内提醒;反馈、收入、合规、ChangeSet、迭代建议及其证据仍必须按业务页面展示。", }; } diff --git a/frontend/src/features/account-settings/accountSettings.test.ts b/frontend/src/features/account-settings/accountSettings.test.ts index 130043eb..e2de7d1e 100644 --- a/frontend/src/features/account-settings/accountSettings.test.ts +++ b/frontend/src/features/account-settings/accountSettings.test.ts @@ -148,6 +148,7 @@ describe("account settings api", () => { const revenue = getPostReleaseNotificationPreference(settings, "revenue_signal"); const compliance = getPostReleaseNotificationPreference(settings, "compliance_blocked"); const iteration = getPostReleaseNotificationPreference(settings, "iteration_recommendation"); + const nextReview = getPostReleaseNotificationPreference(settings, "next_change_review"); expect(feedback.notificationKey).toBe("releaseGate"); expect(feedback.surface).toBe("release_growth"); @@ -163,10 +164,16 @@ describe("account settings api", () => { expect(compliance.notificationKey).toBe("releaseGate"); expect(compliance.reason).toContain("合规"); expect(iteration.notificationKey).toBe("pendingConfirmation"); + expect(iteration.surface).toBe("change_review"); expect(iteration.showInAppReminder).toBe(false); expect(iteration.desktopPreference).toBe(false); expect(iteration.emailDigestPreference).toBe(false); expect(iteration.mutedDetail).toContain("证据仍必须"); + expect(nextReview.notificationKey).toBe("pendingConfirmation"); + expect(nextReview.surface).toBe("change_review"); + expect(nextReview.showInAppReminder).toBe(false); + expect(nextReview.reason).toContain("ChangeSet"); + expect(nextReview.mutedDetail).toContain("ChangeSet"); }); it("falls back missing notification fields to safe defaults", async () => {