For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 实现"只填结果"的五维手动填分功能(0-100 分,家长可给家庭成员填),以及 MBTI 完整体系(标准版 ~30题测评 + 16型人格百科 + 五维联动解读)。
Architecture: 后端新增两组 Controller/Service/Mapper/Entity;前端新增 5 个页面 + 1 个管理端页面;数据库 3 张新表(mbti_questions, mbti_results, mbti_profiles)通过 DatabaseInitializer 迁移;种子数据脚本初始化题库与 16 型画像。
Tech Stack: Java 8 + Spring Boot 2.7.18 + MyBatis-Plus / uni-app Vue 2 (微信小程序) / Vue 2 + Element UI (Web 管理端) / MySQL 8.0
Spec: 本计划基于前期 brainstorming 确认的设计,包含 Part 1(手动填分)与 Part 2(MBTI 体系)两大模块。
@PostMapping,禁止 @GetMapping/@PutMapping/@DeleteMappingResult<T> (code/message/data)JwtInterceptor 拦截 /api/**@Resource,字段名必须与 Bean Name 一致@TableName + @TableId(type = IdType.AUTO)?.、CSS Grid、:key 表达式、new Date(string)(用 parseDate())DatabaseInitializer.runMigrations(),使用 ensureColumn / try-catch 幂等schema.sql 对应 CREATE TABLEdocs/superpowers/api/API_REFERENCE.md 确认无重复mvn clean compile 唯一验证方式| 文件 | 类型 | 说明 |
|---|---|---|
entity/MbtiQuestion.java |
新增 | MBTI 题库实体 |
entity/MbtiResult.java |
新增 | 用户 MBTI 测评结果实体 |
entity/MbtiProfile.java |
新增 | 16型人格画像库实体 |
mapper/MbtiQuestionMapper.java |
新增 | 题库 Mapper |
mapper/MbtiResultMapper.java |
新增 | 结果 Mapper |
mapper/MbtiProfileMapper.java |
新增 | 画像 Mapper |
service/MbtiService.java |
新增 | MBTI 业务接口 |
service/impl/MbtiServiceImpl.java |
新增 | MBTI 业务实现 |
controller/family/MbtiController.java |
新增 | /api/family/mbti 接口 |
controller/family/ManualDimensionScoreController.java |
新增 | /api/family/manual-score 接口 |
service/ManualDimensionScoreService.java |
新增 | 手动填分业务接口 |
service/impl/ManualDimensionScoreServiceImpl.java |
新增 | 手动填分业务实现 |
dto/MbtiQuestionVO.java |
新增 | 题目 VO |
dto/MbtiResultVO.java |
新增 | 结果 VO |
dto/MbtiProfileVO.java |
新增 | 画像 VO |
dto/ManualScoreSubmitDTO.java |
新增 | 手动提交 DTO |
dto/ManualScoreVO.java |
新增 | 手动填分 VO |
config/DatabaseInitializer.java |
修改 | 添加 3 表迁移 |
| 文件 | 类型 | 说明 |
|---|---|---|
pages/family/manual-score-entry.vue |
新增 | 手动填分录入页 |
pages/family/mbti-entry.vue |
新增 | MBTI 入口页(选成员) |
pages/family/mbti-test.vue |
新增 | MBTI 答题页 |
pages/family/mbti-result.vue |
新增 | MBTI 结果页 |
pages/family/mbti-profile.vue |
新增 | MBTI 16型百科页 |
pages/family/self-check-entry.vue |
修改 | 增加"直接填分"按钮 + MBTI 卡片入口 |
utils/api.js |
修改 | 新增 10+ API 封装 |
pages.json |
修改 | 注册 5 个新页面 |
| 文件 | 类型 | 说明 |
|---|---|---|
src/views/admin/MbtiProfiles.vue |
新增 | 16 型配置管理页 |
src/api/mbti.js |
新增 | 管理端 MBTI API |
src/router/index.js |
修改 | 新增路由 |
Files:
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java (搜索 // 迁移 找到最新编号)cfc-backend/src/main/resources/schema.sql (追加 3 表 CREATE TABLE)Interfaces:
Produces: 3 张表结构在数据库中可用
- [ ] **Step 1: 在 DatabaseInitializer.runMigrations() 末尾添加 3 个迁移块**
java
// 迁移XXX: 创建 mbti_questions 表 try {
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS mbti_questions (" +
"id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
"dimension CHAR(1) NOT NULL COMMENT 'E/I/S/N/T/F/J/P', " +
"question_text TEXT NOT NULL COMMENT '题目文本', " +
"option_a TEXT NOT NULL COMMENT '选项 A(正向)', " +
"option_b TEXT NOT NULL COMMENT '选项 B(反向)', " +
"weight DECIMAL(3,2) DEFAULT 1.0 COMMENT '权重', " +
"sort_order INT DEFAULT 0, " +
"is_active TINYINT DEFAULT 1, " +
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
"INDEX idx_dim_active (dimension, is_active)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MBTI 测评题库'");
log.info("已创建 mbti_questions 表");
} catch (Exception e) { /* 忽略 */ }
// 迁移XXX+1: 创建 mbti_results 表 try {
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS mbti_results (" +
"id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
"user_id BIGINT NOT NULL COMMENT '答题人用户ID', " +
"family_member_id BIGINT COMMENT '关联家庭成员ID', " +
"answers_json TEXT COMMENT '用户答案JSON', " +
"type_code CHAR(4) NOT NULL COMMENT 'MBTI 类型', " +
"ei_score INT COMMENT 'E/I 原始分', " +
"sn_score INT COMMENT 'S/N 原始分', " +
"tf_score INT COMMENT 'T/F 原始分', " +
"jp_score INT COMMENT 'J/P 原始分', " +
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
"INDEX idx_user (user_id), " +
"INDEX idx_member (family_member_id)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MBTI 测评结果'");
log.info("已创建 mbti_results 表");
} catch (Exception e) { /* 忽略 */ }
// 迁移XXX+2: 创建 mbti_profiles 表 try {
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS mbti_profiles (" +
"id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
"type_code CHAR(4) NOT NULL UNIQUE COMMENT '类型代码', " +
"name VARCHAR(50) COMMENT '中文名称', " +
"description TEXT COMMENT '核心特质描述', " +
"strengths TEXT COMMENT '优势', " +
"weaknesses TEXT COMMENT '挑战', " +
"career_tendency TEXT COMMENT '职业倾向', " +
"family_style TEXT COMMENT '家庭/育儿风格', " +
"pairing_notes TEXT COMMENT '伴侣/孩子类型搭配建议', " +
"energy_suggestion JSON COMMENT '五维能量联动建议', " +
"is_active TINYINT DEFAULT 1, " +
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
"updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MBTI 人格画像库'");
log.info("已创建 mbti_profiles 表");
} catch (Exception e) { /* 忽略 */ }
- [ ] **Step 2: 同步追加到 schema.sql 末尾**
sql -- 与上面 3 个 CREATE TABLE IF NOT EXISTS 完全一致
- [ ] **Step 3: 编译验证**
bash cd cfc-backend && mvn clean compile
#### Task 0.2: MBTI 种子数据 SQL 脚本
**Files:**
- Create: `cfc-backend/src/main/resources/migration_mbti_seed_data.sql`
**Interfaces:**
- Produces: 30 题题库 + 16 型基础画像数据
markdown
mbti_profiles: 16 条记录(INTJ/INTP/ENTJ/ENTP/INFJ/INFP/ENFJ/ENFP/ISTJ/ISFJ/ESTJ/ESFJ/ISTP/ISFP/ESTP/ESFP),每条含 name/description/strengths/weaknesses/career_tendency/family_style/pairing_notes/energy_suggestion(JSON)
[ ] Step 2: 在 DatabaseInitializer 执行种子数据
// 迁移XXX+3: MBTI 种子数据初始化
try {
String seedSql = FileUtils.readFileToString(new File("src/main/resources/migration_mbti_seed_data.sql"), "UTF-8");
for (String stmt : seedSql.split(";")) {
String trimmed = stmt.trim();
if (!trimmed.isEmpty()) {
jdbcTemplate.execute(trimmed);
}
}
log.info("MBTI 种子数据初始化完成");
} catch (Exception e) {
log.warn("MBTI 种子数据初始化失败(可能已存在): {}", e.getMessage());
}
[ ] Step 3: 编译验证
cd cfc-backend && mvn clean compile
Files:
entity/ManualDimensionScore.java (可复用 FiveDimensionScore,仅 source_type='manual' 区分,无需新表)dto/ManualScoreSubmitDTO.javaCreate: dto/ManualScoreVO.java
- [ ] **Step 1: ManualScoreSubmitDTO**
java
package com.etotem.cfc.dto; import lombok.Data; import java.math.BigDecimal; import java.util.Map;
@Data public class ManualScoreSubmitDTO {
private Long memberId; // 必填
private Map<String, Integer> scores; // 必填: {"body":80,"mind":60,"wisdom":70,"action":50,"wealth":90}
private String note; // 可选备注
}
- [ ] **Step 2: ManualScoreVO (返回前端)**
java package com.etotem.cfc.dto; import lombok.Data; import java.util.Date; import java.util.List;
@Data public class ManualScoreVO {
private Long id; // five_dimension_scores.id
private Long memberId;
private String memberName;
private Map<String, Integer> scores; // 5维度分数
private Integer totalScore; // 5维总和
private Date createdAt;
}
- [ ] **Step 3: 编译验证**
#### Task 1.2: ManualDimensionScoreService 接口与实现
**Files:**
- Create: `service/ManualDimensionScoreService.java`
- Create: `service/impl/ManualDimensionScoreServiceImpl.java`
markdown
[ ] Step 1: 接口定义
package com.etotem.cfc.service;
import com.etotem.cfc.dto.ManualScoreSubmitDTO;
import com.etotem.cfc.dto.ManualScoreVO;
import java.util.List;
public interface ManualDimensionScoreService {
ManualScoreVO submit(ManualScoreSubmitDTO dto, Long userId);
ManualScoreVO getLatest(Long userId, Long memberId);
List<ManualScoreVO> getHistory(Long userId, Long memberId, int limit);
}
[ ] Step 2: 实现类
@Service
public class ManualDimensionScoreServiceImpl implements ManualDimensionScoreService {
@Resource private FiveDimensionScoreMapper fiveDimensionScoreMapper;
@Resource private FiveDimensionSelfCheckMapper selfCheckMapper;
@Resource private FamilyMemberMapper familyMemberMapper;
@Resource private UserMapper userMapper;
@Resource private FiveDimensionScoreService fiveDimensionScoreService;
private final ObjectMapper objectMapper = new ObjectMapper();
@Transactional(rollbackFor = Exception.class)
public ManualScoreVO submit(ManualScoreSubmitDTO dto, Long userId) {
// 1. 校验 memberId 存在且属于当前用户家庭
// 2. 校验 5 维度键全为 body/mind/wisdom/action/wealth,值 0-100,至少一项>0
// 3. 写入 five_dimension_scores (source_type='manual', source_id=自增ID)
// 4. 写入 five_dimension_self_checks (scores_json 存 0-100 映射,totalScore=5维总和,questionIdsJson=[])
// 5. 返回 VO
}
public ManualScoreVO getLatest(Long userId, Long memberId) {
// 查 five_dimension_scores 最近一条 source_type='manual'
}
public List<ManualScoreVO> getHistory(Long userId, Long memberId, int limit) {
// 查历史
}
}
[ ] Step 3: 编译验证
Files:
Create: controller/family/ManualDimensionScoreController.java
- [ ] **Step 1: Controller 实现**
java
@Tag(name = "五维手动填分", description = "直接填写 0-100 分,跳过问卷") @RestController @RequestMapping("/api/family/manual-score") public class ManualDimensionScoreController {
@Resource private ManualDimensionScoreService manualScoreService;
@PostMapping("/submit")
public Result<ManualScoreVO> submit(@RequestBody ManualScoreSubmitDTO dto, @RequestAttribute("userId") Long userId) {
// 校验 userId, 调用 service, 返回 Result
}
@PostMapping("/latest")
public Result<ManualScoreVO> latest(@RequestBody(required=false) Map<String,Object> body, @RequestAttribute("userId") Long userId) {
Long memberId = ParamUtils.getLong(body?.get("memberId"));
// 调用 service
}
@PostMapping("/history")
public Result<List<ManualScoreVO>> history(@RequestBody(required=false) Map<String,Object> body, @RequestAttribute("userId") Long userId) {
Long memberId = ParamUtils.getLong(body?.get("memberId"));
Integer limit = body?.get("limit") != null ? Integer.valueOf(body.get("limit").toString()) : 20;
// 调用 service
}
}
- [ ] **Step 2: 编译验证**
---
### Phase 2: 后端 MBTI 模块
#### Task 2.1: MBTI 实体、Mapper
**Files:**
- Create: `entity/MbtiQuestion.java`
- Create: `entity/MbtiResult.java`
- Create: `entity/MbtiProfile.java`
- Create: `mapper/MbtiQuestionMapper.java`
- Create: `mapper/MbtiResultMapper.java`
- Create: `mapper/MbtiProfileMapper.java`
markdown
[ ] Step 1: MbtiQuestion 实体
@Data @TableName("mbti_questions")
public class MbtiQuestion implements Serializable {
@TableId(type=IdType.AUTO) private Long id;
private String dimension; // E/I/S/N/T/F/J/P
private String questionText;
private String optionA;
private String optionB;
private BigDecimal weight;
private Integer sortOrder;
private Integer isActive;
private Date createdAt;
}
[ ] Step 2: MbtiResult 实体
@Data @TableName("mbti_results")
public class MbtiResult implements Serializable {
@TableId(type=IdType.AUTO) private Long id;
private Long userId;
private Long familyMemberId;
private String answersJson;
private String typeCode; // INTJ 等
private Integer eiScore;
private Integer snScore;
private Integer tfScore;
private Integer jpScore;
private Date createdAt;
}
[ ] Step 3: MbtiProfile 实体
@Data @TableName("mbti_profiles")
public class MbtiProfile implements Serializable {
@TableId(type=IdType.AUTO) private Long id;
private String typeCode; // INTJ 等,唯一
private String name; // 架构师
private String description;
private String strengths;
private String weaknesses;
private String careerTendency;
private String familyStyle;
private String pairingNotes;
private String energySuggestion; // JSON 字符串
private Integer isActive;
private Date createdAt;
private Date updatedAt;
}
[ ] Step 4: 3 个 Mapper 接口 (extends BaseMapper)
[ ] Step 5: 编译验证
Files:
dto/MbtiQuestionVO.javadto/MbtiResultVO.javadto/MbtiProfileVO.javaCreate: dto/SubmitMbtiDTO.java
- [ ] **Step 1: MbtiQuestionVO** (题目含选项 A/B)
java
@Data public class MbtiQuestionVO {
private Long id;
private String dimension; // E/I/S/N/T/F/J/P
private String questionText;
private OptionVO optionA;
private OptionVO optionB;
@Data static class OptionVO { String value; String label; }
}
- [ ] **Step 2: SubmitMbtiDTO**
java @Data public class SubmitMbtiDTO {
private Long familyMemberId;
private List<AnswerItem> answers;
@Data static class AnswerItem { Long questionId; String answer; } // answer: "A" 或 "B"
}
- [ ] **Step 3: MbtiResultVO** (结果含 4 维度分 + 类型代码)
java @Data public class MbtiResultVO {
private Long id;
private String typeCode;
private String typeName; // 中文名
private Integer eiScore;
private Integer snScore;
private Integer tfScore;
private Integer jpScore;
private String eiType; // "E" 或 "I"
private String snType; // "S" 或 "N"
private String tfType; // "T" 或 "F"
private String jpType; // "J" 或 "P"
private MbtiProfileVO profile; // 画像详情
private Date createdAt;
}
- [ ] **Step 4: MbtiProfileVO** (画像详情)
java @Data public class MbtiProfileVO {
private String typeCode;
private String name;
private String description;
private String strengths;
private String weaknesses;
private String careerTendency;
private String familyStyle;
private String pairingNotes;
private Map<String, String> energySuggestion; // 5维度建议
}
- [ ] **Step 5: 编译验证**
#### Task 2.3: MbtiService 接口与实现
**Files:**
- Create: `service/MbtiService.java`
- Create: `service/impl/MbtiServiceImpl.java`
markdown
[ ] Step 1: 接口
public interface MbtiService {
List<MbtiQuestionVO> getQuestions();
MbtiResultVO submit(SubmitMbtiDTO dto, Long userId);
MbtiResultVO getLatest(Long userId, Long memberId);
MbtiProfileVO getProfile(String typeCode);
List<MbtiResultVO> getHistory(Long userId, Long memberId, int limit);
}
[ ] Step 2: 实现核心计算逻辑
@Service
public class MbtiServiceImpl implements MbtiService {
@Resource private MbtiQuestionMapper questionMapper;
@Resource private MbtiResultMapper resultMapper;
@Resource private MbtiProfileMapper profileMapper;
@Resource private FamilyMemberMapper familyMemberMapper;
private final ObjectMapper objectMapper = new ObjectMapper();
public List<MbtiQuestionVO> getQuestions() {
// 查 is_active=1,按 dimension+sort_order 排序,转 VO
}
@Transactional(rollbackFor = Exception.class)
public MbtiResultVO submit(SubmitMbtiDTO dto, Long userId) {
// 1. 校验 memberId
// 2. 加载题库 Map<id, MbtiQuestion>
// 3. 遍历 answers,累加 4 维度分:
// dimension='E' -> eiScore += (answer=="A"? weight : -weight)
// dimension='I' -> eiScore -= (answer=="A"? weight : -weight) // 反向
// S/N、T/F、J/P 同理
// 4. 判定 4 字母:eiScore>0?"E":"I" 等
// 5. typeCode = ei+sn+tf+jp
// 6. 查 profileMapper.selectByTypeCode(typeCode)
// 7. 写入 mbti_results
// 8. 组装 VO 返回
}
// getLatest, getProfile, getHistory 均为简单查询
}
[ ] Step 3: 编译验证
Files:
Create: controller/family/MbtiController.java
- [ ] **Step 1: Controller 实现**
java
@Tag(name = "MBTI 人格测评", description = "标准版 ~30题 + 16型画像 + 五维联动") @RestController @RequestMapping("/api/family/mbti") public class MbtiController {
@Resource private MbtiService mbtiService;
@PostMapping("/questions")
public Result<List<MbtiQuestionVO>> questions(@RequestAttribute("userId") Long userId) {
return Result.success(mbtiService.getQuestions());
}
@PostMapping("/submit")
public Result<MbtiResultVO> submit(@RequestBody SubmitMbtiDTO dto, @RequestAttribute("userId") Long userId) {
return Result.success(mbtiService.submit(dto, userId));
}
@PostMapping("/latest")
public Result<MbtiResultVO> latest(@RequestBody(required=false) Map<String,Object> body, @RequestAttribute("userId") Long userId) {
Long memberId = ParamUtils.getLong(body?.get("memberId"));
return Result.success(mbtiService.getLatest(userId, memberId));
}
@PostMapping("/profile/{typeCode}")
public Result<MbtiProfileVO> profile(@PathVariable String typeCode, @RequestAttribute("userId") Long userId) {
return Result.success(mbtiService.getProfile(typeCode.toUpperCase()));
}
@PostMapping("/history")
public Result<List<MbtiResultVO>> history(@RequestBody(required=false) Map<String,Object> body, @RequestAttribute("userId") Long userId) {
Long memberId = ParamUtils.getLong(body?.get("memberId"));
Integer limit = body?.get("limit") != null ? Integer.valueOf(body.get("limit").toString()) : 20;
return Result.success(mbtiService.getHistory(userId, memberId, limit));
}
}
- [ ] **Step 2: 编译验证**
---
### Phase 3: 前端手动填分页面
#### Task 3.1: manual-score-entry.vue
**Files:**
- Create: `cfc-frontend/pages/family/manual-score-entry.vue`
markdown
底部:提交按钮(主色调渐变),提交后跳转 self-check-result.vue (复用结果页,传参 source=manual)
[ ] Step 2: 逻辑
onLoad 调用 getFamilyMemberList({visibleOnly:true}) 获取成员列表
默认选中当前用户自己
scores 对象响应式绑定 5 维度
提交调用 submitManualScore({memberId, scores}) → 跳转结果页
[ ] Step 3: 样式遵循现有设计 Token (--color-primary, --bg, --shadow-clay 等)
Files:
Modify: cfc-frontend/pages/family/self-check-entry.vue
- [ ] **Step 1: 底部按钮区域增加两个按钮**
html
再次自检 忽略本次 开始自检
直接填分
MBTI 人格测试
- [ ] **Step 2: methods 新增跳转**
javascript goManualScore() { uni.navigateTo({ url: '/pages/family/manual-score-entry' }) }, goMbti() { uni.navigateTo({ url: '/pages/family/mbti-entry' }) }
---
### Phase 4: 前端 MBTI 页面 (4 个页面)
#### Task 4.1: mbti-entry.vue (入口选成员)
**Files:**
- Create: `cfc-frontend/pages/family/mbti-entry.vue`
markdown
"开始测评" 按钮 → navigateTo mbti-test.vue?memberId=xxx
#### Task 4.2: mbti-test.vue (答题页)
**Files:**
- Create: `cfc-frontend/pages/family/mbti-test.vue`
markdown
[ ] 单题卡片模式 (类似 self-check.vue)
进度条:当前题号 / 总题数
题目文本 + 两个选项按钮 (A/B),左右分布
选中高亮,可点击切换
底部:上一题 / 下一题 (最后一题显示"提交")
答案暂存本地数组 answers[]
提交调用 submitMbti({familyMemberId, answers}) → navigateTo mbti-result.vue?id=xxx
#### Task 4.3: mbti-result.vue (结果页)
**Files:**
- Create: `cfc-frontend/pages/family/mbti-result.vue`
markdown
[ ] 大字展示类型代码 (如 INTJ) + 中文名 (架构师) + 动画入场
4 维度雷达图 (Canvas 2D,复用 self-check-result 雷达逻辑,4 轴 E/I S/N T/F J/P)
画像卡片:核心特质 / 优势 / 挑战 / 职业倾向 / 家庭风格 / 搭配建议
五维能量联动建议卡片 (从 profile.energySuggestion 读取,展示 5 个维度建议)
底部按钮:查看百科、分享、重新测评
#### Task 4.4: mbti-profile.vue (16 型百科)
**Files:**
- Create: `cfc-frontend/pages/family/mbti-profile.vue`
markdown
[ ] 4x4 网格卡片 (16 种类型),每卡片显示类型代码 + 中文名 + 1 行标签
点击卡片 → 调用 getMbtiProfile(typeCode) → 弹窗或新页展示完整画像
顶部搜索/筛选:按 E/I、S/N、T/F、J/P 筛选
---
### Phase 5: 管理端 MBTI 配置
#### Task 5.1: 管理端 API 与页面
**Files:**
- Create: `cfc-web/src/api/mbti.js`
- Create: `cfc-web/src/views/admin/MbtiProfiles.vue`
- Modify: `cfc-web/src/router/index.js`
markdown
[ ] Step 1: API 封装 (mbti.js)
export function getMbtiProfileList() { return request('/api/admin/mbti/profile/list', 'POST') }
export function saveMbtiProfile(data) { return request('/api/admin/mbti/profile/save', 'POST', data) }
export function deleteMbtiProfile(id) { return request('/api/admin/mbti/profile/delete', 'POST', {id}) }
export function initMbtiSeedData() { return request('/api/admin/mbti/seed/init', 'POST') }
[ ] Step 2: MbtiProfiles.vue (Element UI Table + Dialog 编辑)
列表展示 16 行:type_code, name, is_active, 操作(编辑/删除)
编辑弹窗:所有字段可编辑,energy_suggestion 用 JSON 编辑器 (textarea + 格式化)
"初始化种子数据"按钮调用 initMbtiSeedData()
[ ] Step 3: 路由注册 (admin 子路由)
#### Task 5.2: 管理端 Controller (可选,若需后端增删改)
**Files:**
- Create: `controller/admin/MbtiProfileController.java` (若管理端走后端 CRUD)
- 或直接在 MbtiService 暴露 admin 方法,MbtiController 复用
markdown
[ ] 视情况新增或复用,编译验证
---
### Phase 6: API 文档同步与验收
#### Task 6.1: 更新 API_REFERENCE.md
**Files:**
- Modify: `docs/superpowers/api/API_REFERENCE.md`
markdown
[ ] 在 Controller 总览表新增: | ManualDimensionScoreController | /api/family/manual-score | 五维手动填分 | — | | MbtiController | /api/family/mbti | MBTI 人格测评 | — | | MbtiProfileController | /api/admin/mbti/profile | MBTI 画像管理(管理端) | — |
[ ] 详细记录每个接口的请求/响应示例
#### Task 6.2: 全量编译 + 功能自测
markdown
[ ] cd cfc-backend && mvn clean compile
[ ] 启动后端,用 Postman/curl 测试 8 个新接口
[ ] 微信开发者工具预览 5 个新页面流程
[ ] 管理端 npm run serve 验证 MBTI 配置页 ```
mvn clean compile 通过,无 Lint 报错推荐 Subagent-Driven 并行执行 (7 个独立子任务可并行):
| 并行组 | 任务 | 预计耗时 |
|---|---|---|
| A | Task 0.1+0.2 (DB迁移+种子) | 30 min |
| B | Task 1.1-1.3 (手动填分后端) | 45 min |
| C | Task 2.1-2.4 (MBTI 后端) | 60 min |
| D | Task 3.1-3.2 (前端手动填分) | 45 min |
| E | Task 4.1-4.4 (前端 MBTI 4页) | 90 min |
| F | Task 5.1-5.2 (管理端) | 45 min |
| G | Task 6.1-6.2 (文档+验收) | 30 min |
两阶段 Review: 每组完成后暂停,人工确认无冲突再合并。
Plan complete and saved to docs/superpowers/plans/2026-09-10-manual-dimension-mbti-plan.md. Two execution options:
1. Subagent-Driven (recommended) - I dispatch a fresh subagent per task group, review between groups, fast iteration
2. Inline Execution - Execute tasks in this session using executing-plans, batch execution with checkpoints
Which approach?