Files
alva/docs/DRIFT.md
T
Claude 150b5011d5 GitOps-deployflöde: publicering till GHCR + Argo CD-synk
Klustret följer git — ingen CI-process har kubectl-åtkomst:

- Nytt publiceringsflöde (.github/workflows/publicera.yml): varje
  main-push bygger de tre bilderna, publicerar till GHCR taggade med
  git-SHA (endast GITHUB_TOKEN, inga externa hemligheter), uppdaterar
  produktions-overlayens taggar med kustomize edit set image och
  committar tillbaka — overlayen ombyggs som verifiering före commit,
  och paths-ignore + [skip ci] förhindrar triggerloopar.
- Produktions-overlay (infra/overlays/produktion): GitOps-sanningen
  för vad som kör; bas = infra/k8s. Rollback = git revert.
- Argo CD-applikation (infra/gitops/argocd-application.yaml):
  automatisk synk med prune + selfHeal; hemligheten ligger medvetet
  utanför både git och synken. Bootstrap = ett kubectl apply.
- DRIFT.md: CI/CD-avsnitt med flödesdiagram, bootstrap, rollback och
  repo-variabeln PLATTFORM_URL.

Verifierat med riktig kustomize v5.4.3: overlayen bygger 17 objekt,
bildbytet slår igenom på alla tre tjänsterna, postgres-init genereras,
och workflowens exakta edit set image-kommandon fungerar. Alla
workflow-/manifest-YAML validerade; 29 vitest-tester gröna.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-03 08:06:27 +00:00

