- 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>
134 lines
5.8 KiB
Markdown
134 lines
5.8 KiB
Markdown
# Kalender
|
|
|
|
## Oversikt
|
|
Kalender er en workspace-blokk for redaksjonell planlegging og tidslinjevisning. Hendelser er nodes i kunnskapsgrafen og kan kobles til episoder, temaer, aktører og channels. Kalendere kan fritt abonnere på hverandre — på tvers av brukere og workspaces.
|
|
|
|
## Konsept
|
|
|
|
### Kalendere som grafnoder
|
|
Hver kalender er en node (`node_type: 'calendar'`). Hendelser er også nodes (`node_type: 'event'`) som tilhører en kalender via en `PART_OF`-relasjon. Dette gir:
|
|
- Full workspace-isolasjon via eksisterende RLS
|
|
- Relasjoner mellom hendelser og resten av kunnskapsgrafen (episoder, aktører, temaer)
|
|
- Channels knyttet til hendelser (diskusjonstråd per hendelse)
|
|
|
|
### Typer kalendere
|
|
|
|
| Type | Eier | Synlighet | Eksempel |
|
|
|------|------|-----------|----------|
|
|
| **Workspace** | Workspace (admin) | Alle medlemmer | "Sidelinja Produksjonskalender" |
|
|
| **Personlig** | Bruker | Kun eier (+ eksplisitt deling) | "Vegards arbeidskalender" |
|
|
| **Offentlig** | Workspace (admin) | Alle som abonnerer | "Sidelinja Publiseringsplan" |
|
|
|
|
### Abonnementsmodell
|
|
Kalendere kan abonnere på andre kalendere via en `SUBSCRIBES_TO`-edge i grafen. Abonnenten ser hendelser read-only — bare kildekalenderen kan redigere.
|
|
|
|
```
|
|
Vegards kalender ──SUBSCRIBES_TO──▶ Sidelinja Produksjon
|
|
Vegards kalender ──SUBSCRIBES_TO──▶ Sidelinja Publisering
|
|
Ekstern partner ──SUBSCRIBES_TO──▶ Sidelinja Publisering (offentlig)
|
|
```
|
|
|
|
**Prinsipp:** Enhver kalender kan abonnere på enhver annen kalender den har tilgang til. Tilgang styres av:
|
|
- Samme workspace → alltid tilgang til workspace-kalendere
|
|
- Cross-workspace → kun til kalendere merket "offentlig"
|
|
- Personlige → kun eier + eksplisitt inviterte
|
|
|
|
### Samlet visning
|
|
UI-et viser én samlet kalendervisning per bruker: alle hendelser fra egne + abonnerte kalendere, fargekodet per kilde. Brukeren kan toggle synlighet per kalender.
|
|
|
|
## Datamodell
|
|
|
|
### Nye node_types
|
|
Krever at `node_type` enum utvides med `'calendar'` og `'event'`.
|
|
|
|
### events-tabell (detalj for event-nodes)
|
|
```sql
|
|
CREATE TABLE events (
|
|
id UUID PRIMARY KEY REFERENCES nodes(id) ON DELETE CASCADE,
|
|
calendar_id UUID NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
starts_at TIMESTAMPTZ NOT NULL,
|
|
ends_at TIMESTAMPTZ,
|
|
all_day BOOLEAN NOT NULL DEFAULT false,
|
|
recurrence JSONB, -- iCal RRULE som JSON (valgfritt)
|
|
location TEXT,
|
|
color TEXT, -- hex fargekode for UI
|
|
created_by TEXT REFERENCES users(authentik_id) ON DELETE SET NULL
|
|
);
|
|
```
|
|
|
|
### calendars-tabell (detalj for calendar-nodes)
|
|
```sql
|
|
CREATE TABLE calendars (
|
|
id UUID PRIMARY KEY REFERENCES nodes(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
color TEXT NOT NULL DEFAULT '#3b82f6',
|
|
visibility TEXT NOT NULL DEFAULT 'workspace'
|
|
CHECK (visibility IN ('workspace', 'personal', 'public')),
|
|
owner_user TEXT REFERENCES users(authentik_id) ON DELETE SET NULL
|
|
-- owner_user er NULL for workspace-kalendere (eid av workspace via nodes.workspace_id)
|
|
);
|
|
```
|
|
|
|
### Abonnementer via graph_edges
|
|
```sql
|
|
-- Kalender A abonnerer på Kalender B
|
|
INSERT INTO graph_edges (workspace_id, source_id, target_id, relation_type)
|
|
VALUES (:ws, :kalender_a, :kalender_b, 'SUBSCRIBES_TO');
|
|
```
|
|
|
|
Krever ny relasjonstype:
|
|
```sql
|
|
INSERT INTO relation_types (name, label, description, system)
|
|
VALUES ('SUBSCRIBES_TO', 'Abonnerer på', 'Kalender følger en annen kalender', true);
|
|
```
|
|
|
|
## ICS/CalDAV-eksport
|
|
|
|
### Read-only ICS-feed
|
|
Hver kalender med `visibility = 'public'` (eller workspace-kalendere for innloggede) får en ICS-URL:
|
|
```
|
|
https://sidelinja.org/cal/{workspace_slug}/{calendar_id}.ics
|
|
```
|
|
|
|
SvelteKit genererer ICS-feeden server-side. Brukere kan legge denne inn i Google Calendar, Apple Calendar, Thunderbird osv.
|
|
|
|
### Ingen import
|
|
Sidelinja importerer ikke fra eksterne kalendere i Fase 1. Sidelinja er kilden til sannhet for sine egne hendelser. Eventuell CalDAV-synk (toveis) er en fremtidig utvidelse.
|
|
|
|
## UI-komponenter
|
|
|
|
### CalendarBlock (workspace-blokk)
|
|
Integreres i det komponerbare side-systemet som blokk-type `calendar`:
|
|
- Månedsvisning (default), ukevisning, listevisning
|
|
- Fargekodet per kalender-kilde
|
|
- Klikk hendelse → åpne detalj med grafkoblinger og channel
|
|
- Dra for å opprette ny hendelse (desktop)
|
|
- Toggle synlighet per abonnert kalender i sidebar-filter
|
|
|
|
### Hendelsesdetalj
|
|
- Tittel, tid, beskrivelse, lokasjon
|
|
- Grafkoblinger: koble til episode, tema, aktør
|
|
- Channel: diskusjonstråd (opprettes on-demand)
|
|
- Deltakere: workspace-medlemmer
|
|
|
|
## Redaksjonell verdi
|
|
Kalenderen er ikke generisk møtebooking — den er **redaksjonell planlegging**:
|
|
- **Publiseringsdatoer**: Når skal Episode 43 ut? Synlig for hele redaksjonen
|
|
- **Innspillingsslots**: Bookede tider i Studioet, koblet til episode-node
|
|
- **Gjeste-intervjuer**: Hendelse koblet til aktør-node, med forberedelseskanal
|
|
- **Research-deadlines**: Koblet til tema-node
|
|
- **Sesongoversikt**: Alle episoder i en sesong som hendelser på tidslinje
|
|
|
|
## Bygger på
|
|
- Kunnskapsgraf (nodes, graph_edges)
|
|
- Workspace-modell og RLS
|
|
- Komponerbare sider (blokk-type `calendar`)
|
|
- Channels (diskusjon per hendelse)
|
|
|
|
## Åpne spørsmål
|
|
- **Recurring events**: RRULE er komplekst. Fase 1 kan starte uten recurrence og legge det til som utvidelse.
|
|
- **Tidssoner**: Alle tider lagres som TIMESTAMPTZ (UTC i PG). Frontend viser i brukerens lokale tidssone. Eksplisitt tidssone per hendelse trengs bare ved reise/eksterne gjester.
|
|
- **Varsler/påminnelser**: Kan kobles til jobbkøen — en `reminder`-jobb som poster i hendelsens channel X minutter før start. Utsettes til Fase 2.
|
|
- **Drag-and-drop i kalender**: Flytte/resize hendelser. Nyttig men ikke kritisk for Fase 1 — enkel klikk-for-å-redigere holder.
|