Zum Hauptinhalt springen

Deploy / Betrieb (Cloudflare) — Runbook (OP-DEPLOY-1)

Stand: Vorbereitet; der erste echte Deploy steht aus (Domain-Transfer + Credentials, s. u.). Ziel: eine Subdomain app.medidentas.com bedient UI + API über einen Worker (Workers + Static Assets). Begründung: ein Origin → Cloudflare Access (R7) schützt UI und API in einer Policy, kein CORS, ein TLS-Zertifikat. Quelle des Stacks: Stack.md (A-4).

1. Architektur des Deploys

app.medidentas.com (Cloudflare Access davor, R7/OP-AUTH-1)

┌──────┴───────────────┐
Static Assets│ Worker medidentas-api│ (server/, Hono)
(Angular UI) │ /api/* → Hono │
dist/browser │ sonst → ASSETS │ ── D1 (medidentas) · Cron (R5)
└───────────────────────┘
  • UI: Angular-Build (client/dist/browser) als Static Assets desselben Workers (wrangler.toml [assets], binding = "ASSETS"). SPA-Deep-Links fallen in server/src/index.ts auf index.html zurück.
  • API: alles unter /api/* → Hono-App (unverändert).
  • DB: D1 medidentas (idempotente Auto-Migration beim Start, db/migrate.ts).
  • Cron: stündliche Wiedervorlage-Erinnerungen (R5, [triggers]).

2. Entscheidungen (28.06.2026)

  • Domain verfügbar: medidentas.com liegt bereits im Cloudflare-Account (Zone aktiv) → der Custom-Domain-Deploy auf app.medidentas.com ist technisch nicht mehr blockiert. Die im OP genannte Übertragung an HQ ist eine organisatorische Folgeaufgabe (Eigentümer-/Account-Zuordnung), kein Deploy-Blocker mehr.
  • EU-Datenresidenz = Pflicht (G-5, OP-DSGVO-1, RISK-17): alle personenbezogenen Daten in der EU: D1 mit EU-Location-Hint anlegen (--location weur ⟶ Western Europe), NextCloud EU-gehostet (A-1), Cloudflare Data Localization Suite (Regional Services + EU Metadata Boundary) für die Zone, keine US-Sub-Prozessoren ohne AVV/SCC (RISK-4/RISK-15). Vor Produktiv-Go-live verbindlich prüfen.
  • Deploy-Weg = CI: CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID als GitHub-Actions-Secrets → Deploy über den manuellen Workflow app-deploy.yml (workflow_dispatch).
  • „Sofort absichern": Betrieb hinter Cloudflare Access mit AUTH_ENFORCED=true von Anfang an. ⚠️ Wichtig: Access (self-hosted) braucht einen Hostnamen in eurer Zone — *.workers.dev lässt sich nicht mit Access schützen. AUTH_ENFORCED=true ohne Access davor ⇒ jeder /api-Request hat keinen cf-access-…-Header ⇒ 401 (App unbedienbar). Konsequenz: der abgesicherte Test läuft auf app.medidentas.com (Zone ist da), nicht auf *.workers.dev.

3. Voraussetzungen

  1. Domain medidentas.comim Cloudflare-Account vorhanden (Zone aktiv). HQ-Eigentümer- Zuordnung: organisatorischer Folgepunkt (OP-DEPLOY-1).
  2. Deploy-Credential: CLOUDFLARE_API_TOKEN (Scopes: Workers Scripts: Edit, D1: Edit, Workers KV/Assets, bei Custom Domain zusätzlich Zone: DNS/Workers Routes) + CLOUDFLARE_ACCOUNT_ID als GitHub-Actions-Secrets. Nie im Repo (RISK-8).
  3. Secrets (per wrangler secret put, nicht im Repo): NEXTCLOUD_URL/USER/APP_PASSWORD (R3/R9, EU- Hosting), später SIGNATUR_PROVIDER + Provider-Keys (R4/OP-SIGN-1).

4. D1-Datenbank anlegen (einmalig, EU-Residenz)

cd server
npx wrangler d1 create medidentas --location weur # EU (Western Europe) — Pflicht (G-5)
# → gibt eine database_id aus; in wrangler.toml unter [[d1_databases]] eintragen
# (Platzhalter REPLACE_WITH_D1_ID ersetzen). Die Auto-Migration läuft beim ersten Request.

5. Empfohlener Weg — abgesichert auf app.medidentas.com (EU)

„Sofort absichern" gewählt + Zone ist verfügbar ⇒ direkt auf die Subdomain (Access schützt keine *.workers.dev). Reihenfolge:

  1. Secrets setzen (GitHub → Settings → Secrets → Actions): CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID.
  2. D1 anlegen (Schritt 4, --location weur) + database_id in wrangler.toml eintragen.
  3. EU-Datenresidenz für die Zone sicherstellen (Data Localization Suite: Regional Services + EU Metadata Boundary) — G-5/RISK-17.
  4. Custom-Domain-Route in wrangler.toml aktivieren: routes = [{ pattern = "app.medidentas.com", custom_domain = true }].
  5. Cloudflare Access Application für app.medidentas.com anlegen (IdP/SSO), Policy auf die berechtigten E-Mails; AUTH_ENFORCED=true + AUTH_BOOTSTRAP_ADMIN=<deine-mail> als Worker-Vars.
  6. Deploy via GitHub Actions: Workflow App Deploy manuell starten (workflow_dispatch).
  7. Smoke-Test: GET /api/health (authEnforced: true), UI lädt, Deep-Link …/mandant/x lädt (SPA-Fallback), Mandant anlegen → Audit-Eintrag mit echter Identität.

6. Optional: ungeschützter Vorab-Smoke-Test auf *.workers.dev

Da die Zone medidentas.com bereits verfügbar ist, ist dieser Schritt i. d. R. nicht nötig — der abgesicherte Weg (§5) ist direkt möglich. Falls dennoch ein schneller Funktions-Check gewünscht ist: ohne Access (Access schützt keine *.workers.dev), daher AUTH_ENFORCED nicht auf true (Dev-Akteur = admin). Kein abgesicherter Betrieb, nur Dummy-Daten, keine produktiven Provider-Secrets/PII. cd client && npm run build && cd ../server && npx wrangler deployhttps://medidentas-api.<account>.workers.dev.

7. CI-Deploy-Workflow

.github/workflows/app-deploy.yml (workflow_dispatch) baut Client + Worker und ruft wrangler deploy, sobald CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID als Secrets gesetzt sind. Bricht nicht das CI Gate (separater, nur manuell ausgelöster Job).

7a. Self-Service-Onboarding freischalten (Slice 9, OP-ONBOARD-1)

Die öffentliche Formularseite läuft außerhalb Cloudflare Access. Damit der Einladungslink nicht im Access-Login landet:

  1. Cloudflare Access → Application Medidentas App: eine Bypass-Policy (Action „Bypass", Include „Everyone") nur für die Pfade /onboarding* und /oeffentlich* hinzufügen. (Alle anderen Pfade bleiben durch „HQ + MK" geschützt.)
  2. Bot-Schutz (empfohlen): Cloudflare Turnstile-Widget anlegen → TURNSTILE_SITEKEY als Worker-Var, wrangler secret put TURNSTILE_SECRET. Ohne Secret wird nicht geprüft (nur Token/Ablauf schützen).
  3. DEMO_MODE (wrangler.toml [vars]) ist aktuell "true" → Einwilligung end-to-end testbar mit Fakes (NextCloud/Signatur), ohne echte eIDAS-Rechtswirkung. Auf "false" stellen, sobald echte NextCloud-/Signatur-Secrets gesetzt sind.
  4. Einwilligungstext (server/src/domain/einwilligung.ts) vor echtem Einsatz juristisch prüfen (RISK-18); bei Textänderung EINWILLIGUNG_VERSION hochzählen.

8. Offene Punkte

  • OP-DEPLOY-1 — Zone medidentas.com ist im Account; offen: Credentials/Secrets + erster Deploy + HQ-Eigentümer-Zuordnung (organisatorisch). S. Lastenheft §11.
  • EU-Datenresidenz (Pflicht, G-5/RISK-17): D1 --location weur, NextCloud EU-gehostet, Cloudflare Data Localization Suite (Regional Services + EU Metadata Boundary), keine US-Sub-Prozessoren ohne SCC.
  • Subdomain-Schema final: app. (Anwendung) — www./Apex bleibt für eine spätere Marketing-Seite frei.