release: freeze V1.2 demo acceptance 2026-10-25
CI/CD Pipeline / Test Shell Guard (Phase 23 Gate) (push) Waiting to run
CI/CD Pipeline / Backend Build & Test (push) Waiting to run
CI/CD Pipeline / Admin Web Build (push) Waiting to run
CI/CD Pipeline / Mini Program Compile Check (push) Waiting to run
CI/CD Pipeline / Migration Validation (push) Blocked by required conditions
CI/CD Pipeline / UI Contracts (source-structure gates) (push) Waiting to run
CI/CD Pipeline / E2E (live stack) (push) Blocked by required conditions
CI/CD Pipeline / Test Shell Guard (Phase 23 Gate) (push) Waiting to run
CI/CD Pipeline / Backend Build & Test (push) Waiting to run
CI/CD Pipeline / Admin Web Build (push) Waiting to run
CI/CD Pipeline / Mini Program Compile Check (push) Waiting to run
CI/CD Pipeline / Migration Validation (push) Blocked by required conditions
CI/CD Pipeline / UI Contracts (source-structure gates) (push) Waiting to run
CI/CD Pipeline / E2E (live stack) (push) Blocked by required conditions
This commit is contained in:
@@ -0,0 +1,363 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user