# Feature: Kalender **Filsti:** `docs/features/kalender.md` ## 1. Konsept Månedsbasert kalendervisning for redaksjonell planlegging. Hendelser er nodes i kunnskapsgrafen og kan kobles til episoder, temaer, aktører og kanban-kort. Komplementerer Kanban ("hva" vs "når"). ## 2. Status **Kalendervisning implementert (mars 2026).** Bruker `scheduled`-edges i stedet for separat `calendar_events`-tabell. CalDAV/ICS-abonnement implementert. ICS-eksport gjenstår. ### Implementert - **Fase 1 (v1, mars 2025):** PG-adapter med `calendars` + `calendar_events` (legacy) - **Fase 2 (v2, mars 2026):** Edge-basert kalender med `scheduled`-edges - Rute: `/calendar` — månedsbasert rutenett - Hendelser er noder med `scheduled`-edge (`metadata.at` = ISO 8601 tidspunkt) - Heldagshendelser bruker `T12:00:00`-konvensjon (tidssone-trygg) - Tidsbaserte hendelser viser klokkeslett i rutenett - Drag-and-drop for å flytte hendelser mellom datoer - Inline-oppretting: klikk + på en dato, angi tittel og valgfritt klokkeslett - Fargekoding basert på `node_kind` (innhold, kommunikasjon, media, samling) - Månedsnavigering med «I dag»-knapp - Hendelsesliste under rutenett for gjeldende måned - Lenke fra mottak-siden med hendelsesteller - Tilgang via `nodeVisibility` (respekterer `node_access`-matrise) - Sanntidsoppdatering via WebSocket (PG LISTEN/NOTIFY) - **ICS-import (oppgave 29.11):** `synops-calendar` CLI som parser ICS-filer - Input: `--file ` eller `--url ` + `--collection-id ` - Duplikatdeteksjon via `metadata.ics_uid` - Oppdatering ved re-import - **CalDAV-abonnement (oppgave 29.12):** Periodisk polling av eksterne kalendere - Abonnement lagres i `metadata.calendar_subscriptions[]` på samlingsnoder - `calendar_poller` i maskinrommet sjekker hvert 60. sekund - Enqueuer `calendar_poll`-jobber som spawner `synops-calendar --url` - API: `POST /intentions/configure_calendar_subscription` og `remove_calendar_subscription` - Støtter Google Calendar, Outlook, og andre ICS/CalDAV-URLer ### Gjenstår — Fase 2 - Kobling til kanban-kort (vis deadline på kalender) - Uke- og dagsvisning - Gjentakende hendelser (RRULE) - Dra-og-slipp for å flytte hendelser mellom datoer - Flerdag-hendelser (vises over flere celler) - Abonnementsmodell (kalender → kalender via graph_edges) - Personlige vs. delte kalendere (via samlings-noder) - ICS-eksport (offentlige kalendere → `/cal/{id}.ics`) - Varsler/påminnelser via jobbkøen ## 3. Datamodell (implementert) ```sql CREATE TABLE calendars ( id UUID PRIMARY KEY REFERENCES nodes(id) ON DELETE CASCADE, parent_id UUID NOT NULL REFERENCES nodes(id), name TEXT NOT NULL, color TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE calendar_events ( id UUID PRIMARY KEY REFERENCES nodes(id) ON DELETE CASCADE, calendar_id UUID NOT NULL REFERENCES calendars(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, color TEXT, linked_node UUID REFERENCES nodes(id) ON DELETE SET NULL, created_by TEXT REFERENCES users(authentik_id), created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` Indekser: `(calendar_id)` og `(calendar_id, starts_at)` for effektiv tidsvindu-filtrering. ## 4. API-endepunkter | Metode | Sti | Beskrivelse | |---|---|---| | GET | `/api/calendar/[calendarId]?from=...&to=...` | Hent kalender med hendelser i tidsvindu | | POST | `/api/calendar/[calendarId]/events` | Opprett hendelse | | PATCH | `/api/calendar/[calendarId]/events/[eventId]` | Oppdater hendelse | | DELETE | `/api/calendar/[calendarId]/events/[eventId]` | Slett hendelse | ## 5. Brukes av | Konsept | Bruk | |---|---| | Redaksjonen | Innspillingsdatoer, publiseringsplan, deadlines | | Foreningen Liberalistene | Styremøter, arrangementer | | Møterommet (fremtidig) | Møteplanlegging | ## 6. Tidssone-håndtering - Heldagshendelser lagres som `T12:00:00` (middag) — unngår datoforskyvning ved UTC-konvertering - Tidshendelser konverteres til ISO via `new Date().toISOString()` (lokal → UTC) - Visning bruker `new Date()` som konverterer tilbake til lokal tid ## 7. Fremtidig: Abonnementsmodell Kalendere kan abonnere på andre kalendere via `SUBSCRIBES_TO`-edge i grafen. Abonnenten ser hendelser read-only. | Type | Eier | Synlighet | |------|------|-----------| | Samlings-node | Admin for samlings-noden | Alle med tilgang via `node_access` | | Personlig | Bruker | Kun eier + eksplisitt deling | | Offentlig | Samlings-node | Alle som abonnerer | ## 8. Fremtidig: ICS-eksport Offentlige kalendere får en ICS-URL (`/cal/{calendar_id}.ics`) for Google Calendar, Apple Calendar etc. ## 9. Instruks for Claude Code * Bruk `eventsForDate()` med lokal dato-konvertering, ikke UTC-substring * Heldagshendelser: `T12:00:00`, aldri `T00:00:00` (tidssone-felle) * Tilgang styres via `node_access`-matrisen * Sjekk `docs/erfaringer/adapter_moenster.md` for hybrid-strategi