feat(api): embed slots with ov replica and public feed

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-20 22:22:19 +08:00
parent eb51069a12
commit aee4b7ac46
23 changed files with 1890 additions and 10 deletions
+37
View File
@@ -17,6 +17,8 @@ import type {
CategoryDeletedPayload,
CategoryUpdatedPayload,
PhotoPublishedPayload,
SlotSettingsPayload,
SlotStateUpdatedPayload,
} from '@photo/contracts';
import type { Prisma } from '@photo/db-cn';
import { ApiException } from '../api-exception';
@@ -51,6 +53,16 @@ type PhotoRow = Prisma.photosGetPayload<Prisma.photosDefaultArgs>;
type PhotoVariantRow = Prisma.photo_variantsGetPayload<
Prisma.photo_variantsDefaultArgs
>;
type EmbedSlotRow = Pick<
Prisma.embed_slotsGetPayload<Prisma.embed_slotsDefaultArgs>,
| 'id'
| 'publicToken'
| 'enabled'
| 'albumId'
| 'configVersion'
| 'settings'
| 'entityVersion'
>;
/**
* album.updated 载荷:albums_ov 展示所需标量 + 翻译全集(locale 升序)。
@@ -131,6 +143,31 @@ export function buildAssetUpdatedPayload(asset: AssetRow): AssetUpdatedPayload {
};
}
/**
* slot.updated 载荷(P4b Task 2):ov 副本重建展示位所需的全量快照。
* albumPublicToken 由调用方按绑定相册行解析传入(未绑定传 null)——embed_slots
* 行只存 albumId,跨表解析归业务事务(绑定校验时已读取相册行,顺带取
* publicToken,避免载荷构建器再查一次)。settings 为归一化存储值直通(写入
* 侧已保证字段齐全)。
*/
export function buildSlotUpdatedPayload(
slot: EmbedSlotRow,
albumPublicToken: string | null,
): SlotStateUpdatedPayload {
return {
slotId: slot.id,
publicToken: slot.publicToken,
enabled: slot.enabled,
albumId: slot.albumId,
albumPublicToken,
configVersion: slot.configVersion,
// Prisma JsonValue → 载荷接口(写入侧已保证形状;接口类型无索引签名,
// 需经 unknown 中转,同 outbox 写入侧约定)。
settings: slot.settings as unknown as SlotSettingsPayload,
entityVersion: slot.entityVersion,
};
}
/**
* photo.published 载荷(契约全集)。能进入 published/hidden 态的照片必经发布
* 事务(变体行+尺寸+publishedAt 齐备);缺任一项属 post-publish 不变量破坏