# 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
  - Tilgjengelig som panel i arbeidsflaten
  - 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 <ics>` eller `--url <url>` + `--collection-id <uuid>`
  - 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
