server/docs/features/kalender.md
vegard 7397c8ad93 Oppdater dokumentasjon: kalender implementert, Lag 2 status
- ARCHITECTURE.md: Kalender markert [~] i Lag 2
- docs/features/kalender.md: Oppdatert med implementert status, API-docs, tidssone-håndtering

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 02:59:09 +01:00

4 KiB

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

PG-adapter ferdig og deployet (mars 2025). Abonnement, ICS-eksport og SpacetimeDB-sync gjenstår.

Implementert

  • Migrering 0003_calendar.sql: calendars + calendar_events (begge FK→nodes)
  • Hendelser er nodes — arver workspace-isolasjon automatisk
  • Heldagshendelser (T12:00:00 for tidssone-trygghet) vs. tidshendelser med klokkeslett
  • Fargekoder per hendelse (7 forhåndsdefinerte) + standard kalenderfarge
  • REST API: GET med tidsvindu-filtrering, POST/PATCH/DELETE hendelser
  • PG polling-adapter med 5 sek intervall
  • CalendarBlock.svelte: månedsrutenett, navigering, opprett/rediger-modal, Escape-lukking
  • linked_node-kolonne for fremtidig kobling til kanban-kort, episoder etc.

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. workspace-kalendere
  • ICS/CalDAV-eksport
  • SpacetimeDB-modul + hybrid-adapter
  • Varsler/påminnelser via jobbkøen

3. Datamodell (implementert)

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
Workspace Workspace (admin) Alle medlemmer
Personlig Bruker Kun eier + eksplisitt deling
Offentlig Workspace Alle som abonnerer

8. Fremtidig: ICS-eksport

Offentlige kalendere får en ICS-URL (/cal/{workspace_slug}/{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)
  • Alt er workspace-scopet via node-modellen
  • Sjekk docs/erfaringer/adapter_moenster.md for hybrid-strategi