SpacetimeDB er nå helt fjernet fra Synops. Sanntid håndteres av PG LISTEN/NOTIFY + WebSocket i portvokteren (maskinrommet). Kode fjernet: - spacetimedb/ Rust-modul og spacetime.json - maskinrommet/src/stdb.rs (HTTP-klient for STDB-reducers) - frontend module_bindings/ (23 auto-genererte filer) - spacetimedb npm-avhengighet fra package.json - scripts/test-sanntid.sh (testet STDB-flyt) Infrastruktur: - Docker-container stoppet og fjernet fra docker-compose.yml - Caddy: fjernet /spacetime/* reverse proxy - maskinrommet-env.sh: fjernet STDB_IP og SPACETIMEDB_*-variabler - .env.example: fjernet SpacetimeDB-seksjoner Dokumentasjon oppdatert: - CLAUDE.md: stack, lagmodell, kjerneprinsipper, driftsmodell - docs/arkitektur.md: skrivestien, lesestien, datalag, teknologivalg - docs/retninger/datalaget.md: migrasjonshistorikk, status "fjernet" - 37 andre docs oppdatert (features, concepts, infra, ops, retninger) - Alle kode-kommentarer med STDB-referanser oppdatert Verifisert: maskinrommet bygger og starter OK, frontend bygger OK, helsesjekk returnerer 200. Caddy reloadet.
392 lines
13 KiB
Markdown
392 lines
13 KiB
Markdown
# Konsept: Arbeidstavlen (Prosjektstyring)
|
||
**Filsti:** `docs/concepts/arbeidstavlen.md`
|
||
|
||
## 1. Konsept
|
||
Alt prosjektarbeid i Synops — oppgaver, bugs, ideer, forslag,
|
||
feature-forespørsler — er noder i PostgreSQL. Én kanban-tavle
|
||
organiserer arbeidet. Claude og Vegard deler samme data via CLI
|
||
og web. Arbeidselementer oppstår organisk fra samtaler, manuelt
|
||
input, eller systemhendelser.
|
||
|
||
## 2. Hvorfor
|
||
|
||
`tasks.md` var en pragmatisk bootstrap. Den har tre fundamentale
|
||
problemer:
|
||
|
||
1. **Race conditions.** Flere Claude-instanser redigerer samme fil
|
||
samtidig. Endringer overskrives, status forsvinner, git-konflikter
|
||
oppstår.
|
||
2. **Fragil parsing.** Bash-scripts parser markdown med regex
|
||
(`grep -P '^\- \[~\]'`). Formateringsendringer knekker parseren.
|
||
3. **Frakoblet fra grafen.** Oppgaver kan ikke lenkes til samtaler,
|
||
dokumenter, eller personer via edges. De lever utenfor
|
||
datamodellen.
|
||
|
||
Løsningen: arbeidselementer er noder. De deltar i grafen som alt
|
||
annet. De har edges til samtaler (hvor ideen kom fra), til
|
||
personer (hvem som jobber), til dokumenter (hva de implementerer),
|
||
og til hverandre (foreldre/barn).
|
||
|
||
## 3. Nodemodell
|
||
|
||
Arbeidselementer bruker `node_kind: 'work_item'`:
|
||
|
||
```
|
||
work_item-node:
|
||
title: "Forbedre lydkvalitet ved opptak"
|
||
content: "Brukere rapporterer at ..." (ren tekst, søkbar)
|
||
metadata: {
|
||
"size": "small", // small | medium | large
|
||
"origin": "chat" // chat | manual | system
|
||
}
|
||
```
|
||
|
||
### Kategorisering via edges, ikke typer
|
||
|
||
Det finnes ingen `node_kind` per kategori (task, bug, idea).
|
||
Distinksjonen gjøres med `tagged`-edges:
|
||
|
||
```
|
||
work_item ──tagged──→ board { "tag": "bug" }
|
||
work_item ──tagged──→ board { "tag": "idea" }
|
||
work_item ──tagged──→ board { "tag": "feature" }
|
||
work_item ──tagged──→ board { "tag": "tech-debt" }
|
||
```
|
||
|
||
Dette følger eksisterende filosofi: edges definerer hva en node er,
|
||
ikke noden selv.
|
||
|
||
### Størrelse er organisk
|
||
|
||
Ingen tvungen hierarki-klassifisering. Et element starter som
|
||
`small` og vokser:
|
||
|
||
```
|
||
"Fiks fade-bug" → small (én commit)
|
||
"Redesign lydpipeline" → medium (noen timer)
|
||
"Redesign lydpipeline" → large (har fått barn-items)
|
||
├── belongs_to: "Nytt EDL-format"
|
||
├── belongs_to: "FFmpeg wrapper"
|
||
└── belongs_to: "Oppdater studio-UI"
|
||
```
|
||
|
||
Samme tekst-primitiv-filosofi: en node kan vokse.
|
||
|
||
## 4. Edge-modell
|
||
|
||
| Edge-type | Source → Target | Metadata | Betydning |
|
||
|-----------|----------------|----------|-----------|
|
||
| `belongs_to` | work_item → board | `{ "position": 1.5 }` | Kortet tilhører tavlen |
|
||
| `status` | work_item → board | `{ "value": "neste" }` | Kolonneplassering |
|
||
| `assigned_to` | work_item → person/agent | — | Hvem jobber på dette |
|
||
| `belongs_to` | work_item → work_item | `{ "position": 1.0 }` | Deloppgave |
|
||
| `source_material` | work_item → content | `{ "context": "summarized", "excerpt": "..." }` | Hvor ideen kom fra |
|
||
| `tagged` | work_item → board | `{ "tag": "bug" }` | Kategorisering |
|
||
| `mentions` | work_item → any node | — | Relatert dokument/feature |
|
||
|
||
`assigned_to` er en ny edge-type. Retning: work_item → person.
|
||
Semantikk: "dette elementet er tildelt denne personen/agenten."
|
||
|
||
Barn-items har sin egen `status`-edge. Et barn kan være ferdig
|
||
mens forelderen fortsatt er i arbeid.
|
||
|
||
## 5. Kanban-oppsettet
|
||
|
||
Tavlen er en `collection`-node med `kanban`-trait:
|
||
|
||
```jsonc
|
||
{
|
||
"node_kind": "collection",
|
||
"title": "Synops Arbeidstavle",
|
||
"metadata": {
|
||
"traits": {
|
||
"kanban": {
|
||
"columns": ["innboks", "backlog", "neste", "pågår", "review", "ferdig"]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Kolonnesemantikk
|
||
|
||
| Kolonne | Hva | Hvem styrer | WIP-grense |
|
||
|---------|-----|-------------|------------|
|
||
| **Innboks** | Ubehandlede elementer fra chat og automatikk | System/@bot | Ingen |
|
||
| **Backlog** | Vurdert, ikke prioritert. Kan være hundrevis | Vegard | Ingen |
|
||
| **Neste** | Prioritert og klar. Claude plukker herfra | Vegard | ~10 |
|
||
| **Pågår** | Noen jobber aktivt på dette | Claude/Vegard | 2–3 |
|
||
| **Review** | Implementert, venter på Vegards sjekk | Claude | ~5 |
|
||
| **Ferdig** | Arkivert. Alltid søkbart | System | Ingen |
|
||
|
||
### Bevegelsesregler
|
||
|
||
```
|
||
Innboks → Backlog/Neste Vegard triagerer
|
||
Backlog → Neste Vegard prioriterer
|
||
Neste → Pågår Claude/Vegard starter. assigned_to-edge opprettes
|
||
Pågår → Review Claude ferdig. Commits refererer work_item UUID
|
||
Review → Ferdig Vegard bekrefter
|
||
Review → Pågår Vegard ber om endringer
|
||
Enhver → Backlog Deprioritering
|
||
```
|
||
|
||
### Backlog-visning
|
||
|
||
Backlog trenger ikke være kanban. Hundrevis av elementer er
|
||
bedre i en filtrert listevisning med søk, tags og sortering.
|
||
Bare **Neste → Pågår → Review → Ferdig** er aktive kanban-lanes.
|
||
|
||
## 6. @bot-konvensjonen
|
||
|
||
`@bot` er Synops sin generiske markør for AI-assistanse i
|
||
samtaler. Boten er først og fremst en **samtalepartner** — den
|
||
svarer på spørsmål, forklarer, diskuterer og hjelper. I tillegg
|
||
fanger den opp actionable innhold og oppretter noder i bakgrunnen.
|
||
|
||
### Boten er en generell samtalepartner
|
||
|
||
`@bot` svarer på alt:
|
||
|
||
```
|
||
"Hva betyr CTR?"
|
||
→ Forklaring i chatten. Ingen node.
|
||
|
||
"Lydkvaliteten var dårlig i dag"
|
||
→ Svar + diskusjon i chatten.
|
||
→ work_item i innboks: "Undersøk lydkvalitet" + tagged "bug"
|
||
|
||
"Kan du sjekke om RSS-feeden oppdaterte seg?"
|
||
→ Kjører synops-rss, rapporterer resultat i chatten.
|
||
|
||
"Vi bør legge til kapittelmerkering"
|
||
→ Diskuterer i chatten.
|
||
→ work_item i innboks: "Kapittelmerkering i podcast" + tagged "idea"
|
||
|
||
"Forklar hvordan edge-validering fungerer"
|
||
→ Forklaring i chatten. Ingen node.
|
||
```
|
||
|
||
Brukeren merker bare at de får svar. Noder dukker opp i
|
||
innboksen i bakgrunnen for Vegard å triagere.
|
||
|
||
### To output-kanaler
|
||
|
||
1. **Chat-svar** (alltid) — boten svarer i samtalen
|
||
2. **Noder** (når relevant) — boten oppretter work_items,
|
||
melder fra om feil, fanger opp forslag
|
||
|
||
Kanal 2 er usynlig for brukeren. De ser bare svaret.
|
||
|
||
### Slik fungerer det
|
||
|
||
1. En bruker skriver i en kommunikasjonsnode der bot-agenten er
|
||
`member_of`.
|
||
2. Portvokteren trigger `agent_respond`-jobb (eksisterende flow).
|
||
3. Boten svarer i samtalen.
|
||
4. Boten vurderer: er noe her actionable?
|
||
5. Hvis ja: oppretter riktig node-type med riktig tag.
|
||
|
||
### Hva fanges opp?
|
||
|
||
| Innhold | Resultat | Tag |
|
||
|---------|----------|-----|
|
||
| Bug / feil / noe virker ikke | work_item + mentions berørt cli_tool | `bug` |
|
||
| Idé / forslag / "vi bør" | work_item | `idea` |
|
||
| Feature-forespørsel | work_item | `feature` |
|
||
| Teknisk gjeld / "dette er rotete" | work_item | `tech-debt` |
|
||
| Generelt spørsmål | Bare chat-svar, ingen node | — |
|
||
|
||
### Hva opprettes?
|
||
|
||
For hvert actionable element:
|
||
- `work_item`-node med tittel og beskrivelse
|
||
- `belongs_to`-edge → arbeidstavlen
|
||
- `status`-edge med `value: "innboks"`
|
||
- `source_material`-edge → chat-meldingen (proveniens)
|
||
- `tagged`-edge med riktig kategori
|
||
- `mentions`-edges til berørte noder (verktøy, features)
|
||
- Eventuelt `assigned_to`-edge til agent-noden (om boten kan
|
||
gjøre det selv)
|
||
|
||
Vegard triagerer innboksen og prioriterer.
|
||
|
||
### Ruting
|
||
|
||
`@bot` rutes av portvokteren basert på kontekst:
|
||
- Standard: Claude (nåværende `agent_respond`-flyt)
|
||
- Fremtidig: spesialiserte agenter, andre modeller, eller
|
||
regelbaserte svar — uten endring i brukergrensesnittet
|
||
|
||
## 7. Task runner og jobbhenting
|
||
|
||
### CLI: `synops-tasks`
|
||
|
||
```bash
|
||
synops-tasks --list [--status <status>] [--tag <tag>]
|
||
synops-tasks --next # neste fra "neste"-kolonnen
|
||
synops-tasks --claim <uuid> --write # atomisk: status → pågår + assigned_to
|
||
synops-tasks --complete <uuid> --write # status → review
|
||
synops-tasks --prompt <uuid> # generer prompt for autonom sesjon
|
||
```
|
||
|
||
`--claim` bruker `SELECT ... FOR UPDATE` for atomisk status-
|
||
endring. Ingen race conditions.
|
||
|
||
### Task runner
|
||
|
||
`run-next-task.sh` blir en tynn wrapper:
|
||
|
||
```bash
|
||
TASK_JSON=$(synops-tasks --next --format json)
|
||
TASK_ID=$(echo "$TASK_JSON" | jq -r '.id')
|
||
synops-tasks --claim "$TASK_ID" --write
|
||
claude -p --dangerously-skip-permissions \
|
||
"$(synops-tasks --prompt "$TASK_ID")"
|
||
synops-tasks --complete "$TASK_ID" --write
|
||
```
|
||
|
||
### Stale-deteksjon
|
||
|
||
Items som har stått i "pågår" lenger enn 60 minutter uten
|
||
commit frigjøres tilbake til "neste":
|
||
|
||
```bash
|
||
synops-tasks --unstale --write
|
||
```
|
||
|
||
## 8. CLAUDE.md som bootstrap
|
||
|
||
CLAUDE.md forblir prosjektets startdokument — det lastes alltid
|
||
inn i konteksten. Strukturen beholdes i hovedsak, men
|
||
oppgavehenting endres:
|
||
|
||
**Erstatt tasks.md-referanser med:**
|
||
|
||
```markdown
|
||
## Arbeidshenting
|
||
Oppgaver hentes fra arbeidstavlen (PG). Bruk CLI:
|
||
- `synops-tasks --next` — vis neste oppgave
|
||
- `synops-tasks --list` — vis hele tavlen
|
||
- `synops-tasks --claim <uuid> --write` — ta en oppgave
|
||
- `synops-tasks --complete <uuid> --write` — marker ferdig
|
||
|
||
Task runner: `./scripts/run-next-task.sh`
|
||
Se `docs/concepts/arbeidstavlen.md` for full spesifikasjon.
|
||
```
|
||
|
||
Doc-treet i CLAUDE.md beholdes — det er verdifull navigasjon.
|
||
Endringen er kirurgisk: erstatt oppgaverelaterte instruksjoner.
|
||
|
||
## 9. Migrering fra tasks.md
|
||
|
||
### Steg 1: Opprett arbeidstavle-noden
|
||
Én `collection`-node med kanban-trait og seks kolonner.
|
||
Fast UUID som dokumenteres i CLAUDE.md.
|
||
|
||
### Steg 2: Migrer gjenstående oppgaver
|
||
Script leser `tasks.md`, oppretter `work_item`-noder for
|
||
gjenstående `- [ ]`-elementer. Ferdigstilte `[x]`-elementer
|
||
kan migreres til "ferdig" for historikk, eller forbli i
|
||
`tasks.md` som lesbart arkiv i git-historikken.
|
||
|
||
Fase- og avhengighetsinfo overføres til `metadata` og
|
||
`belongs_to`-edges mellom relaterte items.
|
||
|
||
### Steg 3: Switch task runner
|
||
`run-next-task.sh` bruker `synops-tasks` i stedet for
|
||
markdown-parsing. `tasks.md` redigeres ikke lenger.
|
||
|
||
## 10. CLI og web: samme data
|
||
|
||
```
|
||
Terminal (Claude/Vegard) Web (SvelteKit)
|
||
│ │
|
||
synops-tasks --list KanbanTrait panel
|
||
synops-tasks --claim <uuid> Drag-and-drop kolonne
|
||
psql → direkte SQL Arbeidsflaten
|
||
│ │
|
||
└──────────── PG ──────────────────┘
|
||
│
|
||
↕ synk
|
||
│
|
||
PG LISTEN/NOTIFY → WebSocket → sanntid i frontend
|
||
```
|
||
|
||
| Grensesnitt | Leser fra | Skriver til |
|
||
|-------------|-----------|-------------|
|
||
| `synops-tasks` CLI | PG direkte | PG direkte |
|
||
| Web (KanbanTrait) | WebSocket (PG) | Maskinrommet → PG |
|
||
| `synops-respond` | PG | PG (via maskinrommet) |
|
||
|
||
Ingen nytt UI trengs — arbeidstavlen er bare en `collection`-node
|
||
med kanban-trait. Vegard ser den på arbeidsflaten ved siden av
|
||
andre paneler.
|
||
|
||
## 11. Komponenter
|
||
|
||
| Feature | Rolle i Arbeidstavlen |
|
||
|---------|----------------------|
|
||
| Kanban (trait) | Visuell tavle med kolonner og drag-and-drop |
|
||
| Chat | @bot i samtaler skaper arbeidselementer |
|
||
| `synops-tasks` CLI | Claude og scripts henter/oppdaterer arbeid |
|
||
| `synops-respond` | Boten oppretter work_items fra chat-innsikt |
|
||
| Jobbkø | `run-next-task.sh` orkestrerer autonome sesjoner |
|
||
|
||
## 12. Utviklingsfaser
|
||
|
||
1. Opprett arbeidstavle-noden i PG med kanban-trait og seks kolonner.
|
||
2. Implementer `synops-tasks` CLI (list, next, claim, complete, prompt).
|
||
3. Migrer gjenstående oppgaver fra `tasks.md`.
|
||
4. Oppdater `run-next-task.sh` til å bruke `synops-tasks`.
|
||
5. Utvid `synops-respond` til å opprette work_items fra chat.
|
||
6. Oppdater CLAUDE.md med ny arbeidshenting-seksjon.
|
||
|
||
## 13. Fallback: `synops-snapshot`
|
||
|
||
PG nede betyr at Claude mister tilgang til verktøyoversikt,
|
||
arbeidstavle og arkitektur-noder. Løsningen er en generert
|
||
snapshot-fil som alltid ligger i repo:
|
||
|
||
```bash
|
||
synops-snapshot --write
|
||
→ Kobler til PG
|
||
→ Henter: cli_tool-noder, work_items (neste/pågår/review),
|
||
arbeidstavle-status, aktive agenter
|
||
→ Skriver til docs/snapshot.md
|
||
→ Deterministisk output — ingen diff hvis ingenting endret seg
|
||
```
|
||
|
||
### Når den kjøres
|
||
- **Automatisk:** Post-hook i `run-next-task.sh` etter hver oppgave
|
||
- **Periodisk:** Cron (hvert 5. minutt) som sikkerhetsnett
|
||
- **Manuelt:** `synops-snapshot --write` ved behov
|
||
|
||
### Hva den inneholder
|
||
- Alle `cli_tool`-noder med usage og metadata
|
||
- Arbeidstavle-status (antall per kolonne, items i neste/pågår)
|
||
- Siste endringer (nyeste work_items)
|
||
- Tidsstempel for når snapshot ble generert
|
||
|
||
### CLAUDE.md-referanse
|
||
```markdown
|
||
## Fallback-kontekst
|
||
Hvis PG er utilgjengelig, se `docs/snapshot.md` for siste kjente
|
||
tilstand. Generert av `synops-snapshot`. Ikke rediger manuelt.
|
||
```
|
||
|
||
Filen committes og pushes som del av normal arbeidsflyt.
|
||
`synops-snapshot` er selv et CLI-verktøy og en `cli_tool`-node
|
||
i grafen.
|
||
|
||
## 14. Avgrensning
|
||
|
||
- Arbeidstavlen erstatter `tasks.md` for prosjektstyring.
|
||
Den erstatter **ikke** docs-filer — arkitektur, retninger,
|
||
feature-specs og konseptdokumenter lever fortsatt som
|
||
markdown i `docs/`.
|
||
- `@bot` er en chat-konvensjon, ikke en ny primitiv. Den bruker
|
||
eksisterende `member_of`-edge og `agent_respond`-flyt.
|
||
- Work items er noder i grafen — ikke en separat
|
||
prosjektstyringsmodul. De følger alle regler for noder,
|
||
edges, visibility og tilgangskontroll.
|