From 7e1793b8ac9e423b58378d61962f0d624f64455b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 7 Aug 2026 11:47:26 +0000 Subject: [PATCH] =?UTF-8?q?Drifts=C3=A4ttningspaketen:=20agentanvisningar?= =?UTF-8?q?=20och=20paketering=20i=20sex=20zip-steg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skriptet deploy/paketera.sh skär plattformen i numrerade paket i driftsättningsordning: plan med SHA256-summor, AWS-basen, backend- bilderna, webbilden, arbetslasten och slutkontrollen. Varje paket bär sin egen ANVISNING-AGENT.md med steg, verifiering och stoppvillkor, plus fillista och versionsstämpel under paketunik väg så att alla paket kan packas upp i samma arbetskatalog. Ordningen är motiverad i planen: basen före bilderna (registret måste finnas), bilderna före arbetslasten (apply drar dem), verifieringen sist. 02 och 03 är utpekat parallelliserbara med samma bildtagg. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt --- felsokning/deploy/README.md | 37 ++++++++++ felsokning/deploy/anvisningar/00-plan.md | 54 ++++++++++++++ felsokning/deploy/anvisningar/01-aws-bas.md | 71 +++++++++++++++++++ felsokning/deploy/anvisningar/02-tjanster.md | 67 +++++++++++++++++ felsokning/deploy/anvisningar/03-webb.md | 71 +++++++++++++++++++ .../deploy/anvisningar/04-arbetslast.md | 57 +++++++++++++++ .../deploy/anvisningar/05-verifiering.md | 59 +++++++++++++++ felsokning/deploy/paketera.sh | 63 ++++++++++++++++ 8 files changed, 479 insertions(+) create mode 100644 felsokning/deploy/README.md create mode 100644 felsokning/deploy/anvisningar/00-plan.md create mode 100644 felsokning/deploy/anvisningar/01-aws-bas.md create mode 100644 felsokning/deploy/anvisningar/02-tjanster.md create mode 100644 felsokning/deploy/anvisningar/03-webb.md create mode 100644 felsokning/deploy/anvisningar/04-arbetslast.md create mode 100644 felsokning/deploy/anvisningar/05-verifiering.md create mode 100755 felsokning/deploy/paketera.sh diff --git a/felsokning/deploy/README.md b/felsokning/deploy/README.md new file mode 100644 index 0000000..33fbd68 --- /dev/null +++ b/felsokning/deploy/README.md @@ -0,0 +1,37 @@ +# Driftsättningspaketen + +Paketeringen skär plattformen i numrerade zip-paket, ett per +driftsättningssteg, avsedda att utföras av agenter i ordning. Varje +paket bär sin egen `ANVISNING-AGENT.md` — den som packar upp ett paket +ska inte behöva något annat än paketet och det föregående stegets +utdata. + +```sh +bash felsokning/deploy/paketera.sh +``` + +| Paket | Innehåll | Steg | +| --- | --- | --- | +| `00-plan.zip` | Driftsättningsplanen + SHA256-summor för övriga paket | Läses först, verifierar leveransen | +| `01-aws-bas.zip` | `infra/aws` + `infra/postgres-init.sql` | Terraform: VPC, EKS, Aurora, S3, ECR, KMS, hemligheter, domän, larm | +| `02-tjanster.zip` | `services/` — plattform, ai-orkester, gemensam | Bygg och publicera backendbilderna till ECR, initiera schemat | +| `03-webb.zip` | `app/` (utan `node_modules`/`dist`) + `supabase/` | Bygg och publicera webbilden | +| `04-arbetslast.zip` | `infra/terraform` | Terraform: arbetslasten i klustret, ingress, DNS | +| `05-verifiering.zip` | `docs/` | Slutkontroll av den driftsatta miljön, driftdokumentation | + +Ordningen är driftsättningsordningen och den är inte förhandlingsbar: +basen före bilderna (registret måste finnas), bilderna före arbetslasten +(poddarna drar dem vid apply), verifieringen sist. Skälen står i +respektive anvisning. + +Vad som medvetet INTE packas: `node_modules` (återskapas ur +`package-lock.json`), `app/dist` (byggs i webbilden med miljöns egna +byggargument), `.git`, och värdapplikationens rotkataloger — ALVA:s +plattform är `felsokning/`. + +Anvisningstexterna ligger i `anvisningar/` och versionshanteras här; +skriptet lägger in dem i paketen under `paket//` tillsammans +med `INNEHALL.txt` (fillista) och `PAKET.txt` (version, git-SHA, +byggtid) — vägen är paketunik så att alla paket kan packas upp i samma +arbetskatalog. Summorna i `00-plan.zip` beräknas över de färdiga +paketen — verifiera dem innan något packas upp. diff --git a/felsokning/deploy/anvisningar/00-plan.md b/felsokning/deploy/anvisningar/00-plan.md new file mode 100644 index 0000000..8c29509 --- /dev/null +++ b/felsokning/deploy/anvisningar/00-plan.md @@ -0,0 +1,54 @@ +# Driftsättningsplan · ALVA på AWS + +Detta paket läses först. Det innehåller planen och SHA256-summorna för +de fem arbetspaketen. Allt är egenhostat i ett eget AWS-konto — ingen +extern byggtjänst, inget externt register. + +## Leveransen + +| Paket | Steg | Utförs av | +| --- | --- | --- | +| `01-aws-bas.zip` | AWS-basen: VPC, EKS, Aurora, S3, ECR, KMS, Secrets Manager, Route 53, larm | Agent med AWS-behörighet | +| `02-tjanster.zip` | Backendbilderna (plattform, ai-orkester) byggs, testas och publiceras; databasschemat initieras | Agent med Docker + ECR-push | +| `03-webb.zip` | Webbilden byggs med miljöns byggargument och publiceras | Agent med Docker + ECR-push | +| `04-arbetslast.zip` | Arbetslasten i klustret: tjänster, ingress, DNS, nätverkspolicyer | Agent med kluster-behörighet | +| `05-verifiering.zip` | Slutkontroll av den driftsatta miljön | Valfri agent, läsbehörighet räcker | + +## Ordningen och varför + +`01` före `02`/`03`: bilderna kan inte publiceras förrän registret +finns. `02`/`03` före `04`: arbetslastens poddar drar bilderna vid +apply — en apply mot tomma repon ger poddar i `ImagePullBackOff`. +`05` sist, alltid: ett steg utan verifiering är inte utfört. +`02` och `03` är oberoende av varandra och får köras parallellt av två +agenter; alla andra steg är sekventiella. + +## Innan något packas upp + +```sh +sha256sum -c SHA256SUMS.txt +``` + +Stämmer inte en summa: stanna och rapportera. Packa upp paketen i EN +gemensam arbetskatalog — vägarna är relativa `felsokning/` och lägger +sig i ett träd (`infra/`, `services/`, `app/`, `docs/`). Varje pakets +anvisning, fillista och versionsstämpel ligger under +`paket//` och krockar därför aldrig med de andras. + +## Verktyg som förutsätts + +Terraform (version enligt `versions.tf`), AWS CLI v2 med behörighet i +målkontot, Docker, Node 22, `kubectl`, `jq`, `psql`. Region enligt +`variables.tf` (standard `eu-north-1`). + +## Regler som gäller varje steg + +1. **Fortsätt aldrig förbi en misslyckad verifiering.** Rapportera vad + som fallerade och stanna — nästa paket förutsätter det förra. +2. **Hemligheter går aldrig in i Terraform, git eller ett paket.** + De sätts direkt i Secrets Manager; tillståndsfilen får aldrig se dem. +3. **En bildtagg pekar på ett bygge, för alltid.** Registret har + oföränderliga taggar; välj en ny tagg per bygge (git-SHA:t i + `PAKET.txt` är rätt val) och använd SAMMA tagg i steg 02, 03 och 04. +4. **Rapportera utfall ordagrant** — vad som kördes, vad som verifierades, + vad som återstår. `terraform output karta` är kvittot i steg 01 och 04. diff --git a/felsokning/deploy/anvisningar/01-aws-bas.md b/felsokning/deploy/anvisningar/01-aws-bas.md new file mode 100644 index 0000000..bf011af --- /dev/null +++ b/felsokning/deploy/anvisningar/01-aws-bas.md @@ -0,0 +1,71 @@ +# Paket 01 · AWS-basen + +Detta paket lägger grunden: nätverk i tre lager, EKS-klustret, Aurora +PostgreSQL, S3 för bilagor, ECR, KMS-nycklar, Secrets Manager, Route 53 +och larm. Allt efterföljande läser den här basens utdata. + +## Förutsättningar + +AWS-behörighet i målkontot, Terraform enligt `infra/aws/versions.tf`. +Läs `infra/aws/README.md` — den förklarar varje val; denna anvisning +är utförandeordningen. + +## Steg + +```sh +cd infra/aws +terraform init +terraform validate +terraform plan -out plan.ut # granska: inga destruktiva ändringar väntas i en ny miljö +terraform apply plan.ut +terraform output karta # hela basen i klartext — bifoga i rapporten +``` + +Variabler som ska sättas medvetet (via `-var` eller en tfvars-fil som +INTE innehåller hemligheter): `doman`, `zon_id`, `larm_epost`, och +`tillatna_api_cidr` snävat till de adresser som ska nå API-servern. +Standardvärdet är öppet enbart för att en ny miljö ska gå att nå alls. + +## Efter apply — fyra saker Terraform inte gör + +1. **Claude-nyckeln** in i Secrets Manager (Terraform ska inte känna + den): + ```sh + aws secretsmanager put-secret-value \ + --secret-id felsokning-produktion/app \ + --secret-string "$(aws secretsmanager get-secret-value --secret-id felsokning-produktion/app \ + --query SecretString --output text | jq '.anthropic_api_key = "sk-ant-…"')" + ``` +2. **Databasschemat.** Aurora ligger i ett datalager utan routing ut; + kör `infra/postgres-init.sql` inifrån klustret: + ```sh + aws eks update-kubeconfig --name + kubectl run psql --rm -i --image=postgres:16 --restart=Never -- \ + psql "" < ../postgres-init.sql + ``` + Det är samma fil som integrationstestet kör — de kan inte glida isär. +3. **Verifiera att `tillatna_api_cidr` är snävat** om det inte gjordes + före apply. +4. **Bekräfta larmprenumerationen** — SNS skickar ett + bekräftelsemejl till `larm_epost`; utan klick går larmen ingenstans. + +## Verifiering — allt ska vara sant innan steget rapporteras klart + +```sh +terraform output karta # kvar_att_gora ska vara tomt utom det som uttryckligen skjutits upp +kubectl get nodes # samtliga Ready +aws ecr describe-repositories \ + --query 'repositories[].repositoryName' # tre repon: web, plattform, ai-orkester +kubectl run schema --rm -i --image=postgres:16 --restart=Never -- \ + psql "" -c "\dt" # tabellerna ur postgres-init.sql finns +``` + +Rapportera `terraform output karta` ordagrant, registeradressen och +klusternamnet — steg 02–04 behöver dem. + +## Stoppvillkor + +Faller `terraform apply`, kör inte om i blindo: läs felet, åtgärda +orsaken, kör `plan` igen och granska. Ett kluster utan Ready-noder +eller ett `kvar_att_gora` med oförklarade punkter betyder stopp, inte +vidare till paket 02. diff --git a/felsokning/deploy/anvisningar/02-tjanster.md b/felsokning/deploy/anvisningar/02-tjanster.md new file mode 100644 index 0000000..1f8b922 --- /dev/null +++ b/felsokning/deploy/anvisningar/02-tjanster.md @@ -0,0 +1,67 @@ +# Paket 02 · Backendtjänsterna + +Detta paket innehåller `services/`: plattformstjänsten (auth, +händelse-API, delning, fakturering), AI-orkestern och den delade koden +i `gemensam/`. Här byggs och publiceras de två backendbilderna. + +Kräver att paket 01 är klart och verifierat: registret och databasen +finns, och du har registeradressen ur dess rapport. Paket 03 är +oberoende av detta paket och får köras parallellt av en annan agent — +men med SAMMA bildtagg. + +## Steg 1 — testa före bygge + +Grönt lokalt är villkoret för att bygga över huvud taget: + +```sh +cd services/plattform +npm ci +bash integrationstest.sh # hela ärendeflödet mot en lokal server +bash aterstallningstest.sh # säkerhetskopian går att läsa tillbaka +``` + +## Steg 2 — bygg bilderna + +Byggkontexten är `services/` — Dockerfilerna hämtar den delade +observationsmodulen därifrån. Taggen är git-SHA:t ur `PAKET.txt`; +registret har oföränderliga taggar, så en tagg som redan finns kan +inte återanvändas. + +```sh +cd services +REG= # t.ex. …dkr.ecr.eu-north-1.amazonaws.com +TAGG= + +docker build -f plattform/Dockerfile -t "$REG/felsokning-plattform:$TAGG" . +docker build -f ai-orkester/Dockerfile -t "$REG/felsokning-ai-orkester:$TAGG" . +``` + +Exakta reponamn: `aws ecr describe-repositories` — avviker de från +raderna ovan gäller registrets namn, inte anvisningens. + +## Steg 3 — publicera + +```sh +aws ecr get-login-password | docker login --username AWS --password-stdin "$REG" +docker push "$REG/felsokning-plattform:$TAGG" +docker push "$REG/felsokning-ai-orkester:$TAGG" +``` + +## Verifiering + +```sh +aws ecr describe-images --repository-name felsokning-plattform \ + --query 'imageDetails[].imageTags' | grep "$TAGG" +aws ecr describe-images --repository-name felsokning-ai-orkester \ + --query 'imageDetails[].imageTags' | grep "$TAGG" +docker run --rm "$REG/felsokning-plattform:$TAGG" node --version # bilden startar +``` + +Rapportera taggen och båda bildernas digest — paket 04 sätter taggen i +`bildtagg` och digesten är svaret på "vilken kod kör i produktion". + +## Stoppvillkor + +Rött integrationstest eller återställningstest: bygg ingenting. +Misslyckad push mot befintlig tagg betyder att taggen redan är använd — +välj en ny tagg (nytt SHA), skriv aldrig över. diff --git a/felsokning/deploy/anvisningar/03-webb.md b/felsokning/deploy/anvisningar/03-webb.md new file mode 100644 index 0000000..beb63f7 --- /dev/null +++ b/felsokning/deploy/anvisningar/03-webb.md @@ -0,0 +1,71 @@ +# Paket 03 · Webbklienten + +Detta paket innehåller `app/` (källkod, utan `node_modules` och `dist`) +och `supabase/` (värdapplikationens migrationsunderlag). Här byggs och +publiceras webbilden — en statisk SPA bakom oprivilegierad nginx. + +Kräver att paket 01 är klart. Oberoende av paket 02 — får köras +parallellt, men med SAMMA bildtagg. + +## Steg 1 — testa före bygge + +```sh +cd app +npm ci +npx vitest run # hela sviten ska vara grön +npm run typkontroll +npm run lint # jämför mot baslinjen i rapporten från leverantören +``` + +## Steg 2 — bygg bilden + +Vite-variablerna bakas in vid byggtillfället och skickas som +byggargument — en färdig bild är alltså knuten till sin miljö. +Plattforms- och orkesteradresserna är miljöns publika adresser (ur +paket 01:s `karta`); Supabase-värdena är värdapplikationens och hämtas +ur organisationens Supabase-projekt. + +```sh +cd app +REG= +TAGG= # samma tagg som paket 02 + +docker build \ + --build-arg VITE_PLATTFORM_URL="https://" \ + --build-arg VITE_AI_ORKESTER_URL="https://" \ + --build-arg VITE_SUPABASE_URL="" \ + --build-arg VITE_SUPABASE_PUBLISHABLE_KEY="" \ + --build-arg VITE_SUPABASE_PROJECT_ID="" \ + -t "$REG/felsokning-web:$TAGG" . +``` + +Den publicerbara Supabase-nyckeln är publik per definition — men den +är det ENDA nyckelvärde som får förekomma i ett byggargument. Allt +hemligt bor i Secrets Manager och når bara backendtjänsterna. + +## Steg 3 — publicera + +```sh +aws ecr get-login-password | docker login --username AWS --password-stdin "$REG" +docker push "$REG/felsokning-web:$TAGG" +``` + +## Verifiering + +```sh +aws ecr describe-images --repository-name felsokning-web \ + --query 'imageDetails[].imageTags' | grep "$TAGG" + +# Bilden serverar och svarar: +docker run --rm -d -p 8080:8080 --name webbprov "$REG/felsokning-web:$TAGG" +curl -fsS http://127.0.0.1:8080/ | grep -q "
-o wide # web, plattform, ai-orkester uppe i angivet antal repliker +kubectl get ingress -n # ALB-adress tilldelad +aws acm list-certificates \ + --query 'CertificateSummaryList[].{d:DomainName,s:Status}' # ISSUED för domänen + +# Hälsokontrollerna genom hela kedjan (DNS → ALB → tjänst): +curl -fsS https:///halsa +curl -fsS https:///halsa +curl -fsS https:/// | grep -q "
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}' +``` +Varje pod kör exakt den bild och tagg som paket 02/03 rapporterade — +jämför digest, inte bara tagg. + +**2. Kedjan utifrån.** +```sh +curl -fsS https:///halsa +curl -fsS https:///halsa +curl -fsS https:/// | grep -q "
/ | grep -i strict-transport-security +``` + +**3. Grinden spärrar på servern.** Skapa ett provärende via API:t och +begär avslut utan uppfyllda krav — svaret ska vara hindren, inte ett +förseglat ärende. (Flödet i detalj: `docs/OPERATIONS.md`.) + +**4. Säkerhetskopiering och återställning.** +```sh +aws rds describe-db-clusters --query 'DBClusters[].{id:DBClusterIdentifier,pitr:EarliestRestorableTime}' +``` +PITR-fönstret finns. Larmet för utebliven backupmätpunkt är aktivt i +CloudWatch — det larmar på SAKNAD data, kontrollera att det inte redan +larmar. + +**5. Larmen är beväpnade.** Fyra larm i CloudWatch, ingen i `ALARM`, +och SNS-prenumerationen på `larm_epost` är bekräftad, inte +`PendingConfirmation`. + +**6. Hemligheterna ligger rätt.** `terraform.tfvars` i paket 04 +innehåller inga nyckelvärden; `kubectl get secret -n ` visar +speglade hemligheter från External Secrets, inte handlagda. + +## Rapporten + +Slutrapporten listar varje kontroll med utfall och belägg (kommandot +och dess svar), bildtagg + digest per tjänst, och det som medvetet +lämnats: obekräftade prenumerationer, öppna CIDR, uppskjutna punkter +ur paket 01. En avvikelse gör inte rapporten misslyckad — en +orapporterad avvikelse gör det. + +Driftdokumentationen som gäller därefter: `docs/OPERATIONS.md` +(drift), `docs/ALVA-SYSTEMBESKRIVNING.md` (systemet), +`docs/GARANTISTANDARD-FGS.md` (garantiflödet). diff --git a/felsokning/deploy/paketera.sh b/felsokning/deploy/paketera.sh new file mode 100755 index 0000000..453fa33 --- /dev/null +++ b/felsokning/deploy/paketera.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# Paketerar plattformen i numrerade zip-paket för agentdriven +# driftsättning på AWS. Se README.md i samma katalog. +# +# Paketen byggs i en arbetskatalog och flyttas färdiga till målet — +# ett avbrutet skript lämnar aldrig ett halvt paket där någon kan +# hitta det. Summorna i 00-plan beräknas över de färdiga paketen, +# därför byggs 00 sist trots att det läses först. +set -euo pipefail + +ROT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # felsokning/ +UT="${1:?ange målkatalog för paketen}" +mkdir -p "$UT" + +VERSION="$(node -e 'import(process.argv[1]).then(m => console.log(m.PLATTFORMSVERSION))' \ + "$ROT/services/gemensam/version.mjs" 2>/dev/null || echo "okänd")" +SHA="$(git -C "$ROT" rev-parse --short HEAD 2>/dev/null || echo "utan-git")" +STAMPEL="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + +# paketera ... — vägarna är relativa ROT. +paketera() { + local namn="$1" anvisning="$2"; shift 2 + local arbets; arbets="$(mktemp -d)" + + # node_modules återskapas ur package-lock; dist byggs i webbilden. + tar -C "$ROT" -cf - --exclude=node_modules --exclude=app/dist "$@" | + tar -C "$arbets" -xf - + + # Metafilerna ligger under paket// så att alla paket kan packas + # upp i SAMMA arbetskatalog utan att skriva över varandras. + mkdir -p "$arbets/paket/$namn" + cp "$ROT/deploy/anvisningar/$anvisning" "$arbets/paket/$namn/ANVISNING-AGENT.md" + printf '%s · %s · paketerad %s · paket %s\n' \ + "$VERSION" "$SHA" "$STAMPEL" "$namn" > "$arbets/paket/$namn/PAKET.txt" + (cd "$arbets" && find . -type f | sort | sed 's|^\./||') > "$arbets/paket/$namn/INNEHALL.txt" + + (cd "$arbets" && zip -qrX "$namn.zip" .) + mv "$arbets/$namn.zip" "$UT/" + rm -rf "$arbets" + du -h "$UT/$namn.zip" | awk '{print " " $2 " " $1}' +} + +echo "paketerar $VERSION ($SHA) → $UT" +rm -f "$UT"/0[0-5]-*.zip + +paketera 01-aws-bas 01-aws-bas.md infra/aws infra/postgres-init.sql +paketera 02-tjanster 02-tjanster.md services +paketera 03-webb 03-webb.md app supabase +paketera 04-arbetslast 04-arbetslast.md infra/terraform +paketera 05-verifiering 05-verifiering.md docs + +# 00-plan: planen + summorna över de fem färdiga paketen. +arbets="$(mktemp -d)" +cp "$ROT/deploy/anvisningar/00-plan.md" "$arbets/DRIFTSATTNING.md" +printf '%s · %s · paketerad %s · paket 00-plan\n' \ + "$VERSION" "$SHA" "$STAMPEL" > "$arbets/PAKET.txt" +(cd "$UT" && sha256sum 0[1-5]-*.zip) > "$arbets/SHA256SUMS.txt" +(cd "$arbets" && zip -qrX 00-plan.zip .) +mv "$arbets/00-plan.zip" "$UT/" +rm -rf "$arbets" +du -h "$UT/00-plan.zip" | awk '{print " " $2 " " $1}' + +echo "klart — läs 00-plan.zip först"