feature/m6-missions #3
Reference in New Issue
Block a user
Delete Branch "feature/m6-missions"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Addresses spec-reviewer + code-reviewer feedback on the M6 bundle: Critical: - frontend/src/lib/missions.ts: add `listPrefix()` so TanStack invalidation catches every filtered list variant; the previous `list()` returned `['missions','list',{}]` and only matched the exact empty-filter cache, leaving filtered tables stale after create/transition/delete. - backend/app/services/missions.py: acquire the same per-scenario `pg_advisory_xact_lock` key used by `set_scenario_tests` before snapshotting; without it a concurrent M5 reorder could freeze a torn snapshot under READ COMMITTED. Sorted by key to avoid deadlocks with another snapshotter. Important: - backend/app/api/missions.py: `@require_perm("mission.update", "mission.archive")` on the transition endpoint so users without either perm get 403 before the body is parsed (no shape leak via 400). - backend/app/services/missions.py: escape `%` / `_` / `\` in user-typed `q` / `client` LIKE search; users can no longer trigger wildcard semantics by typing literal `%`. Added `escape='\\'` arg on every .like(). - backend/app/services/missions.py: filter `MissionTest.deleted_at` and `MissionScenario.deleted_at` in the list-item and detail counts so M7+ soft-deletes don't drift the totals silently. Nits: - backend/app/api/users.py: order `/users/roster` by email for stable rendering + deterministic e2e selectors. - frontend/src/pages/MissionDetailPage.tsx: distinct accent per transition target (cyan/orange/green/teal) matching the status legend. - e2e/tests/m6-missions.spec.ts: switch fragile `getByRole(name=/In Progress/i)` to the stable `mission-transition-in_progress` data-testid. New tests: - test_create_mission_rejects_soft_deleted_scenario - test_transition_perm_gate_runs_before_payload_parse - test_search_treats_wildcards_as_literals Suite: 106 pytest passing (was 103), 43 Playwright passing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>The M6 SPA shipped the create wizard but the detail page was read-only — even though the backend already exposed PUT /missions/{id}, POST /missions/{id}/scenarios, and PUT /missions/{id}/members. So once a mission was created you couldn't fix a typo in the client name, add a scenario you forgot, or change member assignments without curl. Added three modals on the detail page, gated by `is_admin || mission.update`: - Edit metadata (header button, 3xl modal): name + client + dates + markdown description, same validation as the wizard step 1. - Add scenarios (Tests tab): scenario picker matching wizard step 2, calls POST /missions/{id}/scenarios which appends snapshots at current_max_position + 1. - Edit members (Members tab): roster + red/blue toggles, calls PUT /missions/{id}/members (full-set replace), pre-populated with the current member set. The detail page now imports useAuth so `canEdit` is computed once and shared between the three buttons. E2E: new "detail page edits metadata, appends scenarios, edits members" spec exercises the three modals end-to-end. M6 e2e count is now 6. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>