From 8681c55bc8b144dd859af0ea1c79ea97671a9de0 Mon Sep 17 00:00:00 2001 From: vegard Date: Fri, 20 Mar 2026 02:34:50 +0000 Subject: [PATCH] =?UTF-8?q?Kvalitetsprinsipper:=20gj=C3=B8r=20det=20riktig?= =?UTF-8?q?,=20=C3=A9n=20gang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retningslinje for kode og konfigurasjon. Ti prinsipper: ikke hardkod det dynamiske, forstå hvorfor noe fungerer, én mekanisme per problem, konfigurer på lavest nivå, wildcard over spesifikk, sjekkliste for nye domener, test med andre øyne, dokumenter beslutninger, preferer fjerning over tillegg, én fiks ikke to workarounds. Motivert av ORIGIN-fellen ved multi-subdomain. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/retninger/kvalitetsprinsipper.md | 135 ++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 docs/retninger/kvalitetsprinsipper.md diff --git a/docs/retninger/kvalitetsprinsipper.md b/docs/retninger/kvalitetsprinsipper.md new file mode 100644 index 0000000..3da6dad --- /dev/null +++ b/docs/retninger/kvalitetsprinsipper.md @@ -0,0 +1,135 @@ +# Kvalitetsprinsipper — gjør det riktig, én gang + +## Motivasjon + +Bedre med én komponent som fungerer perfekt enn 200 som fungerer +halvveis. Gaffatape-løsninger skaper teknisk gjeld som vokser +eksponentielt. Disse prinsippene gjelder all kode og konfigurasjon +i Synops. + +## 1. Ikke hardkod det som kan utledes + +Hvis verdien kan leses fra konteksten (request, miljø, database), +ikke hardkod den i en konfigurasjonsfil. + +**Feil:** +``` +ORIGIN=https://ws.synops.no # låser hostname +DOMAIN=sidelinja.org # låser domene +API_URL=https://api.sidelinja.org # hardkodet URL +``` + +**Riktig:** +``` +AUTH_TRUST_HOST=true # les hostname fra request +MASKINROMMET_URL=http://127.0.0.1:3100 # intern, hostname-uavhengig +``` + +Spørsmålet å stille: "Hvis vi legger til et subdomain eller bytter +domene i morgen, hva går i stykker?" Hvis svaret er noe — det er +hardkodet og bør utledes dynamisk. + +## 2. Forstå *hvorfor* noe fungerer + +Ikke bare at det fungerer. Når du setter en konfigverdi og ting +begynner å virke, forstå mekanismen. Ellers vet du ikke hva som +knekker når konteksten endres. + +**Feil:** "Jeg la til ORIGIN og da fungerte det." +**Riktig:** "SvelteKit bruker ORIGIN for å bygge event.url. +AUTH_TRUST_HOST=true lar den lese fra Host-headeren i stedet. +Vi trenger ORIGIN bare hvis vi ikke stoler på proxyen — men +Caddy setter riktig Host." + +## 3. Én mekanisme per problem + +Ikke to løsninger som delvis overlapper. Det skaper forvirring +om hvilken som faktisk gjør jobben, og konflikter når de ikke +er enige. + +**Feil:** CSRF-beskyttelse i SvelteKit *og* OIDC PKCE+state. +Når de konflikter (cross-origin POST) vet du ikke hvilken du +skal stole på. + +**Riktig:** OIDC eier CSRF for auth-flyten. SvelteKit sin +origin-sjekk deaktiveres eksplisitt med dokumentert begrunnelse. + +## 4. Konfigurer på lavest mulig nivå + +Foretrekk infrastruktur-konfig over applikasjons-konfig. +Foretrekk konvensjon over konfigurasjon. + +``` +Caddy (routing, TLS, domener) + → SvelteKit (hostname-deteksjon, roller) + → Komponent (viser riktig innhold) +``` + +Ikke la SvelteKit gjøre Caddy sin jobb (ruting). Ikke la +komponenter gjøre SvelteKit sin jobb (auth-sjekk). + +## 5. Wildcard over spesifikk der det er trygt + +Cookie på `.synops.no` fremfor `ws.synops.no` — fordi vi eier +alle subdomener. Caddy lytter på alle domener vi konfigurerer. +Ikke begrens noe du må utvide senere. + +Unntak: sikkerhet. CSRF-token er host-bound (`__Host-`). +Autentisering er domeneovergripende (`.synops.no`). + +## 6. Sjekkliste for nye subdomener/domener + +Før du legger til et nytt domene/subdomain, sjekk: + +- [ ] Finnes det en ORIGIN-variabel som hardkoder hostname? +- [ ] Er cookie-domene kompatibelt (`.synops.no`)? +- [ ] Er OIDC redirect URI registrert i Authentik? +- [ ] Er Caddy-blokken lagt til? +- [ ] Finnes det hardkodede URLer i koden (`https://ws.synops.no/...`)? +- [ ] Bruker koden `event.url.hostname` riktig? + +## 7. Test med andre øyne + +Etter implementering, tenk: "Hva skjer om..." +- ...vi legger til et tredje subdomain? +- ...vi bytter fra synops.no til annet domene? +- ...en bruker har gammel cache/cookies? +- ...Caddy restarter med nytt sertifikat? + +Hvis svaret er "det går i stykker" — det er hardkodet. + +## 8. Dokumenter beslutninger, ikke bare kode + +Ikke bare *hva* som ble gjort, men *hvorfor*. Og spesielt: +*hva vi vurderte og valgte bort*. Neste person (eller neste +Claude-sesjon) som leser koden trenger å forstå intensjonen, +ikke bare mekanismen. + +## 9. Preferer fjerning over tillegg + +Hvis du kan løse problemet ved å fjerne kode/konfig i stedet +for å legge til, gjør det. Fjerne ORIGIN var bedre enn å legge +til ORIGIN-liste med flere domener. + +Mindre kode = færre feil = enklere å forstå. + +## 10. Én fiks, ikke to workarounds + +Når noe ikke fungerer, finn rotårsaken. Ikke legg på et lag +med workarounds som maskerer problemet. To workarounds er +verre enn én ufikset bug — fordi de interagerer uforutsigbart. + +**Feil:** +1. ORIGIN hardkodet → fungerer for ws +2. adm fungerer ikke → legg til hostname-sjekk i hooks +3. Cookie fungerer ikke → sett wildcard-domene +4. CSRF blokkerer → deaktiver CSRF + +(Fire endringer for å kompensere for én feilkonfigurert variabel) + +**Riktig:** +1. Fjern ORIGIN (rotårsaken) +2. Cookie wildcard (nødvendig for multi-subdomain uansett) +3. CSRF deaktivering (riktig når OIDC eier auth-flyten) + +(Tre endringer, men hver er riktig i seg selv — ikke workarounds)