Add GameForge sprints and tasks functionality

cgen-5531fa58665046dc892bcac60954d8b9
This commit is contained in:
Builder.io 2025-11-15 17:02:11 +00:00
parent bdd221f1a6
commit d821441005

View file

@ -0,0 +1,186 @@
-- GameForge Sprints and Tasks
-- Manage sprints (development cycles) and tasks within each sprint
-- GameForge Sprints Table
-- Organize work into time-boxed sprints for iterative development
create table if not exists public.gameforge_sprints (
id uuid primary key default gen_random_uuid(),
project_id uuid not null references public.gameforge_projects(id) on delete cascade,
sprint_number int not null,
title text not null,
description text,
phase text not null default 'planning' check (phase in ('planning', 'active', 'completed', 'cancelled')),
status text not null default 'pending' check (status in ('pending', 'active', 'on_hold', 'completed')),
goal text, -- High-level sprint goal/focus area
start_date timestamptz,
end_date timestamptz,
planned_velocity int, -- Estimated story points or tasks
actual_velocity int, -- Actual completed story points or tasks
created_by uuid not null references public.user_profiles(id) on delete set null,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (project_id, sprint_number)
);
create index if not exists gameforge_sprints_project_id_idx on public.gameforge_sprints (project_id);
create index if not exists gameforge_sprints_phase_idx on public.gameforge_sprints (phase);
create index if not exists gameforge_sprints_status_idx on public.gameforge_sprints (status);
create index if not exists gameforge_sprints_start_date_idx on public.gameforge_sprints (start_date desc);
create index if not exists gameforge_sprints_created_by_idx on public.gameforge_sprints (created_by);
-- GameForge Sprint Members Table
-- Track which team members are participating in a sprint
create table if not exists public.gameforge_sprint_members (
id uuid primary key default gen_random_uuid(),
sprint_id uuid not null references public.gameforge_sprints(id) on delete cascade,
user_id uuid not null references public.user_profiles(id) on delete cascade,
role text not null default 'contributor' check (role in ('lead', 'contributor', 'reviewer')),
joined_at timestamptz not null default now(),
created_at timestamptz not null default now(),
unique (sprint_id, user_id)
);
create index if not exists gameforge_sprint_members_sprint_id_idx on public.gameforge_sprint_members (sprint_id);
create index if not exists gameforge_sprint_members_user_id_idx on public.gameforge_sprint_members (user_id);
create index if not exists gameforge_sprint_members_role_idx on public.gameforge_sprint_members (role);
-- GameForge Tasks Table
-- Individual work items/tasks assigned within sprints
create table if not exists public.gameforge_tasks (
id uuid primary key default gen_random_uuid(),
sprint_id uuid references public.gameforge_sprints(id) on delete set null,
project_id uuid not null references public.gameforge_projects(id) on delete cascade,
title text not null,
description text,
status text not null default 'todo' check (status in ('todo', 'in_progress', 'in_review', 'done', 'blocked')),
priority text not null default 'medium' check (priority in ('low', 'medium', 'high', 'critical')),
estimated_hours numeric(6, 1), -- Story points or hours estimate
actual_hours numeric(6, 1), -- Actual time spent
assigned_to uuid references public.user_profiles(id) on delete set null,
created_by uuid not null references public.user_profiles(id) on delete set null,
due_date timestamptz,
completed_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists gameforge_tasks_sprint_id_idx on public.gameforge_tasks (sprint_id);
create index if not exists gameforge_tasks_project_id_idx on public.gameforge_tasks (project_id);
create index if not exists gameforge_tasks_assigned_to_idx on public.gameforge_tasks (assigned_to);
create index if not exists gameforge_tasks_created_by_idx on public.gameforge_tasks (created_by);
create index if not exists gameforge_tasks_status_idx on public.gameforge_tasks (status);
create index if not exists gameforge_tasks_priority_idx on public.gameforge_tasks (priority);
create index if not exists gameforge_tasks_due_date_idx on public.gameforge_tasks (due_date);
-- Enable RLS
alter table public.gameforge_sprints enable row level security;
alter table public.gameforge_sprint_members enable row level security;
alter table public.gameforge_tasks enable row level security;
-- RLS Policies: gameforge_sprints
create policy "Sprints are readable by authenticated users" on public.gameforge_sprints
for select using (auth.role() = 'authenticated');
create policy "Project leads can create sprints" on public.gameforge_sprints
for insert with check (
exists(
select 1 from public.gameforge_projects
where id = project_id and lead_id = auth.uid()
)
);
create policy "Project leads can update sprints" on public.gameforge_sprints
for update using (
exists(
select 1 from public.gameforge_projects
where id = project_id and lead_id = auth.uid()
)
);
-- RLS Policies: gameforge_sprint_members
create policy "Sprint members are readable by team" on public.gameforge_sprint_members
for select using (
exists(
select 1 from public.gameforge_sprint_members sm
where sm.sprint_id = sprint_id and sm.user_id = auth.uid()
)
or exists(
select 1 from public.gameforge_sprints gs
join public.gameforge_projects gp on gs.project_id = gp.id
where gs.id = sprint_id and gp.lead_id = auth.uid()
)
);
create policy "Users can join sprints" on public.gameforge_sprint_members
for insert with check (
auth.uid() = user_id
or exists(
select 1 from public.gameforge_sprints gs
join public.gameforge_projects gp on gs.project_id = gp.id
where gs.id = sprint_id and gp.lead_id = auth.uid()
)
);
create policy "Users can leave sprints" on public.gameforge_sprint_members
for delete using (auth.uid() = user_id);
-- RLS Policies: gameforge_tasks
create policy "Tasks are readable by sprint members" on public.gameforge_tasks
for select using (
exists(
select 1 from public.gameforge_sprint_members
where sprint_id = sprint_id and user_id = auth.uid()
)
or sprint_id is null
or exists(
select 1 from public.gameforge_projects
where id = project_id and lead_id = auth.uid()
)
);
create policy "Project leads and assignees can create tasks" on public.gameforge_tasks
for insert with check (
auth.uid() = created_by
and (
assigned_to is null
or assigned_to = auth.uid()
or exists(
select 1 from public.gameforge_projects
where id = project_id and lead_id = auth.uid()
)
)
);
create policy "Assigned users and leads can update tasks" on public.gameforge_tasks
for update using (
auth.uid() = assigned_to
or exists(
select 1 from public.gameforge_projects
where id = project_id and lead_id = auth.uid()
)
);
-- Triggers for updated_at
create or replace function public.set_gameforge_sprint_updated_at()
returns trigger as $$
begin
new.updated_at = now();
return new;
end;
$$ language plpgsql;
create trigger gameforge_sprints_set_updated_at
before update on public.gameforge_sprints
for each row execute function public.set_gameforge_sprint_updated_at();
create trigger gameforge_tasks_set_updated_at
before update on public.gameforge_tasks
for each row execute function public.set_gameforge_sprint_updated_at();
-- Comments
comment on table public.gameforge_sprints is 'GameForge sprints: time-boxed development cycles for iterative game development';
comment on table public.gameforge_sprint_members is 'Track team members participating in each sprint';
comment on table public.gameforge_tasks is 'Individual tasks/work items within GameForge projects and sprints';
comment on column public.gameforge_sprints.phase is 'Sprint lifecycle: planning → active → completed (or cancelled)';
comment on column public.gameforge_sprints.goal is 'High-level focus area or objective for the sprint';
comment on column public.gameforge_tasks.status is 'Task workflow: todo → in_progress → in_review → done (or blocked)';