docs: fix Phase 2 spec issues from review round 1

- CRITICAL: add Namespace entity field补齐 note (type, avatar_url, updatedAt)
- MAJOR: add CLI publish interface deviation note in key decisions
- MAJOR: define search behavior when q is empty + homepage list API
- MAJOR: add SkillRepository.incrementDownloadCount method
- MAJOR: add SecurityConfig update strategy note
- MAJOR: add Web publish interface deviation note
- MINOR: add missing Repository methods for namespace/member
- MINOR: add awaitTerminationSeconds to async thread pool
- MINOR: add starCount to search response
- MINOR: add namespace_slug to skill_search_document
- Clarify bundle.zip repacking strategy
- Add entity alignment verification to Chunk 1 acceptance criteria
This commit is contained in:
vsxd 2026-03-12 00:37:17 +08:00
parent 8b0ffc28c4
commit 46bda26f9e

View file

@ -13,6 +13,8 @@
| 架构模式 | 领域服务集中式(方案 A | 与 Phase 1 一致domain 模块包含领域服务 + 应用服务 |
| Chunk 策略 | 后端先行Chunk 1 后端Chunk 2 前端) | API 稳定后再做前端,减少联调返工 |
| 前端风格 | 现代产品风Vercel/Linear 风格) | 使用 frontend-design 技能优化设计质量 |
| CLI publish 接口 | Phase 2 去掉 `auto_submit` 参数,直接返回 PUBLISHED | 与 `05-business-flows.md` 有意偏差Phase 3 回补 `auto_submit` 并调整默认 status |
| Web publish 接口 | `POST /api/v1/skills/{namespace}/publish` | 与 CLI 分开路径但共用 service`06-api-design.md` 未定义此路径Phase 2 新增 |
## Tech Stack沿用 Phase 1 + 新增)
@ -115,6 +117,7 @@ Phase 1 已有表:`user_account`, `identity_binding`, `api_token`, `role`, `pe
| id | BIGSERIAL PK | |
| skill_id | BIGINT NOT NULL UNIQUE FK → skill | 一 skill 一条 |
| namespace_id | BIGINT NOT NULL | 用于空间过滤 |
| namespace_slug | VARCHAR(64) NOT NULL | 冗余,搜索结果直接返回无需 join |
| owner_id | BIGINT NOT NULL | 用于 PRIVATE 可见性判定 |
| title | VARCHAR(256) | |
| summary | VARCHAR(512) | |
@ -230,11 +233,14 @@ skillhub:
Phase 1 已创建 `Namespace``NamespaceMember` 实体及 JPA Repository。Phase 2 新增领域服务。
> **注意Phase 1 实体补齐** — 现有 `Namespace.java` 缺少 `type`NamespaceType 枚举GLOBAL/TEAM`avatar_url` 字段,`NamespaceMember.java` 缺少 `updatedAt` 字段,但 V1 数据库表已包含这些列。Phase 2 实现时需先补齐这些字段,确保 JPA 实体与数据库 schema 完全对齐。新增 `NamespaceType` 枚举。
#### NamespaceService`skillhub-domain`
```
createNamespace(slug, displayName, description, creatorUserId) → Namespace
- slug 格式校验 + 保留词校验 + 唯一性校验
- type 固定为 TEAM用户不可创建 GLOBAL 类型GLOBAL 由 Flyway 预置)
- 创建 namespace 记录
- 创建者自动成为 OWNER插入 namespace_member
@ -274,6 +280,8 @@ listMembers(namespaceId, page, size) → Page<NamespaceMember>
getMemberRole(namespaceId, userId) → Optional<NamespaceRole>
```
> **Repository 补充** — Phase 1 的 `NamespaceRepository` 需新增 `Page<Namespace> findByStatus(NamespaceStatus status, Pageable pageable)` 方法。`NamespaceMemberRepository` 需新增 `Page<NamespaceMember> findByNamespaceId(Long namespaceId, Pageable pageable)``void deleteByNamespaceIdAndUserId(Long namespaceId, Long userId)` 方法。
### 3.2 Slug 校验规则
```java
@ -309,6 +317,8 @@ public class SlugValidator {
权限判定复用 Phase 1 的 `RbacService`,新增 namespace 级别检查方法。
> **SecurityConfig 更新** — Phase 1 的 `SecurityConfig``.requestMatchers("/api/v1/skills/**", "/api/v1/namespaces/**").permitAll()` 放行了所有 skills/namespaces 路径。Phase 2 新增了需要认证的写操作publish、tag 管理等需要细化安全配置GET 请求 permitAllPOST/PUT/DELETE 请求 authenticated。具体做法按 HTTP method + path 组合配置,或在 Controller 层通过 `@PreAuthorize` 注解做权限校验(推荐后者,更灵活)。
---
## 4. 技能发布核心链路
@ -341,6 +351,7 @@ public interface SkillRepository {
Page<Skill> findByNamespaceIdAndStatus(Long namespaceId, SkillStatus status, Pageable pageable);
Skill save(Skill skill);
List<Skill> findByOwnerId(Long ownerId);
void incrementDownloadCount(Long skillId); // UPDATE skill SET download_count = download_count + 1 WHERE id = ?
}
public interface SkillVersionRepository {
@ -484,7 +495,8 @@ publishSkill(namespaceSlug, zipInputStream, publisherId, visibility) → SkillVe
⑧ 写入对象存储
- 逐文件上传到 skills/{skillId}/{versionId}/{filePath}
- 计算每个文件的 SHA-256
- 生成 bundle.zip 到 packages/{skillId}/{versionId}/bundle.zip
- 生成 bundle.zip在服务端内存中重新打包仅包含通过校验的文件而非直接使用用户上传的原始 zip
- bundle.zip 写入 packages/{skillId}/{versionId}/bundle.zip
⑨ 持久化
- 创建 skill_versionstatus=PUBLISHED
- 批量创建 skill_file 记录
@ -782,6 +794,13 @@ searchSkills(keyword, namespaceSlug, sortBy, page, size, currentUser) → Search
```
GET /api/v1/skills?q=keyword&namespace=slug&sort=relevance&page=0&size=20
q 参数为空时退化为列表查询(按 sort 字段排序,返回所有可见技能)。
首页精选/热门/最新列表复用搜索接口:
- 精选GET /api/v1/skills?sort=relevance&size=6无 q 参数,按综合排序)
- 热门下载GET /api/v1/skills?sort=downloads&size=6
- 最新发布GET /api/v1/skills?sort=newest&size=6
Response:
{
"code": 0,
@ -793,6 +812,7 @@ Response:
"displayName": "Code Review",
"summary": "...",
"downloadCount": 1234,
"starCount": 56,
"ratingAvg": 4.5,
"ratingCount": 10,
"latestVersion": "1.2.0",
@ -897,6 +917,8 @@ public class AsyncConfig {
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("event-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(25); // 配合 30s shutdown timeout 优雅停机
executor.initialize();
return executor;
}
@ -1261,7 +1283,8 @@ web/src/
**验收标准:**
1. `V2__phase2_skill_tables.sql` 迁移成功,所有新表和索引创建
2. 对象存储 LocalFile 实现可用S3 实现可用Docker Compose MinIO
2. Phase 1 实体补齐:`Namespace.java` 补 type/avatarUrl`NamespaceMember.java` 补 updatedAt新增 `NamespaceType` 枚举
3. 对象存储 LocalFile 实现可用S3 实现可用Docker Compose MinIO
3. 命名空间 CRUD + 成员管理 API 全部可用
4. CLI 发布接口:上传 zip → 校验 → 存储 → PUBLISHED返回版本信息
5. 技能详情、版本列表、文件清单、文件内容 API 可用