Oppdater docs etter SpacetimeDB-loven-implementering
synkronisering.md: oppdater implementeringsstatus, marker PG-lekkasjer som fikset spacetimedb_integrasjon.md: nye lærdommer om timestamps, reducer-params, schema-migrering og AI-worker-flyt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4001c05648
commit
17b2c44bdd
2 changed files with 71 additions and 20 deletions
|
|
@ -32,21 +32,36 @@ DbConnection.builder()
|
|||
- `onConnect`-callback mottar `DbConnection`, ikke `EventContext`
|
||||
- `onConnectError`-callback har signatur `(ctx, errMessage)` der `errMessage` er en string
|
||||
|
||||
## 3. BigInt-tidsstempler
|
||||
## 3. Timestamps — bruk SDK-metoder, ikke interne felter
|
||||
|
||||
SpacetimeDB `Timestamp`-type bruker `microsSinceEpoch` som er `BigInt`. JavaScript kan ikke blande BigInt med Number:
|
||||
SpacetimeDB `Timestamp`-objektet har en intern property `__timestamp_micros_since_unix_epoch__` (BigInt). **Ikke bruk den direkte** — bruk SDK-metodene:
|
||||
|
||||
```typescript
|
||||
// FEIL — TypeError: Cannot mix BigInt and other types
|
||||
const ms = micros / 1000;
|
||||
// FEIL — microsSinceEpoch finnes ikke, __timestamp_micros_since_unix_epoch__ er internt
|
||||
const micros = row.createdAt?.microsSinceEpoch;
|
||||
|
||||
// RIKTIG — sjekk type, bruk BigInt-divisjon
|
||||
const ms = typeof micros === 'bigint'
|
||||
? Number(micros / 1000n)
|
||||
: Number(micros) / 1000;
|
||||
// RIKTIG — bruk SDK-metoder
|
||||
const iso = row.createdAt?.toISOString(); // "2026-03-15T23:57:11.677139Z"
|
||||
const date = row.createdAt?.toDate(); // Date-objekt
|
||||
const ms = row.createdAt?.toDate()?.getTime(); // millisekunder for sortering
|
||||
```
|
||||
|
||||
**Referanse:** `web/src/lib/chat/spacetime.svelte.ts` — `spacetimeRowToMessage()`.
|
||||
### Timestamp-parsing i Rust-modul (warmup)
|
||||
|
||||
PG returnerer timestamps som `"2026-03-15 23:57:11.677139+00"`. chrono parser IKKE `+00` — krever `+00:00`:
|
||||
|
||||
```rust
|
||||
// FEIL — chrono gir ParseError(TooShort) på "+00"
|
||||
let dt = s.parse::<chrono::DateTime<chrono::FixedOffset>>();
|
||||
|
||||
// RIKTIG — normaliser PG-offset først
|
||||
let normalized = if s.ends_with("+00") { format!("{}:00", s) } else { s.to_string() };
|
||||
let dt = chrono::DateTime::parse_from_str(&normalized, "%Y-%m-%d %H:%M:%S%.f%:z");
|
||||
```
|
||||
|
||||
Uten korrekt parsing faller `load_messages` tilbake til `ctx.timestamp` (nåtidspunkt), og alle meldinger får samme klokkeslett.
|
||||
|
||||
**Referanse:** `spacetimedb/src/lib.rs` — `parse_timestamp()`, `web/src/lib/chat/spacetime.svelte.ts` — `spacetimeRowToMessage()`.
|
||||
|
||||
## 4. Rust-modul — borrow checker med SpacetimeDB-makroer
|
||||
|
||||
|
|
@ -105,7 +120,8 @@ Ny modell:
|
|||
|
||||
### Sync-flyt (ST → PG)
|
||||
- SyncOutbox-events prosesseres hver 1. sekund
|
||||
- Støtter: `messages/insert`, `messages/delete`, `messages/update`, `message_reactions/insert`, `message_reactions/delete`
|
||||
- Støtter: `messages/insert`, `messages/delete`, `messages/update`, `messages/ai_update`, `message_reactions/insert`, `message_reactions/delete`
|
||||
- `ai_update`-action: oppdaterer body + metadata + edited_at i PG, inserter revisjon
|
||||
|
||||
## 7. Subscription-begrensninger
|
||||
|
||||
|
|
@ -130,3 +146,38 @@ Eksempel:
|
|||
|
||||
### Fallback
|
||||
PG-polling adapter (`pg.svelte.ts`) brukes kun når SpacetimeDB ikke er konfigurert. Markeres som `readonly: true`.
|
||||
|
||||
## 8. Reducer-parameternavn — unngå underscore-prefix
|
||||
|
||||
SpacetimeDB eksponerer Rust-parameternavn direkte i HTTP JSON API-et. Underscore-prefix (`_workspace_id`) blir til `_workspace_id` i JSON, ikke `workspace_id`:
|
||||
|
||||
```rust
|
||||
// FEIL — HTTP-kall med {"workspace_id": "..."} feiler med 400
|
||||
pub fn set_ai_processing(ctx: &ReducerContext, id: String, _workspace_id: String) { ... }
|
||||
|
||||
// RIKTIG — bruk vanlig navn, suppress warning med let _ = &var;
|
||||
pub fn set_ai_processing(ctx: &ReducerContext, id: String, workspace_id: String) -> Result<(), String> {
|
||||
let _ = &workspace_id;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 9. Schema-migrering ved nye kolonner
|
||||
|
||||
Å legge til kolonner på eksisterende SpacetimeDB-tabeller krever `--delete-data` ved publish. Dette sletter all data og krever warmup på nytt:
|
||||
|
||||
```bash
|
||||
# Feiler uten --delete-data:
|
||||
# "Adding a column metadata to table chat_message requires a default value annotation"
|
||||
echo "y" | spacetime publish sidelinja-realtime --server local --delete-data
|
||||
```
|
||||
|
||||
## 10. AI-worker-flyt via SpacetimeDB
|
||||
|
||||
Worker som gjør AI-behandling av meldinger:
|
||||
1. Leser meldingens body fra PG (OK — PG er persistent lager)
|
||||
2. Kaller `set_ai_processing` reducer → frontend ser pulsering umiddelbart
|
||||
3. Kaller AI Gateway med prompt
|
||||
4. Kaller `ai_update_message` reducer → SpacetimeDB oppdaterer body/metadata/edited_at atomisk, lagrer revisjon, legger outbox-entry
|
||||
5. Sync-worker persisterer til PG via `ai_update` action
|
||||
6. Ved feil: `clear_ai_processing` reducer rydder flagget
|
||||
|
|
|
|||
|
|
@ -150,20 +150,20 @@ Skillet er: **data frontend viser** → SpacetimeDB. **Data kun worker trenger**
|
|||
|
||||
### Ferdig
|
||||
- **SpacetimeDB som cache foran PG:** PG er autoritativ, SpacetimeDB er varm cache. Frontend snakker kun med SpacetimeDB.
|
||||
- **SpacetimeDB Rust-modul** (`spacetimedb/src/lib.rs`): `ChatMessage`, `MessageReaction` og `SyncOutbox`-tabeller. Reducers: `send_message`, `delete_message`, `edit_message`, `add_reaction`, `remove_reaction`, `load_messages`, `load_reactions`, `clear_channel`, `mark_synced`.
|
||||
- **Worker warmup** (`worker/src/warmup.rs`): Ved oppstart lastes siste 100 meldinger + reaksjoner per kanal fra PG → SpacetimeDB. Kanaler ryddes først med `clear_channel` for å unngå duplikater.
|
||||
- **Worker sync** (`worker/src/sync.rs`): Poller `sync_outbox` hvert 1. sekund. Håndterer insert/delete/update for meldinger og insert/delete for reaksjoner.
|
||||
- **SpacetimeDB-adapter** (`web/src/lib/chat/spacetime.svelte.ts`): Ren SpacetimeDB-adapter. Ingen PG API-kall. Bruker `onInsert`/`onUpdate`/`onDelete` callbacks for sanntid. Reaksjoner bygges fra `message_reaction`-tabellen.
|
||||
- **SpacetimeDB Rust-modul** (`spacetimedb/src/lib.rs`): `ChatMessage` (med `metadata`, `edited_at`), `MessageReaction`, `MessageRevision` og `SyncOutbox`-tabeller. Reducers: `send_message`, `delete_message`, `edit_message`, `add_reaction`, `remove_reaction`, `load_messages`, `load_reactions`, `load_revisions`, `clear_channel`, `mark_synced`, `set_ai_processing`, `clear_ai_processing`, `ai_update_message`.
|
||||
- **Worker warmup** (`worker/src/warmup.rs`): Ved oppstart lastes meldinger (med metadata/edited_at), reaksjoner og revisjoner per kanal fra PG → SpacetimeDB. Originale timestamps parses korrekt. Kanaler ryddes først med `clear_channel` for å unngå duplikater.
|
||||
- **Worker sync** (`worker/src/sync.rs`): Poller `sync_outbox` hvert 1. sekund. Håndterer insert/delete/update/ai_update for meldinger og insert/delete for reaksjoner.
|
||||
- **SpacetimeDB-adapter** (`web/src/lib/chat/spacetime.svelte.ts`): Ren SpacetimeDB-adapter. Null PG API-kall (`fetch()`). Bruker `onInsert`/`onUpdate`/`onDelete` callbacks for sanntid. Reaksjoner bygges fra `message_reaction`-tabellen. Revisjoner leses fra `message_revision`-tabellen.
|
||||
- **PG-fallback** (`web/src/lib/chat/pg.svelte.ts`): Brukes kun når SpacetimeDB ikke er konfigurert. Markert som `readonly: true`.
|
||||
- **Adapter-mønster:** `ChatConnection`-interface med `send`, `edit`, `delete`, `react` metoder. Factory velger basert på env-variabel.
|
||||
|
||||
### Gjenstår — brudd på SpacetimeDB-loven som må fikses
|
||||
- **`enrichFromPg` i spacetime-adapteren** — frontend leser metadata/edited_at fra PG fordi SpacetimeDB-modulen mangler disse feltene. MÅ fjernes ved å utvide SpacetimeDB-modulen.
|
||||
- **Worker AI-vask skriver til PG direkte** — metadata, body og revisjoner skrives til PG. MÅ endres til å skrive til SpacetimeDB via reducers.
|
||||
- **Revisjoner kun i PG** — `message_revisions`-tabell finnes kun i PG. MÅ speiles i SpacetimeDB-modulen.
|
||||
- **`ChatMessage` mangler felter** — `metadata` (jsonb), `edited_at` (timestamp) mangler i SpacetimeDB-modulen.
|
||||
### Fikset (mars 2026)
|
||||
- **`enrichFromPg` fjernet** — SpacetimeDB-modulen har nå `metadata` og `edited_at` på `ChatMessage`. Frontend leser alt fra SpacetimeDB, null `fetch()`-kall i adapteren.
|
||||
- **Worker AI-vask via reducers** — `set_ai_processing`, `ai_update_message` og `clear_ai_processing` reducers erstatter direkte PG-skriving. Sync-worker persisterer til PG via `ai_update` outbox-action.
|
||||
- **Revisjoner i SpacetimeDB** — `MessageRevision`-tabell med `load_revisions` warmup-reducer. Frontend leser revisjoner via `getRevisions()` fra `conn.db.message_revision`.
|
||||
- **Warmup med metadata** — `load_messages` inkluderer `metadata`, `edited_at` og parser originale timestamps korrekt.
|
||||
|
||||
### Gjenstår — andre
|
||||
### Gjenstår
|
||||
- **Workspace-partisjonering (§7):** SpacetimeDB-modulen har `workspace_id`-felt men bruker ikke workspace-token på tilkobling ennå.
|
||||
- **Pin/konvertering via SpacetimeDB:** Pin og kanban/kalender-konvertering går fortsatt direkte til PG API.
|
||||
- **Lazy warmup per kanal:** Alle aktive kanaler oppvarmes ved oppstart. Kan optimaliseres til per-kanal ved tilkobling.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue