# Konsept: Valgomaten (Crowdsourced & Datadrevet)
**Filsti:** `docs/concepts/valgomaten.md`

## 1. Konsept & Kjernefilosofi
Neste generasjons valgomat tar et oppgjør med den redaktørstyrte, endimensjonale modellen. Istedenfor forhåndsdefinerte akser styrer brukerne innholdet "bottom-up" gjennom et marked for akser. Valgomaten kombinerer friksjonsfri "Tinder-swiping" for folk flest, med et dyptgående redaksjonelt verktøy for nerdene, alt bygget på toppen av Sidelinjas eksisterende Kunnskapsgraf og sanntidsinfrastruktur.

### 1.1 Markedsmekanisme
Brukere kan fritt opprette nye politiske akser og spørsmål. Dimensjoner som engasjerer (får mange svar) "bobler opp" og blir standardakser, mens irrelevante forsvinner. Ingen begrensning på antall akser — systemet støtter komplekse skillelinjer i samfunnet.

### 1.2 Teoretisk fundament (Default-akser)
For å unngå "Blank Canvas"-syndromet startes plattformen med anerkjente rammeverk som fungerer som ankere:
* **John Haidts Moral Foundations Theory:** Omsorg, Rettferdighet, Lojalitet, Autoritet, Renhet.
* **Rokkans skillelinjer:** Sentrum/periferi, by/land, religiøs/sekulær.
* **Nanny State Index:** Formynderstat vs. personlig frihet og ansvar.
* **Intensjon vs. Resultat:** Støttes politikk på bakgrunn av teoretisk målsetting eller empirisk utfall?

## 2. Brukeropplevelse (Trakten)
Valgomaten er bygget som en to-trinns trakt for å maksimere viral spredning samtidig som dataintegriteten bevares.

### 2.1 Forsiden: Friksjonsfri & Anonym
* **Mekanikk:** Ingen registrering kreves for å starte. SvelteKit genererer en anonym UUID som lagres i `localStorage`.
* **UX:** Et rent kortstokk-grensesnitt (Tinder-stil swipe). Påstand på forsiden, brukeren velger Enig/Uenig.
* **Tre-trinns kalibrering (OKCupid-inspirert):**
  1. Hva mener du?
  2. Hva ønsker du at kandidaten skal mene?
  3. Hvor viktig er dette for deg?
* **Dealbreakers (Negative Veto):** Brukere kan sette absolutte grenser (f.eks. "Uansett hvor enige vi er om skatt, matcher jeg aldri med en som er for/mot vindkraft").
* **Sanntid:** PCA (Prinsipalkomponentanalyse) beregnes og oppdaterer brukerens posisjon for hvert swipe.

### 2.2 Baksiden: "Snu kortet" (Krever innlogging)
For avansert interaksjon må brukeren logge inn via Authentik (SSO). Den anonyme sesjonen flettes da automatisk med brukerprofilen. På baksiden av kortet finner man:
* **Folkets Redaksjonsmøte:** Mulighet til å se andres kommentarer til spørsmålet, foreslå endringer, og stemme opp/ned forbedringsforslag.
* **Podcast-snarveien:** Hvis spørsmålet er knyttet til et *Tema* i Kunnskapsgrafen, vises en "Play"-knapp. Caddy (`Accept-Ranges: bytes`) streamer tidsstemplede lydsegmenter fra tidligere Sidelinja-episoder der dette temaet ble diskutert.
* **Multi-akse vekting:** Innsikt i hvilke akser spørsmålet påvirker (f.eks. 80% Klima, 20% Sentrum/Periferi), med mulighet for å foreslå nye akse-koblinger.

## 3. Matching & Resultat

### 3.1 Individfokus
Matcher velgeren mot spesifikke lokalpolitikere og listekandidater, ikke bare mot det sentrale partiprogrammet.

### 3.2 PCA (Prinsipalkomponentanalyse)
Matematisk reduksjon av kompleksitet. Algoritmen koker ned brukerens svar på tvers av 50+ variabler til de 2-3 hovedfaktorene som faktisk styrer vedkommendes politiske kompass, og visualiserer disse spesifikt for brukeren.

## 4. Crowdsourcing & Dataintegritet

### 4.1 Uforanderlig Historikk (Versjonering)
Et spørsmål i PostgreSQL kan *aldri* endres (`UPDATE`) etter at folk har begynt å svare på det.
* Hvis et forbedringsforslag stemmes frem (eller godkjennes av redaksjonen), opprettes en ny versjon (f.eks. `Spørsmål 42 (v2)`).
* Brukere beholder sine resultater knyttet til den nøyaktige teksten de leste. Algoritmen vet at v1 og v2 tilhører samme politiske konsept.

### 4.2 Opprettelse av nye spørsmål og akser (Sandkassen)
* **Inkubator:** Innloggede brukere kan opprette nye spørsmål eller definere helt nye akser (ved å angi to motpoler). Disse havner i en "Sandkasse" og vises ikke på forsiden før de har fått nok organisk engasjement fra andre innloggede brukere.
* **Vekting via Graph Edges:** Koblingen mellom et spørsmål og en akse lagres som en relasjon i `graph_edges`. Når brukere "stemmer opp" at et spørsmål tilhører en spesifikk akse, øker feltet `confidence`. Denne `confidence`-scoren brukes som multiplikator i match-algoritmen.

