- 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>
78 lines
2.9 KiB
Markdown
78 lines
2.9 KiB
Markdown
# 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)
|
|
|
|
```typescript
|
|
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:
|
|
|
|
```typescript
|
|
// 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.ts` — `spacetimeRowToMessage()`.
|
|
|
|
## 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:
|
|
|
|
```rust
|
|
// 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
|
|
|
|
```bash
|
|
# 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`).
|