- synkronisering.md: ~5s → ~1s, trådbasert warmup med per-kanal config - adapter_moenster.md: omskrevet — dokumenterer nåværende arkitektur + historiske anti-patterns - chat.md: implementeringsstatus oppdatert til mars 2026 - spacetimedb_integrasjon.md: trådbasert warmup og admin-UI dokumentert Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
66 lines
3.1 KiB
Markdown
66 lines
3.1 KiB
Markdown
# Erfaring: Adapter-mønster for chat (PG ↔ SpacetimeDB)
|
|
|
|
## 1. Mønsteret
|
|
|
|
Et felles interface (`ChatConnection`) med to implementasjoner:
|
|
- **SpacetimeDB-adapter** (primær) — all data fra SpacetimeDB, worker håndterer warmup + sync
|
|
- **PG-adapter** (fallback) — polling hvert 3 sek, brukes kun når SpacetimeDB ikke er konfigurert
|
|
|
|
Factory-funksjon velger adapter basert på miljøvariabel (`VITE_SPACETIMEDB_URL`).
|
|
|
|
```
|
|
ChatBlock.svelte → createChat() → SpacetimeDB-adapter (primær)
|
|
→ PG-adapter (fallback, readonly)
|
|
```
|
|
|
|
**Fordeler:**
|
|
- Kan teste PG-adapter isolert uten Docker/SpacetimeDB
|
|
- Fallback er trivielt — fjern env-variabelen
|
|
- Komponenten vet ingenting om hvilken adapter som brukes
|
|
- ChatConnection-interface har `edit()`, `delete()`, `react()` — ingen direkte PG API-kall fra komponenten
|
|
|
|
**Referanse:** `web/src/lib/chat/` — hele mappen er organisert etter dette mønsteret.
|
|
|
|
## 2. Historisk anti-pattern: Lazy wrapper som byttet 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.
|
|
|
|
## 3. Historisk anti-pattern: Hybrid-adapter (PG + SpacetimeDB samtidig)
|
|
|
|
Den andre iterasjonen brukte en hybrid-adapter som hentet historikk fra PG via REST og lyttet på SpacetimeDB for nye meldinger. Dette skapte:
|
|
|
|
- Kompleks dedup-logikk (`deletedIds` Set, merge av PG- og ST-meldinger)
|
|
- Race conditions mellom PG-polling og SpacetimeDB-callbacks
|
|
- BigInt-konverteringer og workarounds i frontend
|
|
|
|
**Løsningen:** SpacetimeDB som cache foran PG. Worker gjør warmup (PG → ST) ved oppstart, frontend snakker kun med SpacetimeDB. Ingen merge-logikk nødvendig.
|
|
|
|
## 4. Nåværende arkitektur
|
|
|
|
SpacetimeDB er en varm cache foran PostgreSQL:
|
|
- **Worker warmup:** Ved oppstart lastes meldinger + reaksjoner fra PG → SpacetimeDB per kanal
|
|
- **Frontend → SpacetimeDB:** Subscription gir alle meldinger (historikk fra warmup + nye)
|
|
- **SpacetimeDB → PG:** Sync-worker poller `sync_outbox` hvert sekund
|
|
- **PG er autoritativ** — ved SpacetimeDB-restart oppvarmes fra PG
|
|
|
|
**Fordeler over hybrid:**
|
|
- Ingen dedup, merge eller deletedIds
|
|
- Frontend-koden er dramatisk enklere
|
|
- Konsistent datamodell — alt kommer fra én kilde
|
|
- Reaksjoner håndteres via SpacetimeDB-tabeller, ikke PG API
|
|
|
|
## 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-adapter med warmup.** Worker laster data fra PG ved oppstart.
|
|
3. **Bruk samme factory-mønster.** Felles interface, env-variabel for valg.
|
|
4. **Legg til warmup-config** i `channels.config` (eller tilsvarende config-felt).
|
|
5. **Test begge adaptere uavhengig** før du integrerer i UI-komponenten.
|