Commit Graph

4 Commits

Author SHA1 Message Date
Claude 19796bec70 Terraform blir enda vägen, och backup ett obligatoriskt val
Kustomize- och Argo CD-vägen är borttagen. Den beskrev samma system en
gång till och kunde inte köras samtidigt som Terraform utan att de
motarbetade varandra — selfHeal återställde det Terraform ändrade och
prune tog bort det Terraform skapade. Kvar utanför Terraform är bara
postgres-init.sql, som läses av både definitionen och integrationstestet
så att schemat inte kan glida isär från det som testas.

Säkerhetskopieringen var en förhoppning: en StatefulSet med en volym och
ingen kopia. Går volymen förlorad är det inte "data" som försvinner utan
varje ärendes bevisvärde — vad som kontrollerades, av vem, när, med
vilken evidens — och det går inte att återskapa i efterhand.

databas_lage är därför ett obligatoriskt val utan standardvärde:

  extern    managerad Postgres, leverantörens backup och PITR
            (rekommenderat i produktion)
  cnpg      CloudNativePG i klustret: basbackup 02:30, kontinuerlig
            WAL-arkivering till objektlagring, PITR och failover
  inbyggd   en volym, ingen backup — spärras av en precondition när
            miljön är produktion

Preconditions fångar felkonfiguration vid plan i stället för vid drift:
extern utan anslutning, cnpg utan backupmål eller nycklar, inbyggd i
produktion.

Driftsättningen är nu två åtskilda flöden. Publicera bygger och taggar
bilderna vid varje main-push; Driftsätt startas för hand med en tagg mot
en GitHub-miljö som kan kräva godkännande, kör fmt/init/validate/plan/
apply, skriver ut kartan och rökkontrollerar hälsa och API-spec. En bild
i registret är inte samma sak som en bild som kör. Rollback är att köra
Driftsätt igen med en tidigare tagg. CI kör dessutom terraform validate
på varje PR — den kontroll jag inte kunde köra själv.

Två fel hittade vid egengranskning av definitionen: schemafilen delades
på semikolon, vilket hade klippt itu plpgsql-funktionen med
append-only-triggern (nu hela filen via postInitApplicationSQLRefs), och
null-satta fält i kubernetes_manifest utelämnas nu i stället.

Verifierat: 87 vitest-tester, typkontroll, eslint, OpenAPI-validering,
terraform fmt, statisk referenskontroll av modulen och integrationstest
mot riktig Postgres. terraform validate kunde inte köras här —
registry.terraform.io är blockerad av sessionens egress-policy, därav
CI-jobbet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-03 22:16:52 +00:00
Claude b069c9a12f Organisationslagret: multi-tenant med roller, integrationstestat
Master Prompts tenant- och rollmodell implementerad i den självhostade
plattformen:

- Registrering skapar organisation + systemadministratör (transaktion);
  admin skapar övriga användare (tekniker/arbetsledare/admin) i sin
  organisation via nytt UI och POST /api/anvandare. Roll + organisation
  ligger i JWT-anspråken och verifieras alltid på servern.
- All ärendedata organisationsknuten: ärenden skapas i användarens
  organisation, händelse-API:t verifierar tillhörighet per anrop och
  GET /api/arenden listar bara egna organisationens ärenden.
- Schemat flyttat till infra/k8s/postgres-init.sql och genereras in som
  ConfigMap via kustomize — samma fil används av integrationstestet.
  Nya tabeller: organisationer; anvandare med organisation_id + roll
  (check-constraint); arenden med organisation_id + index.
- Integrationstest (services/plattform/integrationstest.sh) mot riktig
  Postgres, kört grönt lokalt och tillagt i CI: registrering, synk,
  idempotens (händelser skrivs aldrig över), append-only-triggern,
  organisationsisolering (404 över gränsen), publik delning med
  filtrering, rollstyrning (tekniker nekas användarhantering) och
  delad arbetsyta inom organisationen.
- Klienten: registreringsformulär med organisationsfält, kontopanel
  med roll och organisation, admin-panel för användarhantering.

Verifierat: integrationstestets 12 kontroller gröna mot Postgres 16,
28 vitest-tester gröna, produktionsbygge ok, YAML validerad,
Playwright-röktest grönt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-03 07:04:32 +00:00
Claude 7c24186cc5 Helt självhostat: plattformsbackend, Postgres i klustret, klientläge
Sista externa beroendet borta — hela stacken kör i eget kluster:

- Ny plattformstjänst (services/plattform): egen inloggning
  (registrering + inloggning, lösenord bcrypt-hashade med pgcrypto,
  HS256-JWT), append-only händelse-API för synken (endast insert,
  on conflict do nothing) och publik delningsendpoint för Live Share
  med samma filtrering som Supabase-funktionen. Fail closed utan
  hemligheter; inga update/delete-operationer exponeras.
- Postgres som StatefulSet med PVC och init-schema; append-only
  garanterat i databasen med triggers på både händelser och ärenden —
  historik kan inte ändras oavsett ansluten roll. CloudNativePG
  rekommenderas för produktion i docs.
- JWT-hemligheten delas mellan plattform och AI-orkester (orkestern
  läser JWT_SECRET med SUPABASE_JWT_SECRET som fallback) — flödet
  livetestat: plattformens token accepteras av orkestern, fel
  hemlighet och utgångna tokens avvisas.
- Klienten får självhostat läge via VITE_PLATTFORM_URL: inloggnings-
  panel på startsidan, synk mot plattformens API (samma konfliktfria
  flätning), Live Share via /api/delad och AI via klustrets orkester.
  Utan variabeln är Supabase-läget oförändrat.
- Ingress routar /api/ai → orkestern, /api + /halsa → plattformen,
  / → webben; kustomize inkluderar hela stacken; CI bygger alla tre
  bilderna; DRIFT.md omskriven för självhostad drift.

Verifierat: 28 vitest-tester gröna (inkl. append-only-triggers och
API-ytan), plattformstjänsten livetestad (hälsa, 401, fail closed),
JWT-paritet mellan tjänsterna testad, alla manifest YAML-validerade,
produktionsbygge ok, Playwright-röktest grönt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-03 01:41:58 +00:00
Claude 03f1ef20f6 Allt i Kubernetes: containrar, manifest, orkestertjänst och CI
Målarkitekturen ur Master Prompt som kod:

- Webben containeriserad (flerstegs-Dockerfile → oprivilegierad nginx
  med SPA-fallback, hashade assets cachas hårt, säkerhetsheaders).
- AI-orkestern som egen tjänst (services/ai-orkester): samma routing
  och AI-regler som edge-funktionen men körbar som pod — egen
  HS256-JWT-verifiering (fail closed), /halsa, storleksgränser,
  read-only container som kör som node-användaren. Livetestad:
  hälsokontroll ok, 401 utan/med ogiltig token, 400-validering bakom
  giltig JWT.
- Kubernetes-manifest (infra/k8s, kustomize): namespace, Deployments
  med readiness/liveness och åtstramad securityContext, Services,
  HPA 2–10 pods på 70 % CPU, PodDisruptionBudgets, Ingress med TLS
  via cert-manager, secret-mall (riktiga värden skapas utanför git).
- Klienten väljer AI-väg vid bygget: VITE_AI_ORKESTER_URL → tjänsten
  i klustret, annars Supabase-edge-funktionen. Samma orkester i båda,
  låst av paritetstest.
- CI-arbetsflöde: tester + produktionsbygge + verifierande
  containerbyggen av båda bilderna på varje push/PR.
- docs/DRIFT.md: arkitekturdiagram, driftsättningssteg, skalning,
  och vad som återstår mot full självhostning.

Verifierat: 27 vitest-tester gröna, produktionsbygge ok, alla
K8s-manifest YAML-validerade, orkestertjänsten livetestad,
Playwright-röktest grönt.

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