feat(contracts,api): UI-01 cover, preview, scope=own and embed config extensions
契约扩展(全部可选/可空,旧客户端零感知)+ cn/ov 实现 + e2e 权限矩阵:
- AlbumSummary += cover(kind=cover state=effective 最新行的短期签名 URL,
列表/详情按页批量组装非 N+1;未配置为 null)
- AdminPhoto += preview{thumb,browse}(变体齐备且未删除才签发;隐藏仅
admin/owner;协作者仅自己上传,scope=own 服务端过滤 uploaderId,
成员资格逐请求裁决)
- listAlbumPhotos += scope=all|own(缺省 all 行为不变:仅 owner/admin,
协作者 403;own 任何有效成员)
- EmbedSlotSettings += imageFit/offsetX/offsetBottom/zIndex(cn PATCH 校验
→ slot-state 投影 → ov 公开回读;settings 为 Json 列免迁移,读侧
normalizeStoredSettings 兜旧形状默认值)
- Flutter 模型同步(SignedUrl/PhotoPreview/AlbumPhotoScope,可空容错)
e2e:ui01-contracts 9 例(封面选取/字节取回/N+1 计数断言、preview 权限
矩阵、scope 过滤与 403/404/400)+ embed ⑨ 配置链路;全量 e2e 257 通过。
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -949,6 +949,11 @@ paths:
|
||||
相册照片管理列表(区别于公开列表):全部状态可见(unpublished/published/
|
||||
hidden/deleted),条目含 uploader 脱敏信息。按 uploadedAt 与 ID 稳定倒序
|
||||
游标分页。
|
||||
|
||||
scope(UI-01 可选扩展,缺省 all=既有行为不变):协作者显式查询自己
|
||||
上传的照片——服务端过滤 uploaderId=当前用户,成员资格逐请求校验;
|
||||
仅 owner/admin 可用 all(协作者 all → 403)。条目 preview 按请求者
|
||||
权限逐张裁决(见 PhotoPreview)。
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
@@ -962,6 +967,17 @@ paths:
|
||||
description: 分类 ID 过滤。
|
||||
schema:
|
||||
type: string
|
||||
- name: scope
|
||||
in: query
|
||||
description: |
|
||||
数据范围(UI-01):all=本相册全部照片(缺省,仅 owner/admin);
|
||||
own=仅当前用户上传(任何有效成员,服务端过滤)。
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- all
|
||||
- own
|
||||
default: all
|
||||
- $ref: '#/components/parameters/CursorQuery'
|
||||
- name: limit
|
||||
in: query
|
||||
@@ -987,7 +1003,9 @@ paths:
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'403':
|
||||
description: 仅创建者或管理员可访问管理列表(AUTH_FORBIDDEN)。
|
||||
description: |
|
||||
仅创建者或管理员可访问全量管理列表(scope=all 或缺省时协作者
|
||||
AUTH_FORBIDDEN);scope=own 需相册有效成员。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -1915,6 +1933,8 @@ paths:
|
||||
返回展示位绑定相册的近期已发布照片(≤20,按 publishedAt 与 ID 稳定
|
||||
倒序,小尺寸缩略图省流量)与相册摘要。lang 语义:auto(缺省)或取值
|
||||
不支持时按相册 defaultLocale 回退(不报 400,与公开相册一致)。
|
||||
settings(UI-01)返回后台配置的归一化全集(嵌入端应用后台配置,
|
||||
data-* 覆盖优先)。
|
||||
|
||||
- 防探测:slotToken 不存在、展示位停用(enabled=false)或未绑定相册
|
||||
一律 404 NOT_FOUND(同码同文案,不区分原因,避免枚举探测)。
|
||||
@@ -2797,6 +2817,16 @@ components:
|
||||
统计副本最近同步时间(P2 A27:ov→cn 统计快照在本相册的应用时刻);
|
||||
null 表示尚无回传应用(viewCountReplica 副本位仍为初始 0)。照片级
|
||||
点赞副本(PhotoRecord.likeCount)的同步时间不经相册行表达。
|
||||
cover:
|
||||
description: |
|
||||
相册封面摘要(UI-01,readOnly 可选扩展):当前生效封面资产
|
||||
(album_assets kind=cover、state=effective 的最新一行)的短期
|
||||
签名 URL;未配置封面为 null。列表端点按页批量组装(非逐相册
|
||||
查询);旧客户端忽略本字段不受影响。
|
||||
readOnly: true
|
||||
anyOf:
|
||||
- $ref: '#/components/schemas/SignedUrl'
|
||||
- type: 'null'
|
||||
|
||||
AlbumList:
|
||||
allOf:
|
||||
@@ -3513,6 +3543,21 @@ components:
|
||||
readOnly: true
|
||||
description: 展示姓名(来自用户资料)。
|
||||
|
||||
PhotoPreview:
|
||||
type: object
|
||||
description: |
|
||||
管理端照片预览(UI-01,readOnly):thumb/browse 短期签名 URL 与过期
|
||||
时间。签发条件(服务端逐张裁决):请求者有该照片管理权(admin 全部 /
|
||||
相册 owner 本相册全部 / 协作者仅自己上传)且照片有有效变体、未删除;
|
||||
隐藏照片仅 admin/owner 签发。不满足条件时 AdminPhoto.preview 为 null
|
||||
(PhotoRecord 本身仍如实返回)。URL 过期后经列表重取刷新。
|
||||
required: [thumb, browse]
|
||||
properties:
|
||||
thumb:
|
||||
$ref: '#/components/schemas/SignedUrl'
|
||||
browse:
|
||||
$ref: '#/components/schemas/SignedUrl'
|
||||
|
||||
AdminPhoto:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/PhotoRecord'
|
||||
@@ -3521,6 +3566,14 @@ components:
|
||||
properties:
|
||||
uploader:
|
||||
$ref: '#/components/schemas/AdminPhotoUploader'
|
||||
preview:
|
||||
description: |
|
||||
受权限管理的照片预览(UI-01,readOnly 可选扩展;无变体/已删除/
|
||||
无权签发时为 null)。旧客户端忽略本字段不受影响。
|
||||
readOnly: true
|
||||
anyOf:
|
||||
- $ref: '#/components/schemas/PhotoPreview'
|
||||
- type: 'null'
|
||||
|
||||
AdminPhotoList:
|
||||
allOf:
|
||||
@@ -4012,7 +4065,9 @@ components:
|
||||
description: |
|
||||
展示位展示设置。整体提交语义:创建时 settings 可整体缺省(各字段按
|
||||
下列缺省值落库),提供时字段齐全;更新为整体替换(未单独提交
|
||||
settings 则保持不变)。响应中字段恒齐全。
|
||||
settings 则保持不变)。响应中字段恒齐全。UI-01 新增字段
|
||||
(imageFit/offsetX/offsetBottom/zIndex)为可选扩展:提交时可缺省
|
||||
(按默认值归一化落库),旧 JSON/旧客户端零影响;响应恒为归一化全集。
|
||||
required: [position, size, intervalMs, lang, collapsedDefault]
|
||||
properties:
|
||||
position:
|
||||
@@ -4041,6 +4096,33 @@ components:
|
||||
type: boolean
|
||||
description: 初始是否收起(收起后仅展示小把手,点击展开)。
|
||||
default: false
|
||||
imageFit:
|
||||
type: string
|
||||
description: |
|
||||
轮播图片适配方式(UI-01):contain=完整展示于 4:3 舞台(中性底);
|
||||
cover=裁切填满舞台。可缺省(默认 contain)。
|
||||
enum:
|
||||
- contain
|
||||
- cover
|
||||
default: contain
|
||||
offsetX:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 120
|
||||
description: 组件距宿主页面边缘的水平偏移(像素,UI-01)。可缺省。
|
||||
default: 16
|
||||
offsetBottom:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 240
|
||||
description: 组件距宿主页面底部的垂直偏移(像素,UI-01)。可缺省。
|
||||
default: 24
|
||||
zIndex:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 2147483000
|
||||
description: 组件在宿主页面的层级(UI-01)。可缺省。
|
||||
default: 1000
|
||||
|
||||
EmbedSlot:
|
||||
type: object
|
||||
@@ -4374,6 +4456,8 @@ components:
|
||||
照片,按 publishedAt 与 ID 稳定倒序,上限 20(空数组=相册暂无已发布
|
||||
照片,嵌入端展示空态卡)。album 当前恒非 null(未绑定/停用的展示位
|
||||
公开端一律 404 防探测);null 为契约前瞻保留,嵌入端按空态处理。
|
||||
settings(UI-01 可选扩展)为后台配置的归一化全集(缺字段按默认值
|
||||
补齐)——嵌入端据此应用后台配置,data-* 覆盖优先于它。
|
||||
required: [slotToken, configVersion, album, photos]
|
||||
properties:
|
||||
slotToken:
|
||||
@@ -4386,6 +4470,13 @@ components:
|
||||
minimum: 1
|
||||
readOnly: true
|
||||
description: 配置版本(嵌入端变更检测:版本变化即整体重置渲染)。
|
||||
settings:
|
||||
description: |
|
||||
展示设置(UI-01 可选扩展;ov 副本 JSON 按契约默认值归一化后返回,
|
||||
恒为全集)。旧客户端忽略本字段不受影响。
|
||||
readOnly: true
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/EmbedSlotSettings'
|
||||
album:
|
||||
description: 绑定相册摘要;未绑定为 null(当前部署不会出现,见 schema 描述)。
|
||||
anyOf:
|
||||
|
||||
@@ -141,13 +141,22 @@ export interface SlotStateUpdatedPayload {
|
||||
entityVersion: number;
|
||||
}
|
||||
|
||||
/** 展示位设置载荷(契约 EmbedSlotSettings 的载荷形状;字段恒齐全)。 */
|
||||
/**
|
||||
* 展示位设置载荷(契约 EmbedSlotSettings 的载荷形状;字段恒齐全)。
|
||||
* UI-01 新增字段为可选:cn 写入侧恒发归一化全集,但部署切替期间 outbox/
|
||||
* sync_inbox 中在途事件仍是旧形状——消费侧(ov 投影/公开读)须对缺字段按
|
||||
* 契约默认值归一化,不得假设恒在。
|
||||
*/
|
||||
export interface SlotSettingsPayload {
|
||||
position: string; // left|right
|
||||
size: string; // sm|md
|
||||
intervalMs: number;
|
||||
lang: string; // auto|zh-CN|en
|
||||
collapsedDefault: boolean;
|
||||
imageFit?: string; // contain|cover(默认 contain)
|
||||
offsetX?: number; // 0..120(默认 16)
|
||||
offsetBottom?: number; // 0..240(默认 24)
|
||||
zIndex?: number; // 1..2147483000(默认 1000)
|
||||
}
|
||||
|
||||
// 运行时校验用:全部合法事件类型字符串。satisfies 保证 数组 ⊆ 接口 union;
|
||||
|
||||
+71
-2
@@ -418,6 +418,11 @@ export interface paths {
|
||||
* @description 相册照片管理列表(区别于公开列表):全部状态可见(unpublished/published/
|
||||
* hidden/deleted),条目含 uploader 脱敏信息。按 uploadedAt 与 ID 稳定倒序
|
||||
* 游标分页。
|
||||
*
|
||||
* scope(UI-01 可选扩展,缺省 all=既有行为不变):协作者显式查询自己
|
||||
* 上传的照片——服务端过滤 uploaderId=当前用户,成员资格逐请求校验;
|
||||
* 仅 owner/admin 可用 all(协作者 all → 403)。条目 preview 按请求者
|
||||
* 权限逐张裁决(见 PhotoPreview)。
|
||||
*/
|
||||
get: operations["listAlbumPhotos"];
|
||||
put?: never;
|
||||
@@ -905,6 +910,8 @@ export interface paths {
|
||||
* 返回展示位绑定相册的近期已发布照片(≤20,按 publishedAt 与 ID 稳定
|
||||
* 倒序,小尺寸缩略图省流量)与相册摘要。lang 语义:auto(缺省)或取值
|
||||
* 不支持时按相册 defaultLocale 回退(不报 400,与公开相册一致)。
|
||||
* settings(UI-01)返回后台配置的归一化全集(嵌入端应用后台配置,
|
||||
* data-* 覆盖优先)。
|
||||
*
|
||||
* - 防探测:slotToken 不存在、展示位停用(enabled=false)或未绑定相册
|
||||
* 一律 404 NOT_FOUND(同码同文案,不区分原因,避免枚举探测)。
|
||||
@@ -1379,6 +1386,13 @@ export interface components {
|
||||
* 点赞副本(PhotoRecord.likeCount)的同步时间不经相册行表达。
|
||||
*/
|
||||
readonly statsSyncedAt: string | null;
|
||||
/**
|
||||
* @description 相册封面摘要(UI-01,readOnly 可选扩展):当前生效封面资产
|
||||
* (album_assets kind=cover、state=effective 的最新一行)的短期
|
||||
* 签名 URL;未配置封面为 null。列表端点按页批量组装(非逐相册
|
||||
* 查询);旧客户端忽略本字段不受影响。
|
||||
*/
|
||||
readonly cover?: components["schemas"]["SignedUrl"] | null;
|
||||
};
|
||||
AlbumList: components["schemas"]["CursorPageMeta"] & {
|
||||
items: components["schemas"]["AlbumSummary"][];
|
||||
@@ -1754,8 +1768,24 @@ export interface components {
|
||||
/** @description 展示姓名(来自用户资料)。 */
|
||||
readonly displayName: string;
|
||||
};
|
||||
/**
|
||||
* @description 管理端照片预览(UI-01,readOnly):thumb/browse 短期签名 URL 与过期
|
||||
* 时间。签发条件(服务端逐张裁决):请求者有该照片管理权(admin 全部 /
|
||||
* 相册 owner 本相册全部 / 协作者仅自己上传)且照片有有效变体、未删除;
|
||||
* 隐藏照片仅 admin/owner 签发。不满足条件时 AdminPhoto.preview 为 null
|
||||
* (PhotoRecord 本身仍如实返回)。URL 过期后经列表重取刷新。
|
||||
*/
|
||||
PhotoPreview: {
|
||||
thumb: components["schemas"]["SignedUrl"];
|
||||
browse: components["schemas"]["SignedUrl"];
|
||||
};
|
||||
AdminPhoto: components["schemas"]["PhotoRecord"] & {
|
||||
uploader: components["schemas"]["AdminPhotoUploader"];
|
||||
/**
|
||||
* @description 受权限管理的照片预览(UI-01,readOnly 可选扩展;无变体/已删除/
|
||||
* 无权签发时为 null)。旧客户端忽略本字段不受影响。
|
||||
*/
|
||||
readonly preview?: components["schemas"]["PhotoPreview"] | null;
|
||||
};
|
||||
AdminPhotoList: components["schemas"]["CursorPageMeta"] & {
|
||||
items: components["schemas"]["AdminPhoto"][];
|
||||
@@ -2043,7 +2073,9 @@ export interface components {
|
||||
/**
|
||||
* @description 展示位展示设置。整体提交语义:创建时 settings 可整体缺省(各字段按
|
||||
* 下列缺省值落库),提供时字段齐全;更新为整体替换(未单独提交
|
||||
* settings 则保持不变)。响应中字段恒齐全。
|
||||
* settings 则保持不变)。响应中字段恒齐全。UI-01 新增字段
|
||||
* (imageFit/offsetX/offsetBottom/zIndex)为可选扩展:提交时可缺省
|
||||
* (按默认值归一化落库),旧 JSON/旧客户端零影响;响应恒为归一化全集。
|
||||
*/
|
||||
EmbedSlotSettings: {
|
||||
/**
|
||||
@@ -2069,6 +2101,28 @@ export interface components {
|
||||
* @default false
|
||||
*/
|
||||
collapsedDefault: boolean;
|
||||
/**
|
||||
* @description 轮播图片适配方式(UI-01):contain=完整展示于 4:3 舞台(中性底);
|
||||
* cover=裁切填满舞台。可缺省(默认 contain)。
|
||||
* @default contain
|
||||
* @enum {string}
|
||||
*/
|
||||
imageFit: "contain" | "cover";
|
||||
/**
|
||||
* @description 组件距宿主页面边缘的水平偏移(像素,UI-01)。可缺省。
|
||||
* @default 16
|
||||
*/
|
||||
offsetX: number;
|
||||
/**
|
||||
* @description 组件距宿主页面底部的垂直偏移(像素,UI-01)。可缺省。
|
||||
* @default 24
|
||||
*/
|
||||
offsetBottom: number;
|
||||
/**
|
||||
* @description 组件在宿主页面的层级(UI-01)。可缺省。
|
||||
* @default 1000
|
||||
*/
|
||||
zIndex: number;
|
||||
};
|
||||
/**
|
||||
* @description 展示位条目(管理视角)。albumId/albumTitle 为当前绑定相册(null=未
|
||||
@@ -2244,12 +2298,19 @@ export interface components {
|
||||
* 照片,按 publishedAt 与 ID 稳定倒序,上限 20(空数组=相册暂无已发布
|
||||
* 照片,嵌入端展示空态卡)。album 当前恒非 null(未绑定/停用的展示位
|
||||
* 公开端一律 404 防探测);null 为契约前瞻保留,嵌入端按空态处理。
|
||||
* settings(UI-01 可选扩展)为后台配置的归一化全集(缺字段按默认值
|
||||
* 补齐)——嵌入端据此应用后台配置,data-* 覆盖优先于它。
|
||||
*/
|
||||
PublicEmbedSlot: {
|
||||
/** @description 展示位公开令牌(回显请求路径)。 */
|
||||
readonly slotToken: string;
|
||||
/** @description 配置版本(嵌入端变更检测:版本变化即整体重置渲染)。 */
|
||||
readonly configVersion: number;
|
||||
/**
|
||||
* @description 展示设置(UI-01 可选扩展;ov 副本 JSON 按契约默认值归一化后返回,
|
||||
* 恒为全集)。旧客户端忽略本字段不受影响。
|
||||
*/
|
||||
readonly settings?: components["schemas"]["EmbedSlotSettings"];
|
||||
/** @description 绑定相册摘要;未绑定为 null(当前部署不会出现,见 schema 描述)。 */
|
||||
album: components["schemas"]["PublicEmbedAlbum"] | null;
|
||||
/** @description 近期照片(publishedAt 与 ID 稳定倒序,小尺寸缩略图)。 */
|
||||
@@ -3598,6 +3659,11 @@ export interface operations {
|
||||
visibility?: components["schemas"]["PhotoVisibility"];
|
||||
/** @description 分类 ID 过滤。 */
|
||||
categoryId?: string;
|
||||
/**
|
||||
* @description 数据范围(UI-01):all=本相册全部照片(缺省,仅 owner/admin);
|
||||
* own=仅当前用户上传(任何有效成员,服务端过滤)。
|
||||
*/
|
||||
scope?: "all" | "own";
|
||||
/** @description 分页游标(上一页响应的 nextCursor)。 */
|
||||
cursor?: components["parameters"]["CursorQuery"];
|
||||
/** @description 每页条数。 */
|
||||
@@ -3631,7 +3697,10 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
401: components["responses"]["Unauthorized"];
|
||||
/** @description 仅创建者或管理员可访问管理列表(AUTH_FORBIDDEN)。 */
|
||||
/**
|
||||
* @description 仅创建者或管理员可访问全量管理列表(scope=all 或缺省时协作者
|
||||
* AUTH_FORBIDDEN);scope=own 需相册有效成员。
|
||||
*/
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
|
||||
Reference in New Issue
Block a user