PocketBase crash-loopt sinds SSO-deploy: migratie-replay botst met bestaande Labs-database — Microsoft-login onbruikbaar #18

Closed
opened 2026-07-11 08:46:21 +00:00 by rve · 0 comments
Owner

Symptomen

  • Sinds de deploy van de Azure SSO-feature (PR #17) is PocketBase op de live omgeving (Labs, learning-platform.labs.respellion.tech) down: de container crash-loopt en reageert nergens op. Elke /api/* call geeft 502 ("Backend unavailable").
  • Klikken op "Sign in with Microsoft" geeft een serverfout (de frontend kan auth-methods / authWithOAuth2 niet bereiken).

Root cause (primair) — migratie-replay tegen een bestaande database

Vóór PR #17 draaide PocketBase op de server zonder --migrationsDir:

# infra/development/site/compose.yml (vóór 3af105b)
command: ["serve", "--http=0.0.0.0:8090", "--dir=/pb/pb_data"]

De collections op de server zijn destijds out-of-band aangemaakt (via scripts/setup-pb-collections.mjs / admin UI), dus de _migrations-ledger in pb_data is leeg — PocketBase heeft daar nooit een migratie gedraaid.

PR #17 (3af105b) voegde voor het eerst de mount + flag toe:

command: ["serve", ..., "--migrationsDir=/pb/pb_migrations", "--hooksDir=/pb/pb_hooks"]
volumes:
  - ./pb_migrations:/pb/pb_migrations

Bij de eerstvolgende start probeert PocketBase daardoor de volledige historie (±80 migratiebestanden) opnieuw af te spelen tegen een database die dat schema al heeft. De allereerste migratie faalt al:

pocketbase-learning   ... Restarting (0) Less than a second ago
Error: failed to apply migration 1778948471_created_content.js:
  id: The model id is invalid or already exists.;
  name: Collection name must be unique (case insensitive)..

(bron: TEMP DIAGNOSTIC-stap in Gitea Actions run #86, 2026-07-02 — live containerlogs van de server)

Een gefaalde migratie abort pocketbase serverestart: unless-stoppedoneindige crash-loop sinds 24 juni (run #83, deploy van fab7a12). Caddy geeft 502 op alle /api/*.

Waarom de eerdere fixes niet hielpen

d519107 (relation-velden verwijderen/terugzetten) en 89d3395 (OAuth2 conditioneel bij ontbrekende env) repareren allebei 1781000000_team_members_to_auth.js — maar de server komt daar nooit aan: hij sneuvelt al op het eerste bestand. De ENTRA_* secrets staan overigens sinds 24-06 13:55Z correct in Gitea (vóór de eerste deploy), dus ontbrekende secrets waren níet de oorzaak van de outage.

Secundaire defecten (lokaal gereproduceerd/geverifieerd)

  1. De as-merged migratie crasht óók op elke database mét data. Lokaal gereproduceerd (PocketBase v0.30.4, fab7a12-versie, verse DB met volledige migratieketen):

    CAUGHT#1 GoError: [team_members] failed to delete due to existing relation references: micro_learning_completions, theme_session_completions
    Error: failed to apply migration 1781000000_team_members_to_auth.js: name: Collection name must be unique (case insensitive).; oauth2: (providers: (0: (clientId: cannot be blank; clientSecret: cannot be blank.).).).
    

    De try/catch (_) {} slikt de delete-fout in, waarna de create faalt. Dit is op main deels gefixt (d519107), maar destructief: veld verwijderen + terugzetten gooit de team_member_id-kolomdata weg. De niet-gemergde branch fix/issue-16-azure-pb-crash (2628041) lost dit netter op (relation → text-conversie, data blijft staan) maar is nooit gemerged.

  2. Env-afhankelijke one-shot migratie ("de trap"). Migraties draaien exact één keer. Als 1781000000 een keer applied wordt terwijl ENTRA_CLIENT_ID/SECRET leeg zijn (89d3395-gedrag), wordt de collection permanent zonder OAuth2-provider aangemaakt; secrets later toevoegen doet dan niets meer. Provider-configuratie hoort niet in een one-shot migratie thuis maar in een idempotente reconciliatie bij elke start (pb_hook onBootstrap).

  3. Silent error swallowing (catch (_) {}) maskeerde de echte fout twee weken lang.

  4. Geen health-gate in de deploy: run #83 t/m #88 zijn allemaal "success" terwijl PocketBase crash-loopt. De playbooks checken alleen docker compose up, niet of PB gezond opkomt.

  5. docker-compose.yml (root) vereist nu .env.local (env_file zonder required: false, d519107): lokale compose-start faalt hard als dat bestand ontbreekt.

  6. (Minor) Twee migraties delen prefix 1781000000 (created_theme_sessions, team_members_to_auth) — werkt nu (lexicografisch), maar fragiel.

Voorgestelde fix

  1. Baseline ledger-sync migratie (sorteert vóór alles, bv. 1000000000_baseline_ledger_sync.js): detecteert een out-of-band-geprovisioned DB (schema bestaat, ledger leeg) en schrijft de historische migratiebestanden als "applied" in _migrations, zodat de replay overgeslagen wordt en de keten doorloopt naar de echte nieuwe migraties. Concept lokaal bewezen: de runner checkt de ledger per bestand, dus dit werkt binnen één boot. Op verse DB's en bestaande dev-DB's is dit een no-op.
  2. 1781000000_team_members_to_auth.js robuust maken op basis van branch fix/issue-16-azure-pb-crash (2628041): relation-velden → text-conversie (geen dataverlies, unieke index herbouwd), idempotent (skip als team_members al auth is), geen silent catches, provider alleen koppelen als env aanwezig.
  3. OIDC-provider reconciliatie in pb_hooks (onBootstrap): bij elke start de OAuth2-config van team_members bijwerken vanuit ENTRA_* env (idempotent). Heelt ook omgevingen waar de migratie al zonder secrets applied is.
  4. Health-gate in beide deploy-playbooks: na docker compose up wachten tot PocketBase healthy is (health-endpoint/containerstatus), anders faalt de deploy zichtbaar in CI.
  5. docker-compose.yml: env_file optioneel maken (required: false).

Verificatie (Definition of Done)

  • Verse DB, zonder ENTRA-env → PB boot, WARN, geen provider (geen crash)
  • Verse DB, mét ENTRA-env → PB boot, auth-methods toont Microsoft/OIDC
  • Server-scenario: DB geprovisioned zonder ledger (setup-script) + data in completions → PB boot, ledger gesynct, team_members = auth-collection, provider actief, team_member_id-data behouden
  • Bestaande lokale dev-DB (ledger wél gevuld) → no-op, boot schoon
  • Migratie al applied zonder secrets → hook zet provider alsnog aan bij eerstvolgende start mét secrets
  • Deploy-pipeline faalt zichtbaar als PB niet healthy wordt
  • E2E op Labs: login met Microsoft werkt door de perimeter-gate heen (popup + /api/oauth2-redirect + realtime)

Omgevingen

  • Labs (de facto productie voor gebruikers): down sinds 24-06 — dit issue.
  • Production (infra/production): Deploy to Production is nog nooit uitgevoerd (0 runs). Bij een eerste échte prod-deploy geldt: lege pb_data → keten applied schoon; bestaande out-of-band DB → zelfde fix dekt het af.

Referenties

  • Crash-bewijs: Gitea Actions run #86 (task 1211), TEMP DIAGNOSTIC-stap (ad88f06, branch fix-sso)
  • Eerste kapotte deploy: run #83 (fab7a12, 2026-06-24T14:07Z)
  • Laatste deploy (nog steeds kapot): run #88 (89d3395, 2026-07-11T08:23Z)
  • Gerelateerd: #16 (feature), PR #17, niet-gemergde branch fix/issue-16-azure-pb-crash (ed1b1eb, 2628041)
## Symptomen - Sinds de deploy van de Azure SSO-feature (PR #17) is PocketBase op de live omgeving (Labs, `learning-platform.labs.respellion.tech`) **down**: de container crash-loopt en reageert nergens op. Elke `/api/*` call geeft 502 ("Backend unavailable"). - Klikken op **"Sign in with Microsoft"** geeft een serverfout (de frontend kan `auth-methods` / `authWithOAuth2` niet bereiken). ## Root cause (primair) — migratie-replay tegen een bestaande database Vóór PR #17 draaide PocketBase op de server **zonder** `--migrationsDir`: ```yaml # infra/development/site/compose.yml (vóór 3af105b) command: ["serve", "--http=0.0.0.0:8090", "--dir=/pb/pb_data"] ``` De collections op de server zijn destijds **out-of-band** aangemaakt (via `scripts/setup-pb-collections.mjs` / admin UI), dus de `_migrations`-ledger in `pb_data` is **leeg** — PocketBase heeft daar nooit een migratie gedraaid. PR #17 (3af105b) voegde voor het eerst de mount + flag toe: ```yaml command: ["serve", ..., "--migrationsDir=/pb/pb_migrations", "--hooksDir=/pb/pb_hooks"] volumes: - ./pb_migrations:/pb/pb_migrations ``` Bij de eerstvolgende start probeert PocketBase daardoor **de volledige historie (±80 migratiebestanden) opnieuw af te spelen** tegen een database die dat schema al heeft. De allereerste migratie faalt al: ``` pocketbase-learning ... Restarting (0) Less than a second ago Error: failed to apply migration 1778948471_created_content.js: id: The model id is invalid or already exists.; name: Collection name must be unique (case insensitive).. ``` *(bron: TEMP DIAGNOSTIC-stap in Gitea Actions run #86, 2026-07-02 — live containerlogs van de server)* Een gefaalde migratie abort `pocketbase serve` → `restart: unless-stopped` → **oneindige crash-loop sinds 24 juni (run #83, deploy van fab7a12)**. Caddy geeft 502 op alle `/api/*`. ### Waarom de eerdere fixes niet hielpen `d519107` (relation-velden verwijderen/terugzetten) en `89d3395` (OAuth2 conditioneel bij ontbrekende env) repareren allebei `1781000000_team_members_to_auth.js` — maar **de server komt daar nooit aan**: hij sneuvelt al op het eerste bestand. De ENTRA_* secrets staan overigens sinds 24-06 13:55Z correct in Gitea (vóór de eerste deploy), dus ontbrekende secrets waren níet de oorzaak van de outage. ## Secundaire defecten (lokaal gereproduceerd/geverifieerd) 1. **De as-merged migratie crasht óók op elke database mét data.** Lokaal gereproduceerd (PocketBase v0.30.4, fab7a12-versie, verse DB met volledige migratieketen): ``` CAUGHT#1 GoError: [team_members] failed to delete due to existing relation references: micro_learning_completions, theme_session_completions Error: failed to apply migration 1781000000_team_members_to_auth.js: name: Collection name must be unique (case insensitive).; oauth2: (providers: (0: (clientId: cannot be blank; clientSecret: cannot be blank.).).). ``` De `try/catch (_) {}` slikt de delete-fout in, waarna de create faalt. Dit is op main deels gefixt (d519107), maar **destructief**: veld verwijderen + terugzetten gooit de `team_member_id`-kolomdata weg. De niet-gemergde branch `fix/issue-16-azure-pb-crash` (2628041) lost dit netter op (relation → text-conversie, data blijft staan) maar is nooit gemerged. 2. **Env-afhankelijke one-shot migratie ("de trap").** Migraties draaien exact één keer. Als `1781000000` een keer applied wordt terwijl `ENTRA_CLIENT_ID/SECRET` leeg zijn (89d3395-gedrag), wordt de collection **permanent zonder OAuth2-provider** aangemaakt; secrets later toevoegen doet dan niets meer. Provider-configuratie hoort niet in een one-shot migratie thuis maar in een idempotente reconciliatie bij elke start (pb_hook `onBootstrap`). 3. **Silent error swallowing** (`catch (_) {}`) maskeerde de echte fout twee weken lang. 4. **Geen health-gate in de deploy**: run #83 t/m #88 zijn allemaal "success" terwijl PocketBase crash-loopt. De playbooks checken alleen `docker compose up`, niet of PB gezond opkomt. 5. **`docker-compose.yml` (root) vereist nu `.env.local`** (`env_file` zonder `required: false`, d519107): lokale compose-start faalt hard als dat bestand ontbreekt. 6. *(Minor)* Twee migraties delen prefix `1781000000` (`created_theme_sessions`, `team_members_to_auth`) — werkt nu (lexicografisch), maar fragiel. ## Voorgestelde fix 1. **Baseline ledger-sync migratie** (sorteert vóór alles, bv. `1000000000_baseline_ledger_sync.js`): detecteert een out-of-band-geprovisioned DB (schema bestaat, ledger leeg) en schrijft de historische migratiebestanden als "applied" in `_migrations`, zodat de replay overgeslagen wordt en de keten doorloopt naar de echte nieuwe migraties. *Concept lokaal bewezen: de runner checkt de ledger per bestand, dus dit werkt binnen één boot.* Op verse DB's en bestaande dev-DB's is dit een no-op. 2. **`1781000000_team_members_to_auth.js` robuust maken** op basis van branch `fix/issue-16-azure-pb-crash` (2628041): relation-velden → text-conversie (geen dataverlies, unieke index herbouwd), idempotent (skip als `team_members` al auth is), geen silent catches, provider alleen koppelen als env aanwezig. 3. **OIDC-provider reconciliatie in `pb_hooks`** (`onBootstrap`): bij elke start de OAuth2-config van `team_members` bijwerken vanuit `ENTRA_*` env (idempotent). Heelt ook omgevingen waar de migratie al zonder secrets applied is. 4. **Health-gate in beide deploy-playbooks**: na `docker compose up` wachten tot PocketBase healthy is (health-endpoint/containerstatus), anders faalt de deploy zichtbaar in CI. 5. **`docker-compose.yml`**: `env_file` optioneel maken (`required: false`). ## Verificatie (Definition of Done) - [ ] Verse DB, zonder ENTRA-env → PB boot, WARN, geen provider (geen crash) - [ ] Verse DB, mét ENTRA-env → PB boot, `auth-methods` toont Microsoft/OIDC - [ ] **Server-scenario**: DB geprovisioned zonder ledger (setup-script) + data in completions → PB boot, ledger gesynct, `team_members` = auth-collection, provider actief, `team_member_id`-data behouden - [ ] Bestaande lokale dev-DB (ledger wél gevuld) → no-op, boot schoon - [ ] Migratie al applied zonder secrets → hook zet provider alsnog aan bij eerstvolgende start mét secrets - [ ] Deploy-pipeline faalt zichtbaar als PB niet healthy wordt - [ ] E2E op Labs: login met Microsoft werkt door de perimeter-gate heen (popup + `/api/oauth2-redirect` + realtime) ## Omgevingen - **Labs (de facto productie voor gebruikers): down sinds 24-06** — dit issue. - **Production (`infra/production`)**: `Deploy to Production` is nog nooit uitgevoerd (0 runs). Bij een eerste échte prod-deploy geldt: lege `pb_data` → keten applied schoon; bestaande out-of-band DB → zelfde fix dekt het af. ## Referenties - Crash-bewijs: Gitea Actions run #86 (task 1211), TEMP DIAGNOSTIC-stap (ad88f06, branch `fix-sso`) - Eerste kapotte deploy: run #83 (fab7a12, 2026-06-24T14:07Z) - Laatste deploy (nog steeds kapot): run #88 (89d3395, 2026-07-11T08:23Z) - Gerelateerd: #16 (feature), PR #17, niet-gemergde branch `fix/issue-16-azure-pb-crash` (ed1b1eb, 2628041)
rve closed this issue 2026-07-11 11:54:38 +00:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rve/learning-platform#18