docs(education): record migration closure evidence
This commit is contained in:
@@ -1,12 +1,22 @@
|
||||
# Current State
|
||||
|
||||
> Phase 0 static assessment generated on 2026-07-29. No build, test, application startup, PostgreSQL connection, or Flyway migration was executed during this assessment.
|
||||
> Phase 0 static assessment originally generated on 2026-07-29. Updated on 2026-07-31 after bounded implementation through V4180, full Education tests against disposable PostgreSQL, server compilation, and the student harness.
|
||||
|
||||
## Executive summary
|
||||
## Current implementation summary
|
||||
|
||||
Phase 0 remains a read-only architecture assessment, not an implementation claim. Verified evidence shows the target is on feature/education-core-loop with a heavily dirty worktree, while the source checkout has no local or remote feature/education-core-loop ref and is main at 033701a. The target contains a meaningful committed core-loop slice (ce02f8a) plus substantial dirty provider/catalog/session work, so all roadmap status must distinguish committed, dirty, absent, and runtime-unverified behavior. EDU-003 has now decided public tenant resolution: Origin/Referer are forgeable browser-context claims rather than trusted identity; headless lookup uses the constrained System-name Public Tenant Handle; successful lookup accepts tenant-existence disclosure while unknown/disabled/expired failures are identical; exact wire errors, canonical host-only websites, a secure-default local flag, and abuse controls are assigned to EDU-004. This is distinct from the already verified authenticated tenant mismatch rejection in TenantSecurityWebFilter; /education/context still requires EDU-004 Member/UserType enforcement. The most reliable core-loop slice remains provider-neutral fail-closed question content handling across the active default Scalar path, conditional Java path, safe catalog projection, and persisted session restoration. Core-loop schema is not proven to be in active Flyway: V4010 is a placeholder, V4020 is catalog-only, and practice/report/idempotency DDL is untracked manual SQL. Native reads are an intentional explicit-scope bypass requiring mapper audit, while schema foreign keys do not enforce tenant-consistent graphs. Phase 0 coverage must also add first-class Auth/Profile/extended Learning, granular tenant-admin, and granular platform-admin groups. Paid access, provider authority, option schema, public graph semantics, and source baseline remain product/architecture decisions.
|
||||
The target branch now contains the complete student core loop, tenant/identity enforcement, module-owned PostgreSQL Flyway migrations V4010–V4200, bounded tenant content authoring, import job and asset contracts, class/invitation relationships, education entitlement bindings, a representative extended-learning wave, and operational dependency/health contracts. The full Education suite passed against disposable PostgreSQL (596 tests), the server reactor compiled successfully, and the fixture-based student harness passed six browser flows. These tests executed the module-owned Flyway chain in isolated disposable test schemas; they are not evidence that a shared Pilot or production database was migrated. Production deployment, real Pilot data, production scanner/parser adapters, automatic Mall/Pay/CRM fulfillment events, and selected deferred learning families remain outside the verified implementation.
|
||||
|
||||
## Verified program decisions
|
||||
This document retains the original Phase 0 findings below as provenance. Current ticket status is authoritative in [`issues/README.md`](issues/README.md), and rollout evidence is tracked by [`../pilot-acceptance-runbook.md`](../pilot-acceptance-runbook.md).
|
||||
|
||||
## Original Phase 0 executive summary
|
||||
|
||||
Verified evidence showed the target on `feature/education-core-loop` with a heavily dirty worktree, while the source checkout had no local or remote branch with that name and remained at `033701a`. The assessment identified a meaningful committed core-loop slice plus substantial provider/catalog/session work that still required classification. It selected provider-neutral fail-closed question handling, tenant/principal enforcement, atomic idempotency, PostgreSQL/Flyway takeover, and catalog graph integrity as the immediate blockers. Those bounded blockers have since been implemented and verified; this paragraph is retained only as historical context.
|
||||
|
||||
## Original Phase 0 decisions and unknowns
|
||||
|
||||
The remaining sections are the immutable investigation record from 2026-07-29. Items phrased as pending may now be resolved by later tickets and migrations; use the current summary and ticket index above for delivery status.
|
||||
|
||||
### Decisions recorded during Phase 0
|
||||
|
||||
- Verified source provenance is limited: /Users/tiku1/code/tiku-backend has only main and origin/main at 033701a785c7012139e7f86995eea6041225592e; no local or remote feature/education-core-loop ref exists. Use main/033701a provisionally only, or obtain explicit approval for that baseline.
|
||||
- Verified target branch is feature/education-core-loop and its worktree is dirty. Current read-only inventory reports 65 modified tracked files and 97 untracked entries; preserve all, and do not rely on an older 21-untracked count.
|
||||
@@ -22,7 +32,7 @@ Phase 0 remains a read-only architecture assessment, not an implementation claim
|
||||
- Do not expose paid/private practice until entitlement semantics and public target contracts are decided.
|
||||
- No tests, builds, PostgreSQL connections, Flyway execution, or runtime verification were performed; all conclusions are static repository evidence unless explicitly marked otherwise.
|
||||
|
||||
## Unknowns
|
||||
### Unknowns recorded during Phase 0
|
||||
|
||||
- EDU-003 decided the public resolver threat model and contract. Browser headers are forgeable context claims; a constrained Public Tenant Handle supports headless clients; success discloses tenant existence; unknown/disabled/expired failures are identical; exact errors, canonical websites, local activation, Member-only context, and abuse controls are assigned to EDU-004.
|
||||
- Whether a future System-owned immutable Tenant Code or authenticated/signed locator is required beyond the accepted public-handle contract.
|
||||
|
||||
@@ -125,10 +125,11 @@ The durable artifact classification, adoption matrix, version allocation, backfi
|
||||
16. Membership is an ordered replace-all command available only in DRAFT. Every member must be a current-tenant `TENANT_OWNED` PUBLISHED Question, and duplicate Question IDs are rejected rather than collapsed or upserted.
|
||||
17. Activation exposes the collection route only when the collection and its existing Content Node are available. Archiving closes only collection-route discovery; it does not alter direct Question visibility or historical Practice Question Snapshots.
|
||||
18. `access_rules` is descriptive reserved metadata in this slice, not entitlement enforcement. PUBLIC Question curation, dynamic filters, paid/private access, Category, Practice Blueprint, and Content Entry creation are excluded.
|
||||
19. Protected lifecycle transition tokens rely on PostgreSQL object ownership separation: an explicit Flyway owner role creates V4080/V4100/V4110 token tables, while the runtime master datasource role must neither own nor write them. Local/dev configuration requires explicit `FLYWAY_USER`/`FLYWAY_PASSWORD`; startup fails closed when any protected table is missing, runtime-owned, inherited through role membership, or runtime-writable. Deployment automation provisions roles and grants outside Flyway because migrations cannot safely create shared login roles or know credential policy.
|
||||
|
||||
19. V4120 closes the bounded EDU-010 Category and Practice Blueprint scope. Category is a standalone Subject-scoped catalog aggregate, not Question classification. Blueprint authoring is limited to exactly one current-tenant NODE or active Manual COLLECTION target; target ownership, route, and counts are server-derived.
|
||||
20. Category and Practice Blueprint use the same `DRAFT → ACTIVE → ARCHIVED`, `authoring_version` CAS, transactional append-only audit, current-tenant ownership, and `JAVA_READ` authority rules as Content Node and Collection. Student reads require ACTIVE lifecycle plus route availability.
|
||||
21. The six added permissions are `education:category:{author,publish,archive}` and `education:practice-blueprint:{author,publish,archive}`. V4120 conditionally seeds permission rows at IDs 6809-6814, fails on conflicting IDs, and assigns no roles.
|
||||
20. V4120 closes the bounded EDU-010 Category and Practice Blueprint scope. Category is a standalone Subject-scoped catalog aggregate, not Question classification. Blueprint authoring is limited to exactly one current-tenant NODE or active Manual COLLECTION target; target ownership, route, and counts are server-derived.
|
||||
21. Category and Practice Blueprint use the same `DRAFT → ACTIVE → ARCHIVED`, `authoring_version` CAS, transactional append-only audit, current-tenant ownership, and `JAVA_READ` authority rules as Content Node and Collection. Student reads require ACTIVE lifecycle plus route availability.
|
||||
22. The six added permissions are `education:category:{author,publish,archive}` and `education:practice-blueprint:{author,publish,archive}`. V4120 conditionally seeds permission rows at IDs 6809-6814, fails on conflicting IDs, and assigns no roles.
|
||||
|
||||
**Permission and data-scope matrix:**
|
||||
|
||||
|
||||
@@ -409,15 +409,7 @@ The migration is complete only when:
|
||||
|
||||
Phase 0 inventory and the first safe-question slice have been executed. Continue through the blocker-aware tickets under [`docs/education/migration/issues/`](issues/README.md).
|
||||
|
||||
Current execution order:
|
||||
|
||||
1. `EDU-002` — restore the full Practice regression baseline;
|
||||
2. `EDU-003` — decide tenant resolution and student-principal policy;
|
||||
3. `EDU-004` — enforce the selected tenant/identity policy;
|
||||
4. `EDU-005` — decide PostgreSQL/Flyway takeover;
|
||||
5. `EDU-006` — deliver the approved Practice schema through module-owned Flyway;
|
||||
6. `EDU-007` through `EDU-009` — verify and complete the student core loop;
|
||||
7. later phases proceed only when their ticket blockers are complete.
|
||||
Current execution order is maintained in [`docs/education/migration/issues/README.md`](issues/README.md). Do not duplicate the live order here; completed bounded tickets remain historical dependencies, while current work follows the ticket index and its blockers.
|
||||
|
||||
Before every ticket:
|
||||
|
||||
|
||||
@@ -57,12 +57,12 @@ FavoriteServiceImplTest
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] Every target class starts its Spring/JUnit context.
|
||||
- [ ] No target class fails because `ScoringService` is missing.
|
||||
- [ ] No target class fails from avoidable Mapper bean-name/type injection ambiguity.
|
||||
- [ ] EDU-001 safe-content assertions remain green.
|
||||
- [ ] Any actual behavior failure is documented with reproducible command and assigned a separate ticket.
|
||||
- [ ] No production behavior or database schema is changed unless a failing regression proves it is necessary and the ticket is explicitly amended.
|
||||
- [x] Every target class starts its Spring/JUnit context.
|
||||
- [x] No target class fails because `ScoringService` is missing.
|
||||
- [x] No target class fails from avoidable Mapper bean-name/type injection ambiguity.
|
||||
- [x] EDU-001 safe-content assertions remain green.
|
||||
- [x] Any actual behavior failure is documented with reproducible command and assigned a separate ticket.
|
||||
- [x] No production behavior or database schema is changed unless a failing regression proves it is necessary and the ticket is explicitly amended.
|
||||
|
||||
## Test command
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ Exact objects and versions are determined by EDU-005 and `flyway-postgresql`.
|
||||
- [x] Annotated SQL and Mapper behavior match PostgreSQL constraints.
|
||||
- [x] Focused repository/integration tests cover uniqueness and tenant scope.
|
||||
- [x] Real PostgreSQL Flyway migrate/validate succeeds in an isolated disposable test environment.
|
||||
- [x] Forward migration V4180 validates adopted Practice scalar types, required nullability, and identifier lengths without modifying V4030–V4060.
|
||||
- [x] Operational docs no longer instruct users to apply MySQL or manual Education SQL for these objects.
|
||||
|
||||
## Verification
|
||||
|
||||
@@ -26,6 +26,9 @@ The bounded capability provides:
|
||||
|
||||
## Deferred scope
|
||||
|
||||
- Production preview requests reference an admitted tenant asset ID; object keys, filenames, media types, and sizes are derived server-side from `education_content_import_asset` and are never accepted from the request body.
|
||||
- The executable question-import service uses the V4130 `education_content_import_job` aggregate directly; the obsolete parallel `education_question_import_job` path has been removed.
|
||||
- Per-job claims, heartbeat/finish fencing, expired lease recovery, bounded attempts, and terminal exhaustion failure use the production PostgreSQL mapper contract.
|
||||
- No generated export file, downloadable export artifact, export worker, or export-job persistence is delivered. Only the request-time redaction policy is established.
|
||||
- No production malware-scanner integration is delivered; the default remains fail-closed `UNAVAILABLE` until an external scanner adapter is configured.
|
||||
- No full CSV/XLSX parser is promised by the fallback. Without an available parser, preview remains metadata-only and execution is blocked.
|
||||
@@ -40,7 +43,7 @@ The bounded capability provides:
|
||||
- [x] CSV/XLSX can return metadata-only preview when the parser is unavailable.
|
||||
- [x] Execute is blocked unless scanning is clean and preview content is executable.
|
||||
- [x] Export requests apply answer/private-field redaction policy.
|
||||
- [ ] Generated export files and the remaining operational features are deferred as listed above.
|
||||
- [x] Generated export files, retention automation, production parser/scanner adapters, operator UI, and legacy re-scan are explicitly outside this bounded capability; their absence is exposed through blockers and fail-closed behavior rather than represented as available.
|
||||
|
||||
## Risk and rollback
|
||||
|
||||
|
||||
@@ -27,6 +27,13 @@ Tenant administrators manage classes, student education relationships, invitatio
|
||||
- Invitation creation is idempotent per tenant, actor, and key with request-hash conflict detection. Acceptance locks the invitation, checks invitee and expiry, and writes relationship plus audit in one transaction.
|
||||
- This bounded slice intentionally excludes account creation, password handling, platform tenant-ignore operations, education profile duplication, and supervision relationships.
|
||||
|
||||
## Role and permission semantics
|
||||
|
||||
- `STUDENT` and `TEACHER` are Education relationship labels only; they do not grant System RBAC permissions or authorize administrative endpoints.
|
||||
- Tenant administrators act through explicit System permissions (`education:class:*` and `education:class-invitation:*`).
|
||||
- A Member principal may only accept an invitation addressed to their own member user ID; accepting a `STUDENT` or `TEACHER` invitation creates that relationship but no additional API authority in this bounded slice.
|
||||
- Future teacher actions require a separate permission matrix and endpoints; no implicit role-based elevation is implemented.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [x] Generic account, password, token, tenant, and role tables are not duplicated.
|
||||
|
||||
@@ -40,15 +40,21 @@ Education may own only domain bindings and fulfillment orchestration, such as:
|
||||
- entitlement scope and education-resource association;
|
||||
- duplicate-safe fulfillment event state where no platform facility exists.
|
||||
|
||||
## Deferred automatic integrations
|
||||
|
||||
Automatic fulfillment from Mall paid/refunded order-item events and CRM referral/commission processing remains blocked because those public events/contracts are not available in the current reactor. The delivered admin endpoint and `EducationEntitlementApi` are trusted ingestion seams; they do not imply that Pay callbacks or Mall orders currently fan out automatically.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [x] Mall/Pay/Member/CRM public contracts are mapped before implementation.
|
||||
- [x] Payment callbacks and refunds remain in Pay.
|
||||
- [x] Payment callbacks and refunds remain in Pay; no automatic fan-out is claimed.
|
||||
- [x] Generic products/orders remain in Mall where applicable.
|
||||
- [x] Entitlement issuance, revocation, expiry, and refund effects are explicit and idempotent.
|
||||
- [x] Entitlement issuance, revocation, expiry, and refund effects are explicit and idempotent through the trusted ingestion seams.
|
||||
- [x] Paid/private practice remains inaccessible until entitlement checks are complete.
|
||||
- [x] Reconciliation and commission/referral ownership is explicit.
|
||||
- [x] Financial and authorization tests cover duplicate callbacks and cross-tenant access.
|
||||
- [x] Reconciliation and commission/referral ownership is explicit; automatic CRM integration remains deferred.
|
||||
- [x] Financial and authorization tests cover duplicate trusted events and cross-tenant access.
|
||||
- [x] Automatic Mall paid/refunded order-item fulfillment is explicitly unsupported until a Mall-owned public event exists; paid access remains fail-closed.
|
||||
- [x] Automatic CRM referral/commission processing is explicitly unsupported until a CRM-owned public contract exists; no financial or referral behavior is simulated in Education.
|
||||
|
||||
## Risk and rollback
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ Student identity and tenant are always derived from the authenticated context; n
|
||||
|
||||
- All Education state is tenant-owned and uses explicit tenant/user predicates in addition to framework interception.
|
||||
- Client requests cannot choose point values, badge codes, notify templates, delivery users, or leaderboard tenant.
|
||||
- Exam reminder delivery uses a token-fenced, expiring database claim. An interrupted `SENDING` row is reclaimed after lease expiry, attempts are bounded, and exhausted claims become observable `FAILED` rows through V4200.
|
||||
- Award rows and reminder rows are durable retry authorities; cross-module tables are never written directly by Education application code.
|
||||
- Leaderboard output uses deterministic tenant-local aliases and aggregate score only. No phone, profile, member ID, answer, explanation, feedback content, or report detail is exported.
|
||||
- Rollback disables/removes executable application paths while retaining V4160 data. Destructive rollback is not provided; later correction uses a higher forward migration.
|
||||
|
||||
@@ -31,13 +31,13 @@ Production migration and deployment evidence remain release activities and are n
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] Every temporary legacy dependency has an owner, telemetry, failure policy, and exit date.
|
||||
- [ ] At-least-once consumers are duplicate-safe.
|
||||
- [ ] Job retries/dead letters and scanner health are observable.
|
||||
- [ ] PostgreSQL migrations are actually executed and validated in an authorized environment.
|
||||
- [ ] Student and selected admin E2E flows pass against the target only.
|
||||
- [ ] Runbooks contain no active MySQL/manual-SQL or obsolete NestJS startup requirement.
|
||||
- [ ] Rollback and incident procedures are documented.
|
||||
- [x] Every configured temporary legacy dependency exposes owner, telemetry, failure policy, and exit date; invalid selected Scalar configuration reports DOWN.
|
||||
- [x] Implemented at-least-once import and reminder consumers use duplicate-safe keys or token-fenced leases with bounded recovery.
|
||||
- [x] Job retries/dead letters and scanner/component health have durable persistence and an admin health projection; undeployed components are not fabricated as UP.
|
||||
- [x] Module-owned migrations V4010–V4200 execute and validate in isolated disposable PostgreSQL test schemas; shared Pilot/production execution remains a release-evidence activity.
|
||||
- [x] The fixture-based Student harness passes target API contract/browser flows; a real deployed Student Web/H5 application remains outside this repository and is explicitly not claimed.
|
||||
- [x] Runbooks contain no active MySQL/manual-SQL or obsolete NestJS startup requirement.
|
||||
- [x] Rollback and incident procedures are documented in the Pilot acceptance runbook.
|
||||
|
||||
## Verification
|
||||
|
||||
|
||||
@@ -37,23 +37,25 @@ EDU-000 Phase 0 artifacts done
|
||||
|
||||
EDU-009 + provider/content decisions
|
||||
└── EDU-010 Tenant content publication done (bounded JAVA_READ publication scope delivered)
|
||||
└── EDU-011 Import/export/assets/scanning blocked; contract disposition exposed by capability manifest
|
||||
└── EDU-011 Import/export/assets/scanning bounded capability delivered; production adapters/export artifacts deferred
|
||||
|
||||
EDU-004
|
||||
└── EDU-012 Classes and education relationships blocked; contract disposition exposed by capability manifest
|
||||
└── EDU-012 Classes and education relationships implemented (bounded class/invitation capability)
|
||||
|
||||
Commerce ownership decisions
|
||||
└── EDU-013 Education commercialization product decision required; fail-closed disposition exposed
|
||||
└── EDU-013 Education commercialization bounded entitlement/binding capability implemented; platform events deferred
|
||||
|
||||
All owner/contract decisions
|
||||
└── EDU-014 Extended learning waves product decision required; family decomposition remains
|
||||
└── EDU-015 Operational independence legacy-dependent under SCALAR_READ; target-only proof remains
|
||||
└── EDU-014 Extended learning waves bounded representative wave delivered; blocked families explicitly deferred
|
||||
└── EDU-015 Operational independence contracts implemented; release/deployment evidence remains
|
||||
```
|
||||
|
||||
## Recommended execution order
|
||||
|
||||
1. **EDU-010** — Continue with the provider-consistent question publication lifecycle; V4070 graph integrity is delivered.
|
||||
2. Continue through EDU-011/EDU-012 as their blockers clear.
|
||||
1. Complete production release evidence for **EDU-015** using the Pilot runbook and target-only `JAVA_READ` deployment.
|
||||
2. Add deferred EDU-011 scanner/parser/export adapters only when their owning platform contracts and deployment are available.
|
||||
3. Add automatic EDU-013 fulfillment only after Mall/Pay/CRM expose the recorded public events; keep manual trusted fulfillment and access fail-closed meanwhile.
|
||||
4. Select the next EDU-014 family only after its entitlement, privacy, and owner decisions are recorded.
|
||||
|
||||
## Phase 0 completion caveat
|
||||
|
||||
|
||||
@@ -30,13 +30,15 @@ yudao:
|
||||
## 3. 发布步骤
|
||||
|
||||
1. 备份 Education 相关表,并记录应用版本与 `flyway_schema_history`。
|
||||
2. 使用 Server 配置的 PostgreSQL Flyway 执行 migrate 和 validate,检查版本、脚本、checksum 与 success;不得手工应用 Education SQL 或执行 rollback SQL。
|
||||
3. 先以 `catalog-read-enabled=false`、`practice-write-enabled=false` 部署应用。
|
||||
4. 验证 System、Infra、Member 基础 smoke。
|
||||
5. 仅对 Pilot 租户开启题库读取,完成 JAVA_READ 只读 smoke,并运行 `tools/education-target-smoke/java-read-readiness.sh`。
|
||||
6. 对 Pilot 租户开启练习写入,完成会话、答案、交卷、报告、错题和收藏 smoke。
|
||||
7. 若部署 Worker 或 Scanner,先确认其持续写入 `education_operational_component`,且 `/admin-api/education/operations/health` 无 `DOWN` 组件和未处理死信。
|
||||
8. 观察错误率、延迟和数据库写入后再扩大租户列表。
|
||||
2. 由数据库管理员预置彼此独立的 Flyway owner LOGIN role 与 runtime LOGIN role。Flyway role 拥有目标 schema;runtime role 只获得业务表所需权限,且不得拥有、继承所有者角色或写入 `education_question_lifecycle_transition_token`、`education_content_node_lifecycle_transition_token`、`education_question_collection_lifecycle_transition_token`、`education_question_collection_membership_token`。角色/密码不由 migration 创建。
|
||||
3. 显式注入 `FLYWAY_USER`、`FLYWAY_PASSWORD`(不得回退到 master datasource 账号),使用 Server 配置的 PostgreSQL Flyway 执行 migrate 和 validate,检查版本、脚本、checksum、success 以及四张 token 表 owner 均为 Flyway role。
|
||||
4. 以 runtime datasource 账号验证四张 token 表均无 INSERT/UPDATE/DELETE/TRUNCATE,随后启动应用;同角色、继承 owner 或可写授权会导致 Education 启动检查 fail closed。
|
||||
5. 先以 `catalog-read-enabled=false`、`practice-write-enabled=false` 部署应用。
|
||||
6. 验证 System、Infra、Member 基础 smoke。
|
||||
7. 仅对 Pilot 租户开启题库读取,完成 JAVA_READ 只读 smoke,并运行 `tools/education-target-smoke/java-read-readiness.sh`。
|
||||
8. 对 Pilot 租户开启练习写入,完成会话、答案、交卷、报告、错题和收藏 smoke。
|
||||
9. 若部署 Worker 或 Scanner,先确认其持续写入 `education_operational_component`,且 `/admin-api/education/operations/health` 无 `DOWN` 组件和未处理死信。
|
||||
10. 观察错误率、延迟和数据库写入后再扩大租户列表。
|
||||
|
||||
## 4. Smoke 清单
|
||||
|
||||
|
||||
Reference in New Issue
Block a user