Files
TakeoutSaaS.AdminApi/docs/api/announcements-api.md
MSuMshk 857f776447 feat: 实现完整的多租户公告管理系统
核心功能:
- 公告状态机(草稿/已发布/已撤销)支持发布、撤销和重新发布
- 发布者范围区分平台级和租户级公告
- 目标受众定向推送(全部租户/指定角色/指定用户)
- 平台管理、租户管理和应用端查询API
- 已读/未读管理和未读统计

技术实现:
- CQRS+DDD架构,清晰的领域边界和事件驱动
- 查询性能优化:数据库端排序和限制,估算策略减少内存占用
- 并发控制:修复RowVersion配置(IsRowVersion→IsConcurrencyToken)
- 完整的FluentValidation验证器和输入保护

测试验证:
- 36个测试全部通过(27单元+9集成)
- 性能测试达标(1000条数据<5秒)
- 代码质量评级A(优秀)

文档:
- 完整的ADR、API文档和迁移指南
- 交付报告和技术债务记录
2025-12-20 19:57:09 +08:00

315 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 公告管理 API 文档
> 最后更新日期2025-12-20
本文档覆盖公告管理相关 API包括平台公告、租户公告管理端接口以及应用端已认证用户接口。
## 统一约定
- 认证方式:`Authorization: Bearer <JWT>`
- 时间字段均为 UTCISO 8601
- 雪花 ID 以字符串形式序列化返回。
- 统一响应结构:`ApiResponse<T>`
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {},
"errors": null,
"traceId": "01JH...",
"timestamp": "2025-12-20T12:00:00Z"
}
```
分页结构:
```json
{
"items": [],
"page": 1,
"pageSize": 20,
"totalCount": 0,
"totalPages": 0
}
```
## 关键枚举与字段
- `AnnouncementStatus``Draft(0)``Published(1)``Revoked(2)`
- `TenantAnnouncementType``System(0)``Billing(1)``Operation(2)``SYSTEM_PLATFORM_UPDATE(3)``SYSTEM_SECURITY_NOTICE(4)``SYSTEM_COMPLIANCE(5)``TENANT_INTERNAL(6)``TENANT_FINANCE(7)``TENANT_OPERATION(8)`
- `PublisherScope``Platform(0)``Tenant(1)`(只读字段)
- `RowVersion`并发控制字段Base64 字符串)。
## 目标受众TargetType / TargetParameters
系统使用 `TargetType`(不区分大小写)+ `TargetParameters(JSON)` 过滤可见公告:
- `ALL_TENANTS`:平台全量(可带约束)
- `TENANT_ALL`:单租户全量
- `SPECIFIC_TENANTS`
- `USERS` / `SPECIFIC_USERS` / `USER_IDS`
- `ROLES` / `ROLE`
- `PERMISSIONS` / `PERMISSION`
- `MERCHANTS` / `MERCHANT_IDS`
`TargetParameters` 示例:
```json
{
"tenantIds": [100000000000000001],
"userIds": [200000000000000001],
"merchantIds": [300000000000000001],
"roles": ["OpsManager"],
"permissions": ["tenant-announcement:read"],
"departments": ["NorthRegion"]
}
```
注意:`TargetParameters` 为字符串 JSON解析失败会导致公告对该用户不可见失败即隐藏
## 数据流(示意)
```mermaid
flowchart LR
Client[客户端] --> API[API Controller]
API --> Mediator[MediatR]
Mediator --> Handler[Query/Command Handler]
Handler --> Repo[Repository]
Repo --> DB[(PostgreSQL)]
```
---
# 平台公告 API
> 路由前缀:`/api/platform/announcements`(无版本前缀)
### 1) 创建平台公告
- **方法**POST
- **路径**`/api/platform/announcements`
- **权限**`platform-announcement:create`
- **请求体**`CreateTenantAnnouncementCommand`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**400 / 403
请求示例:
```json
{
"title": "平台升级通知",
"content": "系统将于今晚 23:00 维护。",
"announcementType": 0,
"priority": 10,
"effectiveFrom": "2025-12-20T00:00:00Z",
"effectiveTo": null,
"targetType": "all_tenants",
"targetParameters": null
}
```
响应示例:
```json
{
"success": true,
"code": 200,
"data": {
"id": "900123456789012345",
"tenantId": "0",
"title": "平台升级通知",
"status": "Draft"
}
}
```
### 2) 查询平台公告列表
- **方法**GET
- **路径**`/api/platform/announcements`
- **权限**`platform-announcement:create`
- **查询参数**
- `page` / `pageSize`
- `status`Draft/Published/Revoked
- `announcementType`
- `isActive`
- `effectiveFrom` / `effectiveTo`
- `onlyEffective`
- **响应**`ApiResponse<PagedResult<TenantAnnouncementDto>>`
- **错误码**403
示例:`GET /api/platform/announcements?page=1&pageSize=20&status=Published`
### 3) 获取平台公告详情
- **方法**GET
- **路径**`/api/platform/announcements/{announcementId}`
- **权限**`platform-announcement:create`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**403 / 404
### 4) 更新平台公告(仅草稿)
- **方法**PUT
- **路径**`/api/platform/announcements/{announcementId}`
- **权限**`platform-announcement:create`
- **请求体**`UpdateTenantAnnouncementCommand`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**403 / 404 / 409
请求示例:
```json
{
"title": "平台升级通知(更新)",
"content": "维护时间调整为 23:30。",
"targetType": "all_tenants",
"targetParameters": null,
"rowVersion": "AAAAAAAAB9E="
}
```
### 5) 发布平台公告
- **方法**POST
- **路径**`/api/platform/announcements/{announcementId}/publish`
- **权限**`platform-announcement:publish`
- **请求体**`PublishAnnouncementCommand`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**403 / 404 / 409
请求示例:
```json
{ "rowVersion": "AAAAAAAAB9E=" }
```
### 6) 撤销平台公告
- **方法**POST
- **路径**`/api/platform/announcements/{announcementId}/revoke`
- **权限**`platform-announcement:revoke`
- **请求体**`RevokeAnnouncementCommand`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**403 / 404 / 409
请求示例:
```json
{ "rowVersion": "AAAAAAAAB9E=" }
```
---
# 租户公告管理 API管理端
> 路由前缀:`/api/admin/v{version}/tenants/{tenantId}/announcements`
### 1) 查询租户公告列表
- **方法**GET
- **路径**`/api/admin/v1/tenants/{tenantId}/announcements`
- **权限**`tenant-announcement:read`
- **查询参数**
- `page` / `pageSize`
- `status` / `announcementType`
- `isActive` / `effectiveFrom` / `effectiveTo` / `onlyEffective`
- **响应**`ApiResponse<PagedResult<TenantAnnouncementDto>>`
- **错误码**403
### 2) 获取租户公告详情
- **方法**GET
- **路径**`/api/admin/v1/tenants/{tenantId}/announcements/{announcementId}`
- **权限**`tenant-announcement:read`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**403 / 404
### 3) 创建租户公告
- **方法**POST
- **路径**`/api/admin/v1/tenants/{tenantId}/announcements`
- **权限**`tenant-announcement:create`
- **请求体**`CreateTenantAnnouncementCommand`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**400 / 403
请求示例:
```json
{
"title": "租户公告",
"content": "新品上线提醒",
"announcementType": 0,
"priority": 5,
"effectiveFrom": "2025-12-20T00:00:00Z",
"targetType": "roles",
"targetParameters": "{\"roles\":[\"OpsManager\"]}"
}
```
### 4) 更新租户公告(仅草稿)
- **方法**PUT
- **路径**`/api/admin/v1/tenants/{tenantId}/announcements/{announcementId}`
- **权限**`tenant-announcement:update`
- **请求体**`UpdateTenantAnnouncementCommand`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**403 / 404 / 409
### 5) 发布租户公告
- **方法**POST
- **路径**`/api/admin/v1/tenants/{tenantId}/announcements/{announcementId}/publish`
- **权限**`tenant-announcement:publish`
- **请求体**`PublishAnnouncementCommand`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**403 / 404 / 409
### 6) 撤销租户公告
- **方法**POST
- **路径**`/api/admin/v1/tenants/{tenantId}/announcements/{announcementId}/revoke`
- **权限**`tenant-announcement:revoke`
- **请求体**`RevokeAnnouncementCommand`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**403 / 404 / 409
### 7) 删除租户公告
- **方法**DELETE
- **路径**`/api/admin/v1/tenants/{tenantId}/announcements/{announcementId}`
- **权限**`tenant-announcement:delete`
- **响应**`ApiResponse<bool>`
- **错误码**403
### 8) 标记公告已读(兼容旧路径)
- **方法**POST
- **路径**`/api/admin/v1/tenants/{tenantId}/announcements/{announcementId}/read`
- **权限**`tenant-announcement:read`
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**403 / 404
---
# 应用端公告 API已认证用户
> 路由前缀:`/api/app/announcements`(目前挂载在 AdminApi
### 1) 获取可见公告列表
- **方法**GET
- **路径**`/api/app/announcements`
- **权限**:登录即可
- **查询参数**`page` / `pageSize`(其他筛选参数会被覆盖为已发布与有效期内)
- **响应**`ApiResponse<PagedResult<TenantAnnouncementDto>>`
- **错误码**401
### 2) 获取未读公告列表
- **方法**GET
- **路径**`/api/app/announcements/unread`
- **权限**:登录即可
- **查询参数**`page` / `pageSize`
- **响应**`ApiResponse<PagedResult<TenantAnnouncementDto>>`
- **错误码**401
### 3) 标记公告已读
- **方法**POST
- **路径**`/api/app/announcements/{announcementId}/mark-read`
- **权限**:登录即可
- **请求体**:无
- **响应**`ApiResponse<TenantAnnouncementDto>`
- **错误码**401 / 404
---
## 常见错误码
- **400**:参数验证失败
- **401**:未认证
- **403**:无权限
- **404**:公告不存在或不可见
- **409**:状态冲突(例如已发布不可编辑)
> 提示:实际错误码与消息由 `BusinessException` 和中间件统一返回。