96 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Guidad Felsökning Drift i Kubernetes (helt självhostat)
Målarkitekturen ur [Master Prompt](MASTER-PROMPT.md) som kod: hela stacken körbar i eget kluster — webb, AI-orkester, plattformsbackend (auth + händelse-API + Live Share) och Postgres. Inga externa tjänstberoenden utöver Anthropic-API:et för AI-anropen.
## Arkitektur
```mermaid
flowchart LR
T[Tekniker] -->|HTTPS| I[Ingress + TLS]
T2[Kund via delningslänk] -->|HTTPS| I
I -->|/| W[web\n210 pods, HPA]
I -->|/api/ai| A[ai-orkester\n210 pods, HPA]
I -->|/api, /halsa| P[plattform\n210 pods, HPA]
A -->|Claude API| C[(Anthropic)]
P --> DB[(Postgres\nStatefulSet + PVC)]
K[Secret: felsokning-hemligheter] --> A & P & DB
```
| Komponent | Vad | Var |
| --- | --- | --- |
| `web` | SPA:n bakom oprivilegierad nginx (`Dockerfile`, `docker/nginx.conf`) | Deployment + Service + HPA + PDB |
| `plattform` | Självhostad backend (`services/plattform`): **multi-tenant** — registrering skapar organisation + systemadministratör, admin hanterar användare (tekniker/arbetsledare/admin), all ärendedata organisationsisolerad. Inloggning (bcrypt via pgcrypto, HS256-JWT med roll + org i anspråken), append-only händelse-API, publik delningsendpoint | Deployment + Service + HPA + PDB |
| `ai-orkester` | AI-orkestern (`services/ai-orkester`): fyra uppgifter routade till Sonnet 5 / Opus 5 / Haiku 4.5 — verifierar plattformens JWT (delad hemlighet) | Deployment + Service + HPA + PDB |
| `postgres` | Händelselogg + användare; **append-only garanterat med databastriggers** — historik kan inte ändras eller raderas oavsett roll | StatefulSet + PVC (10 Gi). Produktion: CloudNativePG-operatorn för backup/failover/PITR |
| Hemligheter | `anthropic-api-key`, `jwt-secret` (delas av plattform + orkester), `postgres-losenord` | Secret `felsokning-hemligheter` — aldrig i bilder eller manifest |
**Klienten har två driftlägen**, valda vid bygget: med `VITE_PLATTFORM_URL` går inloggning, synk, Live Share och AI mot klustret (helt självhostat); utan den används Supabase-läget (edge-funktion + managerad Postgres/Auth) som tidigare. Samma händelsemodell, samma orkester — låst av paritetstester.
## Driftsätta
```sh
# 1. Bygg och publicera bilderna (ersätt registry i infra/k8s/*.yaml)
docker build -t ghcr.io/ORG/guidad-felsokning-web \
--build-arg VITE_PLATTFORM_URL=https://app.exempel.se .
docker build -t ghcr.io/ORG/guidad-felsokning-ai-orkester services/ai-orkester
docker build -t ghcr.io/ORG/guidad-felsokning-plattform services/plattform
docker push ghcr.io/ORG/guidad-felsokning-web
docker push ghcr.io/ORG/guidad-felsokning-ai-orkester
docker push ghcr.io/ORG/guidad-felsokning-plattform
# 2. Skapa secret:en (eller använd External Secrets/Sealed Secrets)
kubectl create namespace guidad-felsokning
kubectl -n guidad-felsokning create secret generic felsokning-hemligheter \
--from-literal=anthropic-api-key='sk-ant-…' \
--from-literal=jwt-secret="$(openssl rand -base64 48)" \
--from-literal=postgres-losenord="$(openssl rand -base64 24)"
# 3. Applicera manifesten (Postgres initieras med schema + append-only-triggers)
kubectl apply -k infra/k8s
# 4. Verifiera
kubectl -n guidad-felsokning get pods
curl https://app.exempel.se/halsa # → {"status":"ok"} (plattformen)
curl https://app.exempel.se/api/openapi.yaml # API-first: hela API-specen
```
Byt domän och cert-issuer i `infra/k8s/ingress.yaml`. Att skapa nya organisationer är öppet i beta — stäng med `REGISTRERING_OPPEN=false` på plattformens Deployment; användare inom en organisation skapas alltid av dess systemadministratör.
## Multi-tenant och roller
Enligt Master Prompt: varje kund är en egen tenant, ingen data blandas mellan kunder.
- **Registrering skapar organisationen** och gör användaren till systemadministratör.
- **Admin skapar användare** (tekniker/arbetsledare/admin) i sin organisation — via UI:t eller `POST /api/anvandare`.
- **All ärendedata är organisationsknuten**: ärenden skapas i användarens organisation och händelse-API:t verifierar organisationstillhörighet på varje anrop — en annan organisations ärenden ger 404.
- **Rollen ligger i JWT:n** och verifieras på servern; klienten anpassar bara UI:t.
Integrationstestet (`services/plattform/integrationstest.sh`, körs även i CI mot riktig Postgres) verifierar hela kedjan: registrering, synk, idempotens, append-only-triggern, organisationsisolering, delningsfiltrering och rollstyrning.
## Säkerhet och robusthet
- **Append-only i tre lager:** klienten lägger bara till, API:t exponerar inga update/delete, och databastriggers avvisar ändringar även för en felkonfigurerad roll.
- **JWT-flödet är verifierat tvärs tjänsterna:** plattformen signerar, orkestern verifierar samma hemlighet; fel hemlighet och utgångna tokens avvisas (testat).
- Alla containrar kör **non-root** utan capabilities; backend-tjänsterna med read-only rotfilsystem. Båda failar closed utan sina hemligheter.
- **HPA** 210 pods per tjänst på 70 % CPU; **PDB** minst en pod uppe vid noddränering; readiness/liveness-prober överallt (`pg_isready` för Postgres).
## CI/CD med GitOps
**CI** (`.github/workflows/ci.yml`): tester, produktionsbygge, integrationstest mot riktig Postgres och verifierande containerbyggen på varje push/PR.
**CD** (`.github/workflows/publicera.yml` + Argo CD): klustret följer git — ingen CI-process har kubectl-åtkomst.
```mermaid
flowchart LR
P[Push till main] --> B[Bygg + publicera\n3 bilder till GHCR\ntaggade med git-SHA]
B --> O[Uppdatera\ninfra/overlays/produktion\n+ commit till git]
O --> A[Argo CD ser ändringen] --> S[Synkar klustret\nprune + selfHeal]
```
1. Varje main-push bygger de tre bilderna, publicerar till GHCR (`GITHUB_TOKEN`, inga externa hemligheter) och uppdaterar produktions-overlayens taggar med `kustomize edit set image` — overlayen ombyggs som verifiering innan commiten.
2. **Argo CD är enda vägen in i klustret.** Bootstrap en gång: installera Argo CD, ersätt repo-URL:en i `infra/gitops/argocd-application.yaml` och `kubectl apply -f` den. Därefter: `prune` tar bort det som försvinner ur git, `selfHeal` återställer manuella klusteravvikelser.
3. **Rollback = `git revert`** av gitops-commiten — Argo CD synkar tillbaka föregående SHA-taggade bilder.
4. Repo-variabeln `PLATTFORM_URL` (Settings → Variables) styr webbyggets `VITE_PLATTFORM_URL`/`VITE_AI_ORKESTER_URL`. Hemligheten `felsokning-hemligheter` ligger utanför både git och synken.
Manuell `kubectl apply -k infra/k8s` (avsnittet Driftsätta ovan) fungerar fortfarande för miljöer utan Argo CD.