-- =====================================================================
-- 0048 — Modul „Stellenbeschreibungen"
-- =====================================================================
-- KI- + textbaustein-gestützte, compliance-konforme Stellenbeschreibungen.
-- Hängt an den bestehenden Stellen (positions) des Organigramm-Moduls;
-- der compliance-relevante Teil wird datengetrieben aus
-- compliance_role_bindings + den Framework-YAMLs gespeist (nicht von der KI).
--
-- Drei Tabellen:
--   job_description_blocks   — wiederverwendbare Textbausteine
--   job_descriptions         — 1 Beschreibung pro Stelle (aktueller Stand)
--   job_description_versions — append-only Historie bei jeder Freigabe
--
-- Alle Tabellen sind admin-only (RLS an, KEINE anon-Policy → Default deny);
-- gelesen/geschrieben wird ausschließlich per Service-Role.

-- ── Textbausteine ────────────────────────────────────────────────────
create table if not exists public.job_description_blocks (
  id                 uuid primary key default gen_random_uuid(),
  slug               text not null unique,
  category           text not null default 'allgemein',
  title              text not null,
  body               text not null default '',
  -- Steuert die automatische Vorauswahl im Editor.
  is_default         boolean not null default false,
  -- Herkunft für aus Compliance-Frameworks abgeleitete Bausteine
  -- (rein informativ; der verbindliche Compliance-Abschnitt kommt live
  -- aus den Bindings, nicht aus diesen Bausteinen).
  source_framework_id text,
  source_role_id      text,
  sort_order         integer not null default 0,
  created_at         timestamptz not null default now(),
  updated_at         timestamptz not null default now()
);

create index if not exists job_description_blocks_category_idx
  on public.job_description_blocks (category, sort_order);

-- ── Stellenbeschreibungen (1 pro Stelle) ─────────────────────────────
create table if not exists public.job_descriptions (
  id              uuid primary key default gen_random_uuid(),
  position_id     uuid not null unique
                    references public.positions(id) on delete cascade,
  title           text not null default '',
  -- Strukturierte Abschnitte: { zweck, einordnung, aufgaben[],
  -- befugnisse[], anforderungen[], vertretung, ... } als JSON.
  content_json    jsonb not null default '{}'::jsonb,
  status          text not null default 'draft'
                    check (status in ('draft', 'review', 'approved')),
  generated_by_ai boolean not null default false,
  model_used      text,
  version         integer not null default 1,
  approved_by     text,
  approved_at     timestamptz,
  created_at      timestamptz not null default now(),
  updated_at      timestamptz not null default now()
);

create index if not exists job_descriptions_position_idx
  on public.job_descriptions (position_id);

-- ── Versions-Historie (Snapshot bei „Freigeben") ─────────────────────
create table if not exists public.job_description_versions (
  id                  uuid primary key default gen_random_uuid(),
  job_description_id  uuid not null
                        references public.job_descriptions(id) on delete cascade,
  version             integer not null,
  title               text not null default '',
  content_json        jsonb not null default '{}'::jsonb,
  created_by          text,
  created_at          timestamptz not null default now()
);

create index if not exists job_description_versions_jd_idx
  on public.job_description_versions (job_description_id, version desc);

-- ── updated_at-Trigger (set_updated_at existiert seit 0023) ───────────
drop trigger if exists trg_job_description_blocks_updated_at
  on public.job_description_blocks;
create trigger trg_job_description_blocks_updated_at
  before update on public.job_description_blocks
  for each row execute function public.set_updated_at();

drop trigger if exists trg_job_descriptions_updated_at
  on public.job_descriptions;
create trigger trg_job_descriptions_updated_at
  before update on public.job_descriptions
  for each row execute function public.set_updated_at();

-- ── RLS: admin-only (Default deny, kein anon-Grant) ──────────────────
alter table public.job_description_blocks   enable row level security;
alter table public.job_descriptions         enable row level security;
alter table public.job_description_versions enable row level security;

-- Service-Role (umgeht RLS) braucht trotzdem Tabellen-Grants. Auf
-- Self-Host-Instanzen sind Default-Privileges nicht garantiert — daher
-- explizit. Bewusst NICHT an anon/authenticated (admin-only).
grant select, insert, update, delete on
  public.job_description_blocks,
  public.job_descriptions,
  public.job_description_versions
to service_role;

-- ── Modul-Default: „job_descriptions" in enabled_modules aufnehmen ────
-- Bestandsinstanzen, die das Modul (noch) nicht kennen, bleiben unberührt
-- — der Operator schaltet es unter /admin/funktionen frei. Hier wird nur
-- der Spalten-Default für ganz neue Instanzen erweitert.
do $$
begin
  if exists (
    select 1 from information_schema.columns
    where table_schema = 'public' and table_name = 'site_settings'
      and column_name = 'enabled_modules'
  ) then
    alter table public.site_settings
      alter column enabled_modules
      set default array['business_cards']::text[];
  end if;
end $$;

-- ── Seed: generische Standard-Textbausteine ──────────────────────────
-- Out-of-the-box-Startset. Idempotent über den slug. Operatoren können
-- sie unter /admin/stellenbeschreibungen/bausteine anpassen oder löschen.
insert into public.job_description_blocks
  (slug, category, title, body, is_default, sort_order)
values
  ('allgemeine-pflichten', 'Allgemein', 'Allgemeine Pflichten',
   'Wahrnehmung der übertragenen Aufgaben mit der gebotenen Sorgfalt; Einhaltung der betrieblichen Anweisungen, Richtlinien und gesetzlichen Vorgaben; wirtschaftlicher und schonender Umgang mit Betriebsmitteln.',
   true, 0),
  ('zusammenarbeit', 'Allgemein', 'Zusammenarbeit & Kommunikation',
   'Konstruktive Zusammenarbeit mit vor- und nachgelagerten Bereichen; rechtzeitige Information der Vorgesetzten über wesentliche Vorgänge; serviceorientiertes Auftreten gegenüber Kund:innen und Bürger:innen.',
   true, 1),
  ('arbeitssicherheit', 'Arbeitsschutz', 'Arbeitssicherheit & Gesundheitsschutz',
   'Einhaltung der Arbeitsschutz- und Unfallverhütungsvorschriften (DGUV); Nutzung der vorgeschriebenen persönlichen Schutzausrüstung; unverzügliche Meldung von Gefährdungen, Beinaheunfällen und Mängeln.',
   true, 2),
  ('datenschutz', 'Datenschutz', 'Datenschutz-Grundpflichten',
   'Vertraulicher Umgang mit personenbezogenen Daten gemäß DSGVO und BDSG; Datenverarbeitung ausschließlich im Rahmen der zugewiesenen Aufgaben; Wahrung des Datengeheimnisses auch über das Beschäftigungsverhältnis hinaus.',
   true, 3),
  ('informationssicherheit', 'Informationssicherheit', 'Informationssicherheit',
   'Beachtung der Informationssicherheits-Richtlinien (ISMS nach ISO/IEC 27001); sorgsamer Umgang mit Zugangsdaten und Informationswerten; Meldung von Sicherheitsvorfällen an die zuständige Stelle.',
   false, 4),
  ('vertretungsregelung', 'Allgemein', 'Vertretungsregelung',
   'Im Verhinderungsfall wird die Stelle durch die benannte Vertretung wahrgenommen. Eine geordnete Übergabe laufender Vorgänge ist sicherzustellen.',
   false, 5)
on conflict (slug) do nothing;
