refactor(db): migrate Identity schema

Complete schema ownership by moving all ASP.NET Identity tables to an additive provider-aware migration. Preserve credentials, security state, preferences, roles, claims, external logins, tokens, indexes, and cascades.
This commit is contained in:
cesnimda
2026-08-30 22:02:35 +02:00
parent 90ca23de33
commit 058d13de47
10 changed files with 311 additions and 261 deletions
+1 -1
View File
@@ -558,7 +558,7 @@ SEC-008 implements the same durable state machine with `<final>.uploading` and `
### P3-1 — Reduce dual schema ownership incrementally
**Status (2026-08-30): in progress.** All 49 model tables now have an executable, disjoint creation-owner classification. Twenty-eight formerly reconciler-created tables—including authentication support, email-provider connections, CV persistence/history, job-workspace AI notes, append-only AI interactions, workflow checklists, cover-letter history, durable interview preparation, and the complete Career Profile aggregate—have moved through additive provider-aware migrations with legacy-row preservation, downgrade/retry safety, startup-DDL removal, fresh SQLite runtime proof and generated MariaDB SQL. The Gmail decision migration also closes its missing MariaDB creation path. Only the seven ASP.NET Identity tables remain startup-created; see `docs/verification/jt-019-schema-ownership.md` and V-194V-207.
**Status (2026-08-30): complete.** All 49 model tables have an executable, disjoint creation-owner classification and are migration-owned. All 35 formerly startup-created tables—including authentication/Identity, email-provider connections, CV persistence/history, job-workspace AI notes, workflow documents, durable interview preparation, and the complete Career Profile aggregate—moved through additive provider-aware migrations with legacy-row preservation, downgrade/retry safety, startup-DDL removal, fresh SQLite chain proof, and generated MariaDB SQL. The reconciler now performs guarded compatibility repair only. See `docs/verification/jt-019-schema-ownership.md` and V-194V-208.
- **Findings/scope:** JT-019; inventory reconciler operations and move stable schema ownership to EF migrations in small steps.
- **Dependencies:** provider upgrade fixtures and P2-2 restore safety.
+1
View File
@@ -239,3 +239,4 @@ Output was reduced to filenames and commit counts. The token artifact appears un
| V-205 | Ownership/migration chain; populated adoption/downgrade/retry; document/FK/index assertions; MariaDB script; full backend | Repository root / disposable local SQLite | Move append-only cover-letter revision history to migration ownership without losing recoverable documents | PASS — focused ownership/migration 17/17; manual and AI revisions plus source/action metadata survive adoption, downgrade and re-upgrade; owner/job/version index exists; deleting the parent application cascades through history; generated MariaDB SQL is provider-safe; startup no longer creates the table; full backend 733/733 | MariaDB SQL generated only; no provider account or production migration. Guarded malformed-empty/index/auto-increment repair remains temporarily. Sixteen reconciler-owned tables remain | JT-019 cover-letter history transfer complete; interview-preparation items and career-profile aggregate continue incrementally |
| V-206 | Ownership/migration chain; populated adoption/downgrade/retry; practice-state/FK/index assertions; MariaDB script; full backend | Repository root / disposable local SQLite | Move durable interview-preparation items to migration ownership without losing user or AI preparation content | PASS — focused ownership/migration 18/18; user-authored and AI-generated questions, answers, prepared state and source metadata survive adoption, downgrade and re-upgrade; owner/job/sort index exists; deleting the parent application cascades through preparation items; generated MariaDB SQL is provider-safe; startup no longer creates the table; full backend 734/734 | MariaDB SQL generated only; no provider account or production migration. Guarded malformed-empty/index/auto-increment repair remains temporarily. Fifteen reconciler-owned tables remain | JT-019 feature-table transfers complete; the Career Profile aggregate and Identity group remain dependency-aware batches |
| V-207 | Ownership/migration chain; populated aggregate adoption/downgrade/retry; JSON/text/FK/index assertions; MariaDB script; full backend | Repository root / disposable local SQLite | Move the canonical Career Profile, append-only history, and six relational child types to migration ownership without losing career data | PASS — focused ownership/migration 19/19; canonical and long-tail JSON, Norwegian text, version history, experience, education, skill, project, certification and language rows survive adoption, downgrade and re-upgrade; all 14 aggregate indexes exist; deleting the profile cascades through history and children; generated MariaDB SQL uses bounded indexed keys and provider-safe types; startup creates none of the eight tables; full backend 735/735 | MariaDB SQL generated only; no production migration. Guarded historical LongTailJson/index/auto-increment repairs remain temporarily. Seven reconciler-owned Identity tables remain | JT-019 feature and career transfers complete; isolate the Identity ownership boundary next |
| V-208 | Ownership/migration chain; populated Identity adoption/downgrade/retry; credential/preference/FK/index assertions; MariaDB script; full backend; fresh application startup | Repository root / disposable local SQLite | Complete JT-019 by moving the seven ASP.NET Identity tables to migration ownership without invalidating authentication data | PASS — focused ownership/migration 20/20; password hash, Bokmål preference, 2FA state, role assignment, role/user claims, external login and token survive adoption, downgrade and re-upgrade; all eight Identity indexes exist; user and role deletion cascades remain effective; generated MariaDB SQL is provider-safe; startup creates no model tables; full backend 736/736; a fresh application applies the complete chain, reaches Identity role initialization and listens normally | MariaDB SQL generated only; no production migration. The historical AspNetUsers compatibility bootstrap and guarded column/index repairs remain for chain traversal and legacy upgrades. Launch settings supplied an existing policy-invalid development admin password, producing a non-fatal seed warning | JT-019 complete; future work may retire individual repair statements only after provider-backed historical fixtures prove them redundant |
+11 -10
View File
@@ -65,7 +65,8 @@ already-correct database. Two consequences worth knowing:
Created by EF migrations, never by the reconciler:
`AccountDeletionFiles`, `AccountDeletionRequests`, `AiInteractions`, `AiUsageRecords`, `AiWorkspaceNotes`,
`ApplicationChecklistItems`, `Attachments`, `CareerCertifications`, `CareerEducations`,
`ApplicationChecklistItems`, `AspNetRoleClaims`, `AspNetRoles`, `AspNetUserClaims`, `AspNetUserLogins`,
`AspNetUserRoles`, `AspNetUsers`, `AspNetUserTokens`, `Attachments`, `CareerCertifications`, `CareerEducations`,
`CareerExperiences`, `CareerLanguages`, `CareerProfiles`, `CareerProfileVersions`, `CareerProjects`,
`CareerSkills`, `Companies`, `CoverLetterVersions`,
`Correspondences`, `CvExtractionRuns`, `CvUploadArtifacts`, `CvVariants`, `CvVariantVersions`,
@@ -132,6 +133,11 @@ child tables) moved in `20260830133000_AdoptCareerProfileSchema`. Canonical/long
append-only history, stable child keys and ordering are retained; bounded MariaDB owner/item keys
keep all aggregate indexes provider-safe.
The ASP.NET Identity aggregate moved in `20260830134000_AdoptIdentitySchema`. Accounts, password
hashes, security/2FA state, UI preferences, roles, claims, external logins, tokens, indexes, and
cascades are retained. The earlier guarded `AspNetUsers` bootstrap remains only so historical
standalone migration traversal can reach later additive user-column migrations.
The reconciler may **repair** these (add a missing column, add an index, fix a non-`AUTO_INCREMENT`
primary key) and may seed the default `RuleSettings` row — but it must never `CREATE TABLE` them.
It used to create `RuleSettings`, which is precisely why a clean install failed with
@@ -139,12 +145,8 @@ It used to create `RuleSettings`, which is precisely why a clean install failed
### Reconciler-owned
The seven ASP.NET Identity tables are currently reconciler-owned, despite older wording that
called them migration-owned: `AspNetRoles`, `AspNetUsers`, `AspNetRoleClaims`, `AspNetUserClaims`,
`AspNetUserLogins`, `AspNetUserRoles`, and `AspNetUserTokens`. Guarded migration bootstraps for
`AspNetUsers` supports standalone traversal but does not yet transfer ownership. The historical
`AiInteractions` bootstrap remains in the migration chain, but its current owner is the later
provider-aware adoption migration.
None. The reconciler contains guarded historical repair logic, but it no longer creates EF model
tables. Compatibility bootstraps inside old migrations are chain prerequisites, not current owners.
`StartupSchemaOwnership` is the executable inventory. Its tests require every EF model table to
have exactly one creation owner and keep compatibility bootstraps out of the migration-owned set.
@@ -222,9 +224,8 @@ everything inside it.
Standalone EF tooling is also supported for a blank SQLite database. The historical initial
migration now supplies the stable JobApplication columns required by later SQLite rebuilds, and
guarded compatibility bootstraps provide the reconciler-owned source tables used by later additive
migrations. Application startup may subsequently reconcile the remaining Identity and auxiliary
tables without losing rows.
guarded compatibility bootstraps provide source tables used by later additive migrations.
Application startup may subsequently apply guarded historical column/index repairs without losing rows.
## Production upgrade
+11 -2
View File
@@ -44,6 +44,8 @@ cohesive table groups. It does not attempt to delete the legacy reconciler whole
- Added `20260830133000_AdoptCareerProfileSchema` for the canonical profile, append-only history,
and all six ordered relational child types. Legacy JSON, Norwegian text, stable keys, and cascade
ownership are retained.
- Added `20260830134000_AdoptIdentitySchema` for the complete ASP.NET Identity aggregate, preserving
accounts, password hashes, 2FA state, preferences, roles, claims, external logins, and tokens.
- Corrected the ownership runbook: new tables now default to migrations; the reconciler is legacy
compatibility code to retire one dependency group at a time.
@@ -87,14 +89,21 @@ migration.
- A populated Career Profile with history, long-tail JSON, Norwegian text, experience, education,
skills, projects, certifications, and languages survives adoption, downgrade, and re-upgrade; all
14 aggregate indexes and parent cascades remain effective.
- A populated Identity account with password hash, Bokmål preference, 2FA state, role assignment,
role/user claims, external login, and token survives adoption, downgrade, and re-upgrade; all eight
Identity indexes and user/role cascades remain effective.
- Generated MariaDB SQL contains the provider-correct `SystemEmailSettings` DDL.
- Full backend: 735/735 passed after the Career Profile aggregate transfer.
- Full backend: 736/736 passed after the Identity aggregate transfer.
- Fresh application startup over a new disposable SQLite data root applied the complete chain,
queried/seeded Identity roles, and reached the healthy listening state with no schema failure.
- Fresh application startup over a new disposable SQLite database applied
`20260830120000_AdoptSystemEmailSettingsSchema` and reached the healthy listening state.
## Remaining JT-019 work
Seven model tables remain startup-created: the ASP.NET Identity group.
No EF model tables remain startup-created. JT-019's creation-ownership transfer is complete; the
startup reconciler now performs compatibility repair only and can be reduced further when historical
provider fixtures prove individual repairs obsolete.
with parent dependencies. Transfer them in small dependency-aware migrations with blank, populated,
retry and MariaDB runtime proof. Column/index repairs must remain until historical upgrade fixtures
prove each one redundant.
+2 -1
View File
@@ -57,6 +57,7 @@ Updated: 2026-08-30
- Moved append-only cover-letter revision history into a provider-aware migration; manual and AI text, source/action metadata, ordering, and application cascades are preserved.
- Moved durable interview-preparation items into a provider-aware migration; user and AI content, answers, practice state, sources, ordering, and application cascades are preserved.
- Moved the complete Career Profile aggregate into a provider-aware migration; canonical and long-tail JSON, version history, all six relational child types, stable ordering, indexes, and cascades are preserved.
- Completed JT-019 by moving all seven ASP.NET Identity tables into provider-aware migration ownership; accounts, credentials, 2FA state, preferences, roles, claims, external logins, tokens, indexes, and cascades are preserved. Startup schema code is now repair-only.
### In progress
@@ -87,7 +88,7 @@ Updated: 2026-08-30
- Focused frontend: 2 suites, 6 tests passed.
- Full frontend: 64 suites, 272 tests passed.
- Next production build and TypeScript: passed.
- Full backend: 735/735 tests passed after the Career Profile aggregate JT-019 transfer.
- Full backend: 736/736 tests passed after completing the Identity/JT-019 ownership transfer.
- Portable Playwright launcher: resolved the user-local .NET 9 SDK; backend Release build passed with 0 warnings/errors.
- Playwright: initial full run 9/10 exposed the intentional mobile Settings control change; updated focused rerun passed 1/1. A final complete browser rerun remains in the end-of-batch gate.
- Focused backend match/intelligence verification: 34/34 passed.