diff --git a/apps/api/internal/service/state.go b/apps/api/internal/service/state.go index 3543417..8bb19db 100644 --- a/apps/api/internal/service/state.go +++ b/apps/api/internal/service/state.go @@ -80,7 +80,7 @@ var defaultProjectStates = []struct { {name: "Todo", color: "#60646C", sequence: 25000, group: "unstarted"}, {name: "In Progress", color: "#F59E0B", sequence: 35000, group: "started"}, {name: "Done", color: "#46A758", sequence: 45000, group: "completed"}, - {name: "Cancelled", color: "#9AA4BC", sequence: 55000, group: "canceled"}, + {name: "Cancelled", color: "#9AA4BC", sequence: 55000, group: "cancelled"}, } func (s *StateService) ensureDefaultStates(ctx context.Context, projectID, workspaceID uuid.UUID) error { diff --git a/apps/api/internal/service/state_default_test.go b/apps/api/internal/service/state_default_test.go new file mode 100644 index 0000000..48b7549 --- /dev/null +++ b/apps/api/internal/service/state_default_test.go @@ -0,0 +1,29 @@ +package service + +import "testing" + +// Every seeded default state must use a group the app actually recognises. +// This guards against typos like "canceled" vs "cancelled", which silently +// broke auto-close, auto-archive and progress bucketing for every new project. +func TestDefaultProjectStatesUseValidGroups(t *testing.T) { + for _, st := range defaultProjectStates { + if !validStateGroups[st.group] { + t.Errorf("default state %q has group %q which is not in validStateGroups", st.name, st.group) + } + } + + // The Cancelled state specifically must be in the "cancelled" group so + // auto-close/archive and progress charts pick it up. + var found bool + for _, st := range defaultProjectStates { + if st.name == "Cancelled" { + found = true + if st.group != "cancelled" { + t.Errorf("Cancelled state group = %q; want \"cancelled\"", st.group) + } + } + } + if !found { + t.Fatal("no default Cancelled state found") + } +} diff --git a/apps/api/migrations/000013_fix_cancelled_state_group.down.sql b/apps/api/migrations/000013_fix_cancelled_state_group.down.sql new file mode 100644 index 0000000..be4945e --- /dev/null +++ b/apps/api/migrations/000013_fix_cancelled_state_group.down.sql @@ -0,0 +1,5 @@ +-- This migration fixes a typo in existing data. There is no safe way to +-- reverse it: we can't tell which "cancelled" rows were the mistyped default +-- versus states that were always spelled correctly, and reintroducing the typo +-- would just bring the bug back. Intentionally a no-op. +SELECT 1; diff --git a/apps/api/migrations/000013_fix_cancelled_state_group.up.sql b/apps/api/migrations/000013_fix_cancelled_state_group.up.sql new file mode 100644 index 0000000..e81db3d --- /dev/null +++ b/apps/api/migrations/000013_fix_cancelled_state_group.up.sql @@ -0,0 +1,6 @@ +-- Every project's default "Cancelled" state was seeded with the group +-- "canceled" (one L) while the rest of the app matches on "cancelled" (two L). +-- That mismatch made auto-close a no-op, kept cancelled issues out of +-- auto-archive, and mis-bucketed them as "backlog" in every progress chart. +-- Correct the existing rows so they line up with the seed fix. +UPDATE states SET "group" = 'cancelled' WHERE "group" = 'canceled';