synops/docs/features/varsler.md
vegard 6370b02cc7 26.7 ferdig: utgående varsler med brukerpreferanser
Vaktmesteren kan nå sende epost-varsler og WebSocket-push til brukere
via synops-notify, med respekt for brukerens preferanser.

Endringer:
- jobs.rs: send_notification jobbtype som delegerer til synops-notify CLI
- synops-notify: preferansesjekk fra metadata.preferences.notifications
  (opt-out-modell, per-kanal og per-type bryter, --skip-preferences)
- intentions.rs: POST /intentions/send_notification (admin-only)
- Dokumentasjon: docs/features/varsler.md

Preferanseskjema (i brukernodens metadata):
  preferences.notifications.email: bool (global epost-bryter)
  preferences.notifications.ws: bool (global WS-bryter)
  preferences.notifications.<type>: bool (per-type, f.eks. task_assigned)
2026-03-19 02:08:00 +00:00

3.3 KiB

Varsler (notifications)

Vaktmesteren kan sende varsler til brukere via epost og/eller WebSocket-push. Konfigurerbart per bruker i metadata.preferences.

Arkitektur

Trigger (orkestreringsscript, intention, manuelt)
  │
  ▼
Jobbkø: send_notification
  │
  ▼
synops-notify CLI
  │
  ├── Sjekk metadata.preferences.notifications
  │
  ├── Epost: synops-mail --send → msmtp → Brevo SMTP
  └── WebSocket: notification-node i PG → NOTIFY → portvokteren → klient

Kanaler

Kanal Beskrivelse
email Epost via msmtp/Brevo. Slår opp adresse i auth_identities.
ws Oppretter notification-node med node_access → PG NOTIFY → WebSocket.
both Begge kanaler.

Brukerpreferanser

Lagres i brukerens node (node_kind='person'), i metadata.preferences.notifications.

Opt-out-modell: Alt er aktivert som default. Brukere skrur av det de ikke vil ha. Manglende felt = aktivert.

Skjema

{
  "preferences": {
    "notifications": {
      "email": true,            // global epost-bryter
      "ws": true,               // global WS-bryter
      "task_assigned": true,    // per-type: ny oppgave tildelt
      "article_approved": true, // per-type: artikkel godkjent
      "comment_reply": true     // per-type: svar på kommentar
    }
  }
}

Evalueringslogikk

  1. Ingen preferanser satt → alle kanaler aktivert
  2. Per-type bryter (task_assigned: false) → begge kanaler deaktivert for den typen
  3. Global kanal-bryter (email: false) → epost deaktivert for alle typer
  4. --skip-preferences → ignorer preferanser (for systemkritiske varsler)

Bruk

CLI (direkte)

# WebSocket-varsel (default)
synops-notify --to <node_id> --message "Tekst" --channel ws

# Epost-varsel
synops-notify --to <node_id> --message "Tekst" --subject "Emne" --channel email

# Begge kanaler med type-sjekk
synops-notify --to <node_id> --message "Ny oppgave" --channel both \
  --notification-type task_assigned

# Ignorer preferanser (systemkritisk)
synops-notify --to <node_id> --message "Viktig" --channel email --skip-preferences

Via jobbkø

{
  "job_type": "send_notification",
  "payload": {
    "to": "a0eebc99-...",
    "message": "Du har fått en ny oppgave",
    "subject": "Ny oppgave",
    "channel": "both",
    "notification_type": "task_assigned"
  }
}

Via API (intention)

POST /intentions/send_notification
{
  "to": "a0eebc99-...",
  "message": "Artikkelen din er godkjent",
  "subject": "Artikkel godkjent",
  "channel": "both",
  "notification_type": "article_approved"
}

Krever admin-rolle. Legger jobben i køen med prioritet 10.

Orkestreringsscript

Varsler kan trigges fra orkestreringsscript:

NÅR edge opprettet OG type = "member_of"
  KJØR synops-notify --to {event.target_id} --message "Ny oppgave tildelt" --channel both --notification-type task_assigned

Varslingstyper

Konvensjon for notification_type-feltet:

Type Beskrivelse
task_assigned Ny oppgave tildelt
article_approved Innsendt artikkel godkjent
article_rejected Innsendt artikkel avvist
comment_reply Svar på kommentar
communication_ended Møte/samtale avsluttet
mention Nevnt i en node

Nye typer legges til etter behov — ingen hardkodet liste i koden.