fix(baseline): 修复管理基线文档一致性问题并补充安全/日志规范

Critical修复:
- CI配置MySQL→PostgreSQL对齐架构决策
- 错误码格式统一为分段格式(系统-模块-分类-序号)
- 覆盖率指标统一(Domain 90%/Application 80%/新增 90%)

Major修复:
- 分支策略统一为trunk-based,去掉develop分支
- muse-studio部署描述修正为Vite SPA静态部署
- muse-studio提交类型统一为英文前缀
- API路径统一为/app-api,端口对齐48080
- DROP COLUMN措辞修正为条件性禁止
- 增加规范优先级声明

新增文档:
- 05-安全开发规范.md(认证授权/输入校验/AI安全/审计)
- 06-日志与可观测性规范.md(日志级别/结构化/链路追踪/监控)
- muse-admin测试编写指南
This commit is contained in:
zizi 2026-05-24 11:36:22 +08:00
parent 63af750808
commit 7277b9c558
10 changed files with 298 additions and 30 deletions

View File

@ -5,6 +5,15 @@
- 适用范围:muse-cloud / muse-admin / muse-studio / muse-design-docs 四仓全局
- 目标读者:AI agent、人类开发者、架构师、项目管理者
## 规范优先级
当多份文档存在冲突时,按以下优先级执行:
1. 各仓库 CLAUDE.md(最具体的约束)
2. 全局总则和跨仓协作规范(通用规则)
3. dev-guide 开发指南(参考性指导)
如果发现冲突,应修正低优先级文档使其与高优先级对齐,而非忽略。
## 1. 开发模式定义
### 1.1 职责分工
@ -67,7 +76,7 @@
每个仓库遵循各自 CLAUDE.md 中定义的语言和框架规范:
- muse-cloud:Java / Spring Boot / MyBatis-Plus 规范
- muse-admin:Vue 3 / TypeScript / Vben Admin 规范
- muse-studio:React / TypeScript / Next.js 规范
- muse-studio:React / TypeScript / Vite SPA 规范
- muse-design-docs:Markdown 文档规范
### 3.2 跨仓一致性约定
@ -76,7 +85,7 @@
| 约定项 | 统一标准 | 说明 |
|---|---|---|
| 错误码格式 | `{模块编号}_{错误编号}`,6 位数字 | 模块编号见后端-02 |
| 错误码格式 | `{系统}-{模块}-{分类}-{序号}` | 系统:1=muse;模块:001=content, 002=ai, 003=knowledge, 004=market, 005=account, 006=meta;分类:000=通用, 001=参数校验, 002=业务规则, 003=权限, 004=外部依赖;序号:000-999。示例:1-001-002-001 表示 content 模块的业务规则错误第 1 号 |
| API 路径命名 | 小写 kebab-case | `/app-api/work/text-block` |
| 日期时间格式 | ISO 8601(`2026-05-24T10:30:00+08:00`) | 前后端传输统一 |
| 分页参数 | `pageNo`(从 1 开始)/ `pageSize`(默认 20,最大 100) | 请求参数 |

View File

