Plan · waves & rollback

Michel Media — Migration Plan

Versie 1 · 2026-05-07 · gebaseerd op DISCOVERY.md

Strategische uitgangspunten

  1. Eigen alles, voor zover praktisch en betaalbaar.
  2. Bedrijfskritiek = eigen hardware of cloud waar je voor betaalt (Cloudflare, Mac mini). Niet werk-VPS.
  3. Cloudflare als platform (Pages, Workers, R2, D1) waar mogelijk, paid tier OK.
  4. Mac mini als 24/7 hub — productiever maken loont meer dan NAS behouden.
  5. NAS-exit gepland, niet vandaag uitgevoerd. Camera-vraag eerst beantwoord.
  6. Cashspot wordt afgesloten, Coolify wordt afgebouwd na de twee resterende deploys gemigreerd zijn.

Filosofie per wave

Volgorde

Wave 0   → Foundations (Syncthing + parity + R2 fundering)        ~3 uur
Wave 1   → SPOF mitigatie (Vaultwarden encrypted export)          ~30 min
Wave 2   → Mac mini server prep (Docker + tunnel + Caddy)         ~2 uur
Wave 3   → Vaultwarden migratie naar Mac mini                     ~2 uur
Wave 4   → Paperless migratie naar Mac mini                       ~3 uur
Wave 5   → soulwise-site → Cloudflare Pages                       ~1 uur
Wave 6   → dekei1 migratie (decisie + uitvoer)                    ~3-5 uur
Wave 7   → plex VPS schoonmaak (Coolify + Supabase + Happy)       ~2 uur
Wave 8   → NAS audit + Time Machine via Mac mini                  ~3 uur
Wave 9   → Camera transitie (geparkeerd tot beslissing)           tbd

Totaal geschat: 18-25 uur, verspreid over 6-9 weken in eigen tempo.


Wave 0 — Foundations

Doel: Mac mini wordt hot standby voor MacBook. Volledige Claude Code + shell parity. Encrypted backup-pijp naar R2 staat. Hierop bouwen alle andere waves voort.

Prerequisites: - Mac mini bereikbaar via ssh macmini (al ✓) - Cloudflare R2 paid tier ingeschakeld (vereist creditcard op CF account, al gekoppeld) - Syncthing installeren beide kanten

