契约版本:1.3 状态:已确认,Q2-B更新时间范围检索接口基线 外部字段风格:
camelCase
数据库字段风格:snake_case
本文件是 /api/v1 的唯一人工可读接口契约。执行会话必须完整读取 DMS_FUNCTION_CONTRACT.md 和本文件。
后续建立的 backend/openapi/openapi.yaml 是本文件的机器可读镜像,不得另行发明字段、路径或枚举。两者不一致时不得自行选择,必须提交统领会话裁决。
以下旧路径明确废止,不得实现,也不得由前端调用:
/api/v1/documents/{id}/children
/api/v1/documents/{id}/materials
/api/v1/documents/recent
/api/v1/documents/search
/api/v1/documents/{id}/restore
/api/v1/attachments/{id}/preview
/api/v1/attachments/{id}/download
主案子方案、主案附件、搜索、最近更新和文件读取必须使用本文定义的规范路径。
其中 /api/v1/documents/{id}/restore 永久废止,由以下独立回收站资源替代,不提供重定向、别名或兼容调用:
GET /api/v1/recycle-bin/documents
POST /api/v1/recycle-bin/documents/{id}/restore
Base path: /api/v1
Authorization: Bearer <accessToken>
X-Request-Id: <UUID,可选>
除登录和健康检查外,所有接口需要有效 Token。
客户端未传 X-Request-Id 时由后端生成。响应头和 JSON 响应体均返回同一个请求 ID:
X-Request-Id: <requestId>
BIGINT;Z 的 ISO 8601,例如 2026-07-23T03:00:00.000Z;{
"code": "OK",
"message": "success",
"data": {},
"requestId": "8ed3e305-73a8-4af7-8f39-1b86b9a2dad2"
}
创建成功使用 HTTP 201,其他普通成功使用 200。删除成功仍返回上述 JSON,不使用 204。
{
"items": [],
"page": 1,
"pageSize": 20,
"total": 0,
"totalPages": 0
}
默认值:
page=1pageSize=20pageSize=100{
"code": "DATA_VERSION_CONFLICT",
"message": "数据已被其他用户修改,请刷新后重试",
"details": {
"currentRowVersion": 3
},
"requestId": "8ed3e305-73a8-4af7-8f39-1b86b9a2dad2"
}
details 无附加信息时为 null,不得省略。
| HTTP | 含义 |
|---|---|
| 200 | 查询、更新、删除或普通操作成功 |
| 201 | 创建成功 |
| 400 | 参数、结构或业务前置条件格式错误 |
| 401 | 未登录、Token无效或已失效 |
| 403 | 角色、密级或操作权限不足 |
| 404 | 对象不存在或已逻辑删除 |
| 409 | 数据版本、唯一性、引用关系等冲突 |
| 413 | 文件、批量数量或请求总体过大 |
| 415 | 文件格式或预览格式不支持 |
| 500 | 未处理的服务器错误 |
更新、删除、权限全量保存、挂载和解除挂载请求必须携带目标资源的 rowVersion。版本不一致返回:
HTTP 409
code = DATA_VERSION_CONFLICT
成功修改后返回新的 rowVersion。
预览和下载成功时不使用 JSON 包装。
PDF预览:
Content-Type: application/pdf
Content-Disposition: inline; filename*=UTF-8''...
X-Request-Id: ...
下载:
Content-Type: 实际MIME类型或application/octet-stream
Content-Disposition: attachment; filename*=UTF-8''...
X-Request-Id: ...
文件接口失败时返回普通 JSON 错误响应。
USER
ADMIN
AUDITOR
DOCUMENT_BROWSER
BACKEND_MANAGEMENT
AUDIT_LOG
MAIN
SUB_PLAN
ATTACHMENT
DRAFT
PUBLISHED
ARCHIVED
PUBLIC
INTERNAL
SECRET
CONFIDENTIAL
TOP_SECRET
ALL_AUTHENTICATED
ORGANIZATION
CUSTOM
POLICY
WORK_STANDARD
TABLE
DIAGRAM
OTHER
ORG
USER
VIEW
DOWNLOAD
EDIT
CONFIG_PERMISSION
DELETE
BIND_ATTACHMENT
UNBIND_ATTACHMENT
RESTORE_DOCUMENT
SCENE
STYLE
SITUATION
VERSION
OTHER
用户、组织和分类统一使用:
ENABLED
DISABLED
SUCCESS
FAILURE
LOGIN
LOGOUT
VIEW_DOCUMENT
DOWNLOAD_DOCUMENT
UPLOAD_DOCUMENT
BATCH_IMPORT
EDIT_DOCUMENT
DELETE_DOCUMENT
CREATE_CATEGORY
EDIT_CATEGORY
DELETE_CATEGORY
CHANGE_PERMISSION
BIND_ATTACHMENT
UNBIND_ATTACHMENT
AUTH
CATEGORY
DOCUMENT
ATTACHMENT
PERMISSION
ATTACHMENT_BINDING
{
"id": "1",
"username": "admin",
"realName": "系统管理员",
"organizationId": "10",
"organizationName": "机关",
"roleCode": "ADMIN",
"securityLevel": "TOP_SECRET",
"status": "ENABLED",
"allowedModules": [
"DOCUMENT_BROWSER",
"BACKEND_MANAGEMENT"
]
}
第一阶段模块映射固定为:
USER:DOCUMENT_BROWSERADMIN:DOCUMENT_BROWSER、BACKEND_MANAGEMENTAUDITOR:AUDIT_LOG前端必须使用后端返回的 allowedModules,不得根据角色自行补全模块。
{
"id": "100",
"categoryCode": "SCENE_A",
"categoryName": "XXXX场景A",
"categoryType": "SCENE",
"parentId": null,
"categoryPath": "/XXXX场景A",
"sortNo": 10,
"documentCount": 3,
"rowVersion": 0,
"children": []
}
{
"id": "1001",
"documentName": "2024年度综合应急预案",
"summary": "方案内容概述",
"documentType": "MAIN",
"status": "PUBLISHED",
"securityLevel": "SECRET",
"visibilityType": "ORGANIZATION",
"visibilitySummary": "作战部",
"categoryId": "100",
"categoryName": "XXXX场景A",
"categoryPath": "/XXXX场景A",
"parentDocumentId": null,
"rootDocumentId": "1001",
"attachmentType": null,
"fileExtension": "docx",
"tags": ["应急", "年度"],
"childCount": 3,
"attachmentCount": 2,
"viewCount": 12,
"downloadCount": 4,
"createdByName": "系统管理员",
"createdAt": "2026-07-23T03:00:00.000Z",
"updatedAt": "2026-07-23T03:00:00.000Z",
"rowVersion": 2,
"allowedActions": ["VIEW", "DOWNLOAD", "EDIT"]
}
ATTACHMENT 返回时:
categoryId/categoryName/categoryPath/parentDocumentId/rootDocumentId 为 null;visibilityType 固定 ALL_AUTHENTICATED;securityLevel 固定 PUBLIC;attachmentType 必填。DocumentDetail 包含 DocumentSummary 的全部字段,并增加:
{
"originalFileName": "2024年度综合应急预案.docx",
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"fileSize": 204800,
"fileHash": "SHA-256十六进制字符串",
"permissionSummary": {
"organizationCount": 2,
"userCount": 3,
"inheritedFromMainPlan": false
}
}
{
"id": "1001",
"documentName": "2024年度综合应急预案",
"documentType": "MAIN",
"originalFileName": "2024年度综合应急预案.docx",
"categoryId": "100",
"categoryName": "XXXX场景A",
"parentDocumentId": null,
"securityLevel": "SECRET",
"documentStatus": "PUBLISHED",
"deletedAt": "2026-07-26T03:00:00.000Z",
"updatedBy": "1",
"updatedByName": "系统管理员",
"deletedBy": {
"userId": "1",
"username": "admin",
"realName": "系统管理员",
"organizationName": "机关"
},
"rowVersion": 3
}
categoryId、categoryName、parentDocumentId、updatedBy、updatedByName和deletedBy允许为 null。deletedBy存在时,其四个字段也分别允许为 null。
删除人取与目标ID、目标类型匹配的最近一次成功 DELETE_DOCUMENT 审计快照:
MAIN和SUB_PLAN匹配 targetType=DOCUMENT;ATTACHMENT匹配 targetType=ATTACHMENT;null;updatedBy 或 updatedByName 冒充删除人。{
"document": {},
"restoredPermissionCount": 2,
"skippedPermissionCount": 1,
"restoredBindingCount": 3,
"skippedBindingCount": 1
}
document使用 DocumentDetail 字段,但恢复响应必须通过纯序列化生成,不得增加 viewCount、写入 VIEW_DOCUMENT 审计或触发文档详情查询的查看副作用。
GET /api/v1/health无需认证。
{
"code": "OK",
"message": "success",
"data": {
"service": "dms",
"status": "UP"
},
"requestId": "uuid"
}
健康检查不得泄露数据库密码、Token密钥和磁盘绝对路径。
POST /api/v1/auth/login无需认证。
请求:
{
"username": "admin",
"password": "password",
"keepSignedIn": true
}
成功:
{
"code": "OK",
"message": "success",
"data": {
"accessToken": "jwt",
"tokenType": "Bearer",
"expiresIn": 7200,
"user": {}
},
"requestId": "uuid"
}
user 使用 UserSummary。用户名或密码错误统一返回 401 INVALID_CREDENTIALS,不得泄露用户是否存在。
Token有效期固定为:
keepSignedIn=false:expiresIn=7200;keepSignedIn=true:expiresIn=604800。第一阶段不签发刷新令牌。
POST /api/v1/auth/logout请求体为空。成功后递增当前用户 authVersion,使该用户全部旧Token失效。
GET /api/v1/users/me返回当前 UserSummary。
GET /api/v1/organizations/tree查询参数:
keyword:可选,组织名称或编码;status:可选。返回组织树数组,每个节点至少包含:
{
"id": "10",
"orgCode": "ORG-10",
"orgName": "作战部",
"parentId": null,
"orgPath": "/作战部",
"sortNo": 10,
"status": "ENABLED",
"children": []
}
GET /api/v1/users查询参数:
organizationIdincludeDescendants,默认 falsekeywordstatuspagepageSize返回 PageResult<UserSummary>。
GET /api/v1/categories/tree查询参数:
keyword:只搜索分类名称或编码;status:可选。返回 CategoryNode[]。
POST /api/v1/categories管理员接口。
{
"categoryCode": "SCENE_A",
"categoryName": "XXXX场景A",
"categoryType": "SCENE",
"parentId": null,
"sortNo": 10
}
返回新建 CategoryNode,HTTP 201。
PUT /api/v1/categories/{id}管理员接口。
{
"categoryName": "新名称",
"categoryType": "SCENE",
"parentId": null,
"sortNo": 20,
"rowVersion": 1
}
移动分类不能形成环。成功返回更新后的 CategoryNode。
DELETE /api/v1/categories/{id}查询参数:
rowVersion=<integer>
存在有效子分类或有效主案、子方案时返回 409 CATEGORY_IN_USE。
GET /api/v1/documents查询参数:
documentType:逗号分隔,可为 MAIN,SUB_PLAN;不用于查询附件;categoryIdkeywordsecurityLevelvisibilityTypestatusupdatedFromupdatedTosortBy:仅允许 documentName/createdAt/updatedAt/viewCount/downloadCountsortDirection:asc/descpagepageSize页签调用规则:
主案列表: documentType=MAIN
全部方案: documentType=MAIN,SUB_PLAN
最近更新: documentType=MAIN,SUB_PLAN&sortBy=updatedAt&sortDirection=desc
关键词搜索也使用本接口,不建立独立 /search 路径。
updatedFrom作用为 updated_at >= updatedFrom,updatedTo作用为 updated_at <= updatedTo;同时提供时为闭区间,且 updatedFrom不得晚于 updatedTo。时间参数必须是包含明确时区的ISO 8601时间,前端统一发送UTC Z格式;空字符串、无时区时间、非法格式或反向区间返回 400 INVALID_ARGUMENT。时间条件在数据库查询和分页之前执行。
返回 PageResult<DocumentSummary>。
POST /api/v1/documents管理员接口,multipart/form-data:
file:一个文件;metadata:JSON字符串。主案 metadata:
{
"documentName": "主案名称",
"documentType": "MAIN",
"summary": "概述",
"categoryId": "100",
"securityLevel": "SECRET",
"visibilityType": "ORGANIZATION",
"status": "DRAFT",
"tags": ["标签"]
}
子方案 metadata 增加:
{
"documentType": "SUB_PLAN",
"parentDocumentId": "1001"
}
子方案 parentDocumentId 必须指向有效主案。返回 DocumentDetail,HTTP 201。
POST /api/v1/documents/batch-import管理员接口,multipart/form-data:
files:重复文件字段;items:JSON数组字符串,与 files 按顺序一一对应。每个 items[n] 使用单文件 metadata 的结构。数组长度与文件数量不一致返回 400 BATCH_MANIFEST_MISMATCH。
每个文件独立事务,整体 HTTP 200:
{
"code": "OK",
"message": "success",
"data": {
"total": 2,
"successCount": 1,
"failureCount": 1,
"items": [
{
"index": 0,
"originalFileName": "a.docx",
"success": true,
"document": {}
},
{
"index": 1,
"originalFileName": "b.exe",
"success": false,
"errorCode": "UNSUPPORTED_FILE_TYPE",
"errorMessage": "不支持的文件类型"
}
]
},
"requestId": "uuid"
}
GET /api/v1/documents/{id}仅用于 MAIN 和 SUB_PLAN,返回 DocumentDetail。
PUT /api/v1/documents/{id}管理员接口,只编辑元数据,不替换文件。
{
"documentName": "新名称",
"summary": "新概述",
"categoryId": "100",
"securityLevel": "SECRET",
"visibilityType": "CUSTOM",
"status": "PUBLISHED",
"tags": ["标签1", "标签2"],
"rowVersion": 2
}
不允许修改 documentType、parentDocumentId、rootDocumentId 和文件身份字段。
DELETE /api/v1/documents/{id}查询参数:
rowVersion=<integer>
主案存在有效子方案时返回 409 MAIN_PLAN_HAS_CHILDREN。成功返回:
{
"id": "1001",
"deleted": true
}
GET /api/v1/main-plans/{id}/sub-plans查询参数:
keywordstatusupdatedFromupdatedTopagepageSizesortBysortDirection时间范围作用于直属子方案自身的 updated_at,语义和错误规则与9.1相同。返回 PageResult<DocumentSummary>。id 不是有效主案时返回 404 MAIN_PLAN_NOT_FOUND。
GET /api/v1/attachments查询参数:
keywordattachmentTypefileExtensionupdatedFromupdatedTosortBysortDirectionpagepageSize返回 PageResult<DocumentSummary>,只包含有效 ATTACHMENT。
POST /api/v1/attachments管理员接口,multipart/form-data:
filemetadata
{
"documentName": "附件名称",
"attachmentType": "POLICY",
"summary": "说明",
"tags": ["制度"]
}
后端强制:
documentType=ATTACHMENT
securityLevel=PUBLIC
visibilityType=ALL_AUTHENTICATED
categoryId=null
返回 DocumentDetail,HTTP 201。
POST /api/v1/attachments/batch-import与文档批量导入相同,使用重复 files 和顺序对应的 items。每个 item 使用附件 metadata 结构,每文件独立事务。
GET /api/v1/attachments/{id}返回附件 DocumentDetail。
PUT /api/v1/attachments/{id}管理员接口:
{
"documentName": "新名称",
"attachmentType": "WORK_STANDARD",
"summary": "新说明",
"tags": ["规范"],
"rowVersion": 1
}
不得修改附件固定密级、固定可见范围和文件身份。
DELETE /api/v1/attachments/{id}查询参数:
rowVersion=<integer>
存在有效挂载时:
HTTP 409
code = ATTACHMENT_IN_USE
details.mountedPlanCount
details.mainPlans
GET /api/v1/attachments/{id}/main-plans返回:
{
"items": [
{
"id": "1001",
"documentName": "主案名称",
"categoryName": "XXXX场景A",
"securityLevel": "SECRET"
}
],
"total": 1
}
GET /api/v1/main-plans/{id}/attachments返回当前主案有效挂载附件,支持:
keywordattachmentTypeupdatedFromupdatedTopagepageSize每项使用附件 DocumentSummary,增加:
{
"bindingId": "5001",
"bindingSortNo": 10,
"mountedPlanCount": 3
}
时间范围作用于附件文档自身的 updated_at,不使用 doc_attachment_binding的创建时间、更新时间或 bindingSortNo;语义和错误规则与9.1相同。
POST /api/v1/main-plans/{id}/attachments/bind管理员接口:
{
"attachmentIds": ["2001", "2002"],
"mainPlanRowVersion": 3
}
请求内重复ID自动去重;已经挂载的附件不重复创建。
{
"createdCount": 1,
"existingCount": 1,
"attachmentCount": 5,
"mainPlanRowVersion": 4
}
DELETE /api/v1/main-plans/{id}/attachments/{attachmentId}查询参数:
mainPlanRowVersion=<integer>
逻辑删除挂载关系,不删除附件。返回最新附件计数和主案版本。
GET /api/v1/documents/{id}/permissions主案返回:
{
"documentId": "1001",
"sourceDocumentId": "1001",
"inherited": false,
"visibilityType": "CUSTOM",
"documentRowVersion": 3,
"entries": [
{
"id": "7001",
"subjectType": "ORG",
"subjectId": "10",
"subjectName": "作战部",
"canView": true,
"canDownload": true,
"canEdit": false,
"canManagePermission": false,
"canDelete": false
}
]
}
子方案可调用该查询接口,但返回所属主案权限:
sourceDocumentId 为主案ID;inherited=true。共享附件调用返回 400 ATTACHMENT_HAS_NO_ACL。
PUT /api/v1/documents/{id}/permissions只允许对 MAIN 调用。子方案返回 409 SUB_PLAN_PERMISSION_INHERITED。
{
"visibilityType": "CUSTOM",
"documentRowVersion": 3,
"entries": [
{
"subjectType": "ORG",
"subjectId": "10",
"canView": true,
"canDownload": true,
"canEdit": false,
"canManagePermission": false,
"canDelete": false
}
]
}
规则:
ALL_AUTHENTICATED 时 entries 必须为空;ORGANIZATION 时只允许 ORG;CUSTOM 允许 ORG 和 USER;400 DUPLICATE_PERMISSION_SUBJECT;以下两个接口适用于 MAIN、SUB_PLAN 和 ATTACHMENT,不再建立附件专用文件路径。
GET /api/v1/documents/{id}/preview415 PREVIEW_UNAVAILABLE;403 DOCUMENT_VIEW_FORBIDDEN;404 FILE_NOT_FOUND。GET /api/v1/documents/{id}/downloadDOWNLOAD;仅有效 ADMIN 可以访问本章接口。USER和AUDITOR返回 403 FORBIDDEN。
本阶段只支持 MAIN、SUB_PLAN和ATTACHMENT的回收站查询与单条恢复。不支持分类、用户或组织恢复,不支持批量恢复、物理删除、自动清理、保留期限、ACL或挂载关系独立恢复,也不移动文件到 recycle 目录。
GET /api/v1/recycle-bin/documents查询参数:
keyworddocumentType:MAIN|SUB_PLAN|ATTACHMENTcategoryId:字符串IDdeletedFrom:带 Z 的ISO 8601 UTC时间deletedTo:带 Z 的ISO 8601 UTC时间page,默认1pageSize,默认20、最大100sortField:仅允许 deletedAt|documentName|documentType|updatedAtsortDirection:asc|desc,默认 desc固定查询 isDeleted=true 且 deletedAt!=null。删除时间区间采用 [deletedFrom, deletedTo);允许只传一个边界,两者都传时必须满足 deletedFrom < deletedTo。不接受无时区、本地偏移时间或数字时间戳。
keyword只搜索文档名称、概述、searchText和原文件名,使用参数化包含匹配。空字符串按未传处理。
默认排序为 deletedAt desc, id desc;其他排序也使用 id作为同方向次级排序。返回 PageResult<RecycleBinDocumentSummary>,所有ID均为字符串。
POST /api/v1/recycle-bin/documents/{id}/restore请求体必须且只能包含:
{
"rowVersion": 3
}
rowVersion必须为非负整数。成功使用HTTP 200并返回 RestoreDocumentResult。
通用恢复校验:
rowVersion与当前删除记录一致;文件检查采用两阶段方案:事务前完成完整哈希和格式校验,保持文件句柄并记录文件状态;事务内锁定数据库记录后、提交前重新检查状态。变化时返回 RESTORE_FILE_CHANGED。数据库事务不能锁定磁盘文件,当前以应用独占管理UUID正式文件为前提。
MAIN恢复采用方案B:
deletedAt和updatedBy的级联删除ACL和挂载关系;ORGANIZATION最终必须至少存在一个有效且 canView=true 的ORG权限;CUSTOM允许空权限集合,普通用户默认无权访问;ALL_AUTHENTICATED最终权限集合必须为空;documentCount、主案 childCount和attachmentCount;allowedActions由现有授权服务动态计算。SUB_PLAN恢复:
parentDocumentId和rootDocumentId必须指向同一有效MAIN;childCount。ATTACHMENT恢复后强制保持:
documentType=ATTACHMENT
securityLevel=PUBLIC
visibilityType=ALL_AUTHENTICATED
categoryId=null
parentDocumentId=null
rootDocumentId=null
附件不创建或恢复ACL,不自动恢复历史挂载,mountedPlanCount按当前有效关系统计。若异常存在指向已删除附件的有效挂载,返回关系冲突。
正式允许同类型文档同名、相同原文件名、分类下同名、同一主案下同名子方案、相同文件哈希以及不同文档使用相同哈希但各自保存独立文件路径。恢复冲突只处理有效ACL唯一冲突、有效挂载唯一冲突及主键或结构一致性冲突。
版本规则:
rowVersion;409 DATA_VERSION_CONFLICT及 details.currentRowVersion;成功审计使用 RESTORE_DOCUMENT,包括操作者、组织、目标快照、文档类型、版本前后值、原删除时间、恢复及跳过关系数量、父文档和分类ID、客户端IP、User-Agent和requestId。不得记录绝对路径、文件正文、数据库连接信息或文件哈希。最小范围内恢复失败不写业务审计,只写安全应用日志和统一错误响应。
固定锁顺序:
B8实现必须创建 0002_add_restore_audit_action,不得修改 0001_initial_schema。迁移必须:
sys_audit_log.action_type CHECK,加入 RESTORE_DOCUMENT;doc_document增加索引 (is_deleted, deleted_at, id);GET /api/v1/audit/logs查询参数:
keywordcreatedFromcreatedTouserIdorganizationIdactionTypeoperationResulttargetTypetargetIdpagepageSizesortDirection,默认 desc返回分页日志:
{
"id": "9001",
"username": "admin",
"realName": "系统管理员",
"organizationName": "机关",
"actionType": "DOWNLOAD_DOCUMENT",
"targetType": "DOCUMENT",
"targetId": "1001",
"targetName": "主案名称",
"operationResult": "SUCCESS",
"failureReason": null,
"clientIp": "127.0.0.1",
"requestId": "uuid",
"createdAt": "2026-07-23T03:00:00.000Z"
}
GET /api/v1/statistics/documents{
"planDocumentCount": 64,
"mainPlanCount": 21,
"subPlanCount": 43,
"attachmentCount": 18,
"todayViewerCount": 12
}
planDocumentCount = mainPlanCount + subPlanCount,不包含附件。
GET /api/v1/audit/statistics/trend参数:createdFrom、createdTo、granularity=DAY|WEEK|MONTH。
返回:
{
"items": [
{
"period": "2026-07-23",
"operationCount": 25
}
]
}
GET /api/v1/audit/statistics/actions参数:createdFrom、createdTo。
返回动作分布:
{
"items": [
{
"actionType": "VIEW_DOCUMENT",
"count": 20
}
]
}
GET /api/v1/audit/statistics/users参数:createdFrom、createdTo、limit,limit 默认10、最大100。
返回活跃用户:
{
"items": [
{
"userId": "1",
"realName": "系统管理员",
"organizationName": "机关",
"operationCount": 15
}
]
}
实现可以增加更细错误码,但不得改变以下语义:
INVALID_ARGUMENT
INVALID_CREDENTIALS
TOKEN_INVALID
TOKEN_EXPIRED
USER_DISABLED
AUTH_VERSION_MISMATCH
FORBIDDEN
SECURITY_LEVEL_FORBIDDEN
DOCUMENT_VIEW_FORBIDDEN
DOCUMENT_DOWNLOAD_FORBIDDEN
RESOURCE_NOT_FOUND
FILE_NOT_FOUND
UNSUPPORTED_FILE_TYPE
PREVIEW_UNAVAILABLE
PAYLOAD_TOO_LARGE
BATCH_MANIFEST_MISMATCH
DATA_VERSION_CONFLICT
CATEGORY_IN_USE
MAIN_PLAN_HAS_CHILDREN
ATTACHMENT_IN_USE
ATTACHMENT_HAS_NO_ACL
SUB_PLAN_PERMISSION_INHERITED
DUPLICATE_PERMISSION_SUBJECT
INTERNAL_ERROR
DOCUMENT_NOT_DELETED
FILE_INTEGRITY_MISMATCH
FILE_PATH_INVALID
RESTORE_FILE_CHANGED
RESTORE_CATEGORY_INVALID
RESTORE_PARENT_INVALID
RESTORE_PERMISSION_INVALID
RESTORE_RELATION_CONFLICT
恢复错误码定义:
| code | HTTP | message | details |
|---|---|---|---|
DOCUMENT_NOT_DELETED |
409 | 文档当前不在回收站中 | documentId |
FILE_INTEGRITY_MISMATCH |
409 | 文档文件完整性校验失败 | reason=SIZE_MISMATCH\|HASH_MISMATCH\|TYPE_MISMATCH |
FILE_PATH_INVALID |
500 | 文档存储路径异常 | null |
RESTORE_FILE_CHANGED |
409 | 校验期间文件发生变化 | null |
RESTORE_CATEGORY_INVALID |
409 | 原方案分类无效,无法恢复 | categoryId、reason=NOT_FOUND\|DELETED\|DISABLED |
RESTORE_PARENT_INVALID |
409 | 原所属主案无效,无法恢复 | parentDocumentId、reason=NOT_FOUND\|DELETED\|WRONG_TYPE\|ROOT_MISMATCH |
RESTORE_PERMISSION_INVALID |
409 | 恢复后无法形成有效权限配置 | invalidCount、reason=NO_VALID_ORGANIZATION_PERMISSION\|ALL_AUTHENTICATED_HAS_PERMISSIONS |
RESTORE_RELATION_CONFLICT |
409 | 历史权限或挂载关系与当前有效关系冲突 | permissionConflictCount、bindingConflictCount |
错误响应不得泄露绝对路径、哈希、SQL、数据库连接信息或内部异常堆栈。
每个业务阶段实现接口时,必须同步更新 OpenAPI,并满足:
operationId 唯一;type: string、pattern: '^[0-9]+$';type: string、format: date-time;info.version升级为 1.1.0,同步回收站路径、DTO、错误码、RESTORE_DOCUMENT和迁移后的枚举。/api/v1/documents/{id}/restore不得进入OpenAPI。GET /api/v1/config/ui-dictionaries
ADMIN、AUDITOR、USER均可访问。200,统一响应中的 data 为 UiDictionaries。401;启动期配置错误导致应用启动失败,运行期意外错误使用统一 500。DictionaryOption:
{
"code": "INTERNAL",
"label": "内部",
"sortNo": 20
}
UiDictionaries:
{
"version": "2026.1",
"locale": "zh-CN",
"dictionaries": {
"securityLevels": [
{
"code": "INTERNAL",
"label": "内部",
"sortNo": 20
}
]
}
}
dictionaries必须固定包含以下14个数组:roleCodes、allowedModules、documentTypes、documentStatuses、securityLevels、visibilityTypes、attachmentTypes、subjectTypes、allowedActions、categoryTypes、enabledStatuses、auditResults、auditActions、auditTargets。
每个数组按 sortNo、code稳定排序。外部字段使用 camelCase,sortNo为整数,code和label为字符串。响应不得包含配置路径、加载时间或内部异常;响应体 requestId 与 X-Request-Id保持一致,CORS沿用现有 /api/v1规则。
默认配置位于 backend/dms/resources/ui-dictionaries.zh-CN.json,可通过服务端环境变量 DMS_UI_DICTIONARY_CONFIG_PATH覆盖。配置在启动时严格校验并加载,修改后重启生效,不提供热更新。
前端:
code;401 统一清理Token并触发登录失效;allowedActions;后端:
snake_case 直接泄露到 JSON;执行会话不得直接修改本文件。接口需要变化时,应提交:
经统领会话确认后,提高契约版本,并同步功能契约、OpenAPI、前端类型和自动化测试。
版本1.1经统领会话批准,增加独立回收站查询和单条文档恢复,旧文档恢复路径继续永久废止。
版本1.2经统领会话批准,增加 GET /api/v1/config/ui-dictionaries 只读接口和严格启动配置规则;既有业务路径、枚举代码及数据库值不变,OpenAPI同步升级为 1.2.0。
版本1.3经统领会话批准,为方案、直属子方案和已挂载附件三个既有查询接口统一增加文档更新时间闭区间筛选;不新增路径、DTO、数据库字段或迁移,OpenAPI同步升级为 1.3.0。Office预览使用1.4或后续版本。