# Arbeidsflaten — verktøy og rom

**Status: Besluttet.**

> Arbeidsflaten er en spatial canvas der verktøy-paneler lever side ved side.
> Brukeren arrangerer sitt eget rom. Drag-and-drop mellom verktøy er
> kjerneinteraksjonen. Innhold flyter mellom verktøy via nye noder og edges.

## Observasjoner

Synops har bygget chat, kanban, kalender, studio, kunnskapsgraf — hver som
sin visning. De er alle spørringer mot samme graf, men de lever på separate
ruter (`/chat/[id]`, `/board/[id]`, `/calendar`). Brukeren navigerer mellom
dem.

Tidligere beskrev vi at innhold "vokser" mellom kategorier: en chatmelding
kan "bli" en artikkel ved å få edges. Arkitektonisk elegant, men klønete i
praksis — du vil ikke redigere en chatboble til en langform-artikkel.

Observasjoner som ledet hit:

- **Verktøy-spesifikke oppgaver trenger verktøy-spesifikke grensesnitt.**
  En artikkel-editor er ikke en chat-input. Et lydstudio er ikke en
  medieavspiller. Å late som alt er én overflate gir dårlig UX.
- **Kontekstbytte koster.** Å navigere mellom /chat og /board og /calendar
  bryter flyten. Verktøyene bør leve side ved side.
- **Innhold bør flyttes mellom verktøy, ikke muteres.**
  Når en chatmelding inspirerer en artikkel, bør resultatet være en *ny*
  artikkelnode med en edge tilbake til meldingen — ikke en mutert melding.

## Tesen

**Arbeidsflaten er et personlig rom med verktøy-paneler.** Brukeren
arrangerer sin egen flate med de verktøyene de trenger. Drag-and-drop
mellom paneler er den primære interaksjonen for å flytte innhold.

Nøkkelprinsipp: **Noder føder nye noder.** Når innhold flyttes mellom
verktøy, opprettes nye noder med `source_material`-edges tilbake til
kilden. Originalen forblir uendret. Artikkelen sporer sine kilder
gjennom grafen.

## Verktøy-paneler

Hvert verktøy er en selvinneholdt Svelte-komponent som:
- Tar `nodeId` / `collectionId` + config som props
- Håndterer egen datahenting og tilstand
- Respekterer container-størrelse (responsive innenfor panelet)
- Kan maksimeres til fullskjerm
- Implementerer drag-and-drop mottak der det gir mening

| Verktøy | Hva det gjør | Aksepterer drag |
|---------|--------------|-----------------|
| **Chat** | Sanntidsmeldinger i kommunikasjonsnode | Vilkårlig node → del som melding |
| **Artikkelverktøy** | TipTap langform-editor | Chatbobler, tekst, transkripsjoner, bilder, lyd |
| **Kanban** | Oppgavestyring med kolonner | Chatbobler, tekst → ny oppgave |
| **Kalender** | Tidslinje med `scheduled`-edges | Kanban-kort, chatbobler → ny hendelse |
| **Lydstudio** | Waveform-redigering, ffmpeg-prosessering | Lydfiler → åpne i studio |
| **Kunnskapsgraf** | D3-visualisering av noder og edges | — (visuell utforsker) |
| **Transkripsjon** | Segmenter synkronisert med lyd | — (les-visning) |
| **Dagbok** | Private notater, kronologisk | — (personlig) |
| **AI-verktøy** | Konfigurerbar AI-tekstbehandling med prompt-velger | Tekstnoder, chatbobler, transkripsjoner → AI-prosessert output |

## Drag-and-drop mellom verktøy

### Mekanisme

1. Bruker drar en node fra verktøy A
2. Under drag vises drop-soner i kompatible verktøy
3. Ved drop: mål-verktøyet bestemmer hva som skjer
4. Typisk: ny node opprettes + `source_material`-edge til kilden
5. Alternativt: eksisterende node får ny edge (lettvekts-triage)

### To moduser

| Modus | Hva skjer | Når |
|-------|-----------|-----|
| **Innholdstransfer** | Ny node opprettes med `source_material`-edge | Innholdet transformeres (chat → artikkel, chat → oppgave) |
| **Lettvekts-triage** | Eksisterende node får ny edge | Kontekst legges til (node → kanban-board, node → kalender) |

Default avhenger av verktøy-paret. Bruker kan overstyre med modifier-tast
(Shift = alltid ny node).

## Kompatibilitetsmatrise

| Kilde → Mål | Artikkelverktøy | Chat | Kanban | Kalender | Studio |
|---|---|---|---|---|---|
| **Chatboble** | Ny artikkelnode, sitert tekst, `source_material` | (samme kontekst) | Ny oppgave + `source_material` | Ny hendelse + `source_material` | — |
| **Tekst/notat** | Kopier inn, `source_material` | Del som melding med `mentions` | Ny oppgave | Ny hendelse | — |
| **Lydfil** | Sett inn avspiller, `has_media` | Del med mention | — | — | Åpne i studio |
| **Lydfil → Lydfil** | — | — | — | — | **Inkompatibel** |
| **Transkripsjon** | Sett inn tekst + `source_material` | Del utdrag | — | — | — |
| **Kanban-kort** | Kopier innhold + `source_material` | Del som melding | (flytt mellom kolonner) | Legg til `scheduled` edge | — |
| **Bilde** | Sett inn + `has_media` | Del som melding | — | — | — |
| **Vilkårlig node** | — | Del-melding med `mentions` | — | — | — |
| **AI-verktøy → node** | — | — | — | — | — |

