Fix #18: migratie-ledger-sync + deploy-proof Azure SSO #19

Merged
rve merged 1 commits from fix/issue-18-migration-ledger-sso into main 2026-07-11 11:54:38 +00:00
Owner

Closes #18

Wat dit oplost

PocketBase op Labs crash-loopt sinds de SSO-deploy (24-06): PR #17 mountte voor het eerst --migrationsDir, waardoor de volledige migratie-historie werd afgespeeld tegen een database die out-of-band geprovisioned is (lege _migrations-ledger) — crash op het allereerste bestand, elke /api/* call 502, "Sign in with Microsoft" kapot. Zie de volledige analyse in #18.

De fix (5 onderdelen)

  1. 1000000000_baseline_ledger_sync.js — detecteert schema-zonder-ledger en markeert de 79 historische migraties als applied; no-op op verse/normale DB's.
  2. 1781000000_team_members_to_auth.js — idempotency-guard, relation→text mét databehoud (PocketBase difft velden op id → kolom wordt via SQL geback-upt en teruggezet), index-rebuild, geen silent catches.
  3. pb_hooks/entra_oidc.pb.js + utils.js — OIDC-provider wordt bij elke start + cron-minuut gereconcilieerd vanuit ENTRA_* env (compare-before-save, warn-once). Heelt ook een DB die zonder secrets migreerde; secret-rotatie = env wijzigen + herstart.
  4. Health-gate in beide deploy-playbooks — deploy faalt zichtbaar mét containerlogs als PB niet healthy wordt (runs #83–#88 waren "groen" terwijl PB down was). ⚠️ infra/ staat in PROTECTED.md; wijziging is expliciet gevraagd in issue #18.
  5. docker-compose.yml.env.local weer optioneel (⚠️ idem PROTECTED.md).

Plus: pb_hooks/team_members.pb.js naar het require()-patroon (JSVM draait callbacks geïsoleerd; neemt Leroy's fix van de fix-sso branch over) en documentatie (auth-spec ADR 006–008, AI_AGENT gotcha's).

Verificatie (DoD uit #18)

Lokaal tegen PocketBase v0.30.4, 7 scenario's / 15 asserts — 15/15 PASS:

Scenario Resultaat
S1 verse DB zonder env boot + WARN, geen provider
S2 verse DB met env boot + Microsoft-provider actief
S3 out-of-band DB mét data (= Labs) ledger-sync, auth-collection, provider actief, team_member_id behouden, reboot in-sync
S4 legacy dev-DB (ledger gevuld) baseline no-op, upgrade schoon
S5 migratie zonder secrets → env later provider door reconciler geactiveerd
S6 re-run guard skip, healthy, provider intact
S7 provisioning-hook (require-patroon) role=admin via allow-list, defaults gezet

npm test: 112/112. Lint: 1513 pre-existing problemen (app/-scaffolding), 0 nieuw.

Na de merge: deploy-dev draait automatisch; de nieuwe health-gate bewijst dat PB op Labs healthy wordt. Enige resterende handmatige check: eenmalig inloggen met een echt Microsoft-account door de perimeter heen (E2E-checkbox in #18).

🤖 Generated with Claude Code

Closes #18 ## Wat dit oplost PocketBase op Labs crash-loopt sinds de SSO-deploy (24-06): PR #17 mountte voor het eerst `--migrationsDir`, waardoor de volledige migratie-historie werd afgespeeld tegen een database die out-of-band geprovisioned is (lege `_migrations`-ledger) — crash op het allereerste bestand, elke `/api/*` call 502, "Sign in with Microsoft" kapot. Zie de volledige analyse in #18. ## De fix (5 onderdelen) 1. **`1000000000_baseline_ledger_sync.js`** — detecteert schema-zonder-ledger en markeert de 79 historische migraties als applied; no-op op verse/normale DB's. 2. **`1781000000_team_members_to_auth.js`** — idempotency-guard, relation→text mét databehoud (PocketBase difft velden op id → kolom wordt via SQL geback-upt en teruggezet), index-rebuild, geen silent catches. 3. **`pb_hooks/entra_oidc.pb.js` + `utils.js`** — OIDC-provider wordt bij elke start + cron-minuut gereconcilieerd vanuit `ENTRA_*` env (compare-before-save, warn-once). Heelt ook een DB die zonder secrets migreerde; secret-rotatie = env wijzigen + herstart. 4. **Health-gate in beide deploy-playbooks** — deploy faalt zichtbaar mét containerlogs als PB niet healthy wordt (runs #83–#88 waren "groen" terwijl PB down was). ⚠️ `infra/` staat in PROTECTED.md; wijziging is expliciet gevraagd in issue #18. 5. **`docker-compose.yml`** — `.env.local` weer optioneel (⚠️ idem PROTECTED.md). Plus: `pb_hooks/team_members.pb.js` naar het `require()`-patroon (JSVM draait callbacks geïsoleerd; neemt Leroy's fix van de `fix-sso` branch over) en documentatie (auth-spec ADR 006–008, AI_AGENT gotcha's). ## Verificatie (DoD uit #18) Lokaal tegen PocketBase v0.30.4, 7 scenario's / 15 asserts — **15/15 PASS**: | Scenario | Resultaat | |---|---| | S1 verse DB zonder env | boot + WARN, geen provider | | S2 verse DB met env | boot + Microsoft-provider actief | | S3 out-of-band DB mét data (= Labs) | ledger-sync, auth-collection, provider actief, `team_member_id` behouden, reboot in-sync | | S4 legacy dev-DB (ledger gevuld) | baseline no-op, upgrade schoon | | S5 migratie zonder secrets → env later | provider door reconciler geactiveerd | | S6 re-run guard | skip, healthy, provider intact | | S7 provisioning-hook (require-patroon) | role=admin via allow-list, defaults gezet | `npm test`: 112/112. Lint: 1513 pre-existing problemen (app/-scaffolding), 0 nieuw. **Na de merge**: deploy-dev draait automatisch; de nieuwe health-gate bewijst dat PB op Labs healthy wordt. Enige resterende handmatige check: eenmalig inloggen met een echt Microsoft-account door de perimeter heen (E2E-checkbox in #18). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
rve added 1 commit 2026-07-11 09:15:04 +00:00
fix: heal migration-ledger mismatch and make Azure SSO deploy-proof (#18)
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 39s
On Pull Request to Main / publish (pull_request) Successful in 1m9s
On Pull Request to Main / deploy-dev (pull_request) Successful in 3m1s
d79e69aad2
PocketBase on Labs crash-looped since the SSO deploy (PR #17): mounting
--migrationsDir for the first time replayed the entire migration history
against a database that was provisioned out-of-band (empty _migrations
ledger) and died on 1778948471_created_content.js. On top of that the
team_members->auth migration had its own crash paths and trapped OAuth2
config inside a one-shot, env-dependent migration.

- pb_migrations/1000000000_baseline_ledger_sync.js: detects an
  out-of-band provisioned DB (schema exists, ledger empty) and marks the
  79 historical migrations as applied; no-op on fresh or already-synced DBs
- pb_migrations/1781000000_team_members_to_auth.js: idempotency guard,
  relation->text conversion WITH data preservation (PocketBase diffs
  fields by id, so the column is backed up and restored via SQL), unique
  index rebuild, no silent catches, env only as fast-path
- pb_hooks/entra_oidc.pb.js + pb_hooks/utils.js: reconcile the Entra OIDC
  provider from ENTRA_* env on every bootstrap + cron tick
  (compare-before-save, warn-once); heals environments that migrated
  without secrets and supports secret rotation without re-apply
- pb_hooks/team_members.pb.js: require() pattern — JSVM runs callbacks as
  isolated programs, top-level helpers are not in scope (adopts Leroy's
  fix from the fix-sso branch)
- infra/*/site/deploy-playbook.yml: health-gate after compose up — the
  deploy fails loudly with container logs when PocketBase does not become
  healthy (runs #83-#88 were green while PB crash-looped)
- docker-compose.yml: .env.local is optional again
- docs/auth-spec.md + AI_AGENT.md: ledger/reconciler documentation, ADRs
  006-008, never-rename-applied-migrations warning

Verified locally against PocketBase v0.30.4 with a 7-scenario DoD matrix
(fresh DB +/- env, out-of-band DB with data incl. data preservation,
populated-ledger upgrade, late-secrets healing, re-run guard, hook
provisioning): 15/15 pass. npm test 112/112.

Closes #18

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
rve merged commit 1a1351ddcb into main 2026-07-11 11:54:38 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rve/learning-platform#19