161 lines
12 KiB
Markdown
161 lines
12 KiB
Markdown
# 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_session` and `education_practice_question`;
|
||
- `education_practice_report` and `education_practice_report_detail`;
|
||
- `education_wrong_question` and `education_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:
|
||
|
||
1. **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.
|
||
2. **V4040 — deterministic Education capability seed, only if still approved**
|
||
- Seed menu IDs `6800`/`6801` idempotently if the existing `EducationCapabilityController` remains 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.
|
||
3. **Later forward cleanup migration**
|
||
- Drop legacy `education_answer_idempotency` and `education_submit_idempotency` only after every adopted environment has verified backfill counts, the application no longer contains active references, and a separately reviewed forward cleanup is approved.
|
||
|
||
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.
|
||
|
||
1. **Empty or platform-only database, no Education tables**
|
||
- Use baseline `4009` only when the non-empty platform schema requires adoption.
|
||
- Run V4010, V4020, then V4030+ normally.
|
||
2. **Manual Practice tables exist, native catalog tables do not**
|
||
- Baseline `4009` may be used.
|
||
- V4020 creates catalog objects; V4030 validates/adopts Practice objects and performs required backfills.
|
||
3. **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.
|
||
4. **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.
|
||
5. **Unknown shared environment**
|
||
- No migration rollout is authorized until its Education tables and `flyway_schema_history` are inventoried.
|
||
|
||
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_idempotency` with deterministic operation values and `ON CONFLICT ... DO NOTHING` only 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 `JSONB` where current runtime/test behavior expects JSONB normalization.
|
||
- Tenant-scoped uniqueness includes `tenant_id` where the business key is tenant-local. `education_practice_report` uses `(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.md` MySQL apply/rollback commands with Flyway/PostgreSQL forward-only instructions;
|
||
- remove the manual Education SQL mounts from `script/docker/docker-compose.yml` so a fresh Docker database is not initialized outside Flyway before server startup;
|
||
- label `sql/postgresql/education/` and `sql/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:
|
||
|
||
```bash
|
||
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:
|
||
|
||
1. initialize a disposable platform database or approved baseline fixture;
|
||
2. run Flyway migrate using the server's exact migration locations and PostgreSQL driver;
|
||
3. run Flyway validate;
|
||
4. inspect `flyway_schema_history` with version, script, checksum, and success;
|
||
5. inspect all approved tables, columns, constraints, indexes, and backfill counts;
|
||
6. run the EDU-016 PostgreSQL persistence suite against the migrated schema;
|
||
7. 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
|
||
|
||
- [x] No published or potentially distributed migration is authorized for editing.
|
||
- [x] Every required table/index/constraint/seed has one intended Flyway owner and version range.
|
||
- [x] Manual SQL is not silently treated as executed history.
|
||
- [x] The plan includes migration packaging and real PostgreSQL execution evidence requirements.
|
||
- [x] 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 `postgresdb` container. Target identity was database `postgres`, user `postgres`, schema `public`; it contained no `flyway_schema_history` relation 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 clean` or destructive down scripts.
|