# Forslag: Avisvisning

## Idé
En read-only blokk som rendrer workspace-aktivitet som en avis — sortert etter prominens (klikk, svar, reaksjoner, graf-koblinger, alder). Ingen redigering, ingen forvaltning, bare et annet blikk inn på det som allerede finnes. Med et søkefelt som lar deg filtrere på en entitet, slik at du kan få "Jonas Gahr Støre-avisen" eller "Skolepolitikk-avisen" — alt vi har om akkurat det temaet/den personen, rangert etter viktighet.

## Hvorfor er dette interessant?

### Et nytt perspektiv uten ny data
All data finnes allerede: meldinger, artikler, graf-koblinger, reaksjoner, svar-tråder, kalender-hendelser. Avisvisningen er bare en spørring + et layout. Ingen ny datamodell, ingen ny input — bare en ny måte å lese på.

### Entitet-filter som superkraft
Kunnskapsgrafen kobler alt til entiteter via `MENTIONS`-edges. Et filter på én entitet gir deg øyeblikkelig alt workspace vet om den — som en personlig nyhetsfeed:

- `#Jonas Gahr Støre` → alle meldinger, artikler, faktoider, episodesegmenter som nevner ham
- `#Skolepolitikk` → alt om temaet, på tvers av channels og tidsperioder
- `#Episode 42` → alt knyttet til den episoden: research, diskusjon, show notes, publiserte artikler
- Ingen filter → hele workspacets aktivitet, rangert etter prominens

### Arkiv
Innhold som overlever TTL-opprydding (har graf-koblinger, er pinned, har mange svar) er per definisjon det viktige. Avisvisningen har to moduser:

**Dagsaktuelt** (default): Rangert med alders-boost — nytt innhold scorer høyere. Viser det som skjer *nå*.

**Arkiv**: Samme spørring uten alders-boost. Alt som noensinne har hatt tyngde for denne entiteten, kronologisk eller rangert etter total prominens. En historisk oversikt: "Hva har vi sagt og skrevet om skolepolitikk gjennom tidene?"

## Hva bygger den på?
- **Meldingsboks** — alt innhold er meldinger med view-configs
- **Prominens-score** (meldingsboks §7.3) — beregnes fra svar, stemmer, roller, graf-koblinger, alder
- **Kunnskapsgraf** — `MENTIONS`-edges gir entitets-filtrering
- **Komponerbare sider** — avisvisningen er en blokk som kan plasseres på en side

## Skisse

### UI

**Header med søk:**
```
┌─────────────────────────────────────────────────┐
│ 📰 Avis        [# Søk entitet...          ▼]   │
│                  Skolepolitikk                   │
│                  [Dagsaktuelt] [Arkiv]           │
├─────────────────────────────────────────────────┤
```

Søkefeltet er `#`-autocomplete mot entities-tabellen — samme mekanisme som i editoren og chatten. Velg en entitet, avisen filtrerer seg.

**Avis-layout (dagsaktuelt):**
```
┌──────────────────────┬──────────────────────────┐
│                      │ Artikkel: Ny rapport fra  │
│  TOPPSAK             │ Utdanningsforbundet       │
│  (høyest prominens)  │ 12 reaksjoner · 2t siden  │
│                      ├──────────────────────────┤
│  Tittel, ingress,    │ Chat: Interessant tråd i  │
│  forfatter, bilde    │ #Mediepolitikk            │
│  23 svar · 45 min    │ 8 svar · 5t siden         │
│                      ├──────────────────────────┤
│                      │ 📅 I morgen: Intervju med │
│                      │ Kunnskapsministeren        │
├──────┬───────┬───────┴──────┬───────────────────┤
│Fakto-│Segment│ Kanban-kort  │ Notat: Research   │
│ide   │Ep. 42 │ "Skriv intro"│ om PISA-tall      │
│⬆12   │14:23  │ → In Progress│ Oppdatert i går   │
└──────┴───────┴──────────────┴───────────────────┘
```

Størrelsen på hver "sak" bestemmes av prominens-scoren. Toppsaken er størst. Lavere score = mindre kort. Ren CSS grid med dynamisk `grid-row: span N` basert på score-kvantiler.

