synops/docs/retninger/kvalitetsprinsipper.md
vegard 8681c55bc8 Kvalitetsprinsipper: gjør det riktig, én gang
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) <noreply@anthropic.com>
2026-03-20 02:34:50 +00:00

135 lines
4.3 KiB
Markdown

# 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)