223 lines
8.4 KiB
SQL
223 lines
8.4 KiB
SQL
/*
|
|
* -------------------------------------------------------
|
|
* Sitzungsprotokolle (Meeting Protocols) Schema
|
|
* Meeting minutes, agenda items, tasks, attachments
|
|
* -------------------------------------------------------
|
|
*/
|
|
|
|
-- =====================================================
|
|
-- 1. Extend app_permissions
|
|
-- (Moved to 20260411900001_fischerei_enum_values.sql)
|
|
-- =====================================================
|
|
|
|
-- =====================================================
|
|
-- 2. Enums
|
|
-- =====================================================
|
|
|
|
CREATE TYPE public.meeting_item_status AS ENUM(
|
|
'offen',
|
|
'in_bearbeitung',
|
|
'erledigt',
|
|
'vertagt'
|
|
);
|
|
|
|
-- =====================================================
|
|
-- 3. meeting_protocols
|
|
-- =====================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS public.meeting_protocols (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
account_id uuid NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE,
|
|
|
|
-- Identity
|
|
title text NOT NULL,
|
|
protocol_number text,
|
|
|
|
-- Schedule
|
|
meeting_date date NOT NULL,
|
|
meeting_time time,
|
|
end_time time,
|
|
location text,
|
|
|
|
-- Participants
|
|
chair text,
|
|
recorder text,
|
|
attendees jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
absent jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
|
|
-- Content
|
|
summary text,
|
|
|
|
-- Status workflow
|
|
status text NOT NULL DEFAULT 'draft'
|
|
CHECK (status IN ('draft', 'review', 'approved', 'archived')),
|
|
|
|
-- Follow-up
|
|
next_meeting_date date,
|
|
|
|
-- Flags
|
|
is_archived boolean NOT NULL DEFAULT false,
|
|
|
|
-- Meta
|
|
created_by uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
|
updated_by uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX ix_meeting_protocols_account ON public.meeting_protocols(account_id);
|
|
CREATE INDEX ix_meeting_protocols_date ON public.meeting_protocols(account_id, meeting_date DESC);
|
|
CREATE INDEX ix_meeting_protocols_status ON public.meeting_protocols(account_id, status);
|
|
CREATE INDEX ix_meeting_protocols_archived ON public.meeting_protocols(account_id, is_archived);
|
|
|
|
ALTER TABLE public.meeting_protocols ENABLE ROW LEVEL SECURITY;
|
|
REVOKE ALL ON public.meeting_protocols FROM authenticated, service_role;
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON public.meeting_protocols TO authenticated;
|
|
GRANT ALL ON public.meeting_protocols TO service_role;
|
|
|
|
CREATE POLICY meeting_protocols_select ON public.meeting_protocols FOR SELECT TO authenticated
|
|
USING (public.has_role_on_account(account_id));
|
|
CREATE POLICY meeting_protocols_insert ON public.meeting_protocols FOR INSERT TO authenticated
|
|
WITH CHECK (public.has_permission(auth.uid(), account_id, 'meetings.write'::public.app_permissions));
|
|
CREATE POLICY meeting_protocols_update ON public.meeting_protocols FOR UPDATE TO authenticated
|
|
USING (public.has_permission(auth.uid(), account_id, 'meetings.write'::public.app_permissions));
|
|
CREATE POLICY meeting_protocols_delete ON public.meeting_protocols FOR DELETE TO authenticated
|
|
USING (public.has_permission(auth.uid(), account_id, 'meetings.write'::public.app_permissions));
|
|
|
|
CREATE TRIGGER trg_meeting_protocols_updated_at
|
|
BEFORE UPDATE ON public.meeting_protocols
|
|
FOR EACH ROW EXECUTE FUNCTION public.update_account_settings_timestamp();
|
|
|
|
-- =====================================================
|
|
-- 4. meeting_protocol_items (agenda items / TOPs)
|
|
-- =====================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS public.meeting_protocol_items (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
protocol_id uuid NOT NULL REFERENCES public.meeting_protocols(id) ON DELETE CASCADE,
|
|
|
|
-- Ordering
|
|
item_number integer NOT NULL DEFAULT 0,
|
|
sort_order integer NOT NULL DEFAULT 0,
|
|
|
|
-- Content
|
|
title text NOT NULL,
|
|
content text,
|
|
|
|
-- Classification
|
|
item_type text NOT NULL DEFAULT 'information'
|
|
CHECK (item_type IN ('information', 'discussion', 'decision', 'task')),
|
|
|
|
-- Decision tracking
|
|
decision_text text,
|
|
|
|
-- Task tracking
|
|
status public.meeting_item_status NOT NULL DEFAULT 'offen',
|
|
responsible_person text,
|
|
due_date date,
|
|
|
|
-- Meta
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX ix_meeting_protocol_items_protocol ON public.meeting_protocol_items(protocol_id);
|
|
CREATE INDEX ix_meeting_protocol_items_status ON public.meeting_protocol_items(status);
|
|
CREATE INDEX ix_meeting_protocol_items_type ON public.meeting_protocol_items(item_type);
|
|
CREATE INDEX ix_meeting_protocol_items_due ON public.meeting_protocol_items(due_date)
|
|
WHERE due_date IS NOT NULL AND status != 'erledigt';
|
|
|
|
ALTER TABLE public.meeting_protocol_items ENABLE ROW LEVEL SECURITY;
|
|
REVOKE ALL ON public.meeting_protocol_items FROM authenticated, service_role;
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON public.meeting_protocol_items TO authenticated;
|
|
GRANT ALL ON public.meeting_protocol_items TO service_role;
|
|
|
|
CREATE POLICY meeting_protocol_items_select ON public.meeting_protocol_items FOR SELECT TO authenticated
|
|
USING (EXISTS (
|
|
SELECT 1 FROM public.meeting_protocols mp
|
|
WHERE mp.id = meeting_protocol_items.protocol_id
|
|
AND public.has_role_on_account(mp.account_id)
|
|
));
|
|
CREATE POLICY meeting_protocol_items_mutate ON public.meeting_protocol_items FOR ALL TO authenticated
|
|
USING (EXISTS (
|
|
SELECT 1 FROM public.meeting_protocols mp
|
|
WHERE mp.id = meeting_protocol_items.protocol_id
|
|
AND public.has_permission(auth.uid(), mp.account_id, 'meetings.write'::public.app_permissions)
|
|
));
|
|
|
|
CREATE TRIGGER trg_meeting_protocol_items_updated_at
|
|
BEFORE UPDATE ON public.meeting_protocol_items
|
|
FOR EACH ROW EXECUTE FUNCTION public.update_account_settings_timestamp();
|
|
|
|
-- =====================================================
|
|
-- 5. meeting_protocol_attachments
|
|
-- =====================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS public.meeting_protocol_attachments (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
protocol_id uuid NOT NULL REFERENCES public.meeting_protocols(id) ON DELETE CASCADE,
|
|
item_id uuid REFERENCES public.meeting_protocol_items(id) ON DELETE SET NULL,
|
|
|
|
-- File info
|
|
file_name text NOT NULL,
|
|
file_path text NOT NULL,
|
|
file_size bigint,
|
|
content_type text,
|
|
|
|
-- Meta
|
|
created_by uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX ix_meeting_protocol_attachments_protocol ON public.meeting_protocol_attachments(protocol_id);
|
|
CREATE INDEX ix_meeting_protocol_attachments_item ON public.meeting_protocol_attachments(item_id)
|
|
WHERE item_id IS NOT NULL;
|
|
|
|
ALTER TABLE public.meeting_protocol_attachments ENABLE ROW LEVEL SECURITY;
|
|
REVOKE ALL ON public.meeting_protocol_attachments FROM authenticated, service_role;
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON public.meeting_protocol_attachments TO authenticated;
|
|
GRANT ALL ON public.meeting_protocol_attachments TO service_role;
|
|
|
|
CREATE POLICY meeting_protocol_attachments_select ON public.meeting_protocol_attachments FOR SELECT TO authenticated
|
|
USING (EXISTS (
|
|
SELECT 1 FROM public.meeting_protocols mp
|
|
WHERE mp.id = meeting_protocol_attachments.protocol_id
|
|
AND public.has_role_on_account(mp.account_id)
|
|
));
|
|
CREATE POLICY meeting_protocol_attachments_mutate ON public.meeting_protocol_attachments FOR ALL TO authenticated
|
|
USING (EXISTS (
|
|
SELECT 1 FROM public.meeting_protocols mp
|
|
WHERE mp.id = meeting_protocol_attachments.protocol_id
|
|
AND public.has_permission(auth.uid(), mp.account_id, 'meetings.write'::public.app_permissions)
|
|
));
|
|
|
|
-- =====================================================
|
|
-- 6. View: open_meeting_tasks
|
|
-- =====================================================
|
|
|
|
CREATE OR REPLACE VIEW public.open_meeting_tasks AS
|
|
SELECT
|
|
mpi.id AS item_id,
|
|
mpi.protocol_id,
|
|
mp.account_id,
|
|
mp.title AS protocol_title,
|
|
mp.meeting_date,
|
|
mpi.item_number,
|
|
mpi.title AS task_title,
|
|
mpi.content AS task_description,
|
|
mpi.responsible_person,
|
|
mpi.due_date,
|
|
mpi.status,
|
|
CASE
|
|
WHEN mpi.due_date < current_date AND mpi.status != 'erledigt' THEN true
|
|
ELSE false
|
|
END AS is_overdue
|
|
FROM public.meeting_protocol_items mpi
|
|
JOIN public.meeting_protocols mp ON mp.id = mpi.protocol_id
|
|
WHERE mpi.item_type = 'task'
|
|
AND mpi.status != 'erledigt';
|
|
|
|
-- Grant access to the view (RLS on underlying tables still applies)
|
|
GRANT SELECT ON public.open_meeting_tasks TO authenticated;
|
|
GRANT SELECT ON public.open_meeting_tasks TO service_role;
|