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)