## 5. Visualisering & Sidelinja Explorer

### 5.1 Innhenting av referansedata
For å bygge nøyaktige velgerkart, introduseres et valgfritt spørsmål før resultatet vises: *"For å kalibrere landskapet: Hva stemte du ved forrige valg?"*. Dette knytter den anonyme eller innloggede sesjonen mot en parti-`aktør` i Kunnskapsgrafen.

### 5.2 Sidelinja Explorer (Offentlig Graf)
En egen SvelteKit-side der lekfolk og journalister kan analysere dataene.
* **Heatmaps:** Viser klynger ("skyer") av velgermasser basert på partipreferanse på to valgfrie akser.
* **Varder i landskapet:** Historiske figurer (Churchill, Stalin), nåværende politikere og Sidelinjas egne verter ligger inne som faste referansepunkter i grafen. AI-estimerte profiler gir pedagogisk (og underholdende) kontekst.

## 6. AI & Asynkron Prosessering
Av kostnads- og ytelseshensyn skjer all AI-bruk asynkront i backend via jobbkøen og `ai-gateway` (LiteLLM). Ingen live AI-kall i klienten.

* **AI-Kandidater (`valgomat_generate_profile`):** En bakgrunnsjobb analyserer partiprogrammer via `sidelinja/rutine` (Gemini) og genererer "syntetiske" referanseprofiler for listekandidater og historiske figurer. Kandidater kan senere logge inn (Authentik) og overstyre AI-ens svar manuelt.
* **Semantisk deduplisering (`valgomat_moderation`):** En asynkron jobb overvåker nye brukerskapte akser og spørsmål, slår sammen duplikater (f.eks. "Skattetrykk" og "Skattenivå"), og flagger emosjonelt ladede spørsmål for Sidelinja-redaksjonen i Redaksjonens chat.

## 7. Arkitektur & Ansvarsfordeling

| Komponent | Rolle / Ansvar |
|---|---|
| **SvelteKit (Klient)** | UX, Anonym UUID-håndtering i `localStorage`, kortstokk-swipe-grensesnitt, "lazy loading" av baksiden ved innlogging, visning av Heatmaps via Sidelinja Explorer. |
| **Authentik** | SSO for brukere, kandidater og redaksjon. Sammenfletting av anonym UUID med ekte bruker-ID. |
| **Sanntid (WebSocket)** | Match-kalkulering, swiping-logikk, PCA-beregning. Sanntidsoppdateringer via PG LISTEN/NOTIFY + WebSocket. |
| **PostgreSQL** | Kunnskapsgrafen (`nodes`, `graph_edges`). Permanent lagring av spørsmål, akser, versjonshistorikk og aggregerte data for Sidelinja Explorer. |
| **PostgreSQL** | Eneste datakilde for spørsmål, akser, svar og kunnskapsgraf. |
| **Rust Worker (AI)** | Kjører `valgomat_generate_profile` og `valgomat_moderation` via jobbkøen. |

## 8. Dataklassifisering (ref. docs/arkitektur.md 2.2)

| Data | Kategori | Detaljer |
|---|---|---|
| Spørsmål, akser, versjonshistorikk | Kritisk (PG) | Brukergenerert innhold, krever backup |
| Individuelle svar (aggregert) | Kritisk (PG) | Lagret direkte i PG |
| AI-genererte kandidatprofiler | Avledet (PG) | Kan regenereres fra partiprogrammer |

## 9. Skaleringsrisiko

### PCA-beregning
PCA-beregning er potensielt tung ved mange brukere og akser. Tiltak:
- **Materialized Views i PostgreSQL** for Sidelinja Explorer — aldri kjør tunge aggregeringer on-the-fly. Oppdater views via nattlig jobb.
- **PCA i PG** — beregnes i PostgreSQL med caching og oppdateringsintervall.
- **Overvåk tidlig** — legg til valgomat-spesifikke metrikker i `/admin/observability` (antall aktive sesjoner, PCA-beregningstid).

## 10. Instruks for Claude Code
1. **Datamodell:** Utvid enum `node_type` i PostgreSQL med `valgomat_question` og `valgomat_axis`. Bruk `graph_edges` med `relation_type = 'AFFECTS_AXIS'` og oppdater `confidence`-feltet for å håndtere crowdsourcet vekting av spørsmål opp mot ulike akser.
2. **Swiping-logikk:** Implementer `SubmitSwipe`, `SuggestAxis` og match-algoritmen i maskinrommet. Støtt anonym `session_id`.
3. **State Management:** SvelteKit skal ikke kreve innlogging for forsiden. Implementer Auth-guards slik at opprettelse av spørsmål, stemmegivning på andres forslag og visning av kommentarer gir `403 Forbidden` for uautoriserte og trigger Authentik-flyten.
4. **Explorer API:** Bygg aggregerte Materialized Views i PostgreSQL for Sidelinja Explorer for å unngå tung on-the-fly kalkulering av Heatmaps over millioner av rader.
5. **Jobbtyper:** Registrer `valgomat_generate_profile` og `valgomat_moderation` som jobbtyper i jobbkøen (se `jobbkø.md`). Bruk `sidelinja/rutine` som modellalias.
6. **Versjonering:** Spørsmål er append-only. Nye versjoner er nye rader med referanse til forgjengeren — aldri `UPDATE` på tekst som har mottatt svar.
