server/docs/erfaringer/adapter_moenster.md
vegard a5985ef3f8 Dokumentasjon, erfaringslogg, migrasjoner og infra-oppdateringer
- Omorganiser docs/: konsepter, features, infra og proposals i egne mapper
- Ny docs/erfaringer/ med lærdommer fra chat-implementering (Svelte 5, SpacetimeDB, adapter-mønster)
- Oppdater ARCHITECTURE.md: Lag 1 status, ny §10 Erfaringslogg, SpacetimeDB i lokal dev
- Oppdater synkronisering.md med implementeringsstatus og designvalg
- Oppdater lokal.md med SpacetimeDB og AI Gateway
- Utvid PG-skjema med channels, messages, media_files, message_revisions
- Legg til seed_dev.sql, migration_safety.md, .env.example
- Nye feature-specs: chat, kanban, whiteboard, live_ai, lydmeldinger m.fl.
- Nye konsept-specs: studioet, møterommet, redaksjonen, den asynkrone gjesten m.fl.
- SpacetimeDB og AI Gateway i docker-compose.dev.yml
- collect-docs.sh inkluderer erfaringer/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 01:40:14 +01:00

2.9 KiB

Erfaring: Adapter-mønster for PG ↔ SpacetimeDB

1. Mønsteret som fungerte

Et felles interface (ChatConnection) med to implementasjoner:

  • PG-adapter — polling hvert 3 sek, full-fetch, ingen ekstern avhengighet utover REST API
  • SpacetimeDB hybrid-adapter — PG for historikk + SpacetimeDB WebSocket for sanntidspush

Factory-funksjon velger adapter basert på miljøvariabel (VITE_SPACETIMEDB_URL).

ChatBlock.svelte  →  createChat()  →  PG-adapter (fallback)
                                    →  SpacetimeDB hybrid (hvis URL er satt)

Fordeler:

  • Kan teste PG-adapter isolert uten Docker/SpacetimeDB
  • Fallback er trivielt — fjern env-variabelen
  • Komponenten vet ingenting om hvilken adapter som brukes

Referanse: web/src/lib/chat/ — hele mappen er organisert etter dette mønsteret.

2. Anti-pattern: Lazy wrapper som bytter adapter

Vi prøvde først en "lazy wrapper" som startet med PG-adapter og byttet til SpacetimeDB-adapter når tilkoblingen var klar. Problemet:

  • En plain let activeConnection i wrapperen er ikke reaktiv i Svelte 5
  • Når wrapperen byttet adapter, forsvant meldingene — ny adapter startet med tom liste
  • Svelte-komponentene så aldri byttet fordi proxy-referansen ikke oppdaterte seg

Lærdom: Ikke bytt adapter runtime. Velg én ved oppstart. Hybrid-adapteren løser problemet bedre — den bruker begge kilder samtidig i stedet for å bytte mellom dem.

3. Hybrid fremfor ren SpacetimeDB

Ren SpacetimeDB-tilnærming krever "oppvarming" — lasting av historikk fra PG inn i SpacetimeDB ved oppstart. Dette skaper:

  • Kompleksitet i Rust-modulen (load_messages-reducer)
  • Konfliktrisiko under oppvarming (§8.1 i synkronisering.md)
  • Tom chat inntil oppvarming er ferdig

Hybrid-løsningen: Frontend henter PG-historikk via REST (umiddelbart tilgjengelig) og lytter på SpacetimeDB kun for nye meldinger. Deduplisering skjer i klienten (sjekk mot eksisterende IDer).

Fordeler:

  • Ingen oppvarming nødvendig
  • Historikk er alltid tilgjengelig, selv om SpacetimeDB er nede
  • SpacetimeDB-modulen trenger bare håndtere nye meldinger, ikke historikk

4. Graceful degradation — stille feilhåndtering

SpacetimeDB-adaptere bør aldri vise feilmelding til brukeren ved tilkoblingsproblemer. PG-data er allerede lastet — brukeren har en fungerende chat.

.onConnectError((_ctx, err) => {
  console.warn('[spacetime] connection error, PG-data beholdes:', err);
  // Ingen error-state til UI — PG-data er intakt
})

5. Anbefaling for neste komponent

Når Kanban eller Whiteboard skal bygges med SpacetimeDB:

  1. Start med PG-adapter. Få hele flyten til å fungere med REST/polling først.
  2. Lag SpacetimeDB hybrid-adapter. PG for historikk, SpacetimeDB for sanntid.
  3. Bruk samme factory-mønster. Felles interface, env-variabel for valg.
  4. Test begge adaptere uavhengig før du integrerer i UI-komponenten.