server/docs/erfaringer/spacetimedb_integrasjon.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: SpacetimeDB-integrasjon

1. Genererte bindings — navnekonvensjoner

SpacetimeDB sin spacetime generate --lang typescript produserer bindings med inkonsistente konvensjoner. Sjekk alltid de genererte filene i stedet for å gjette.

Hva Konvensjon Eksempel
Tabell-accessor på conn.db snake_case conn.db.chat_message
Reducer-accessor på conn.reducers camelCase conn.reducers.sendMessage()
Felt-navn i tabellrader camelCase row.channelId, row.authorName
Reducer-parametere Enkelt objekt sendMessage({ id, channelId, body, ... })

Felle: Man forventer at tabell-accessorer er camelCase (chatMessage), men de er snake_case.

2. DbConnection.builder() — API-detaljer (SDK v2)

DbConnection.builder()
  .withUri(spacetimeUrl)
  .withDatabaseName(moduleName)   // IKKE withModuleName
  .withToken(token)
  .onConnect((connection) => {    // første param er DbConnection, ikke EventContext
    connection.subscriptionBuilder()
      .subscribe([`SELECT * FROM chat_message WHERE channel_id = '${id}'`]);
  })
  .build();

Feller:

  • withModuleName() finnes ikke — bruk withDatabaseName()
  • onConnect-callback mottar DbConnection, ikke EventContext
  • onConnectError-callback har signatur (ctx, errMessage) der errMessage er en string

3. BigInt-tidsstempler

SpacetimeDB Timestamp-type bruker microsSinceEpoch som er BigInt. JavaScript kan ikke blande BigInt med Number:

// FEIL — TypeError: Cannot mix BigInt and other types
const ms = micros / 1000;

// RIKTIG — sjekk type, bruk BigInt-divisjon
const ms = typeof micros === 'bigint'
  ? Number(micros / 1000n)
  : Number(micros) / 1000;

Referanse: web/src/lib/chat/spacetime.svelte.tsspacetimeRowToMessage().

4. Rust-modul — borrow checker med SpacetimeDB-makroer

SpacetimeDB-makroer genererer kode som tar eierskap over struct-felter. Bruk verdier før du flytter dem inn i structs:

// FEIL — channel_id er moved inn i ChatMessage, kan ikke bruke i log!() etterpå
let msg = ChatMessage { channel_id, body, ... };
log::info!("Melding i kanal {}", channel_id);  // borrow after move

// RIKTIG — bruk verdien før struct-opprettelse
let log_msg = format!("Melding i kanal {}", channel_id);
let msg = ChatMessage { channel_id, body, ... };
log::info!("{}", log_msg);

5. Publisering og lokal testing

# Publiser modul mot lokal SpacetimeDB (må kjøre i Docker først)
cd spacetimedb
spacetime publish sidelinja-realtime --server http://localhost:3000

# Generer TypeScript-bindings
spacetime generate --lang typescript --out-dir ../web/src/lib/chat/module_bindings \
  --project-path .

Merk: Docker-containeren (clockworklabs/spacetime:latest) må kjøre før publisering. Modulen overlever container-restart (data i volum .docker-data/spacetimedb).