# V1.2 账号生命周期、红娘分配与工作台实施计划 > **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:** 在保留 V1.1 核心业务和现有红娘分配权限的前提下,补齐 V1.2 的用户注册/建档/审核/账号发放/首次授权闭环,确保认证后的资料变更重新审核后才重新展示和匹配,并让普通红娘、红娘组长和管理员使用一致且不可越权的六项工作台统计。 **Architecture:** 继续使用 Spring Boot 模块化单体、PostgreSQL Source of Truth、Redis 只保存验证码/登录失败状态。用户账号生命周期、授权门禁、导入批次和红娘工作台范围分别建模;业务服务通过现有 `CapabilityService`、`ServiceAssignmentPolicy` 和 `DataScopeGuard` 接入,不重建权限体系。工作台采用一个服务端聚合接口,依据当前登录主体推导 scope,卡片和详情列表复用同一组查询条件。 **Tech Stack:** Java 21 / Spring Boot 3 / MyBatis-Plus / PostgreSQL / Redis / Flyway / Vue 3 / TypeScript / 微信原生小程序 / Maven / pnpm / Python pytest。 **Spec:** `C:\Users\13070\.codex\attachments\155243ba-d394-45a0-b100-8c44baf9094d\已粘贴的文本.txt`;审计基线:`docs/audits/V1.2-现状审计与差距矩阵-2026-10-23.md`(若该审计文件尚未写入,则以本计划中的审计结论为准)。 ## Global Constraints - 用户永久免费;不新增 VIP、会员、金币或收费路径。 - PostgreSQL 是 Source of Truth;Redis 不保存业务状态,不覆盖数据库状态。 - 所有权限范围由后端从认证主体、角色、组织和有效分配关系推导;不信任请求体中的 `userId`、`matchmakerId`、`teamId` 或角色字段。 - 审核状态、账号状态、手机号核验、授权、服务资格、凭据发放必须独立存储,禁止合并为一个完成字段。 - 用户完成实名认证后,任何个人资料变更都生成新版本并进入 `pending_review`;新版本审核通过前,不得在推荐、搜索、活动匹配、红娘推荐或其他用户可见资料中使用。 - 资料重新审核期间,后端按“未通过审核”处理;不能只在前端隐藏,也不能继续使用未审核的新资料计算匹配。 - 未确认的登录标识、密码发放渠道、授权正式文案、重复资料处理、自动分配算法和看板统计口径在 Gate 0 前不得进入业务代码。 - 不重写 V001-V061;V1.2 新迁移从 V062 开始,所有迁移向前兼容已有数据。 - 不增加第三方依赖;批量导入首版使用 UTF-8/UTF-8 BOM CSV,`.xlsx` 作为明确不支持格式返回可读错误。 - Mock 短信/微信只能在显式测试或演示 profile 启用;生产配置不得把 Mock 验证当作真实核验。 - 每个任务先写失败测试,再写最小实现;任务完成后输出阶段 Completion Report,不自动进入下一任务。 - 任何外部短信、微信、生产数据库和真实用户 UAT 都不是本地测试的替代证据。 ## Gate 0:产品和数据决策冻结 **Files:** - Modify: `docs/governance/open-questions.md` - Modify: `docs/governance/decision-register.md` - Modify: `docs/governance/config-register.md` - Create: `docs/v12/V1.2-状态机与接口契约.md` - Create: `docs/v12/V1.2-字段与统计口径表.md` **必须确认的决策:** 1. 用户登录标识:手机号 + 密码,或平台发放的独立用户名 + 密码。 2. 初始密码的实际发放渠道;失败时由谁、通过什么双人复核流程人工发放。 3. 两份授权书的正式文本、版本号、拒绝后的服务状态和重新授权规则。 4. 历史微信用户的补授权、手机号核验和账号关联策略。 5. 重复手机号/重复资料的拒绝、合并或人工队列规则。 6. 自动分配算法、跨组规则、无可用红娘时的待分配队列行为。 7. 六项看板的状态、时间范围、去重规则和“有效匹配”正式口径。 8. 红娘组长是否可建档、导入、直接分配及调整组内红娘关系。 **验收:** 所有决策进入 `decision-register.md`;仍未确认的内容进入 `open-questions.md`,并在代码计划中标记为配置或阻断,不写成默认业务规则。 --- ### Task 1: 建立 V1.2 状态模型和迁移 **Files:** - Create: `backend/src/main/resources/db/migration/V062__add_v12_user_account_lifecycle.sql` - Create: `backend/src/main/resources/db/migration/V063__add_v12_import_batches.sql` - Create: `backend/src/main/resources/db/migration/V064__add_v12_consent_and_service_state.sql` - Modify: `backend/src/test/resources/schema-h2.sql` - Create: `backend/src/test/java/com/danyang/match/platform/deployment/V12MigrationContractTest.java` - Create: `backend/src/main/java/com/danyang/match/platform/account/entity/UserCredential.java` - Create: `backend/src/main/java/com/danyang/match/platform/account/entity/UserAccountLifecycle.java` - Create: `backend/src/main/java/com/danyang/match/platform/account/entity/UserConsentState.java` - Create: `backend/src/main/java/com/danyang/match/platform/user/entity/UserImportBatch.java` - Create: `backend/src/main/java/com/danyang/match/platform/user/entity/UserImportRow.java` **Interfaces:** - Produces independent fields for `profile_review_status`, `profile_revision`, `published_profile_revision`, `account_creation_status`, `credential_delivery_status`, `phone_verification_status`, `service_consent_status`, and `service_eligibility_status`. - Produces password hash, `must_change_password`, password version, credential issued/used timestamps, and delivery channel/status; never stores plaintext passwords. - Produces import batch and row status/error fields with a unique idempotency key per batch. - Preserves existing `users`, `operators`, `review_tasks`, `consent_records` rows and existing V1.1 status values. - [x] **Step 1: Write migration contract tests** for new tables/columns, allowed status values, indexes, uniqueness, and absence of plaintext credential columns. - [x] **Step 2: Run the contract tests**; initial run failed because V062-V064 did not exist, then passed after implementation. - [x] **Step 3: Add V062-V064 migrations** with backfill-safe columns, batch row uniqueness, and indexes for status/scope queries. - [x] **Step 3a: Add profile revision storage**: retain the last approved/published revision and backfill approved users; atomic profile-write transition is implemented in Task 4 at the service boundary. - [x] **Step 4: Mirror required tables and constraints in `schema-h2.sql`** and keep PostgreSQL-specific DDL covered by migration contract tests. - [x] **Step 5: Add lifecycle entities** without changing existing V1.1 entity semantics; profile write behavior remains a Task 4 concern. - [x] **Step 6: Run migration and entity tests**; no modification to V001-V061. - [x] **Step 7: Write `docs/v12/V1.2-状态机与接口契约.md`** with allowed transitions, terminal states, idempotency behavior, and actor/audit rules. **验收:** Empty PostgreSQL can migrate V001-V064; existing demo data remains readable; duplicate active credential/phone/batch rows are rejected by database constraints. ### Task 2: 实现用户自主注册、手机号核验和历史账号关联 **Files:** - Create: `backend/src/main/java/com/danyang/match/platform/user/dto/UserRegistrationRequest.java` - Create: `backend/src/main/java/com/danyang/match/platform/user/dto/PhoneVerificationRequest.java` - Create: `backend/src/main/java/com/danyang/match/platform/user/service/UserRegistrationService.java` - Create: `backend/src/main/java/com/danyang/match/platform/user/service/PhoneVerificationService.java` - Modify: `backend/src/main/java/com/danyang/match/platform/auth/controller/AuthController.java` - Modify: `backend/src/main/java/com/danyang/match/platform/auth/service/AuthService.java` - Create: `backend/src/main/java/com/danyang/match/platform/auth/provider/SmsVerificationProvider.java` - Create: `backend/src/main/java/com/danyang/match/platform/auth/provider/MockSmsVerificationProvider.java` - Create: `backend/src/main/java/com/danyang/match/platform/auth/provider/ConfiguredSmsVerificationProvider.java` - Create: `backend/src/test/java/com/danyang/match/platform/user/UserRegistrationServiceTest.java` - Create: `backend/src/test/java/com/danyang/match/platform/auth/PhoneVerificationGuardTest.java` - Modify: `miniapp/services/authService.js` - Modify: `miniapp/pages/login/login.ts` - Create: `miniapp/pages/register/register.ts` - Create: `miniapp/pages/register/register.wxml` - Create: `miniapp/pages/register/register.wxss` - Create: `miniapp/pages/register/register.json` **Interfaces:** - `POST /api/v1/auth/register` consumes name, organization, organizationPhone, phone, and verification transaction; returns a pending user reference, never an active service token. - `POST /api/v1/auth/phone/send-code` and `POST /api/v1/auth/phone/verify` use a provider abstraction and one-time Redis transaction; production provider must fail closed when unconfigured. - `POST /api/v1/auth/wechat/login` remains compatible, but new and historical users receive explicit lifecycle state in the response. - Duplicate phone returns a stable conflict code and does not overwrite existing records. - [x] **Step 1: Add failing tests** for phone validation, code expiry/replay, rate limits, duplicate phone, and provider refusal outside test/demo profiles. - [x] **Step 2: Run targeted tests** and confirm failure before implementation. - [x] **Step 3: Implement provider and Redis transaction** with hashed code storage, expiry, attempt limit, cooldown, and audit-safe logs; never log the code or full phone. - [x] **Step 4: Implement registration transaction** that writes the registration application and marks phone verification separately. - [x] **Step 5: Preserve WeChat login compatibility**; ambiguous historical account association remains blocked until its explicit association flow is implemented in a later task. - [x] **Step 6: Add miniapp registration and error/loading states** using existing API and UI conventions. - [x] **Step 7: Run backend tests and miniapp type-check**. **验收:** Unverified users cannot enter the service flow; duplicate phone cannot overwrite existing data; the same verification transaction cannot be replayed; real-provider configuration is required for production. ### Task 3: 实现后台建档、CSV 导入和审核后账号发放 **Files:** - Create: `backend/src/main/java/com/danyang/match/platform/user/dto/OperatorCreateUserRequest.java` - Create: `backend/src/main/java/com/danyang/match/platform/user/dto/UserImportPreviewRequest.java` - Create: `backend/src/main/java/com/danyang/match/platform/user/dto/UserImportPreviewResponse.java` - Create: `backend/src/main/java/com/danyang/match/platform/user/service/UserOnboardingService.java` - Create: `backend/src/main/java/com/danyang/match/platform/user/service/UserImportService.java` - Create: `backend/src/main/java/com/danyang/match/platform/user/service/UserCredentialService.java` - Modify: `backend/src/main/java/com/danyang/match/platform/user/controller/UserController.java` - Modify: `backend/src/main/java/com/danyang/match/platform/review/service/ReviewService.java` - Modify: `backend/src/main/java/com/danyang/match/platform/review/controller/ReviewController.java` - Create: `backend/src/test/java/com/danyang/match/platform/user/UserImportServiceTest.java` - Create: `backend/src/test/java/com/danyang/match/platform/user/UserAccountLifecycleTest.java` - Create: `backend/src/test/java/com/danyang/match/platform/review/ReviewAccountIssuanceTest.java` - Create: `admin-web/src/modules/user/UserCreateView.vue` - Create: `admin-web/src/modules/user/UserImportView.vue` - Modify: `admin-web/src/modules/user/UserManagementView.vue` - Modify: `admin-web/src/router/index.ts` **Interfaces:** - `POST /api/v1/operator/users` creates a draft profile only; it does not bypass phone verification, authorization, or review. - `POST /api/v1/operator/users/import/preview` accepts CSV bytes and returns row-level normalized values/errors without writes. - `POST /api/v1/operator/users/import/commit` consumes a preview batch id plus `Idempotency-Key`, writes valid rows only, and records every row result. - `POST /api/v1/operator/users/{id}/issue-account` is idempotent and allowed only after approved profile + verified phone + required consent policy. - Account issuance returns a masked delivery result and one-time credential reference; plaintext initial password is never persisted or written to logs. - [x] **Step 1: Write failing tests** for permission, CSV encoding/header validation, row errors, duplicate rows within a file, duplicate database phone, preview no-write, commit idempotency, and retry behavior. - [x] **Step 2: Run targeted tests** and confirm failure. - [x] **Step 3: Implement manual create and CSV preview** with explicit required columns: name, organization, organizationPhone, phone; unsupported formats are rejected by the CSV-only endpoint. - [x] **Step 4: Implement commit transaction** with row-level success/failure persistence, Redis idempotency, and no partial overwrite of an existing user. - [x] **Step 5: Connect review approval to account issuance eligibility and profile publication**; approval publishes the reviewed revision while rejection/need-edit preserves the previous published revision. - [x] **Step 6: Implement secure random initial password generation and hash storage** with `must_change_password=true`; only a credential reference is returned. - [x] **Step 7: Add admin UI manual-create and CSV preview/commit workflow** with permission-based visibility. - [x] **Step 8: Run backend tests and admin type-check**. **验收:** Preview performs no database write; commit can be safely retried; failed rows are explainable; approval, phone verification, consent, account status and profile publication remain separate; no plaintext credential is stored; a changed authenticated profile is excluded from matching until its new revision is approved. ### Task 4: 实现用户/红娘登录、首次改密和授权门禁 **Files:** - Create: `backend/src/main/java/com/danyang/match/platform/auth/dto/PasswordLoginRequest.java` - Create: `backend/src/main/java/com/danyang/match/platform/auth/dto/InitialPasswordChangeRequest.java` - Create: `backend/src/main/java/com/danyang/match/platform/account/service/UserCredentialService.java` - Create: `backend/src/main/java/com/danyang/match/platform/account/service/ServiceConsentService.java` - Modify: `backend/src/main/java/com/danyang/match/platform/auth/service/AuthService.java` - Modify: `backend/src/main/java/com/danyang/match/platform/auth/controller/AuthController.java` - Modify: `backend/src/main/java/com/danyang/match/platform/auth/service/OperatorAuthService.java` - Modify: `backend/src/main/java/com/danyang/match/platform/auth/controller/OperatorAuthController.java` - Modify: `backend/src/main/java/com/danyang/match/platform/profile/controller/ProfileController.java` - Modify: `backend/src/main/java/com/danyang/match/platform/profile/service/UserProfileService.java` - Modify: `backend/src/main/java/com/danyang/match/platform/profile/mapper/UserProfileMapper.java` - Modify: `backend/src/main/java/com/danyang/match/platform/capability/service/CapabilityService.java` - Create: `backend/src/main/java/com/danyang/match/platform/account/controller/ServiceConsentController.java` - Create: `backend/src/test/java/com/danyang/match/platform/auth/InitialPasswordGuardTest.java` - Create: `backend/src/test/java/com/danyang/match/platform/account/ServiceConsentGateTest.java` - Create: `backend/src/test/java/com/danyang/match/platform/account/ConsentVersionAuditTest.java` - Create: `miniapp/pages/initial-password/initial-password.ts` - Create: `miniapp/pages/initial-password/initial-password.wxml` - Create: `miniapp/pages/initial-password/initial-password.wxss` - Create: `miniapp/pages/service-consent/service-consent.ts` - Create: `miniapp/pages/service-consent/service-consent.wxml` - Create: `miniapp/pages/service-consent/service-consent.wxss` - Modify: `miniapp/stores/authStore.js` - Modify: `miniapp/app.js` **Interfaces:** - `POST /api/v1/auth/password/login` authenticates the confirmed login identifier and returns `mustChangePassword`, `consentRequired`, and `serviceActive` state. - `POST /api/v1/auth/password/change-initial` is the only non-essential endpoint allowed while `must_change_password=true`; success rotates credential version and invalidates old sessions. - `GET /api/v1/account/service-consent` returns the two required document versions and current user decisions. - `POST /api/v1/account/service-consent` requires explicit positive confirmation for each required document and records version, actor, timestamp, IP, user agent, and audit event. - All match, chat, matchmaker, counseling, appointment and activity service entry points call a shared `ServiceConsentService.requireActive(userId)` or equivalent policy check. - [ ] **Step 1: Write failing tests** for initial-login restriction, wrong password rate limiting, password complexity, old credential invalidation, unchecked consent rejection, version mismatch, withdrawal, and reactivation. - [ ] **Step 2: Run targeted tests** and confirm failure. - [ ] **Step 3: Implement password login and initial-change flow** with the existing JWT/Redis conventions; never expose password hashes or plaintext credentials. - [ ] **Step 4: Implement consent state and audit** using the formal versions from Gate 0; do not treat silence or a pre-checked UI box as consent. - [ ] **Step 5: Add profile revision gate** to profile update endpoints: after authentication, every personal-profile write creates a new revision and moves the profile to `pending_review`; fields that are not personal-profile data must be explicitly classified rather than silently bypassing review. - [ ] **Step 6: Add shared backend gate** to each service boundary. The gate must require the latest profile revision to equal the published approved revision, not just trust the front-end capability response. - [ ] **Step 7: Add miniapp first-login and profile-update routing** for change-password, consent, profile confirmation, pending-review, rejection and resubmission states. - [ ] **Step 8: Run negative permission, profile-revision and service-block tests** plus miniapp type-check. **验收:** Refusal sets the confirmed inactive/suspended service state; protected service APIs reject the user server-side; changing the initial password and accepting both documents are separately auditable; an authenticated profile edit immediately leaves the new revision unpublished and excluded from matching until review approval. ### Task 5: 接入红娘自动分配前置条件和账号管理闭环 **Files:** - Create: `backend/src/main/java/com/danyang/match/platform/matchmaker/service/MatchmakerEligibilityPolicy.java` - Modify: `backend/src/main/java/com/danyang/match/platform/matchmaker/service/MatchmakerAssignmentService.java` - Modify: `backend/src/main/java/com/danyang/match/platform/matchmaker/service/ServiceAssignmentPolicy.java` - Modify: `backend/src/main/java/com/danyang/match/platform/operator/service/OperatorManagementService.java` - Modify: `backend/src/main/java/com/danyang/match/platform/operator/controller/OperatorController.java` - Create: `backend/src/test/java/com/danyang/match/platform/matchmaker/MatchmakerAssignmentEligibilityTest.java` - Create: `backend/src/test/java/com/danyang/match/platform/matchmaker/ProfileRevisionAssignmentGuardTest.java` - Create: `backend/src/test/java/com/danyang/match/platform/operator/OperatorCredentialLifecycleTest.java` - Modify: `backend/src/main/resources/db/migration/V065__add_v12_assignment_eligibility_audit.sql` **Interfaces:** - `MatchmakerEligibilityPolicy.assertEligible(userId)` checks, in order: approved profile, verified phone, required consent, normal account status, confirmed service eligibility. - Existing `MatchmakerAssignmentService.create/transfer` remains the write boundary and calls the policy before creating an active assignment. - Operator creation requires an explicit approved role (`matchmaker` or `matchmaker_leader`), organization scope, secure credential issuance state, and audit record. - Disabling a matchmaker cannot silently drop active assignments; it follows the Gate 0 decision for transfer queue/leader handling. - [ ] **Step 1: Write failing tests** for each missing eligibility condition, concurrent assignment, cross-organization leader denial, disabled target, and re-enable behavior. - [ ] **Step 2: Run targeted tests** and confirm failure. - [ ] **Step 3: Implement `MatchmakerEligibilityPolicy`** by reusing `CapabilityService`, consent policy and the published-profile-revision check; do not duplicate status rules in controllers. - [ ] **Step 4: Connect policy to create/transfer** within the existing transaction and preserve database unique-index race protection. - [ ] **Step 5: Harden operator creation** with request validation, role binding, audit, password policy and initial-change flag. - [ ] **Step 6: Implement disabled-operator assignment handling** exactly as decided at Gate 0, with an audit event and no data loss. - [ ] **Step 7: Run the existing matchmaker suite plus new eligibility tests**. **验收:** No ineligible user can receive an active automatic/manual assignment; ordinary matchmakers cannot claim or browse unassigned users; group leaders remain organization-scoped; disabling a matchmaker leaves an auditable, recoverable assignment state. ### Task 6: 重建六项范围看板和详情一致性 **Files:** - Create: `backend/src/main/java/com/danyang/match/platform/matchmaker/dashboard/MatchmakerDashboardScope.java` - Create: `backend/src/main/java/com/danyang/match/platform/matchmaker/dashboard/MatchmakerDashboardMapper.java` - Create: `backend/src/main/java/com/danyang/match/platform/matchmaker/dashboard/MatchmakerWorkbenchService.java` - Create: `backend/src/main/java/com/danyang/match/platform/matchmaker/dashboard/MatchmakerWorkbenchController.java` - Modify: `backend/src/main/java/com/danyang/match/platform/analytics/AnalyticsService.java` - Create: `backend/src/test/java/com/danyang/match/platform/matchmaker/MatchmakerWorkbenchScopeTest.java` - Create: `backend/src/test/java/com/danyang/match/platform/matchmaker/MatchmakerDashboardConsistencyTest.java` - Create: `backend/src/test/java/com/danyang/match/platform/matchmaker/MatchmakerDashboardAuthorizationTest.java` - Modify: `admin-web/src/services/dashboard.ts` - Modify: `admin-web/src/types/dashboard.ts` - Modify: `admin-web/src/views/DashboardView.vue` - Modify: `admin-web/src/router/index.ts` **Interfaces:** - `GET /api/v1/operator/matchmaker/workbench/dashboard` returns `{ scope, metrics, availability, generatedAt }` for the six cards and shared query metadata. - `MatchmakerDashboardScope` is derived server-side: ordinary matchmaker = active assignments owned by principal; group leader = same organization; administrator = platform scope. - The six metric keys remain `pending_reviews`, `matchmaker_todos`, `counseling_todos`, `station_appointments`, `effective_matches`, and `activity_registrations` to preserve the existing UI contract. - Detail list endpoints receive only pagination/time filters; they cannot receive an alternate operator/team scope. They call the same scope builder and status predicates as the aggregate query. - User/profile-backed metrics and drill-down records exclude rows where `profile_revision != published_profile_revision`; an unreviewed profile revision must not leak through the dashboard or matching data. - [ ] **Step 1: Freeze metric definitions** in `docs/v12/V1.2-字段与统计口径表.md`, including included/excluded statuses, timezone `Asia/Shanghai`, time window, and deduplication. - [ ] **Step 2: Write failing authorization/consistency tests** for ordinary matchmaker, same-team leader, other-team leader, administrator, empty data, permission denied, and aggregate/detail equality. - [ ] **Step 3: Run targeted tests** and confirm failure. - [ ] **Step 4: Implement scope builder and SQL filters** at query level; do not fetch global rows and filter in Vue. Add the published-profile-revision predicate to every user/profile-backed metric and detail query. - [ ] **Step 5: Implement one aggregate endpoint** while preserving older analytics endpoints for existing analytics pages. - [ ] **Step 6: Update `dashboard.ts`** to use the aggregate response for six cards; keep loading, empty, forbidden, partial-failure states distinct. - [ ] **Step 7: Add detail navigation tests** showing a card click cannot broaden the scope. - [ ] **Step 8: Run backend scope tests, admin type-check, build, and UI contract tests**. **验收:** Six cards show `0` for real empty data, a distinct no-permission state for forbidden data, and a distinct failure state for query failure; ordinary matchmaker, leader, and administrator counts match their permitted detail lists; changing request parameters cannot change scope. ### Task 7: 活栈 E2E、文档收口和发布门禁 **Files:** - Create: `tests/e2e/v12_account_lifecycle_test.py` - Create: `tests/e2e/v12_import_and_review_test.py` - Create: `tests/e2e/v12_matchmaker_dashboard_test.py` - Modify: `tests/e2e/conftest.py` - Modify: `backend/src/test/resources/application-test.yml` - Modify: `docs/STATUS.md` - Create: `docs/Phase-V12-Completion-Report.md` - Modify: `docs/api/API_INVENTORY.md` - Modify: `docs/database/MIGRATION_GUIDE.md` - Modify: `README.md` - Modify: `.github/workflows/ci.yml` **Interfaces:** - E2E uses a clean PostgreSQL/Redis stack and explicit test providers; it never treats H2-only results as release evidence. - CI runs migration validation, backend tests, admin type-check/build, miniapp type-check, and V1.2 E2E; any failed gate blocks completion. - Completion report records current commit, migration version, test counts, skipped tests/reasons, runtime configuration, and unresolved production evidence. - [ ] **Step 1: Add E2E fixtures** for a user, duplicate phone, pending/approved review, ordinary matchmaker, same-team leader, other-team leader, and administrator. - [ ] **Step 2: Add the account lifecycle path**: register or import → preview → commit → review → account issue → password login → forced change → two consents → service capability. - [ ] **Step 2a: Add the profile revision path**: approved user edits personal profile → new revision becomes pending → old approved revision remains the only published revision → review approval publishes the new revision → matching and display resume. - [ ] **Step 3: Add negative paths**: duplicate phone, expired code, repeated commit, refused consent, pending/rejected profile excluded from search/recommendation/matchmaker recommendation, cross-team dashboard query, and disabled matchmaker. - [ ] **Step 4: Add dashboard consistency checks** for all six cards and corresponding detail lists under all three role scopes, including exclusion of unpublished profile revisions. - [ ] **Step 5: Run the full local gate**: ```powershell mvn -B -f backend/pom.xml test pnpm --dir admin-web type-check pnpm --dir admin-web build npm --prefix miniapp run type-check python -m pytest tests/e2e -q ``` - [ ] **Step 6: Fix environment blockers separately** if `spawn EPERM`, locked `target/classes`, missing Redis, or missing production-provider credentials occur; do not weaken tests. - [ ] **Step 7: Write Completion Report** with `PASS/PARTIAL/FAIL/NOT_IMPLEMENTED/NOT_VERIFIED` evidence and stop for user acceptance. **验收:** Clean-stack E2E proves the complete V1.2 path and role isolation; CI is green; no historical test count is reused as current evidence; production remains `NO-GO` until real SMS/WeChat, TLS, backup/restore, monitoring, rollback and user UAT are separately proven. ## Dependency Order and Release Gates ```text Gate 0 product decisions | v Task 1 state model and migrations | +--> Task 2 registration and phone verification | | | v +--> Task 3 admin create/import/review/issuance | v Task 4 first login/password/consent gate | +--> Task 5 assignment eligibility | +--> Task 6 scoped dashboard | v Task 7 E2E and release gate ``` **Phase completion rules:** - Gate 0: all mandatory product decisions recorded. - Task 1: V062-V064 migrate on a clean database and existing data remains readable. - Task 2: phone verification cannot be bypassed or replayed. - Task 3: import is previewable, idempotent, auditable and cannot bypass review/consent. - Task 4: initial password, consent and unpublished profile revisions are backend-enforced. - Task 5: assignment eligibility and role scope are negative-tested. - Task 6: cards and details share scope and metric definitions. - Task 7: full current test evidence is recorded and user acceptance is requested. ## Explicitly Deferred - Direct `.xlsx` parsing; first release accepts UTF-8 CSV and returns a clear unsupported-format error for `.xlsx`. - A new automatic assignment algorithm before the product decision; the existing explicit assignment path remains available. - Any payment, VIP, AI代聊, community feed, microservice, Kubernetes, or unrelated V1.2 expansion. - Production SMS/WeChat provider integration, real credentials, production TLS, backup/restore rehearsal and real-user UAT until their environment and owners are available. ## Plan Self-Check - Registration fields, phone verification, duplicate handling: Task 2. - Manual create, CSV preview/commit, row errors, review linkage: Task 3. - Independent account/credential/consent/service states: Task 1 and Task 4. - Initial password rules, hash-only storage, forced change: Task 3 and Task 4. - Authenticated profile update creates a new revision and blocks display/matching until approval: Task 1, Task 3, Task 4, Task 5, Task 6 and Task 7. - Administrator-only matchmaker account opening and group scope: Task 5. - Automatic assignment prerequisites and no-available-matchmaker behavior: Gate 0 and Task 5. - Six dashboard cards, role scopes, empty/error/forbidden states, card/detail consistency: Task 6. - Tests, migrations, frontend builds, clean-stack E2E, documentation and completion report: Task 7. ## Execution Handoff Plan complete and saved to `docs/superpowers/plans/2026-10-23-v12-account-lifecycle-matchmaker-dashboard.md`. Execute it task-by-task with review checkpoints; implementation must begin at Gate 0 and stop after each phase Completion Report.