Files
Inboxintel/docs/discovery/multi-provider/12-migration-guide.md
T
cesnimda 4ce2df0a2b
CI / backend (push) Successful in 52s
CI / frontend (push) Successful in 14s
Deploy Staging / deploy (push) Successful in 18s
CI / backend (pull_request) Successful in 52s
CI / frontend (pull_request) Successful in 15s
Security / secrets (push) Successful in 4s
Security / dependencies (push) Successful in 55s
Security / secrets (pull_request) Successful in 4s
Security / dependencies (pull_request) Successful in 54s
docs: discovery blueprint + multi-provider design (#8)
2026-07-01 19:59:53 +02:00

3.3 KiB

12 — Migration Guide (Part 10)

Moving the current single-account Gmail app to the multi-provider, multi-user model — additive and reversible, no destructive step. Executed as ordered EF Core migrations + idempotent backfills, behind a short maintenance window.

Principles

  • Additive first: create new tables/columns before moving data; keep old columns until parity is verified.
  • Idempotent backfills: safe to re-run; keyed on stable ids.
  • Flag-gated cutover: the new sign-in/model activates behind flags; the old path stays until removed.
  • Reversible: each step has a documented rollback; no data is deleted during migration.

Step-by-step

  1. Schema (additive migration)
    • Create users, accounts, provider_tokens, sessions, user_settings, system_settings, feature_flags, audit_logs.
    • Add account_id, user_id (nullable) to the current email/thread tables; widen search_vector; add nullable embedding vector(768) + pgvector extension.
  2. Identity backfill
    • For the existing operator/user, create a users row; mark the first user = Admin.
    • Create one Google account per existing identity (is_login_identity=true); move current encrypted Gmail tokens → provider_tokens.
  3. Email backfill
    • Set account_id/user_id on all existing Email/thread rows to the default Google account.
    • Regenerate the widened search_vector; leave embedding null (backfilled later by the AI phase).
    • Enforce the new unique keys (account_id, provider_message_id) / (account_id, provider_thread_id).
  4. Config seed
    • Seed feature_flags: provider.google=on, provider.microsoft=off, provider.imap=off, ai.enabled = derived from the current Ai:Mode (Disabled→off), ai.*=off, maintenance.*=off.
    • Create system_settings singleton; create user_settings from any existing per-user prefs (else defaults).
  5. Cutover
    • Enable the new OAuth-as-login + unified sync behind their flags; verify on staging first (the pipeline we built), then production via a tagged release.
  6. Cleanup (later, separate migration)
    • Once parity is confirmed in production, drop obsolete columns/paths. Not part of the cutover.

Verification checklist

  • Existing user signs in via Google → lands on their mail unchanged.
  • Email counts match pre/post; search returns identical results for sample queries.
  • Tokens decrypt and refresh; sync resumes from the correct cursor.
  • No cross-user rows visible (isolation test).

Rollback

  • Pre-cutover: additive changes are inert → simply don't flip the flags; drop new tables if aborting.
  • Post-cutover issue: flip flags off / redeploy previous tag; old columns still present → the legacy path still works. No data was deleted, so no data rollback is needed.

Provider-app prerequisites (operator setup)

  • Google: OAuth client (existing) + redirect /(…)/signin/google; scopes gmail.readonly gmail.modify.
  • Microsoft: register an Entra app; redirect /(…)/signin/microsoft; scopes Mail.Read Mail.ReadWrite offline_access; admin consent if required.
  • IMAP (future): per-account host/credentials; validated against the SSRF allowlist.
  • Because providers are flag-gated, an unconfigured provider is simply hidden — configure, then enable.