feat(albums): soft-delete albums (admin+owner, hidden & irreversible, both app entries)
契约 deleteAlbum(DELETE /albums/{albumId} → 204 幂等)+ status enum 'deleted':
- 服务端:softDelete(canView 404→canManage 403 防枚举;乐观锁 claim +
outbox album.updated priority=high + audit album.delete);列表/详情/更新/
成员/资产/分类/水印/照片/展示位绑定全部 deleted→404;公开端 cn
(status!=='active')与 ov(isAlbumVisibleOv)天然屏蔽;ov 副本经
album.updated 载荷 status 直投自动下线
- Admin:列表表格操作「删除」+ 详情页头「删除相册」(确认含不可恢复说明)
- App:操作面板「删除相册」(红字、二次确认、成功退回列表并刷新)
- 验证:API 56/56、App 397/397(analyze 0)、admin typecheck/lint/test/build 绿
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -267,6 +267,34 @@ paths:
|
||||
/albums/{albumId}:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/AlbumId'
|
||||
delete:
|
||||
operationId: deleteAlbum
|
||||
tags: [albums]
|
||||
summary: 软删除相册
|
||||
description: >-
|
||||
标记 status=deleted(软删除):管理端列表与公开端即刻不可见,成员/上传/
|
||||
资产等全部子资源随之 404;数据保留(物理删除走独立运维流程),不提供
|
||||
恢复端点。权限同「配置相册」(公司管理员或相册创建者)。事件走
|
||||
album.updated(priority=high)同步 ov 副本下线。
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'204':
|
||||
description: 已删除(幂等:重复删除同样 204)。
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'403':
|
||||
description: 无「配置相册」权限(仅创建者或管理员,AUTH_FORBIDDEN)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'404':
|
||||
description: 相册不存在(ALBUM_NOT_FOUND,含已删除)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
get:
|
||||
operationId: getAlbum
|
||||
tags: [albums]
|
||||
@@ -2781,6 +2809,7 @@ components:
|
||||
enum:
|
||||
- active
|
||||
- offline
|
||||
- deleted
|
||||
defaultLocale:
|
||||
$ref: '#/components/schemas/Locale'
|
||||
timezone:
|
||||
@@ -2839,8 +2868,9 @@ components:
|
||||
description: |
|
||||
相册封面摘要(UI-01,readOnly 可选扩展):当前生效封面资产
|
||||
(album_assets kind=cover、state=effective 的最新一行)的短期
|
||||
签名 URL;未配置封面为 null。列表端点按页批量组装(非逐相册
|
||||
查询);旧客户端忽略本字段不受影响。
|
||||
签名 URL;未配置封面为 null。宣传图/封面共用(2026-09-23 决策):
|
||||
未配置封面时回退最新生效宣传图(传一张即可两用)。列表端点按页
|
||||
批量组装(非逐相册查询);旧客户端忽略本字段不受影响。
|
||||
readOnly: true
|
||||
anyOf:
|
||||
- $ref: '#/components/schemas/SignedUrl'
|
||||
@@ -4397,7 +4427,9 @@ components:
|
||||
items:
|
||||
$ref: '#/components/schemas/PublicCategory'
|
||||
banner:
|
||||
description: 封面图签名 URL;未设置为 null。
|
||||
description: |
|
||||
宣传图签名 URL;未设置为 null。宣传图/封面共用(2026-09-23 决策):
|
||||
未配置宣传图时回退最新生效封面(传一张即可两用)。
|
||||
anyOf:
|
||||
- $ref: '#/components/schemas/SignedUrl'
|
||||
- type: 'null'
|
||||
|
||||
+53
-5
@@ -129,7 +129,11 @@ export interface paths {
|
||||
get: operations["getAlbum"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
/**
|
||||
* 软删除相册
|
||||
* @description 标记 status=deleted(软删除):管理端列表与公开端即刻不可见,成员/上传/ 资产等全部子资源随之 404;数据保留(物理删除走独立运维流程),不提供 恢复端点。权限同「配置相册」(公司管理员或相册创建者)。事件走 album.updated(priority=high)同步 ov 副本下线。
|
||||
*/
|
||||
delete: operations["deleteAlbum"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
/**
|
||||
@@ -1340,7 +1344,7 @@ export interface components {
|
||||
* @default active
|
||||
* @enum {string}
|
||||
*/
|
||||
readonly status: "active" | "offline";
|
||||
readonly status: "active" | "offline" | "deleted";
|
||||
defaultLocale: components["schemas"]["Locale"];
|
||||
/** @description 活动 IANA 时区。 */
|
||||
timezone: string;
|
||||
@@ -1389,8 +1393,9 @@ export interface components {
|
||||
/**
|
||||
* @description 相册封面摘要(UI-01,readOnly 可选扩展):当前生效封面资产
|
||||
* (album_assets kind=cover、state=effective 的最新一行)的短期
|
||||
* 签名 URL;未配置封面为 null。列表端点按页批量组装(非逐相册
|
||||
* 查询);旧客户端忽略本字段不受影响。
|
||||
* 签名 URL;未配置封面为 null。宣传图/封面共用(2026-09-23 决策):
|
||||
* 未配置封面时回退最新生效宣传图(传一张即可两用)。列表端点按页
|
||||
* 批量组装(非逐相册查询);旧客户端忽略本字段不受影响。
|
||||
*/
|
||||
readonly cover?: components["schemas"]["SignedUrl"] | null;
|
||||
};
|
||||
@@ -2267,7 +2272,10 @@ export interface components {
|
||||
translation: components["schemas"]["PublicAlbumTranslation"];
|
||||
/** @description 分类列表(按 sortOrder 升序)。 */
|
||||
categories: components["schemas"]["PublicCategory"][];
|
||||
/** @description 封面图签名 URL;未设置为 null。 */
|
||||
/**
|
||||
* @description 宣传图签名 URL;未设置为 null。宣传图/封面共用(2026-09-23 决策):
|
||||
* 未配置宣传图时回退最新生效封面(传一张即可两用)。
|
||||
*/
|
||||
banner: components["schemas"]["SignedUrl"] | null;
|
||||
/**
|
||||
* Format: int64
|
||||
@@ -2922,6 +2930,46 @@ export interface operations {
|
||||
500: components["responses"]["InternalError"];
|
||||
};
|
||||
};
|
||||
deleteAlbum: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
/** @description 相册 ID。 */
|
||||
albumId: components["parameters"]["AlbumId"];
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description 已删除(幂等:重复删除同样 204)。 */
|
||||
204: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
401: components["responses"]["Unauthorized"];
|
||||
/** @description 无「配置相册」权限(仅创建者或管理员,AUTH_FORBIDDEN)。 */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
/** @description 相册不存在(ALBUM_NOT_FOUND,含已删除)。 */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
updateAlbum: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
-- 宣传图/封面共用(用户决策 2026-09-23):albums_ov 增 coverAssetKey 投影列
|
||||
-- (asset.updated kind=cover 分流写入;banner/cover 互为展示层回退)。
|
||||
-- 存量行回填:迁移后由对账 bootstrap(asset.updated 当前态重放)或下次
|
||||
-- cover 资产事件自然补齐,不手工 UPDATE。
|
||||
-- AlterTable
|
||||
ALTER TABLE `albums_ov` ADD COLUMN `coverAssetKey` VARCHAR(255) NULL;
|
||||
@@ -47,7 +47,11 @@ model albums_ov {
|
||||
emergencyDisabled Boolean @default(false)
|
||||
translations Json // [{locale,title,description,venue,address}](cn 原文数组)
|
||||
categories Json // [{id,sortOrder,translations:[{locale,name}]}]
|
||||
// 宣传图/封面投影键(asset.updated 事件按 kind 分列存储)。展示层双向回退
|
||||
// (用户决策 2026-09-23「宣传图和封面用一个」):banner 缺失时公开侧回退
|
||||
// cover 键——需求 §4.2「封面可复用宣传图」基线的反向补充。
|
||||
bannerAssetKey String? @db.VarChar(255)
|
||||
coverAssetKey String? @db.VarChar(255)
|
||||
defaultLocale String @db.VarChar(16)
|
||||
timezone String @default("Asia/Shanghai") @db.VarChar(64)
|
||||
startAt DateTime? @db.DateTime(6)
|
||||
|
||||
Reference in New Issue
Block a user