Stappen:

  1. Syncthing installatie - MacBook: brew install syncthing + start als service - Mac mini: ssh macmini brew install syncthing + start als service - Pair beide instances via web UI (http://localhost:8384)

  2. Sync-folders configureren (eenrichtingsverkeer of two-way per folder; zie FAILOVER-PLAYBOOK voor claude-mem-uitzondering)

Pad Modus Reden
~/.claude/ two-way actieve config, nieuwe skills/plugins
~/.claude-mem/ MBP→mini one-way SQLite single-writer, zie playbook
~/Documents/michelmedia/ two-way actieve werkmap
~/Documents/dekei1/ two-way klant-repo
~/Documents/lurvink/ two-way klant-repo
~/Documents/og/ two-way werk-repo (afhankelijk van NDA)
~/.zshrc, ~/.zsh_history two-way shell
~/.ssh/ handmatig kopiëren beveiligingsoverwegingen
  1. Bootstrap-script opstellen in ~/Documents/michelmedia/infra/bootstrap-mac.sh. Idempotent script dat een verse Mac volledig parity-klaar maakt: - Brew installeer + alle benodigde packages - Apps via brew install --cask: claude, codex, raycast, etc. - npm/pnpm/python/Ruby toolchain - Stelt SSH config en aliases in - Vaultwarden CLI + bw-unlock script - Claude Code v2.x install + login-instructies - claude-mem plugin install - Verifieer parity: end-to-end Claude Code-sessie test

  2. R2 fundering - Maak bucket michelmedia-backups in CF dashboard (regio EU) - Genereer API token met R2 read/write scope - Installeer restic op MacBook én Mac mini (brew install restic) - Initialiseer encrypted repo: restic init --repo s3:https://<account>.r2.cloudflarestorage.com/michelmedia-backups - Encryptie-passphrase opslaan in Vaultwarden (item: "restic R2 backup passphrase")

  3. Nightly backup cron op MacBook (LaunchAgent): - ~/.claude/, ~/.claude-mem/, ~/.ssh/, ~/.zshrc, dotfiles → restic snapshot om 03:00 - Logfile naar ~/.local/share/restic-backup.log - Telegram notificatie via Spotbot bij slagen + bij falen

Verificatie / succes-criteria: - ✓ Syncthing toont "Up to date" voor alle folders na 1 uur - ✓ Bootstrap-script draait zonder fouten op Mac mini en levert werkende Claude Code-sessie - ✓ restic snapshots op R2 toont gisteren-snapshot - ✓ End-to-end test: open Claude Code op Mac mini, voer dummy task uit, claude-mem schrijft observations, observations verschijnen in Mac mini's lokale DB

Rollback: - Syncthing pauzeren in UI bij twijfel; per-folder uit te zetten - Bootstrap-script op Mac mini draait niet-destructief (idempotent) - restic snapshots zijn additief, geen impact op live data


Wave 1 — Vaultwarden SPOF mitigatie

Doel: Het ergste single-point-of-failure dichten zonder dat we Vaultwarden verhuizen. Maximaal 30 minuten werk, voorzichtigheidsnet voordat Wave 2/3 plaatsvinden.

Stappen:

  1. CLI-export: bw login → bw unlock → bw export --format encrypted_json --password "<sterkte-passphrase>" → uploaden naar R2 als vaultwarden/encrypted-export-YYYYMMDD.json
  2. Encrypted file ook kopiëren naar offline USB stick. Stick fysiek opbergen op extern adres (kluis of vertrouwd familieadres).
  3. Encryptie-passphrase noteren op papier in dezelfde kluis (of in Vaultwarden zelf — paradox).
  4. Master password van Vaultwarden noteren op papier in kluis.
  5. Maandelijkse herhaling automatiseren via LaunchAgent + telegram-bericht "vault-export YYYY-MM uploaded".

Verificatie: - ✓ Test-restore op een tijdelijke Vaultwarden-instance (Docker lokaal) werkt - ✓ R2 snapshot zichtbaar via aws s3 ls (rclone of wrangler r2)

Rollback: geen — additief, niets te rollbacken.


Wave 2 — Mac mini server prep

Doel: Mac mini klaar maken om Docker-services te hosten op productie-niveau. Reverse proxy + Cloudflare Tunnel + persistent storage.

Stappen:

  1. Docker Desktop opstarten en in PATH brengen - Auto-start bij login configureren - Resources: 8 GB RAM toewijzen, 4 cores
  2. Tailscale running zetten (huidige error-state oplossen)
  3. Folder layout vaststellen: /Users/michelhelsdingen/Docker/{vaultwarden,paperless,...} voor service-volumes
  4. Cloudflare Tunnel container installeren met eigen tunnel-ID - Maak nieuwe tunnel "macmini-services" via CF dashboard of cloudflared tunnel create macmini-services - Token in macOS Keychain - Container start via Docker Compose, auto-restart unless-stopped
  5. Caddy als reverse proxy in Docker (eenvoudig automatisch HTTPS via tunnel) — of route alles via cloudflared tunnel ingress (geen Caddy nodig)
  6. Test met dummy-service: nginx-test container achter nginx-test.helsdingen.com route

Verificatie: - ✓ Cloudflare dashboard toont actieve tunnel - ✓ Test-route bereikt nginx-test container vanaf publiek internet via CF Access - ✓ Mac mini reboot test: alle services starten weer automatisch

Rollback: Docker stoppen + tunnel verwijderen. Geen impact op Plex VPS.


Wave 3 — Vaultwarden migratie

Doel: vault.helsdingen.com draait op Mac mini, plex Vaultwarden uitgezet maar containers nog aanwezig (1 week buffer).

Stappen:

  1. Snapshot maken op plex VPS: docker stop vaultwarden && tar czf /mnt/docker/backups/vaultwarden-pre-migration-YYYYMMDD.tgz /mnt/docker/vaultwarden/
  2. Sync naar Mac mini: rsync -avz plex:/mnt/docker/vaultwarden/ ~/Docker/vaultwarden/
  3. Mac mini Vaultwarden Docker compose: - Image vaultwarden/server:1.35.6 (zelfde versie als plex) - Volume mount op ~/Docker/vaultwarden - Environment variables overnemen (admin token, signups disabled, etc.) - Tunnel-ingress route: vault.helsdingen.comhttp://vaultwarden:80
  4. Start Mac mini container met aparte test-host eerst: vault-test.helsdingen.com
  5. Login-test, vault decrypt, browser sync, mobile sync (iOS Bitwarden app)
  6. Stop plex Vaultwarden container (niet rm)
  7. DNS swap: vault.helsdingen.com CNAME wijzigen van plex-tunnel naar mac mini-tunnel
  8. Test live na propagation
  9. Wachttijd 7 dagen voordat plex Vaultwarden container verwijderd wordt
  10. Encrypted export pipeline (Wave 1) updaten om Mac mini's volume te exporteren

Verificatie: - ✓ Login succes op vault.helsdingen.com via desktop browser, mobiele app, en bw CLI - ✓ Recent items zichtbaar (geen lege vault) - ✓ Sync van een nieuw item werkt op alle devices - ✓ Mac mini reboot test: Vaultwarden komt weer up

Rollback: - DNS-swap terug naar plex (TTL 5 min) → plex container start opnieuw - Volume op Mac mini blijft als referentie, geen data-verlies


Wave 4 — Paperless migratie

Doel: docs.helsdingen.com draait op Mac mini incl. mail-fetcher en gotenberg/tika. NAS-replicatie als backup-laag.

Stappen:

  1. Snapshot op plex: docker compose -f /mnt/docker/paperless/docker-compose.yml stop && tar czf paperless-pre-migration.tgz /mnt/docker/paperless/
  2. Rsync volume naar Mac mini: rsync -avz plex:/mnt/docker/paperless/ ~/Docker/paperless/
  3. Mac mini Docker Compose met identieke services (paperless, redis, gotenberg, tika, mail-fetcher)
  4. Mail-fetcher: .env-mailfetcher overzetten, mail-fetcher.py ook (incl. recente subject-skip update)
  5. Tunnel route: docs.helsdingen.comhttp://paperless:8000
  6. Test-host eerst: docs-test.helsdingen.com
  7. Verifieer nieuwe scan@ mail wordt verwerkt door Mac mini-mail-fetcher
  8. NAS-replicatie inrichten: - rsync van ~/Docker/paperless/ naar terror:/volume1/docker/paperless-mirror/ om 04:00 nightly - Plus encrypted snapshot naar R2 (restic)
  9. DNS swap docs.helsdingen.com
  10. Buffer 7 dagen, dan plex containers stoppen

Verificatie: - ✓ Web-UI laadt op docs.helsdingen.com - ✓ Bestaande documenten zichtbaar - ✓ Nieuwe mail naar scan@ wordt geclassificeerd binnen 5 minuten - ✓ Cron-backup dump naar terror succesvol (eerste run handmatig triggeren) - ✓ R2 snapshot zichtbaar

Rollback: - DNS terug naar plex - Mail-fetcher op plex weer starten


Wave 5 — soulwise-site naar Cloudflare Pages

Doel: Coolify-deploy soulwise-site (nginx static op soulwiseapp.com) verhuizen naar CF Pages. Eerste warm-up voor dekei1.

Stappen:

  1. Clone michelhelsdingen/soulwise repo lokaal (als nog niet aanwezig)
  2. Bouw lokaal als nginx serveerbare output (dist/ of public/)
  3. CF Pages project aanmaken: soulwise-site
  4. Custom domain soulwiseapp.com + www.soulwiseapp.com
  5. DNS records swappen
  6. Verifieer site online
  7. Coolify deployment uitzetten en verwijderen
  8. GitHub Actions of CF Git-integratie inrichten voor auto-deploy bij push naar main

Verificatie: - ✓ soulwiseapp.com responds 200 OK - ✓ Visuele check: site identiek aan voor migratie - ✓ Auto-deploy test: push naar main triggert nieuwe deploy

Rollback: - DNS terug naar plex (Coolify deployment niet verwijderen tot stabiel)


Wave 6 — dekei1 migratie

Doel: dekei1.ltcdekei.nl van Coolify Next.js + self-hosted Supabase af.

Eerst beslissing nemen voor de Postgres-laag. Drie opties:

Optie Hosting Migratie-werk Maandelijkse kosten Geschikt voor
A. CF Pages + Supabase hosted (Frankfurt) CF + Supabase medium (DB-export/import) gratis tier mogelijk meest pragmatisch, snelst
B. CF Pages + D1 volledig CF hoog (schema-rewrite, geen pgvector etc.) gratis ruim als app simpel genoeg is
C. Mac mini Docker (Next + Postgres beide lokaal) eigen laag, lift-and-shift stroom als je self-host wilt blijven

Aanbeveling: A mits app niet veel Postgres-extensies gebruikt. Eerst auditeren.

Stappen (uitgaande van A):

  1. Repo audit: michelhelsdingen/dekei1. Lijst Postgres extensies, RLS policies, Storage gebruik
  2. Supabase Frankfurt hosted project: bestaande LTC project gebruiken of nieuw aanmaken
  3. Schema dump van self-hosted: pg_dump van Supabase-db container, restore in hosted project via Studio of psql
  4. Storage migratie (indien gebruikt): rsync MinIO bucket → Supabase Storage of R2
  5. App rebuild met nieuwe SUPABASE_URL en keys, deploy naar CF Pages (Next.js SSR via @cloudflare/next-on-pages)
  6. Custom domain dekei1.ltcdekei.nl
  7. Acceptatietest met klant Theo
  8. Coolify deployment uit, self-hosted Supabase containers nog niet aanraken (Wave 7)

Verificatie: - ✓ Site live op CF Pages - ✓ DB queries werken (login, lijst tonen, schrijven) - ✓ Klant heeft minimaal 7 dagen kunnen testen - ✓ Geen errors in Sentry/CF logs

Rollback: - DNS terug naar plex - Self-hosted Supabase blijft in originele staat tot Wave 7


Wave 7 — plex VPS schoonmaak

Doel: Coolify uitzetten, self-hosted Supabase weg, Happy stack uit, irrelevante containers opruimen. plex VPS draait alleen wat daar logisch hoort.

Eindstaat plex VPS containers: - Immich (server, ML, postgres, redis) - Jellyfin (zit niet in huidige container-list — checken of het via Coolify draaide) - Uptime Kuma - Watchtower - Glances - Portainer (nog overwegen of nodig) - Cloudflared tunnel (alleen voor Immich + Jellyfin) - Optioneel: Homepage, change-detection, AI-news-bot, MEXC bot

Stappen:

  1. Coolify uitzetten: docker compose -f /coolify/source/docker-compose.yml down
  2. Self-hosted Supabase 12 containers down + volumes archiveren naar tar in /mnt/docker/backups/
  3. Happy server stack down (4 containers)
  4. n8n: blijft draaien op plex of migreren naar Mac mini? Onderdeel van beslissing in Wave 6 (gerelateerd aan dekei1?)
  5. Cloudflared config updaten — alleen routes overhouden voor diensten die nog op plex draaien
  6. Check disk usage: zou ~50 GB moeten vrijkomen door Supabase + Coolify cleanup
  7. Watchtower configuratie verifiëren

Verificatie: - ✓ Immich + Jellyfin werken op respectievelijke routes - ✓ Geen 404 of broken routes via cloudflared - ✓ disk usage /mnt/docker ligt onder 100 GB

Rollback: containers weer starten (volumes blijven), of restore tar.


Wave 8 — NAS audit + Time Machine via Mac mini

Doel: Beslissen of NAS blijft of weggaat. Time Machine van externe SSD af + naar Mac mini SMB share als secondaire bestemming.

Stappen:

  1. Audit /volume1/homes (2.7 TB): - Inhoud per top-level folder bepalen - Klasificeer: weggooien / R2 archive / Mac mini lokaal / NAS behouden - Dit kan dagen aan triage zijn — niet één sessie
  2. Audit Plex media op NAS (5.8 GB): verhuizen naar plex VPS Jellyfin of weggooien
  3. Surveillance migratie afhankelijk van Wave 9 (camera). Tot dan blijft NAS leven.
  4. Time Machine secondary destination: - Op Mac mini: enable File Sharing + maak TimeMachine share aan (SMB) - Configureer als TM-bestemming in Mac mini's /etc/backup-config - Op MacBook: Systeeminstellingen → Time Machine → Voeg Mac mini toe als 2e doel naast externe SSD
  5. NAS-beslissing: - Als surveillance migreert (Wave 9): NAS leeg en verkopen - Als surveillance blijft: NAS behouden alleen voor camera, andere shares uit

Verificatie: - ✓ Time Machine schrijft naar zowel SSD als Mac mini bij wekelijkse backup - ✓ Geen andere services dependen op NAS shares meer (audit)

Rollback: NAS niet wegdoen voordat 30 dagen volledig draait zonder NAS-toegang.


Wave 9 — Camera transitie (geparkeerd)

Status: Wacht op beslissing. Vrouw gebruikt DS Cam (Synology mobile app). Beelden moeten ergens.

Opties bij beslissing:

Bij C heeft NUC voldoende capaciteit (cams-lxc gebruikt al 1 GB RAM), maar disk-IO voor opnames is een vraag.

Geen actie tot Michel beslist.


Cross-cutting verwijzing