@ -162,7 +162,7 @@ muse-admin / muse-studio 各自维护错误码到用户提示的映射
```
规则:
- 错误码格式:6 位数字,前 3 位模块编号,后 3 位错误编号
- 错误码格式:`{系统}-{模块}-{分类}-{序号}`(详见全局总则 3.2 节)
- 每个模块的错误码范围在 `后端-02` 中分配
- 前端可以合并展示(多个错误码映射到同一用户提示),但不能丢失错误码信息
@ -178,14 +178,14 @@ muse-admin / muse-studio 各自维护错误码到用户提示的映射
### 5.1 分支策略
各仓库统一使用以下分支模型:
各仓库统一采用 trunk-based 开发模式,不使用 develop 分支:
| 分支 | 用途 | 保护规则 |
|---|---|---|
| `main` | 生产就绪代码 | 禁止直接推送,只能通过 PR 合入 |
| `develop` | 开发集成分支 | PR 合入需通过 CI |
| `feature/{描述}` | 功能开发 | 从 develop 拉出,合回 develop |
| `hotfix/{描述}` | 生产紧急修复 | 从 main 拉出,合回 main + develop |
| `main` | 稳定基线,只接受 PR 合入 | 禁止直接推送,只能通过 PR 合入 |
| `feature/{描述}` | 功能开发 | 从 main 拉出,合入 main |
| `fix/{描述}` | 缺陷修复 | 从 main 拉出,合入 main |
| `release/v{版本号}` | 发布准备(可选) | 从 main 拉出,用于集成测试和修复 |
### 5.2 跨仓协调发布

View File

@ -64,11 +64,14 @@ jobs:
# 阶段 3:集成测试
needs: compile
services:
mysql:
image: mysql:8.0
postgres:
image: postgres:16-alpine
env:
MYSQL_ROOT_PASSWORD: test
MYSQL_DATABASE: muse_test
POSTGRES_DB: muse_test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
ports:
- 5432:5432
redis:
image: redis:7
steps:

View File

@ -142,7 +142,7 @@
|---|---|---|
| muse-cloud | 容器化部署(Docker + K8s/Docker Compose) | 支持滚动更新 |
| muse-admin | 静态资源部署(Nginx / CDN) | 构建产物直接部署 |
| muse-studio | 容器化部署(Next.js SSR)或静态导出 | 视 SSR 需求决定 |
| muse-studio | 静态资源部署(Nginx / CDN) | Vite 构建产物为纯静态 SPA |
### 4.2 部署顺序(跨仓协调发布时)
@ -168,7 +168,7 @@
|---|---|---|
| muse-cloud | `/actuator/health` | 数据库连接、Redis 连接、关键依赖 |
| muse-admin | `/health.html` 或 HTTP 200 | 静态资源可访问 |
| muse-studio | `/api/health` | SSR 渲染正常、API 可达 |
| muse-studio | `/health.html` 或 HTTP 200 | 静态资源可达性检查 |
### 4.4 灰度发布(推荐)

View File

@ -0,0 +1,66 @@
# 安全开发规范
## 1. 认证与授权
- 所有 API 必须经过认证(除明确标注的公开接口)
- 权限校验在 Application 层执行,不依赖前端隐藏
- 管理员操作和普通用户操作走不同 API 前缀(/admin-api vs /app-api)
- AI runtime 不能自授权(包级隔离 + ArchUnit 强制)
## 2. 输入校验
- 所有外部输入必须校验(请求参数、文件上传、WebSocket 消息)
- 使用框架提供的校验注解(@Valid、@NotNull 等),不手写正则
- 文件上传:校验类型、大小、内容(不只看扩展名)
- SQL 参数化查询,禁止字符串拼接
## 3. 数据保护
- 敏感字段(密码、token、密钥)不出现在日志、响应、错误信息中
- 数据库中密码使用 BCrypt 加密存储
- API 响应中脱敏:手机号中间 4 位、邮箱 @ 前部分、身份证中间段
- 用户数据隔离:查询必须带 tenant_id / user_id 条件
## 4. 密钥管理
- 禁止在代码中硬编码密钥、token、密码
- 开发环境使用 .env.local(已 gitignore)
- 生产环境使用环境变量或密钥管理服务
- API Key 定期轮换,支持多 key 并存过渡
## 5. AI 特有安全
- Prompt Injection 防护:用户输入与系统 prompt 严格分离
- AI 生成内容标记来源(source_version),不伪装为用户原创
- AI runtime 权限信封(Permission Envelope)由 grant 包签发,runtime 只读
- 保护节点(Protection Node)不可被 AI 替换或修改
## 6. 前端安全
- XSS 防护:使用框架自动转义,富文本使用白名单过滤
- CSRF:使用 token 机制
- 敏感操作(删除、发布、支付)需要二次确认
- 本地存储(IndexedDB/localStorage)不存储敏感信息
## 7. 审计日志
- 所有管理员操作必须记录审计日志
- 审计日志包含:who(操作人)、what(操作内容)、when(时间)、where(IP/设备)、result(结果)
- 审计日志不可修改、不可删除
- 敏感操作(权限变更、数据删除、配置发布)额外记录变更前后值
## 8. 依赖安全
- 使用固定版本号,不使用 ^ 或 ~ 范围
- 定期检查依赖漏洞(npm audit / mvn dependency-check)
- 新增依赖需评估:维护活跃度、已知漏洞、许可证兼容性
- 禁止引入来源不明或名称可疑的包
## 9. Agent 安全行为规则
- 不在代码中硬编码任何密钥或凭据
- 不跳过权限检查或认证中间件
- 不信任前端传来的权限声明
- 不在日志中输出敏感数据
- 发现安全漏洞时立即报告,不静默修复
- 不引入已知有安全漏洞的依赖版本

View File

@ -0,0 +1,100 @@
# 日志与可观测性规范
## 1. 日志级别标准
| 级别 | 使用场景 | 示例 |
|------|----------|------|
| ERROR | 需要人工介入的故障 | 数据库连接失败、外部服务不可达、数据不一致 |
| WARN | 异常但可自动恢复 | 重试成功、降级触发、接近阈值 |
| INFO | 关键业务事件 | 用户登录、作品创建、AI 生成完成、支付成功 |
| DEBUG | 开发调试信息 | 方法入参、中间状态、SQL 语句 |
规则:
- 生产环境默认 INFO 级别
- ERROR 必须包含异常堆栈和上下文
- 禁止在循环中打 INFO/WARN 日志
- DEBUG 日志使用条件判断或 SLF4J 占位符,避免字符串拼接开销
## 2. 结构化日志格式
后端使用 JSON 格式输出:
```json
{
"timestamp": "2024-01-01T12:00:00.000Z",
"level": "INFO",
"traceId": "abc123",
"spanId": "def456",
"service": "muse-cloud",
"module": "content",
"message": "作品创建成功",
"userId": 12345,
"workId": 67890,
"duration": 150
}
```
前端错误上报格式:
```json
{
"timestamp": "...",
"level": "ERROR",
"source": "muse-studio",
"page": "/works/123/editor",
"message": "Block 保存失败",
"error": "NetworkError: timeout",
"userId": 12345,
"context": { "blockId": "...", "revision": 5 }
}
```
## 3. 敏感信息脱敏
日志中禁止出现:
- 密码、token、密钥的明文
- 完整的身份证号、银行卡号
- 用户的完整手机号、邮箱
脱敏规则:
- 手机号:138****1234
- 邮箱:u***@example.com
- token:前 4 位 + ****
## 4. 链路追踪
- 使用 traceId 贯穿请求全链路(网关 → 服务 → 数据库 → 外部调用)
- 前端请求携带 X-Request-Id header
- 异步任务继承父任务的 traceId
- SSE 连接使用 connectionId 关联同一会话的所有事件
## 5. 前端错误监控
- 全局错误边界捕获未处理异常
- API 请求失败自动上报(排除 4xx 客户端错误中的 401/403)
- 编辑器崩溃单独上报(含 Block 状态快照)
- 性能指标上报:FCP、LCP、CLS
## 6. 后端监控指标
关键指标:
- API 响应时间(P50/P95/P99)
- 错误率(5xx / 总请求)
- AI 生成延迟(首 token 时间、总生成时间)
- 数据库连接池使用率
- 消息队列积压量
告警阈值建议:
- API P99 > 3s:WARN
- API P99 > 10s:ERROR
- 错误率 > 1%:WARN
- 错误率 > 5%:ERROR
- DB 连接池 > 80%:WARN
## 7. Agent 日志行为规则
- 关键业务操作必须打 INFO 日志(创建、修改、删除、状态变更)
- 外部调用(AI API、文件存储、消息队列)必须打日志(入参摘要 + 耗时 + 结果)
- 异常处理必须打 ERROR 日志(含堆栈和上下文)
- 不在日志中输出大段正文内容(截取前 100 字符)
- 不在日志中输出完整的 AI prompt(只记录 token 数和模型名)

View File

@ -0,0 +1,90 @@
# muse-admin 测试编写指南
## 1. 测试框架
- 单元测试:Vitest + Vue Test Utils
- 组件测试:@testing-library/vue(推荐)或 Vue Test Utils
- E2E 测试:Playwright(关键管理流程)
## 2. 测试文件组织
测试文件放在被测文件同目录:
```
src/views/muse/governance/
├── MetaSchemaList.vue
├── MetaSchemaList.test.ts
├── MetaSchemaForm.vue
└── MetaSchemaForm.test.ts
```
## 3. 组件测试模板
```typescript
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import MetaSchemaList from './MetaSchemaList.vue'
// Mock API
vi.mock('@/api/muse/governance', () => ({
getMetaSchemaPage: vi.fn().mockResolvedValue({
list: [{ id: 1, name: '角色属性', version: 'v3' }],
total: 1
})
}))
describe('MetaSchemaList 元结构列表', () => {
it('应该正确渲染列表数据', async () => {
const wrapper = mount(MetaSchemaList)
await flushPromises()
expect(wrapper.text()).toContain('角色属性')
})
it('应该在点击新增时打开表单弹窗', async () => {
const wrapper = mount(MetaSchemaList)
await wrapper.find('[data-test="btn-create"]').trigger('click')
expect(wrapper.find('[data-test="form-dialog"]').exists()).toBe(true)
})
})
```
## 4. Composable 测试模板
```typescript
import { describe, it, expect } from 'vitest'
import { useMetaSchemaVersion } from './useMetaSchemaVersion'
describe('useMetaSchemaVersion 版本兼容性检查', () => {
it('应该检测到不兼容的版本变更', () => {
const { isCompatible } = useMetaSchemaVersion()
const result = isCompatible('v2', 'v3', { removedFields: ['age'] })
expect(result).toBe(false)
})
})
```
## 5. API Mock 策略
使用 vi.mock 模拟 API 模块:
- 列表接口返回固定数据
- 创建/更新接口返回成功响应
- 错误场景单独测试(网络错误、权限不足、数据冲突)
## 6. 测试覆盖率
- 新增页面组件:行覆盖率 >= 70%
- 新增 composable/hook:分支覆盖率 >= 80%
- 关键业务逻辑(权限判断、状态转换):分支覆盖率 >= 90%
## 7. E2E 测试(关键流程)
只覆盖高风险管理流程:
- MetaSchema 发布流程(创建 → 编辑 → 发布 → 验证生效)
- 市场资产审核流程(提交 → 审核 → 上架/驳回)
- 权限配置流程(创建角色 → 分配权限 → 验证生效)
## 8. 测试命名规范
- 测试文件:{组件名}.test.ts
- describe:中文描述被测对象
- it:中文描述预期行为,格式"应该{预期行为}"

View File

@ -119,7 +119,7 @@ AI 模块包级隔离:
- 所有 DDL 变更必须通过 Flyway migration
- Migration 文件命名:`V{版本号}__{描述}.sql`(双下划线分隔)
- 每个 migration 文件头部注释说明变更目的和影响范围
- 禁止在 migration 中使用 `DROP COLUMN`(用 `ALTER COLUMN SET DEFAULT` + 应用层忽略)
- 默认禁止 `DROP COLUMN`。确需清理废弃列时,走全局发布规范场景 C 流程(需人类确认 + 观察期后执行)
- 索引命名:`idx_{表名}_{字段名}`
- 唯一约束命名:`uk_{表名}_{字段名}`
- 外键约束:不使用数据库外键,在应用层保证引用完整性
@ -174,10 +174,10 @@ AI 模块包级隔离:
### 覆盖率要求
- Domain 层:行覆盖率 >= 80%
- Application 层:分支覆盖率 >= 70%
- 新增代码:行覆盖率 >= 85%
- CI 中通过 JaCoCo 强制检查
遵循全局总则 4.4 节定义的覆盖率基线:
- Domain 层:行覆盖率 >= 90%
- Application 层:分支覆盖率 >= 80%
- 新增代码:行覆盖率 >= 90%
---

View File

@ -419,15 +419,15 @@ describe('SceneCard 场景卡片', () => {
### 提交信息格式
```
{类型}({模块}): {描述}
{类型}({模块}): {中文描述}
类型:功能 | 修复 | 重构 | 样式 | 测试 | 文档 | 构建 | 杂务
类型:feat | fix | refactor | style | test | docs | chore
模块:editor | agent | knowledge | market | account | common | api
示例:
功能(editor): 实现场景自动保存与 IndexedDB 缓存
修复(agent): 修复 SSE 断线后未自动重连的问题
测试(knowledge): 补充知识库上传组件单元测试
feat(editor): 实现场景自动保存与 IndexedDB 缓存
fix(agent): 修复 SSE 断线后未自动重连的问题
test(knowledge): 补充知识库上传组件单元测试
```
### 分支命名

View File

@ -54,10 +54,10 @@ cp .env.example .env.local
```bash
# API 基础地址(开发环境指向本地或测试服务器)
VITE_API_BASE_URL=http://localhost:8080/api/v1
VITE_API_BASE_URL=http://localhost:48080/app-api
# SSE 事件流地址
VITE_SSE_BASE_URL=http://localhost:8080/sse
VITE_SSE_BASE_URL=http://localhost:48080/sse
# 是否启用 MSW Mock(true 时拦截所有 API 请求)
VITE_ENABLE_MSW=true
@ -106,13 +106,13 @@ export default defineConfig({
port: 5173,
proxy: {
// API 请求代理到后端服务
'/api': {
target: 'http://localhost:8080',
'/app-api': {
target: 'http://localhost:48080',
changeOrigin: true,
},
// SSE 事件流代理(注意 WebSocket 升级)
'/sse': {
target: 'http://localhost:8080',
target: 'http://localhost:48080',
changeOrigin: true,
// SSE 需要禁用响应缓冲
configure: (proxy) => {
@ -124,7 +124,7 @@ export default defineConfig({
},
// 静态资源代理(开发环境)
'/uploads': {
target: 'http://localhost:8080',
target: 'http://localhost:48080',
changeOrigin: true,
},
},