feat: event team management with departments and roles - Migration 023: event_roles, event_departments, event_member_departments tables - Auto-seed default roles (Head Organizer, Team Lead, Organizer, Volunteer, Sponsor) and departments (Logistics, IT & Tech, Marketing, Finance, Program, Sponsorship, Design, Volunteers) on event creation - API: full CRUD for roles, departments, member-department assignments - Enhanced fetchEventMembers with role + department resolution - Team page: sidebar with department filter + role legend, list/dept view toggle, add/edit/remove members with role + multi-department + notes - i18n: 25 new keys in EN and ET for team management - svelte-check: 0 errors, vitest: 112/112 passed
This commit is contained in:
142
supabase/migrations/023_event_team_management.sql
Normal file
142
supabase/migrations/023_event_team_management.sql
Normal file
@@ -0,0 +1,142 @@
|
||||
-- Event Team Management: departments, roles, and member-department assignments
|
||||
-- Supports real-world event teams where members have roles and belong to departments
|
||||
|
||||
-- ============================================================
|
||||
-- 1. Event Roles: customizable per-event position types
|
||||
-- ============================================================
|
||||
CREATE TABLE event_roles (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
color TEXT NOT NULL DEFAULT '#6366f1',
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
is_default BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
UNIQUE(event_id, name)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_event_roles_event ON event_roles(event_id);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. Event Departments: teams/areas within an event
|
||||
-- ============================================================
|
||||
CREATE TABLE event_departments (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
color TEXT NOT NULL DEFAULT '#00A3E0',
|
||||
description TEXT,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
UNIQUE(event_id, name)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_event_departments_event ON event_departments(event_id);
|
||||
|
||||
-- ============================================================
|
||||
-- 3. Evolve event_members: add role_id FK, keep role text as fallback
|
||||
-- ============================================================
|
||||
ALTER TABLE event_members
|
||||
ADD COLUMN role_id UUID REFERENCES event_roles(id) ON DELETE SET NULL,
|
||||
ADD COLUMN notes TEXT;
|
||||
|
||||
-- ============================================================
|
||||
-- 4. Member-Department assignments (many-to-many)
|
||||
-- ============================================================
|
||||
CREATE TABLE event_member_departments (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
event_member_id UUID NOT NULL REFERENCES event_members(id) ON DELETE CASCADE,
|
||||
department_id UUID NOT NULL REFERENCES event_departments(id) ON DELETE CASCADE,
|
||||
assigned_at TIMESTAMPTZ DEFAULT now(),
|
||||
UNIQUE(event_member_id, department_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_emd_member ON event_member_departments(event_member_id);
|
||||
CREATE INDEX idx_emd_department ON event_member_departments(department_id);
|
||||
|
||||
-- ============================================================
|
||||
-- 5. RLS policies
|
||||
-- ============================================================
|
||||
ALTER TABLE event_roles ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE event_departments ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE event_member_departments ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Event roles: org members can view, editors+ can manage
|
||||
CREATE POLICY "Org members can view event roles" ON event_roles FOR SELECT
|
||||
USING (EXISTS (
|
||||
SELECT 1 FROM events e
|
||||
JOIN org_members om ON e.org_id = om.org_id
|
||||
WHERE e.id = event_roles.event_id AND om.user_id = auth.uid()
|
||||
));
|
||||
|
||||
CREATE POLICY "Editors can manage event roles" ON event_roles FOR ALL
|
||||
USING (EXISTS (
|
||||
SELECT 1 FROM events e
|
||||
JOIN org_members om ON e.org_id = om.org_id
|
||||
WHERE e.id = event_roles.event_id AND om.user_id = auth.uid() AND om.role IN ('owner', 'admin', 'editor')
|
||||
));
|
||||
|
||||
-- Event departments: org members can view, editors+ can manage
|
||||
CREATE POLICY "Org members can view event departments" ON event_departments FOR SELECT
|
||||
USING (EXISTS (
|
||||
SELECT 1 FROM events e
|
||||
JOIN org_members om ON e.org_id = om.org_id
|
||||
WHERE e.id = event_departments.event_id AND om.user_id = auth.uid()
|
||||
));
|
||||
|
||||
CREATE POLICY "Editors can manage event departments" ON event_departments FOR ALL
|
||||
USING (EXISTS (
|
||||
SELECT 1 FROM events e
|
||||
JOIN org_members om ON e.org_id = om.org_id
|
||||
WHERE e.id = event_departments.event_id AND om.user_id = auth.uid() AND om.role IN ('owner', 'admin', 'editor')
|
||||
));
|
||||
|
||||
-- Member-department assignments: org members can view, editors+ can manage
|
||||
CREATE POLICY "Org members can view member departments" ON event_member_departments FOR SELECT
|
||||
USING (EXISTS (
|
||||
SELECT 1 FROM event_members em
|
||||
JOIN events e ON em.event_id = e.id
|
||||
JOIN org_members om ON e.org_id = om.org_id
|
||||
WHERE em.id = event_member_departments.event_member_id AND om.user_id = auth.uid()
|
||||
));
|
||||
|
||||
CREATE POLICY "Editors can manage member departments" ON event_member_departments FOR ALL
|
||||
USING (EXISTS (
|
||||
SELECT 1 FROM event_members em
|
||||
JOIN events e ON em.event_id = e.id
|
||||
JOIN org_members om ON e.org_id = om.org_id
|
||||
WHERE em.id = event_member_departments.event_member_id AND om.user_id = auth.uid() AND om.role IN ('owner', 'admin', 'editor')
|
||||
));
|
||||
|
||||
-- ============================================================
|
||||
-- 6. Auto-seed default roles when a new event is created
|
||||
-- ============================================================
|
||||
CREATE OR REPLACE FUNCTION public.seed_event_defaults()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
-- Default roles (generalized from real event data)
|
||||
INSERT INTO public.event_roles (event_id, name, color, sort_order, is_default) VALUES
|
||||
(NEW.id, 'Head Organizer', '#EF4444', 0, false),
|
||||
(NEW.id, 'Team Lead', '#8B5CF6', 1, false),
|
||||
(NEW.id, 'Organizer', '#F59E0B', 2, true),
|
||||
(NEW.id, 'Volunteer', '#10B981', 3, false),
|
||||
(NEW.id, 'Sponsor', '#00A3E0', 4, false);
|
||||
|
||||
-- Default departments (generalized from real event data)
|
||||
INSERT INTO public.event_departments (event_id, name, color, sort_order) VALUES
|
||||
(NEW.id, 'Logistics', '#F59E0B', 0),
|
||||
(NEW.id, 'IT & Tech', '#6366F1', 1),
|
||||
(NEW.id, 'Marketing', '#EC4899', 2),
|
||||
(NEW.id, 'Finance', '#10B981', 3),
|
||||
(NEW.id, 'Program', '#8B5CF6', 4),
|
||||
(NEW.id, 'Sponsorship', '#00A3E0', 5),
|
||||
(NEW.id, 'Design', '#F97316', 6),
|
||||
(NEW.id, 'Volunteers', '#14B8A6', 7);
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
CREATE TRIGGER on_event_created_seed_defaults
|
||||
AFTER INSERT ON events
|
||||
FOR EACH ROW EXECUTE FUNCTION public.seed_event_defaults();
|
||||
Reference in New Issue
Block a user