Status: review
As a client services staff member, I want to create a new election-cycle job for a municipality from the kanban board, so that the municipality is assigned to an election cycle without altering any legacy Access tables.
ID/JCode) join key, cycle name, status, created-by, and created-at"In Setup", capturing actor identity from the authenticated principal and server-side timestampID/JCode. This invariant is enforced project-wide and is the primary regression risk for this story."In Setup" becomes the upstream input for Stories 2.3–2.5; treat the value as the canonical initial state and keep the status enum centralized.Campaign_Tracker.Server/ — add election-cycle feature folder (entity, repository, controller, audit binding) following Epic 1 conventionscampaign-tracker-client/ — add cycle creation UI alongside the kanban view from Story 2.1_bmad-output/implementation-artifacts/_bmad-output/planning-artifacts/epics.md (Epic 2 / Story 2.2)_bmad-output/planning-artifacts/architecture.md (extension-table write path, legacy read-only)_bmad-output/planning-artifacts/ux-design-specification.mdQwen3.6-27B-Q4_K_M (OpenMono.ai)
ElectionCycleJob record with JobId, JCode, CycleId, CycleName, Status, CreatedBy, CreatedAt.IElectionCycleJobRepository with CreateAsync(jCode, cycleId, cycleName, actorIdentity).ElectionCycleJobSaveResult for success/failure reporting.InMemoryElectionCycleJobRepository to support both DI (TimeProvider constructor) and test (custom assignments constructor) paths; GetAllAsync merges seed data with dynamically created jobs without double-counting.ElectionCycleJobsController with POST /api/election-cycles/jobs and GET /api/election-cycles/jobs/{jobId}; ClientServicesAccess policy; audit emission via IAuditService.CreateJobModal component with existing-cycle selector and new-cycle-name input; wired into kanban view on Unassigned lane cards.electionCycleKanbanContracts.ts with createElectionCycleJob, CreateElectionCycleJobRequest, ElectionCycleJobResponse./api/election-cycles/jobs creates jobs with “In Setup” status, captures actor identity and server timestamp, emits ELECTION_CYCLE_JOB_CREATED audit event.[Authorize(Policy = ApplicationPolicy.ClientServicesAccess)] — unauthenticated gets 401, non-ClientServices role gets 403.ILegacyDataAccess exposes only Get* methods; all writes go through IElectionCycleJobRepository (extension layer).Campaign_Tracker.Server/ElectionCycles/ElectionCycleJob.csCampaign_Tracker.Server/ElectionCycles/ElectionCycleJobSaveResult.csCampaign_Tracker.Server/ElectionCycles/IElectionCycleJobRepository.csCampaign_Tracker.Server/ElectionCycles/InMemoryElectionCycleJobRepository.csCampaign_Tracker.Server/Controllers/ElectionCycleJobsController.csCampaign_Tracker.Server.Tests/ElectionCycleJobControllerTests.csCampaign_Tracker.Server.Tests/ElectionCycleKanbanReadModelTests.cscampaign-tracker-client/src/electionCycles/CreateJobModal.tsxcampaign-tracker-client/src/electionCycles/CreateJobModal.test.tsxcampaign-tracker-client/src/electionCycles/electionCycleKanbanContracts.tscampaign-tracker-client/src/electionCycles/electionCycleKanbanView.tsxPowered by TurnKey Linux.