12 KiB
EDU-005 — Decide PostgreSQL/Flyway takeover strategy
- Status: done — forward-only takeover and EDU-006 version plan accepted
- Type: decision
- Phase: 1 / Phase 2 prerequisite
- Blockers: EDU-002
Decision outcome
Education schema ownership moves exclusively to module-owned PostgreSQL Flyway migrations under yudao-module-education/src/main/resources/db/migration/education/. The existing root sql/postgresql/education/ files are classified as manual bootstrap/design history, not Flyway history. The MySQL files are obsolete archival artifacts and must not remain in operational instructions.
V4010__initialize_education_flyway.sql and V4020__create_native_catalog.sql are uncommitted working-tree resources in this checkout, and the inspected local disposable PostgreSQL database has no flyway_schema_history table and no Education tables. This proves neither migration ran in that database, but it does not prove they never ran in another environment. To avoid assigning a second meaning to a potentially distributed version, EDU-006 must preserve both files byte-for-byte and allocate new work from V4030.
No migration or production schema change was executed by EDU-005.
Evidence and classification
| Artifact | Verified state | Classification | Forward disposition |
|---|---|---|---|
V4010__initialize_education_flyway.sql |
Untracked module resource; contains only SELECT 1; packaged in current target/classes |
Potentially distributed Flyway history; execution unverified | Freeze byte-for-byte; do not repurpose |
V4020__create_native_catalog.sql |
Untracked module resource; owns 11 native catalog tables; differs materially from manual 008 |
Potentially distributed Flyway history; execution unverified | Freeze byte-for-byte; do not replace with manual 008 |
sql/postgresql/education/002–005, 007, 009 |
Untracked manual scripts implementing the current Practice/report/wrong/favorite/unified-idempotency model in stages | Manual bootstrap/design history, not active Flyway | Consolidate the approved final state into higher Flyway versions; do not copy the obsolete intermediate tables as fresh schema |
sql/postgresql/education/008 |
Manual native-catalog design predating/diverging from V4020 | Superseded manual design | V4020 remains the only intended Flyway owner of native catalog schema |
sql/postgresql/education/000–001 |
Placeholder schema plus menu/tenant seed scripts | Manual bootstrap/seed history | Do not create a separate education schema; evaluate the still-used education:capability menu seed separately |
sql/mysql/education/** |
Historical MySQL schema, seeds, and rollback scripts | Obsolete archive | Remove from runbooks; retain only if explicitly labeled non-operational archive |
src/test/resources/sql/postgresql/create_tables.sql |
EDU-016 disposable test bridge; 140 PostgreSQL persistence tests passed against it | Temporary test fixture | Replace with Flyway-driven test setup after EDU-006 proves equivalent schema |
| Docker init mounts for manual Education SQL | Dirty Docker configuration mounts 000–009 directly |
Obsolete delivery path | Remove Education manual mounts after Flyway takeover; the server owns migration execution |
Approved schema owner map
V4020 owner — unchanged
V4020 exclusively owns the native catalog tables:
education_region,education_school,education_major,education_subject,education_category;education_content_entry,education_content_node;education_question_collection,education_question,education_practice_blueprint;education_question_collection_question.
EDU-006 does not fold Practice schema into V4020 and does not silently substitute manual 008.
EDU-006 new owner — Practice final state
The new Practice migration owns the final runtime shape of:
education_practice_sessionandeducation_practice_question;education_practice_reportandeducation_practice_report_detail;education_wrong_questionandeducation_wrong_question_idempotency;education_favorite;education_idempotency.
The approved fresh schema does not create education_answer_idempotency or education_submit_idempotency. Current production services use IdempotencyStoreMapper and education_idempotency; the old DOs/Mappers are unused compatibility residue and must be removed or explicitly isolated during EDU-006.
The migration must include all columns already required by runtime code and the proven EDU-016 bridge, including client_sequence, last_client_sequence, review_fingerprint, protected answer snapshots, report content snapshots, JSONB fields, tenant IDs, logical-delete fields, and observed conflict/query indexes.
Version plan for EDU-006
Version numbers are project-wide. With V4020 frozen, the next allocated version is:
- V4030 — Practice core-loop final schema and adoption
- Create the final tables, columns, constraints, and indexes listed above.
- Be adoption-aware for databases that contain manually bootstrapped Practice tables.
- Validate existing column types and required uniqueness before treating existing objects as compatible; fail closed on incompatible shapes rather than silently accepting them.
- Backfill the unified idempotency table from legacy answer/submit tables when those tables exist.
- Preserve old idempotency tables during the initial adoption migration; do not make data destruction a prerequisite for application rollout.
- V4040 — deterministic Education capability seed, only if still approved
- Seed menu IDs
6800/6801idempotently if the existingEducationCapabilityControllerremains an exposed administrator capability. - Keep role assignment outside the migration.
- If the capability endpoint/menu is retired before EDU-006, omit this migration rather than seeding dead UI.
- Seed menu IDs
- Later forward cleanup migration
- Drop legacy
education_answer_idempotencyandeducation_submit_idempotencyonly after every adopted environment has verified backfill counts, the application no longer contains active references, and a separately reviewed forward cleanup is approved.
- Drop legacy
If repository-wide migration inventory changes before implementation, EDU-006 must re-run the version scan and use the next unused project-wide version instead of blindly taking V4030/V4040.
Existing-environment takeover classes
baseline-on-migrate=true with baseline 4009 is an adoption aid, not proof that Education objects match Flyway.
- Empty or platform-only database, no Education tables
- Use baseline
4009only when the non-empty platform schema requires adoption. - Run V4010, V4020, then V4030+ normally.
- Use baseline
- Manual Practice tables exist, native catalog tables do not
- Baseline
4009may be used. - V4020 creates catalog objects; V4030 validates/adopts Practice objects and performs required backfills.
- Baseline
- Manual catalog tables equivalent to V4020 already exist, no Flyway history
- Do not run V4020 into colliding tables.
- First compare the actual schema with the frozen V4020 contract.
- For a verified equivalent environment, use a one-time environment-specific baseline at
4020, then run V4030+. This records adoption, not execution of V4020, and must be documented per environment. - If the schema is not equivalent, correct it through an explicit higher-version adoption path; do not falsify history or edit V4020.
- Flyway history already contains V4010 and/or V4020
- Compare script/checksum/success with the frozen resources.
- Never edit an executed script. Any mismatch or failed row blocks rollout until an environment-specific repair decision is reviewed.
- Unknown shared environment
- No migration rollout is authorized until its Education tables and
flyway_schema_historyare inventoried.
- No migration rollout is authorized until its Education tables and
After all existing environments carry an explicit baseline/history record, changing baseline-on-migrate to false is a separate reviewed configuration ticket. validate-on-migrate=true, clean-disabled=true, and out-of-order=false remain mandatory.
Data compatibility and backfill rules
- Copy legacy answer and submit idempotency rows into
education_idempotencywith deterministic operation values andON CONFLICT ... DO NOTHINGonly after verifying duplicate-key/request-hash compatibility. - Preserve original IDs only if required by references; otherwise allow identity allocation and verify semantic row counts by operation.
- Existing Practice tables must be compared with the final DO/Mapper contract, not merely checked for table-name existence.
- JSON snapshot fields use PostgreSQL
JSONBwhere current runtime/test behavior expects JSONB normalization. - Tenant-scoped uniqueness includes
tenant_idwhere the business key is tenant-local.education_practice_reportuses(tenant_id, session_id)as the final unique report key. - Do not copy Supabase RLS. Framework tenant isolation remains primary; database constraints enforce integrity and idempotency.
- No destructive rollback SQL is delivered. Recovery is application rollback plus a higher-version forward correction.
Documentation and operational corrections
EDU-006 must update operational documentation in the same slice:
- replace
yudao-module-education/README.mdMySQL apply/rollback commands with Flyway/PostgreSQL forward-only instructions; - remove the manual Education SQL mounts from
script/docker/docker-compose.ymlso a fresh Docker database is not initialized outside Flyway before server startup; - label
sql/postgresql/education/andsql/mysql/education/as non-operational history or move them to an explicitly archival location without rewriting history; - replace the EDU-016 temporary PostgreSQL schema bridge with Flyway-driven setup after equivalence is proven;
- state per environment whether Flyway was actually run, validated, or only packaged/compiled.
Required EDU-006 verification
Static and build gates:
git diff --check
mvn -pl yudao-module-education -am -DskipTests clean package
find yudao-module-education/target/classes/db/migration/education -type f -print
mvn -pl yudao-server -am -DskipTests clean compile
Real disposable PostgreSQL gate:
- initialize a disposable platform database or approved baseline fixture;
- run Flyway migrate using the server's exact migration locations and PostgreSQL driver;
- run Flyway validate;
- inspect
flyway_schema_historywith version, script, checksum, and success; - inspect all approved tables, columns, constraints, indexes, and backfill counts;
- run the EDU-016 PostgreSQL persistence suite against the migrated schema;
- test at least the empty/platform-only path and one representative manually bootstrapped adoption path.
Only these real successful executions may be reported as migration success.
Acceptance criteria
- No published or potentially distributed migration is authorized for editing.
- Every required table/index/constraint/seed has one intended Flyway owner and version range.
- Manual SQL is not silently treated as executed history.
- The plan includes migration packaging and real PostgreSQL execution evidence requirements.
- Documentation correction scope is explicit.
Verification performed by EDU-005
- Read project Flyway rules, local/dev Flyway configuration, server dependencies, all active migration locations, manual PostgreSQL/MySQL artifacts, core-loop DOs/Mappers, PostgreSQL test bridge, Docker initialization, Git history, and dirty-tree state.
- Inspected the reachable disposable
postgresdbcontainer. Target identity was databasepostgres, userpostgres, schemapublic; it contained noflyway_schema_historyrelation and no Education tables. Container startup logs state that/docker-entrypoint-initdb.d/*was ignored because the volume was already initialized. - Confirmed V4010/V4020 are currently packaged under
target/classes/db/migration/education/from a prior build. - Did not modify migration SQL, application code, server configuration, Docker configuration, or any database object.
- Did not run Flyway migrate/validate and does not claim a successful database migration.
Risk and rollback
- Risk: High. Existing manually initialized databases may have partially overlapping or divergent table shapes, and a false baseline can hide incompatibility.
- Rollback: No rollback is required for this decision-only ticket. EDU-006 uses forward migrations, preserves legacy idempotency tables during first adoption, and supports application rollback without
flyway cleanor destructive down scripts.