Files
teamvis-selfhost/supabase/migrations/0053_booking_calendar.sql
T
2026-06-25 16:38:31 +02:00

84 lines
4.4 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ====================================================================
-- 0053_booking_calendar — Kalenderbuchung (Booking Phase 1, Microsoft Graph)
-- ====================================================================
-- Baut auf Phase 0 (0052_appointment_requests) auf. Modell: zentrale
-- Azure-AD-App mit *Application Permissions* (IT erteilt EINMAL Admin-
-- Consent) + Opt-in pro Mitarbeiter. Kein Pro-MA-OAuth, keine Refresh-
-- Token-Speicherung — das App-only-Token kommt per Client-Credentials,
-- nur das Client-Secret liegt in der ENV. Siehe docs/booking-modul.md.
--
-- DSGVO: Der Opt-in-Schalter (calendar_connections.enabled) ist die
-- aktive Entscheidung des MA. Zusätzlich beschränkt eine Exchange
-- Application Access Policy die App technisch auf eine Sicherheitsgruppe.
-- ── Pro-MA-Verbindung + Verfügbarkeitsregeln ───────────────────────────
create table if not exists public.calendar_connections (
id uuid primary key default gen_random_uuid(),
employee_id uuid not null unique
references public.employees(id) on delete cascade,
provider text not null default 'microsoft',
-- M365-Postfach für die Graph-Calls (UPN/Mailbox, i. d. R. = Dienst-Mail).
mailbox_upn text not null,
-- Opt-in: nur wenn true, ruft TeamVis Graph für dieses Postfach auf.
enabled boolean not null default true,
-- Verfügbarkeitsregeln (Slots = Arbeitszeit Belegt vergebene Buchungen)
timezone text not null default 'Europe/Berlin',
slot_minutes integer not null default 30,
buffer_minutes integer not null default 0,
min_notice_hours integer not null default 24,
max_advance_days integer not null default 30,
workday_start time not null default '09:00',
workday_end time not null default '17:00',
-- ISO-Wochentage: 1=Montag … 7=Sonntag
workdays integer[] not null default '{1,2,3,4,5}',
-- Diagnostik: letzter erfolgreicher „Verbindung testen", letzter Fehler.
last_verified_at timestamptz,
last_error text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
comment on table public.calendar_connections is
'Opt-in pro Mitarbeiter für die Microsoft-Graph-Kalenderbuchung (Phase 1).';
-- ── Bestätigte Buchungen (echter Kalendereintrag via Graph) ────────────
create table if not exists public.bookings (
id uuid primary key default gen_random_uuid(),
employee_id uuid not null
references public.employees(id) on delete cascade,
appointment_request_id uuid
references public.appointment_requests(id) on delete set null,
start_at timestamptz not null,
end_at timestamptz not null,
time_zone text not null default 'Europe/Berlin',
guest_name text not null,
guest_email text,
guest_phone text,
company text,
subject text,
message text,
meeting_type text, -- 'vor_ort' | 'telefon' | 'video' | null
status text not null default 'confirmed',
-- 'confirmed' | 'cancelled'
graph_event_id text, -- Outlook-Event-ID (für Storno/Update)
ical_uid text,
cancel_token text not null, -- Self-Service-Storno durch den Gast
consent_given boolean not null default false,
source_url text,
created_at timestamptz not null default now()
);
create index if not exists bookings_employee_idx
on public.bookings (employee_id, start_at);
create index if not exists bookings_cancel_token_idx
on public.bookings (cancel_token);
-- ── RLS: admin/service-role only, kein anon-Grant ──────────────────────
-- Frei/Belegt-Lookup und Insert laufen ausschließlich über serverseitige
-- (rate-limitierte) Service-Role-Actions, wie card_leads/appointment_requests.
alter table public.calendar_connections enable row level security;
alter table public.bookings enable row level security;
grant select, insert, update, delete on public.calendar_connections to service_role;
grant select, insert, update, delete on public.bookings to service_role;