# PEVC Local Account Initialization Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 按 PEVC 的模式内置学生 `tzs001`,本地只保存其 BCrypt 密码哈希;SSO 只投影身份和角色,不再读取主平台密码。 **Architecture:** Flyway 迁移一次性插入用户 ID `487`、学生快照和 `STUDENT` 角色关联,密码列仅存 BCrypt 哈希。平台 SSO/CAS 继续验证并投影身份;新投影用户使用随机 BCrypt 密码,和 PEVC 的 SSO 自动建号保持一致。移除当前分支中为镜像主平台密码新增的凭据查询与初始化器。 **Tech Stack:** Java 17, Spring Boot, Spring Security `PasswordEncoder`, Flyway, MyBatis-Plus, JUnit 5. ## Global Constraints - 不修改 `E:\javawork\tianze-pro` 主平台工程。 - 不读取、记录、返回或提交主平台密码明文。 - 仅保留 `TEACHER`、`STUDENT` 两个角色,用户/角色无 CRUD 接口。 - `tzs001` 固定使用平台用户 ID `487` 和 `STUDENT` 角色。 --- ### Task 1: 移除密码镜像防腐接口 **Files:** - Delete: `src/main/java/com/yau/digitalrmb/platformintegration/application/PlatformCredentialRepository.java` - Delete: `src/main/java/com/yau/digitalrmb/platformintegration/domain/PlatformCredential.java` - Delete: `src/main/java/com/yau/digitalrmb/identity/application/PlatformCredentialInitializer.java` - Modify: `src/main/java/com/yau/digitalrmb/platformintegration/infrastructure/JdbcPlatformIdentityRepository.java` - Modify: `src/main/java/com/yau/digitalrmb/identity/application/PlatformIdentityProjectionService.java` - Modify: `src/main/java/com/yau/digitalrmb/platformintegration/interfaces/PlatformSsoController.java` - Modify: `src/main/java/com/yau/digitalrmb/platformintegration/interfaces/CasAuthenticationController.java` - Test: `src/test/java/com/yau/digitalrmb/identity/PlatformIdentityProjectionServiceTest.java` **Interfaces:** - Consumes: `PlatformIdentityProjectionService.project(PlatformActor)`. - Produces: 所有 SSO/CAS 流程仅投影 `PlatformActor`,不包含密码对象或主平台密码查询。 - [ ] **Step 1: 写出失败测试,证明新投影用户拥有 BCrypt 格式的随机密码** ```java projectionService.project(actor); UserEntity user = userMapper.selectById(actor.platformUserId()); assertThat(user.getPasswordHash()).startsWith("$2"); assertThat(passwordEncoder.matches("unknown", user.getPasswordHash())).isFalse(); ``` - [ ] **Step 2: 运行测试确认失败** Run: `mvn -Dtest=PlatformIdentityProjectionServiceTest test -DforkCount=0 -B` Expected: 旧实现写入 `{noop}EXTERNAL_SSO_ONLY`,断言失败。 - [ ] **Step 3: 最小化实现** ```java private void projectUser(PlatformActor actor) { UserEntity user = userMapper.selectById(actor.platformUserId()); if (user == null) { user = new UserEntity(); user.setId(actor.platformUserId()); user.setUsername(actor.account()); user.setPasswordHash(passwordEncoder.encode(UUID.randomUUID().toString())); user.setEnabled(true); userMapper.insert(user); return; } user.setUsername(actor.account()); user.setEnabled(true); userMapper.updateById(user); } ``` 删除凭据类型、仓储、初始化器和所有 `findCredential` 调用;`JdbcPlatformIdentityRepository` 仅保留身份查询。 - [ ] **Step 4: 运行针对性测试** Run: `mvn -Dtest=PlatformIdentityProjectionServiceTest,PlatformSsoControllerTest test -DforkCount=0 -B` Expected: PASS. - [ ] **Step 5: 提交** ```powershell git add src/main/java src/test/java git commit -m "refactor: align sso with pevc local accounts" ``` ### Task 2: 以 Flyway 内置 tzs001 学生账号 **Files:** - Create: `src/main/resources/db/migration/V3__seed_tzs001_local_student.sql` - Test: `src/test/java/com/yau/digitalrmb/security/AuthControllerTest.java` **Interfaces:** - Consumes: `sys_user(id, username, password_hash)`, `platform_user_snapshot`, `sys_user_role` 和现有角色 ID `1002`。 - Produces: 迁移后本地 `POST /api/v1/auth/login` 能用 `tzs001` 和指定初始密码签发 JWT;`GET /api/v1/auth/me` 返回 `STUDENT`。 - [ ] **Step 1: 写出失败集成测试** ```java mvc.perform(post("/api/v1/auth/login") .contentType(MediaType.APPLICATION_JSON) .content("{\"username\":\"tzs001\",\"password\":\"123qwe\"}")) .andExpect(status().isOk()) .andExpect(jsonPath("$.data.accessToken").isNotEmpty()); ``` 移除测试 `@BeforeEach` 中的凭据投影,使测试只依赖迁移。 - [ ] **Step 2: 运行测试确认失败** Run: `mvn -Dtest=AuthControllerTest test -DforkCount=0 -B` Expected: 登录返回 401,因为 V3 迁移尚不存在。 - [ ] **Step 3: 添加仅含 BCrypt 哈希的迁移** ```sql INSERT INTO sys_user (id, username, password_hash, enabled, created_at, updated_at, created_by, updated_by, deleted) VALUES (487, 'tzs001', '$2a$10$ufcw5KFHtOmLzxAsV4C.MuIDOErMlw0iw5J5hc8OMzaTx0u9QYxG6', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'SYSTEM', 'SYSTEM', FALSE); INSERT INTO platform_user_snapshot (platform_user_id, account, display_name, role_key, source_updated_at, synced_at) VALUES (487, 'tzs001', 'tzs001', 'STUDENT', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); INSERT INTO sys_user_role (user_id, role_id) VALUES (487, 1002); ``` 最终 SQL 和日志均不得包含明文密码。 - [ ] **Step 4: 运行集成测试** Run: `mvn -Dtest=AuthControllerTest test -DforkCount=0 -B` Expected: PASS,且 `/me` 角色为 `STUDENT`。 - [ ] **Step 5: 提交** ```powershell git add src/main/resources/db/migration/V3__seed_tzs001_local_student.sql src/test/java/com/yau/digitalrmb/security/AuthControllerTest.java git commit -m "feat: seed tzs001 local student account" ``` ### Task 3: 清理配置、文档与回归验证 **Files:** - Modify: `src/main/java/com/yau/digitalrmb/platformintegration/config/PlatformIntegrationProperties.java` - Modify: `README.md` - Modify: `docs/superpowers/specs/2026-08-03-platform-sso-readonly-design.md` - Delete: `src/test/java/com/yau/digitalrmb/identity/PlatformCredentialInitializerTest.java` - Modify: `src/test/java/com/yau/digitalrmb/platformintegration/infrastructure/JdbcPlatformIdentityRepositoryTest.java` **Interfaces:** - Consumes: PEVC 对 SSO 与迁移账号的职责分离。 - Produces: 无 `local-login`、`PlatformCredential` 或主平台密码查询的可部署后端。 - [ ] **Step 1: 写出仓储回归测试** ```java assertThat(repository.findByPlatformUserId(101L)).contains(actor); ``` 删除依赖 `core_user.PASSWORD` 的断言。 - [ ] **Step 2: 移除过时配置与文档描述** 删除 `PlatformIntegrationProperties.LocalLogin`、密码镜像叙述及其测试;文档改为“SSO 身份投影 + Flyway 内置本地账号”。 - [ ] **Step 3: 运行全量验证** Run: `mvn test -DforkCount=0 -B` Expected: 全部测试 PASS,0 failures,0 errors。 - [ ] **Step 4: 构建可执行包** Run: `mvn package -DskipTests -B` Expected: `target/digital-rmb-backend-0.1.0-SNAPSHOT.jar` 生成成功。 - [ ] **Step 5: 提交** ```powershell git add README.md docs/superpowers/specs src/main/java src/test/java git commit -m "docs: document pevc-style local login" ```