feat(ov): emergency disable channel independent of sync
P2 Task 5(海外紧急停用入口): - ov 新增 POST /v1/internal/emergency/disable|enable(InternalSyncGuard HMAC,albumToken/albumId 恰好其一、都缺省 400;副本不存在 404 ALBUM_NOT_FOUND):直写 albums_ov.emergencyDisabled(唯一 ov 本地可写 位),独立于同步版本链——更高版本 album.updated 重放不解除(e2e 断言 entityVersion 推进而标志保持),恢复仅经显式 enable;幂等语义 (alreadyDisabled/wasDisabled 入审计行) - cn 侧不感知:无对应 cn 状态位、无反向同步(契约描述文档化) - 审计:pino child(audit=emergency 字段常驻每行)结构化日志——偏差 登记:计划原文「写 ov 侧日志文件」落地为字段标记而非独立文件通道 (免新增文件 transport 依赖,P5 运维按字段路由聚合);注入令牌 EMERGENCY_AUDIT_LOGGER,测试覆写为内存目的地断言字段 - isAlbumVisibleOv 共享判定(status=active && publicEnabled && !emergencyDisabled——镜像 cn 公开语义叠加本地停用位):Task 6 公开 API / Task 7 WS subscribe 的 404 ALBUM_NOT_PUBLIC 语义单一实现, 判定矩阵单测锁定 - 契约 [internal] 增 emergency disable/enable 操作与 schema(gen 已跑、 redocly 通过);e2e:token/id 定位、幂等、enable 恢复、未签名 401、 均缺省 400、未知相册 404、同步事件不解除 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
// services/api/src/shared/album-visibility.spec.ts —— isAlbumVisibleOv 判定
|
||||
// 矩阵(P2 Task 5;Task 6 公开 API / Task 7 WS 消费前的单元锁定)。
|
||||
import { isAlbumVisibleOv } from './album-visibility';
|
||||
|
||||
describe('isAlbumVisibleOv', () => {
|
||||
const base = { status: 'active', publicEnabled: true, emergencyDisabled: false };
|
||||
|
||||
it('active + public + 未停用 → 可见', () => {
|
||||
expect(isAlbumVisibleOv(base)).toBe(true);
|
||||
});
|
||||
|
||||
it('status=offline(cn 下线副本值)→ 不可见', () => {
|
||||
expect(isAlbumVisibleOv({ ...base, status: 'offline' })).toBe(false);
|
||||
});
|
||||
|
||||
it('publicEnabled=false(公开关闭)→ 不可见', () => {
|
||||
expect(isAlbumVisibleOv({ ...base, publicEnabled: false })).toBe(false);
|
||||
});
|
||||
|
||||
it('emergencyDisabled=true(ov 本地紧急停用)→ 不可见', () => {
|
||||
expect(isAlbumVisibleOv({ ...base, emergencyDisabled: true })).toBe(false);
|
||||
});
|
||||
|
||||
it('下线 + 紧急停用叠加 → 不可见(多条件同为假不改变语义)', () => {
|
||||
expect(
|
||||
isAlbumVisibleOv({
|
||||
status: 'offline',
|
||||
publicEnabled: false,
|
||||
emergencyDisabled: true,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
// services/api/src/shared/album-visibility.ts —— ov 侧相册「对外可见」判定
|
||||
// 单一实现(P2 Task 5 起;Task 6 公开读 API / Task 7 WS subscribe 共用)。
|
||||
//
|
||||
// 语义与 cn 公开端点(public.service findPublicAlbum)同形:status=active 且
|
||||
// publicEnabled 才公开(三者任一不满足统一 404 ALBUM_NOT_PUBLIC 语义,同码
|
||||
// 防枚举);ov 侧额外叠加**本地**紧急停用位 emergencyDisabled——它独立于同步
|
||||
// 版本链(任何同步事件不得解除,见 emergency.service),停用即等价「不公开」。
|
||||
// startAt/endAt 不参与判定(与 cn 同口径:时间窗不是公开条件)。
|
||||
// 入参为 albums_ov 行的结构子集(Prisma 类型免耦合:Task 6 起消费方直接传行)。
|
||||
export interface AlbumVisibilityOvInput {
|
||||
status: string;
|
||||
publicEnabled: boolean;
|
||||
emergencyDisabled: boolean;
|
||||
}
|
||||
|
||||
/** ov 相册当前是否对观众可见(false → 404 ALBUM_NOT_PUBLIC 语义)。 */
|
||||
export function isAlbumVisibleOv(album: AlbumVisibilityOvInput): boolean {
|
||||
return (
|
||||
album.status === 'active' && album.publicEnabled && !album.emergencyDisabled
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user