**Arkiv-layout:**
```
┌─────────────────────────────────────────────────┐
│ 📰 Arkiv: Skolepolitikk       [Dagsaktuelt] [Arkiv]│
├─────────────────────────────────────────────────┤
│ 2026                                            │
│ ├── Mars: "Ny PISA-rapport" (artikkel, 45 ⬆)   │
│ ├── Mars: Diskusjon om budsjettkutt (23 svar)   │
│ ├── Feb: Episode 42 segment om skolepolitikk    │
│ 2025                                            │
│ ├── Nov: "Lærermangel i distriktene" (artikkel) │
│ ├── Sep: Faktoide: Antall lærerstudenter 2024   │
│ └── ...                                         │
└─────────────────────────────────────────────────┘
```

Arkivet er en kronologisk liste gruppert etter tidsperiode. Enklere layout, tyngre på metadata (type, score, alder). Fungerer som et oppslagsverk.

### Rangering: Alder først, prominens som tiebreaker

Dette er en **avis**, ikke et oppslagsverk. Nytt innhold skal alltid dominere. En fersk melding med 2 svar slår en gammel med 50. Prominens avgjør bare *innenfor omtrent samme tidsperiode* — hvilken av dagens saker er toppsaken.

**Modell: Tidsvinduer med intern prominens-rangering**

Innholdet deles i tidsvinduer. Innenfor hvert vindu rangeres det etter prominens. Vinduer vises i rekkefølge — nyeste først.

```
Siste 24 timer     → rangert etter prominens (dette er "forsiden")
1–3 dager siden    → rangert etter prominens (side 2 / bla-ned)
3–7 dager siden    → rangert etter prominens (eldre nyheter)
7–30 dager siden   → bare det mest prominente overlever (highlights)
```

Brukeren blar nedover for å gå bakover i tid, men innenfor hver tidsperiode ser de det viktigste først.

**SQL-tilnærming:**

```sql
WITH scored AS (
    SELECT
        m.id,
        m.title,
        m.body,
        m.created_at,
        -- Prominens (tiebreaker innenfor tidsvindu)
        (SELECT COUNT(*) FROM messages r WHERE r.reply_to = m.id) * 2
      + (SELECT COUNT(*) FILTER (WHERE reaction = 'upvote')
              - COUNT(*) FILTER (WHERE reaction = 'downvote')
         FROM message_reactions mr WHERE mr.message_id = m.id) * 3
      + (SELECT COUNT(*) FROM graph_edges ge WHERE ge.source_id = m.id) * 5
      + (CASE WHEN EXISTS (SELECT 1 FROM article_view a WHERE a.message_id = m.id) THEN 10 ELSE 0 END)
        AS prominence,
        -- Tidsvindu-bucket
        CASE
            WHEN m.created_at > now() - interval '1 day'  THEN 1
            WHEN m.created_at > now() - interval '3 days' THEN 2
            WHEN m.created_at > now() - interval '7 days' THEN 3
            ELSE 4
        END AS time_bucket
    FROM messages m
    JOIN nodes n ON n.id = m.id
    WHERE n.workspace_id = $workspace_id
      AND ($entity_id IS NULL OR EXISTS (
          SELECT 1 FROM graph_edges ge
          WHERE ge.source_id = m.id
            AND ge.target_id = $entity_id
            AND ge.relation_type = 'MENTIONS'
      ))
      -- Minimumsterskel: ikke vis støy
      AND (
          m.pinned = true
          OR m.title IS NOT NULL
          OR EXISTS (SELECT 1 FROM messages r WHERE r.reply_to = m.id)
          OR EXISTS (SELECT 1 FROM graph_edges ge WHERE ge.source_id = m.id)
          OR EXISTS (SELECT 1 FROM message_reactions mr WHERE mr.message_id = m.id)
      )
)
SELECT *
FROM scored
ORDER BY time_bucket ASC, prominence DESC
LIMIT 30;
```

**Hvorfor tidsvinduer og ikke en multiplikativ formel?**

En `score * recency_decay`-formel er vanskelig å balansere universelt. Med høy decay dominerer alltid det nyeste — prominens betyr ingenting. Med lav decay kryper gamle tungvektere opp og skyver bort nyhetene. Tidsvinduer unngår dette: nytt er alltid først, men innenfor "i dag" får prominens avgjøre hva som er toppsaken.

**Minimumsterskel:** Ikke alt hører hjemme i avisen. En enkel "hei" uten svar, reaksjoner eller graf-koblinger er støy. Spørringen filtrerer bort meldinger som ikke har *noen* form for tyngde (tittel, svar, reaksjoner, edges, pinned). Dette er avisen — ikke firehosen.