**AI-verktøy som mål:**

| Kilde → AI-verktøy | Resultat |
|---|---|
| **Chatboble** | Ny node med AI-output + `derived_from`-edge |
| **Tekst/notat** | Ny node med AI-output + `derived_from`-edge |
| **Transkripsjon** | Ny node med AI-output + `derived_from`-edge |
| **Lydfil/bilde** | Inkompatibel: "AI-verktøyet behandler kun tekst" |

**AI-verktøy som kilde (dra verktøyet → tekstnode):**
Modifiserer noden in-place. Originalen versjoneres. Se `docs/features/ai_verktoy.md`.

"—" betyr at kombinasjonen ikke gir mening og drop-sonen er inaktiv.

## Inkompatibilitet

Ikke alt kan gå overalt. Når en drag er inkompatibel:

1. **Visuell feedback:** Drop-sonen blir rød/grå under drag-over
2. **Forklaring:** Tooltip viser *hvorfor* — ikke bare "kan ikke slippes her"
3. **Alternativ:** Foreslå en bedre handling der det er mulig

### Eksempler

| Forsøk | Feedback |
|--------|----------|
| Lydfil → Lydfil | "Lydfiler kan ikke slås sammen direkte. Åpne i Studioet for å redigere." |
| Bilde → Studio | "Studioet behandler kun lydfiler." |
| Lydfil → Kanban | "Lydfiler kan ikke bli oppgaver direkte. Dra til Chat for å dele, eller til Artikkelverktøyet for å sette inn." |

## Tre lag for arbeidsflaten

Hver bruker har sin egen arbeidsflate. Arrangement lagres som preferanser
på brukernoden.

| Lag | Kilde | Forrang |
|-----|-------|---------|
| **Personlig** | Brukerens eget arrangement | Høyest — overstyrer alt |
| **Node-default** | Samlingens traits foreslår layout | Mellom — utgangspunkt |
| **Plattform-default** | Synops sine standarder | Lavest — fallback |

Eksempel: en samling med `podcast` + `studio` + `chat` traits foreslår
en layout med disse tre panelene. Brukeren kan flytte, legge til, fjerne
paneler fritt. Arrangementet huskes per bruker per kontekst.

### Personlig arbeidsflate (oppgave 19.6)

Hver bruker har én workspace-node (`node_kind: 'workspace'`), opprettet
automatisk ved første besøk via `GET /my/workspace`. Denne er brukerens
standard arbeidsflate — vises på `/workspace` når brukeren ikke er i en
spesifikk samling.

- **Layout:** Lagres i workspace-nodens `metadata.workspace_layout`
  (samme format som samlingslayout, men via `updateNode` i stedet for edge-metadata)
- **Paneler:** Brukeren velger fritt fra verktøymenyen — ikke bundet til traits
- **Navigasjon:** `/` er arbeidsflaten (ws.synops.no). Kontekst-velger
  i headeren bytter til samlingssider
- **Provisjonering:** Backend oppretter workspace-node + owner-edge ved
  første forespørsel. PG-skriving med NOTIFY for sanntidsoppdatering.

## `source_material`-edge

Ny edge-type som kobler en avledet node til kilden den ble laget fra.

```
Artikkel-node ──source_material──→ Chatboble
Artikkel-node ──source_material──→ Transkripsjonssegment
Artikkel-node ──source_material──→ Notat
```

Edge-metadata:
```jsonc
{
  "context": "quoted",      // "quoted", "summarized", "referenced"
  "excerpt": "Den opprinnelige teksten som ble dratt inn"
}
```

Gir artikler sporbar lineage: du kan alltid se *hvor* materialet kom fra.

## Forhold til andre retninger

- **[Rom, ikke forum](rom_ikke_forum.md):** Arbeidsflaten *er* rommet.
  Verktøy-paneler er lagene som kan slås av og på. "Trylle frem, legge
  fra seg" realiseres som paneler som dukker opp og forsvinner.
- **[Universell input](universell_input.md):** Input-primitiven lever
  i hvert verktøy med kontekst-tilpasset konfigurasjon. Arbeidsflaten
  bestemmer *hvor* input havner.
- **[Noder er sentrum](bruker_ikke_workspace.md):** Verktøy er visninger
  av grafen. Arbeidsflaten er brukerens personlige arrangement av disse
  visningene.
- **[Datalaget](datalaget.md):** PG LISTEN/NOTIFY + WebSocket driver
  sanntidsoppdatering mellom paneler. Drag-and-drop oppretter noder/edges
  som propageres via sanntidsstrømmen.

## Hva ville vært annerledes

- Chat, kanban, kalender lever **side ved side**, ikke som separate sider
- Du **drar en chatboble til artikkelverktøyet** i stedet for å "retype"
  den med edges
- Artikkelen **sporer sine kilder** via `source_material`-edges
- Inkompatible handlinger gir **tydelig feedback** med forklaringer
- Brukerens arrangement er **personlig og persistent** — du setter opp
  arbeidsflaten din én gang og den huskes
