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.
13 KiB
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:
- Race conditions. Flere Claude-instanser redigerer samme fil samtidig. Endringer overskrives, status forsvinner, git-konflikter oppstår.
- Fragil parsing. Bash-scripts parser markdown med regex
(
grep -P '^\- \[~\]'). Formateringsendringer knekker parseren. - 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:
{
"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
- Chat-svar (alltid) — boten svarer i samtalen
- 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
- En bruker skriver i en kommunikasjonsnode der bot-agenten er
member_of. - Portvokteren trigger
agent_respond-jobb (eksisterende flow). - Boten svarer i samtalen.
- Boten vurderer: er noe her actionable?
- 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 beskrivelsebelongs_to-edge → arbeidstavlenstatus-edge medvalue: "innboks"source_material-edge → chat-meldingen (proveniens)tagged-edge med riktig kategorimentions-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
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:
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":
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:
## 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
- Opprett arbeidstavle-noden i PG med kanban-trait og seks kolonner.
- Implementer
synops-tasksCLI (list, next, claim, complete, prompt). - Migrer gjenstående oppgaver fra
tasks.md. - Oppdater
run-next-task.shtil å brukesynops-tasks. - Utvid
synops-respondtil å opprette work_items fra chat. - 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:
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.shetter hver oppgave - Periodisk: Cron (hvert 5. minutt) som sikkerhetsnett
- Manuelt:
synops-snapshot --writeved 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
## 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.mdfor prosjektstyring. Den erstatter ikke docs-filer — arkitektur, retninger, feature-specs og konseptdokumenter lever fortsatt som markdown idocs/. @boter en chat-konvensjon, ikke en ny primitiv. Den bruker eksisterendemember_of-edge ogagent_respond-flyt.- Work items er noder i grafen — ikke en separat prosjektstyringsmodul. De følger alle regler for noder, edges, visibility og tilgangskontroll.