feat(account): define post-release notification preferences
This commit is contained in:
parent
d2c92a980f
commit
66ec4c7d1c
|
|
@ -6,6 +6,11 @@ export type AccountAnswerDepth = "concise" | "balanced" | "deep";
|
|||
export type AccountEvidenceDisplay = "summary" | "inline" | "full";
|
||||
export type AccountNotificationKey = "pendingConfirmation" | "executionWriteback" | "releaseGate" | "failureAlert";
|
||||
export type AccountSettingsSaveScope = "local" | "account";
|
||||
export type AccountPostReleaseNotificationEvent =
|
||||
| "feedback_received"
|
||||
| "revenue_signal"
|
||||
| "compliance_blocked"
|
||||
| "iteration_recommendation";
|
||||
export type AccountReleaseNotificationEvent =
|
||||
| "release_gate_blocked"
|
||||
| "release_gate_ready"
|
||||
|
|
@ -59,6 +64,22 @@ export interface AccountReleaseGateNotificationPreference {
|
|||
reason: string;
|
||||
}
|
||||
|
||||
export interface AccountPostReleaseNotificationPreference {
|
||||
event: AccountPostReleaseNotificationEvent;
|
||||
notificationKey: AccountNotificationKey;
|
||||
surface: "release_growth";
|
||||
spaceReadable: boolean;
|
||||
inAppEnabled: boolean;
|
||||
showInAppReminder: boolean;
|
||||
desktopPreference: boolean;
|
||||
emailDigestPreference: boolean;
|
||||
title: string;
|
||||
reason: string;
|
||||
evidencePolicy: "preserve_business_evidence";
|
||||
reminderPolicy: "page_reminder_only";
|
||||
mutedDetail: string;
|
||||
}
|
||||
|
||||
export interface AccountSettings {
|
||||
profile: AccountProfileSettings;
|
||||
aiPreferences: AccountAiPreferenceSettings;
|
||||
|
|
@ -165,6 +186,28 @@ const releaseNotificationEventMeta: Record<
|
|||
},
|
||||
};
|
||||
|
||||
const postReleaseNotificationEventMeta: Record<
|
||||
AccountPostReleaseNotificationEvent,
|
||||
{ notificationKey: AccountNotificationKey; reason: string }
|
||||
> = {
|
||||
feedback_received: {
|
||||
notificationKey: "releaseGate",
|
||||
reason: "Release/Growth 收到发布后用户反馈时使用发布门禁偏好控制页面内提醒;反馈证据本身不受偏好隐藏。",
|
||||
},
|
||||
revenue_signal: {
|
||||
notificationKey: "releaseGate",
|
||||
reason: "Release/Growth 收到收入、转化或增长信号时使用发布门禁偏好控制页面内提醒;收入证据本身不受偏好隐藏。",
|
||||
},
|
||||
compliance_blocked: {
|
||||
notificationKey: "releaseGate",
|
||||
reason: "合规、风控或发布后审核阻塞下一步时使用发布门禁偏好控制页面内提醒;阻塞状态与证据仍必须展示在业务页面。",
|
||||
},
|
||||
iteration_recommendation: {
|
||||
notificationKey: "pendingConfirmation",
|
||||
reason: "AI 生成下一轮迭代建议、需要人类拍板时使用待确认偏好控制页面内提醒;建议对象和证据仍保留。",
|
||||
},
|
||||
};
|
||||
|
||||
export function createDefaultAccountSettings(seed: AccountSettingsSeed = {}): AccountSettings {
|
||||
return {
|
||||
profile: {
|
||||
|
|
@ -303,6 +346,33 @@ export function getReleaseGateNotificationPreference(
|
|||
};
|
||||
}
|
||||
|
||||
export function getPostReleaseNotificationPreference(
|
||||
settings: AccountSettings | Partial<AccountSettings> | null | undefined,
|
||||
event: AccountPostReleaseNotificationEvent
|
||||
): AccountPostReleaseNotificationPreference {
|
||||
const normalized = mergeAccountSettings(createDefaultAccountSettings(), settings || null);
|
||||
const meta = postReleaseNotificationEventMeta[event];
|
||||
const preference = normalized.notifications[meta.notificationKey];
|
||||
const enabled = Boolean(preference.enabled);
|
||||
return {
|
||||
event,
|
||||
notificationKey: meta.notificationKey,
|
||||
surface: "release_growth",
|
||||
spaceReadable: true,
|
||||
inAppEnabled: enabled,
|
||||
showInAppReminder: enabled,
|
||||
desktopPreference: enabled && Boolean(preference.desktop),
|
||||
emailDigestPreference: enabled && Boolean(preference.emailDigest),
|
||||
title: accountNotificationLabels[meta.notificationKey].title,
|
||||
reason: meta.reason,
|
||||
evidencePolicy: "preserve_business_evidence",
|
||||
reminderPolicy: "page_reminder_only",
|
||||
mutedDetail: enabled
|
||||
? "Release/Growth 或 Space 可显示页面内提醒;桌面/邮件只记录偏好,不代表系统级推送已接入。"
|
||||
: "仅静默页面内提醒;反馈、收入、合规、迭代建议及其证据仍必须按业务页面展示。",
|
||||
};
|
||||
}
|
||||
|
||||
export async function getAccountSettings(seed?: AccountSettingsSeed): Promise<AccountSettings> {
|
||||
const defaults = createDefaultAccountSettings(seed);
|
||||
const localSettings = mergeAccountSettings(defaults, readStoredAccountSettings());
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
createDefaultAccountSettings,
|
||||
getAccountNotificationConsumption,
|
||||
getAccountSettings,
|
||||
getPostReleaseNotificationPreference,
|
||||
getReleaseGateNotificationPreference,
|
||||
shouldShowAccountNotification,
|
||||
updateAccountSettings,
|
||||
|
|
@ -132,6 +133,42 @@ describe("account settings api", () => {
|
|||
expect(failedEvent.reason).toContain("failed event");
|
||||
});
|
||||
|
||||
it("maps post-release feedback, revenue, compliance, and iteration events to local reminder preferences", () => {
|
||||
const defaults = createDefaultAccountSettings();
|
||||
const settings = {
|
||||
...defaults,
|
||||
notifications: {
|
||||
...defaults.notifications,
|
||||
releaseGate: { enabled: true, desktop: false, emailDigest: true },
|
||||
pendingConfirmation: { enabled: false, desktop: true, emailDigest: true },
|
||||
},
|
||||
};
|
||||
|
||||
const feedback = getPostReleaseNotificationPreference(settings, "feedback_received");
|
||||
const revenue = getPostReleaseNotificationPreference(settings, "revenue_signal");
|
||||
const compliance = getPostReleaseNotificationPreference(settings, "compliance_blocked");
|
||||
const iteration = getPostReleaseNotificationPreference(settings, "iteration_recommendation");
|
||||
|
||||
expect(feedback.notificationKey).toBe("releaseGate");
|
||||
expect(feedback.surface).toBe("release_growth");
|
||||
expect(feedback.spaceReadable).toBe(true);
|
||||
expect(feedback.showInAppReminder).toBe(true);
|
||||
expect(feedback.desktopPreference).toBe(false);
|
||||
expect(feedback.emailDigestPreference).toBe(true);
|
||||
expect(feedback.reminderPolicy).toBe("page_reminder_only");
|
||||
expect(feedback.evidencePolicy).toBe("preserve_business_evidence");
|
||||
expect(feedback.mutedDetail).toContain("不代表系统级推送已接入");
|
||||
expect(revenue.notificationKey).toBe("releaseGate");
|
||||
expect(revenue.reason).toContain("收入");
|
||||
expect(compliance.notificationKey).toBe("releaseGate");
|
||||
expect(compliance.reason).toContain("合规");
|
||||
expect(iteration.notificationKey).toBe("pendingConfirmation");
|
||||
expect(iteration.showInAppReminder).toBe(false);
|
||||
expect(iteration.desktopPreference).toBe(false);
|
||||
expect(iteration.emailDigestPreference).toBe(false);
|
||||
expect(iteration.mutedDetail).toContain("证据仍必须");
|
||||
});
|
||||
|
||||
it("falls back missing notification fields to safe defaults", async () => {
|
||||
window.localStorage.setItem(
|
||||
"pmflow:account-settings:v1",
|
||||
|
|
|
|||
Loading…
Reference in New Issue