**Tuning over tid:** Vektene (2, 3, 5, 10) og tidsvindu-grensene (1d, 3d, 7d) er konfigurerbare uten migrasjoner. Kan lagres i `workspaces.settings` og justeres per workspace etter behov. Men vi starter med én universell default og justerer basert på faktisk bruk.

**Arkiv-modus:** Ingen tidsvinduer. Sortert etter `created_at DESC` (kronologisk) med prominens som sekundær sortering. Alt som har overlevd TTL-opprydding vises — gruppert etter måned/år.

### Kort-typer

Ulike meldingstyper rendres med ulike kort i avisen:

| Kilde | Kort-layout |
|---|---|
| Melding med mange svar | Tittel/ingress + svar-tall + siste aktivitet |
| Artikkel (article_view) | Tittel + excerpt + forfatter + bilde |
| Kanban-kort | Tittel + kolonne + assignee |
| Kalenderhendelse | Tittel + dato/tid + "om 2 dager" |
| Faktoide (ABOUT-edge) | Innhold + stemme-score + tilknyttet entitet |
| Episodesegment | Episode-tittel + tidsrom + transkripsjon-utdrag |
| Notat med tittel | Tittel + oppdatert-dato |

Alle er lenker — klikk fører deg til meldingen i sin naturlige kontekst (chatten, kanban-brettet, kalenderen, etc.).

### Blokk i komponerbare sider

Avisvisningen er en blokk-komponent (`<NewsView>`) som kan plasseres på en komponerbar side:

```jsonc
{
  "type": "news",
  "config": {
    "entity_id": null,        // null = hele workspacet, UUID = filtrert
    "mode": "current",        // "current" eller "archive"
    "limit": 20
  },
  "span": 2                   // tar gjerne full bredde
}
```

Kan også stå alene som en dedikert side i workspacet — "Avisen" i navigasjonen.

## Åpne spørsmål

### Flere entiteter
- Filtrere på flere entiteter samtidig? "Alt om #Skolepolitikk OG #Støre" (AND) vs "Alt om #Skolepolitikk ELLER #Støre" (OR)?
- Trolig: start med én entitet. Kombiner-logikk er et steg videre.

### Caching
- Prominens-scoren er en tung spørring med subqueries. For en aktiv workspace med mange meldinger bør den caches.
- Materialized view som refreshes periodisk (hvert 5. minutt)? Eller beregnes on-demand med cache-TTL?
- For arkiv-modus er caching enklere — dataen endres sjelden.

### Personalisering
- Ser alle samme avis, eller kan den vektes mot brukerens interesser?
- Start: alle ser det samme. Personalisering er et stort steg (og potensielt en filterboble-felle).

### Layout-algoritme
- Hvor mange "størrelser" av kort? Tre nivåer (stor/medium/liten) er trolig nok.
- Hvordan fordeles plass? Kvantiler: topp-10% er store, neste 30% medium, resten små?
- Responsivt: på mobil stacker alt vertikalt, største sak øverst.

### Oppdatering
- Sanntid (nytt innhold dukker opp)? Eller "pull to refresh" / periodisk?
- Trolig: periodisk (hvert minutt) + manuell refresh-knapp. Sanntid gir en "flimrende" opplevelse i et avis-layout.

## Innsats: Lav–Middels
Spørringen er rett frem (prominens-faktorer finnes allerede). Layout er CSS grid. Kort-komponentene gjenbruker eksisterende `<MessageBox>`-varianter. Den tyngste delen er å tuning av rangering og layout-algoritme for at det skal *føles* som en avis.

## Wow-faktor: Høy
"Skriv #Støre i søkefeltet og få en hel avis med alt vi vet om ham" er en øyeblikkelig aha-opplevelse. Kombinasjonen av graf-filtrering og avis-layout gjør kunnskapsgrafen *synlig* på en måte som graf-visualisering aldri klarer for folk flest.

## Relasjon til andre proposals
- **Komponerbare sider** — avisvisningen er en blokk
- **Tekst-primitiv / Meldingsboks** — all data som vises er meldinger med view-configs
- **Kunnskapsgraf** — entitets-filtrering er en graf-spørring
- **Artikkel-publisering** — publiserte artikler får prominente kort i avisen
