Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

77KB


stepsCompleted:

  • step-01-validate-prerequisites
  • step-02-design-epics
  • step-03-create-stories inputDocuments:
  • _bmad-output/planning-artifacts/prd.md
  • _bmad-output/planning-artifacts/architecture.md
  • _bmad-output/planning-artifacts/ux-design-specification.md

Campaign_Tracker App - Epic Breakdown

Overview

This document provides the complete epic and story breakdown for Campaign_Tracker App, decomposing the requirements from the PRD, UX Design, and Architecture into implementable stories.

Requirements Inventory

Functional Requirements

FR1: Client services staff can create and maintain municipality account profiles linked to existing jurisdiction identifiers. FR2: Client services staff can store and update municipality operational mailing and delivery addresses for election services. FR3: Client services staff can manage municipality service-contact records, including primary and secondary contacts. FR4: Client services staff can view municipality-specific service defaults from prior election cycles. FR5: Client services staff can create a new election-cycle job for a municipality without altering legacy Access tables. FR6: Client services staff can define election-cycle key dates for data files, proofing, pickups, deliveries, and mail activities. FR7: Client services staff can copy configurable planning defaults from the municipality's prior election-cycle job. FR8: Operations users can mark required planning fields complete and see readiness status for each election-cycle job. FR9: Client services staff can configure addressing service for an election-cycle job, including quantities and dependency fields. FR10: Client services staff can configure envelope service options including purple and blue envelope scenarios. FR11: Client services staff can configure office-copy requirements and related production details. FR12: Client services staff can configure sorting service options including quantity, class, permit/meter, and daily-sort flags. FR13: Users can record transportation-relevant service events tied to configured services. FR14: Operations users can schedule and update milestone dates for all configured service events. FR15: Operations users can view milestone timelines by municipality and by date across active election-cycle jobs. FR16: Operations users can detect missing or conflicting required milestones before execution cutoffs. FR17: Operations users can reassign milestone ownership and due dates across teams. FR18: Production users can update job status at defined process checkpoints. FR19: Support and operations users can log exceptions, blockers, and resolution notes against an election-cycle job. FR20: Users can record status transitions with timestamped history for key operational events. FR21: Users can view current and historical process state for a municipality's election-cycle jobs. FR22: Users can generate a transportation report grouped by date and sorted by county and municipality context. FR23: Users can generate a sorting report by municipality for all jobs with sorting enabled. FR24: Users can generate a sorting report by mail date for all jobs with sorting enabled. FR25: Users can export operational reports for downstream consumption in spreadsheet-compatible formats. FR26: Users can filter reports by date ranges, municipality, county, and service-status criteria. FR27: Administrators can manage user roles and permissions for client services, production, transportation, support, and admin functions. FR28: Administrators can manage extension-layer reference values used by planning and status workflows. FR29: Administrators can define required-field rules for election-cycle readiness checks. FR30: Administrators can configure notification/escalation rules for missed or at-risk milestones. FR31: System users can link extension records to existing legacy identifiers (ID, JCode/JurisCode, KitID) for unified workflows. FR32: Administrators can run compatibility validation checks that confirm legacy-table schemas remain unchanged. FR33: Support users can trace report values back to source records across legacy and extension datasets. FR34: Authorized users can correct extension-layer data issues without direct edits to immutable legacy tables.

NonFunctional Requirements

NFR1: 95% of authenticated page loads for core workflows complete in 2 seconds or less under normal operating load. NFR2: 95% of create/update operations for election-cycle records complete with user confirmation in 1 second or less. NFR3: Transportation and sorting report generation completes in 30 seconds or less for standard daily/weekly filters. NFR4: 100% of application traffic is encrypted in transit using TLS 1.2+ and verified by quarterly transport-security scans. NFR5: 100% of sensitive stored operational data is encrypted at rest with platform-managed AES-256 controls, verified by monthly configuration audits. NFR6: 100% of privileged operations enforce role-based authorization checks, and unauthorized requests are blocked and logged. NFR7: Security-relevant actions (authentication events and permission-sensitive updates) are logged within 5 seconds and retained for at least 365 days. NFR8: The system supports at least 10x growth in active election-cycle job volume without requiring legacy schema changes. NFR9: The system supports at least 150 concurrent operational users with p95 response time under 2 seconds and error rate under 1% during peak-period load testing. NFR10: MVP screens for forms, tables, and reports meet WCAG 2.1 AA-aligned criteria relevant to keyboard access, labeling, contrast, and focus visibility. NFR11: 100% of critical workflows are operable by keyboard-only interaction and validated against an accessibility test checklist in each release. NFR12: Legacy Access tables are treated as immutable dependencies, and release gates fail on any unauthorized schema delta against the approved baseline. NFR13: Extension-table joins to legacy identifiers maintain at least 99.9% referential consistency, verified by nightly integrity checks and pre-release validation runs. NFR14: Exported report datasets preserve required field parity for existing operational consumers. NFR15: Planned system availability target is 99.5% monthly during operational hours. NFR16: Every key milestone/status update is stored with audit history sufficient for operational reconstruction. NFR17: Recovery procedures ensure no committed extension-record updates are lost for the previous 24 hours of operations.

Additional Requirements

  • Starter Template (Epic 1, Story 1): ASP.NET Core 10 Web API + Vite React TypeScript. Initialization commands: dotnet new sln -n campaign-tracker, dotnet new webapi -n Campaign_Tracker.Server -f net10.0 --use-controllers, dotnet sln add, npm create vite@latest campaign-tracker-client -- --template react-ts.
  • Anti-corruption data access layer required between modern services and immutable legacy Access structures.
  • Separate operational write path (extension tables) from report read path (join/materialized/query layer) to reduce coupling.
  • Join-key integrity (ID, JCode/JurisCode, KitID) is a platform concern requiring scheduled validation jobs and release-gate checks.
  • Pre-commit validation orchestration as a shared capability: required-field checks, dependency checks, and policy checks before any sensitive state transition.
  • Parity governance workflow: run legacy and modern reports in parallel during transition; define parity acceptance thresholds per report type; require parity evidence as a formal cutover gate.
  • Compliance evidence model: generate and bind evidence artifacts (security events, data residency, accessibility) to release gates, not post-release documentation.
  • Discrepancy triage workflow with owner assignment, resolution status tracking, and closure audit trail.
  • Performance strategy under peak election windows: query shaping, caching strategy, and export throughput optimization for concurrent report generation.

UX Design Requirements

UX-DR1: Implement Ant Design v5 as base component library with custom token configuration — colorPrimary (#1F4E79), teal secondary (#0F766E), interactive accent (#2563EB), semantic status palette (success/warning/error/info/overdue), compact density profile, and Public Sans / IBM Plex Sans typography stack. UX-DR2: Build tri-pane workspace shell as primary application layout — left context/navigation pane (municipality and saved views), center dense editable operations grid, right risk queue + inspector/provenance panel; collapsible secondary pane at 1280–1599px. UX-DR3: Implement MunicipalityCycleWorkspaceGrid custom component — sticky header, column controls, inline editable cells, row status chips, provenance quick-view trigger; states: default, sorted, filtered, inline-editing, validation-error, loading, empty; keyboard row/cell navigation with ARIA sort state. UX-DR4: Implement SafeCommitRail custom component — pre-commit dependency/policy gate; anatomy: validation summary, blocking reasons, corrective links, reason-code selector, commit action; variants: inline rail (grid), drawer rail (detail mode); commit disabled until all checks and reason codes satisfied. UX-DR5: Implement CutoffRiskQueuePanel custom component — persistent urgency queue; anatomy: prioritized cards, countdown/due state, severity badges, owner, quick-open action; always-visible in right pane; reorders deterministically after updates; severity announced with text labels not color alone. UX-DR6: Implement BlockerResolutionDrawer custom component — in-context recovery workspace; anatomy: blocker details, dependency links, assignment, due-by edit, resolution note, save controls; writes exception history on save; returns user to previous context. UX-DR7: Implement DispatchRunBuilder custom component — date range controls, filter set, results grouped by date/county/municipality, quantity notes, export actions; next-day quick mode and 7-day lookahead mode; deep-links to corrective records on data gaps. UX-DR8: Implement ProvenanceTimelinePanel custom component — timestamped events, actor, reason code, changed fields, source link; compact inline preview and full audit view variants; semantic timeline structure for screen readers. UX-DR9: Implement keyboard-first interaction across all operational surfaces: visible 2px focus indicators, logical tab order in grids/forms/drawers/modals, standardized focus management for modal/drawer open/close flows. UX-DR10: Implement role-based workspace entry — distinct default views and saved filter presets for Client Services, Production, Transportation, Support, and Admin roles. UX-DR11: Implement “Next Best Action” prompt system per record to reduce decision latency in operations views. UX-DR12: Implement accessible status semantics — pair all status colors with text labels and icons; WCAG 2.2 AA minimum contrast (4.5:1 normal text, 3:1 large text/UI components); respect reduced-motion preferences. UX-DR13: Implement deterministic filtering/sorting with always-visible active filter chips, saved presets per user role/workspace, and predictable default sort (urgency then due date). UX-DR14: Implement progressive required-field validation — validate inline during edit; hard-block validation at publish/commit checkpoints only; show inline field-level errors plus top-level summary for multi-error states. UX-DR15: Implement desktop-first responsive strategy — minimum supported width 1280px; full tri-pane at 1600px+; compact tri-pane with collapsible secondary at 1280–1599px; reduced read mode with support notice below 1280px.

FR Coverage Map

FR1: Epic 1 - Municipality account profile creation and management FR2: Epic 1 - Municipality operational mailing/delivery addresses FR3: Epic 1 - Municipality service-contact records FR4: Epic 1 - Prior-cycle service defaults FR5: Epic 2 - Election-cycle job creation FR6: Epic 2 - Election-cycle key dates definition FR7: Epic 2 - Prior-cycle planning defaults copy FR8: Epic 2 - Required-field readiness status FR9: Epic 3 - Addressing service configuration FR10: Epic 3 - Purple/blue envelope service configuration FR11: Epic 3 - Office-copy requirements FR12: Epic 3 - Sorting service configuration FR13: Epic 3 - Transportation-relevant service events FR14: Epic 4 - Milestone scheduling and updates FR15: Epic 4 - Milestone timeline views FR16: Epic 4 - Missing/conflicting milestone detection FR17: Epic 4 - Milestone ownership reassignment FR18: Epic 5 - Job status updates at checkpoints FR19: Epic 5 - Exception, blocker, and resolution logging FR20: Epic 5 - Timestamped status transition history FR21: Epic 5 - Current and historical process state view FR22: Epic 5 - Transportation report (early municipality proof point) FR23: Epic 6 - Sorting report by municipality FR24: Epic 6 - Sorting report by mail date FR25: Epic 6 - Report export (spreadsheet-compatible) FR26: Epic 6 - Report filtering by date/municipality/county/status FR27: Epic 1 - Role and permission management foundation FR28: Epic 1 (seed/engine) + Epic 6 (admin UI) - Extension-layer reference value management FR29: Epic 1 (seed/engine) + Epic 6 (admin UI) - Required-field rules for readiness checks FR30: Epic 1 (seed/engine) + Epic 6 (admin UI) - Notification/escalation rule configuration FR31: Epic 1 - Legacy identifier linking (ID, JCode, KitID) FR32: Epic 1 - Legacy schema compatibility validation FR33: Epic 6 - Report-to-source record traceability FR34: Epic 6 - Extension-layer data correction FR35: Epic 2 - Spreadsheet import and column mapping (Story 2.6) FR36: Epic 3 - Proof/contact workflow status handling (Story 3.2 additions)

Epic List

Epic 1: Foundation, Auth, Municipality Profiles & Admin Seed

Users can authenticate and access their role-specific workspace. Municipality account profiles, addresses, contacts, and service defaults are immediately available linked to legacy jurisdiction identifiers. Seed data makes the system operationally functional from day one. Audit logging runs as a shared infrastructure-level service across all epics.

FRs covered: FR1, FR2, FR3, FR4, FR27, FR28 (seed+engine), FR29 (seed+engine), FR30 (seed+engine), FR31, FR32 Architecture: ASP.NET Core 10 + Vite React TS starter template initialization, anti-corruption data access layer, RBAC setup, legacy join-key integrity validation, compatibility check release gates, NFR7 shared audit logging infrastructure UX: Ant Design v5 token setup (UX-DR1), tri-pane workspace shell (UX-DR2), role-based workspace entry (UX-DR10), keyboard-first foundation (UX-DR9), desktop-first responsive strategy (UX-DR15) Implementation note: FR1–FR4 are CRUD-weight stories; FR27–FR32 carry infrastructure weight. Stories can be developed in parallel within the epic by splitting backend and frontend tracks. Adoption target: Epic 2 must begin within 6 weeks of Epic 1 delivery to preserve coordinator adoption momentum.

Epic 2: Election-Cycle Job Creation & Planning

Client services staff can create election-cycle jobs, define key dates, apply prior-cycle defaults, and track required-field readiness status to production-ready publication — with a kanban entry-point that assigns municipalities to cycle lanes (multiple concurrent cycle support included).

FRs covered: FR5, FR6, FR7, FR8 UX: Municipality-to-Cycle Kanban Entry Point (UX-DR16) — municipality cards in multiple cycle lanes; SafeCommitRail component (UX-DR4) built as reusable module for Epic 3 and Epic 5 consumption; progressive required-field validation (UX-DR14) Metric: Epics 2+3 together are the primary delivery point for the 40% election job setup-time reduction KPI (PRD Success Criteria)

Epic 3: Service Configuration

Client services staff can configure all election services on a job: addressing (quantities and dependency fields), purple and blue envelope scenarios, office-copy requirements, sorting options (quantity, class, permit/meter, daily-sort flags), and transportation-relevant service events.

FRs covered: FR9, FR10, FR11, FR12, FR13 UX: MunicipalityCycleWorkspaceGrid (UX-DR3) — inline editable cells, row status chips, deterministic filtering; SafeCommitRail reused from Epic 2 Metric: Epics 2+3 together = 40% setup-time reduction measurement checkpoint; post-Epic 3 coordinator survey recommended

Epic 4: Milestone Scheduling & Timeline Management

Operations teams can schedule and update milestone dates for all configured service events, view milestone timelines by municipality and date across active jobs, detect missing or conflicting required milestones before execution cutoffs, and reassign milestone ownership and due dates across teams.

FRs covered: FR14, FR15, FR16, FR17 UX: CutoffRiskQueuePanel (UX-DR5) — persistent urgency queue, always-visible in right pane; Next Best Action prompts (UX-DR11); deterministic filtering/sorting with saved presets (UX-DR13)

Epic 5: Production Tracking, Exception Management, Audit History & Transportation Report

Production teams can update job statuses at checkpoints, log exceptions and blockers with resolution notes, record timestamped status transitions, and view complete process history. Transportation coordinators receive the first external-facing report — a date-sorted transportation dispatch report grouped by county and municipality — giving municipality clients an early proof point before the full reporting suite.

FRs covered: FR18, FR19, FR20, FR21, FR22 UX: ProvenanceTimelinePanel (UX-DR8) — timestamped events, actor, reason code, changed fields; BlockerResolutionDrawer (UX-DR6) — in-context recovery workspace; accessible status semantics (UX-DR12) External proof point: FR22 transportation report provides municipality clients visible evidence of modernization before Epic 6

Epic 6: Full Reporting Suite, Admin Management UIs & Governance

All remaining operational reports with deterministic filtering and spreadsheet-compatible export. Admin management UIs for reference values, required-field rules, and escalation rules (completing FR28/FR29/FR30 from seed-only to fully configurable). Support analysts get report-to-source traceability and extension-layer data correction tools. Parity governance closes with a defined sunset criteria, named owner, and municipality sign-off before legacy report deprecation.

FRs covered: FR23, FR24, FR25, FR26, FR33, FR34 Admin UIs: FR28 reference value management UI, FR29 required-field rules management UI, FR30 escalation rule configuration UI UX: DispatchRunBuilder (UX-DR7); deterministic filtering with saved presets (UX-DR13) Parity governance: Must include sunset trigger threshold, named operational owner, and municipality client sign-off criteria before legacy report stack is deprecated


Epic 1: Foundation, Auth, Municipality Profiles & Admin Seed

Users can authenticate and access their role-specific workspace. Municipality account profiles are immediately available linked to legacy jurisdiction identifiers. Seed data makes the system operationally functional. Audit logging runs as a shared infrastructure-level service across all epics.

Story 1.1: Project Initialization & Solution Scaffold

As a developer, I want the solution scaffolded with ASP.NET Core 10 Web API and Vite React TypeScript, So that the team has a working, runnable baseline with the correct project structure for all subsequent stories.

Acceptance Criteria:

Given the initialization commands are run (dotnet new sln, dotnet new webapi, npm create vite@latest --template react-ts) When the solution builds Then both Campaign_Tracker.Server and campaign-tracker-client compile without errors

Given the solution is running locally When the Vite dev server starts Then the React app loads at the configured local URL with no console errors

Given the server is running When GET /health is called Then it returns 200 OK with a status payload

Given the solution structure is created When reviewed against the architecture decision Then the .sln file, server project folder, and client project folder exist at expected paths and .gitignore excludes node_modules, bin, obj, and .env files


Story 1.2: Workspace Shell & Ant Design Foundation

As any authenticated user, I want a consistent tri-pane application layout with the Ant Design visual system applied, So that I have a predictable, accessible, and keyboard-navigable operational environment from day one.

Acceptance Criteria:

Given the app loads after authentication When an authenticated user enters the application Then the tri-pane layout renders with a left navigation pane, center content area, and collapsible right panel

Given the Ant Design token configuration is applied When the UI renders Then colorPrimary is #1F4E79, teal secondary is #0F766E, semantic status colors (success/warning/error/info/overdue) match the UX spec, and compact density profile is active (UX-DR1)

Given a user interacts with any focusable element When tabbing through the interface Then visible 2px focus indicators are present on all interactive elements with logical tab order (UX-DR9)

Given the viewport is 1280–1599px When the layout renders Then the right panel is collapsible and the tri-pane adapts to compact mode (UX-DR15)

Given the viewport is below 1280px When the layout renders Then a reduced read mode with a support notice is displayed and full editing is not available

Given any status indicator renders When viewed Then status is conveyed with both color and a text label or icon — never color alone (UX-DR12)


Story 1.3: Keycloak Realm Configuration & OIDC Integration

As any team member, I want to authenticate using Keycloak single sign-on via OpenID Connect, So that I can securely access the application with my organizational credentials.

Acceptance Criteria:

Given a user navigates to the application while unauthenticated When they load any protected route Then they are redirected to the Keycloak login page for the configured realm

Given a user enters valid Keycloak credentials When authentication succeeds Then they receive a JWT access token, are redirected to their role-specific workspace, and the authentication event is logged to the audit service within 5 seconds (NFR7)

Given a user's access token expires When they make an authenticated request Then the refresh token flow silently renews the session or redirects to login if the refresh token is also expired

Given an invalid or expired token is presented to the API When the request is processed Then the API returns 401 Unauthorized and the failed authentication attempt is captured in the audit log

Given the application is deployed When traffic is inspected Then all communication is over TLS 1.2+ (NFR4) and sensitive token data is not exposed in URLs or logs


Story 1.4: Keycloak Role Mapping & Application Authorization

As a developer, I want Keycloak roles mapped to application permission policies enforced on API routes and frontend features, So that each user sees only the capabilities appropriate to their operational role.

Acceptance Criteria:

Given a Keycloak user has the ClientServices role When they authenticate and navigate Then they can access municipality profile and election-cycle creation routes and cannot access admin-only or production-only routes

Given a Keycloak user has the Admin role When they authenticate Then they can access all application routes including admin-sensitive functions

Given a user without a recognized application role authenticates When they access any protected route Then they receive 403 Forbidden and the unauthorized access attempt is logged with actor identity

Given a privileged operation is performed When it completes Then the authorization check result, actor, and resource are captured by the audit logging service within 5 seconds (NFR6, NFR7)

And roles ClientServices, Production, Transportation, Support, and Admin are managed entirely in Keycloak Admin Console — FR27 is satisfied without a custom role management UI


Story 1.5: Shared Audit Logging Infrastructure

As a system, I want all security-relevant and operational events captured by a shared logging service, So that audit history is uniformly available across all application features from day one without per-feature implementation.

Acceptance Criteria:

Given any security-relevant action occurs (auth event, permission check, privileged update) When the action completes Then the event is written to the audit log within 5 seconds including actor identity, timestamp (UTC), action type, resource identifier, and outcome (NFR7)

Given audit records are persisted When the retention policy is evaluated Then records are retained for at least 365 days and are not purgeable by standard application operations (NFR7)

Given any application feature calls the audit logging service When the call is made Then it succeeds using the shared service contract — the calling feature does not implement its own audit persistence

Given an audit record is written When retrieved for review Then it is append-only — no update or delete operations are available on audit records

Given the audit service is unavailable When an auditable action occurs Then the action is blocked or queued — auditable operations must not silently proceed without capture


Story 1.6: Legacy Anti-Corruption Data Access Layer

As a developer, I want a dedicated read-only data access layer for legacy Access-derived entities using fixed join keys, So that legacy data is available to all features without any risk of schema mutation or direct table coupling.

Acceptance Criteria:

Given a feature requests municipality or jurisdiction data When the anti-corruption layer is called Then it returns data joined by ID, JCode/JurisCode, or KitID without modifying any legacy table structure or content (NFR12)

Given the anti-corruption layer executes any query When the operation is inspected Then only SELECT operations are permitted — INSERT, UPDATE, and DELETE on legacy entities are blocked at the layer boundary

Given legacy data is returned through the layer When mapped to the application domain Then it is converted to strongly-typed domain model objects before being returned to any calling feature

Given any application code outside the layer attempts to query legacy tables directly When reviewed in code Then no such direct access exists — the anti-corruption layer is the sole access point for legacy data


Story 1.7: Legacy Schema Compatibility Validation Gate

As an administrator, I want to run a compatibility check that confirms legacy table schemas are unchanged against the approved baseline, So that every release can be gated on legacy integrity before deployment.

Acceptance Criteria:

Given the compatibility check is triggered When it runs against the live database Then it compares all legacy table structures (column names, types, constraints) against the approved schema baseline stored at initialization

Given a structural change is detected on any legacy table When the check completes Then it returns a failure status with a detailed report identifying the affected table, column, and change type (NFR12)

Given no schema drift is detected When the check completes Then it returns a pass confirmation with timestamp, number of tables verified, and zero drift count

Given the check is integrated into the release pipeline When it fails Then the release is blocked automatically and a failure report is surfaced to the administrator

Given an administrator is logged in When they navigate to the compatibility check feature Then they can trigger the check manually and view the most recent check history with timestamps


Story 1.8: Legacy Identifier Linking for Extension Records

As a system user, I want extension records to store and validate legacy identifier references on creation, So that all new capabilities join deterministically to legacy Access records in workflows and reports.

Acceptance Criteria:

Given a new extension record is created (municipality profile, election job, service config) When it is saved Then it stores the appropriate legacy identifier (ID, JCode/JurisCode, or KitID) as a required foreign reference

Given an extension record references a legacy identifier When the anti-corruption layer executes a join Then it returns the correct legacy record with no ambiguity across all active records

Given an extension record is submitted with an invalid or non-existent legacy identifier When validation runs before save Then the save is rejected with a descriptive validation error identifying the invalid reference

Given the nightly integrity check runs When it evaluates all extension-to-legacy joins Then it reports referential consistency and flags any records that fail to resolve, targeting 99.9% consistency (NFR13)


Story 1.9: Seed System Reference Values & Rule Defaults

As a developer, I want the system seeded with default reference values, required-field rules, and escalation rule defaults, So that Epics 2–5 are immediately functional without requiring administrator configuration before use.

Acceptance Criteria:

Given the application initializes for the first time When the seed operation runs Then operational status sets, service template defaults, and extension-layer reference values are populated in the database

Given the seed runs When required-field rules are evaluated Then default readiness fields for election-cycle jobs are defined and evaluable by Epic 2's readiness status feature (FR29)

Given the seed runs When escalation rule defaults are checked Then at least one default rule exists covering overdue milestone alert scenarios (FR30)

Given the seed operation is run multiple times When it completes Then no duplicate records are created — the operation is fully idempotent

Given Epic 6 admin UIs update reference values or rules When the changes are saved Then they persist independently of the seed — rerunning the seed does not overwrite admin-managed values


Story 1.10: Municipality Account Profile

As a client services staff member, I want to create and maintain municipality account profiles linked to legacy jurisdiction identifiers, So that permanent municipality data is managed in the extension layer without modifying legacy Access tables.

Acceptance Criteria:

Given a client services user navigates to municipality management When they create a new municipality profile Then it is saved to the extension layer with a required link to a valid legacy jurisdiction identifier (ID/JCode)

Given a municipality profile is created When the profile is loaded Then the anti-corruption layer resolves the legacy join and displays combined extension and legacy data together in the workspace grid

Given a profile field is updated When saved Then the change is recorded in the audit log with actor identity and timestamp

Given a user attempts to create a profile without a valid legacy jurisdiction identifier When the form is submitted Then the save is rejected with a clear validation message identifying the required legacy link

And no INSERT, UPDATE, or DELETE operations are performed on legacy Access tables at any point


Story 1.11: Municipality Operational Addresses

As a client services staff member, I want to store and update municipality operational mailing and delivery addresses, So that election services reference current address information without depending on legacy records.

Acceptance Criteria:

Given a municipality profile exists When a client services user adds an address Then they can specify mailing or delivery address type, and the record is saved to the extension address table linked to the municipality profile

Given an address is updated When saved Then the previous address is preserved in history, the new address is marked as current, and the change is logged with actor and timestamp

Given an address record is saved When retrieved Then it includes address type, street, city, state, zip, and effective date fields

Given a municipality profile is viewed When addresses are displayed Then mailing and delivery addresses are shown with clear type labels and current/historical status


Story 1.12: Municipality Service Contacts

As a client services staff member, I want to manage municipality service-contact records including primary and secondary contacts, So that the right people can be reached during election operations without consulting legacy records.

Acceptance Criteria:

Given a municipality profile exists When a client services user adds a contact Then they can designate it as primary or secondary contact and save name, role/title, phone, and email

Given a municipality has both a primary and secondary contact When the profile is viewed Then both contacts are displayed with clear primary/secondary designation labels

Given a contact is updated or removed When the change is saved Then it is recorded in the audit log with actor identity and timestamp

Given a user attempts to save a contact without required fields (name, contact type) When the form is submitted Then the save is rejected with inline validation errors identifying the missing fields


Story 1.13: Municipality Prior-Cycle Service Defaults View

As a client services staff member, I want to view municipality-specific service defaults from prior election cycles as a read-only reference, So that I can reference proven configurations when setting up new election-cycle jobs in Epic 2.

Acceptance Criteria:

Given a municipality has at least one completed election-cycle job When a client services user views the prior-cycle defaults panel Then the most recent cycle's service configurations are displayed as read-only reference data

Given a municipality has multiple prior cycles When the defaults panel is viewed Then the most recent cycle is shown by default with a cycle selector control to navigate older cycles

Given no prior cycles exist for a municipality When defaults are requested Then the system displays a clear “No prior cycle defaults available” state with guidance to create the first cycle

And all data in this view is read-only — the apply-to-new-job action is out of scope for this story and delivered in Epic 2 (Story 2.4)


Epic 2: Election-Cycle Job Creation & Planning

Client services staff can create election-cycle jobs, define key dates, apply prior-cycle defaults, and track required-field readiness through to production-ready publication — with a kanban entry point showing municipalities across cycle lanes.

Story 2.1: Municipality-to-Cycle Kanban Entry Point

As a client services staff member, I want a kanban board showing municipalities as cards organized by election cycle lanes, So that I can see at a glance which municipalities are assigned to which cycles and initiate new cycle jobs from a familiar planning view.

Acceptance Criteria:

Given a client services user navigates to the election cycle workspace When the kanban loads Then municipalities with active cycle jobs appear as cards in their respective cycle lane columns, and municipalities with no active jobs appear in an “Unassigned” lane

Given a municipality has jobs in multiple concurrent election cycles When the kanban renders Then the municipality card appears in each relevant cycle lane independently (UX-DR16 multi-lane support)

Given a user views a municipality card When displayed in a cycle lane Then the card shows municipality name, jurisdiction code, cycle job status badge, and a quick-open action

Given a cycle lane contains many municipality cards When the user scrolls within the lane Then the lane column header remains visible and performance is maintained

Given a user interacts with the kanban via keyboard When navigating cards and lanes Then all card actions are reachable without a mouse and focus indicators are visible (UX-DR9)


Story 2.2: Create Election-Cycle Job

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.

Acceptance Criteria:

Given a municipality card is in the Unassigned lane When a client services user initiates job creation Then they can select an existing cycle or name a new cycle, and a new election-cycle extension record is created linked to the municipality's legacy identifier (ID/JCode)

Given an election-cycle job is created When saved Then it is stored in the extension table with the municipality's legacy identifier as a required join key and the municipality card moves to the selected cycle lane on the kanban

Given an election-cycle job is created When the job record is inspected Then it includes municipality reference, cycle name, creation actor, creation timestamp, and a status of “In Setup”

Given a job creation is attempted without selecting or naming a cycle When the form is submitted Then the save is rejected with a clear inline validation message

And no INSERT, UPDATE, or DELETE operations are performed on legacy Access tables at any point


Story 2.3: Election-Cycle Key Dates

As a client services staff member, I want to define election-cycle key dates for data files, proofing, pickups, deliveries, and mail activities, So that the election timeline is established and visible to all operational teams.

Acceptance Criteria:

Given an election-cycle job exists When a client services user opens the key dates section Then they can enter dates for: data file receipt, proofing, customer envelope pickup, customer envelope delivery, purple envelope pickup, purple envelope delivery, blue envelope pickup, blue envelope delivery, sort dates, mail dates, and tray delivery

Given a key date is entered and saved When the job is reloaded Then all entered dates persist and are visible in the job's date summary view

Given a key date entry would create a logical conflict (e.g., mail date before sort date) When the conflicting date is entered Then an inline warning identifies the conflict with specific field names — the save is not blocked but the warning is persistent until resolved

Given a key date is updated When saved Then the change is recorded in the audit log with actor identity and timestamp

Given a user enters dates via keyboard When using the date picker controls Then dates are enterable via keyboard without requiring mouse interaction (UX-DR9)


Story 2.4: Prior-Cycle Defaults Application

As a client services staff member, I want to copy configurable planning defaults from a municipality's prior election-cycle job into a new cycle, So that I can apply proven configurations without re-entering all details from scratch.

Acceptance Criteria:

Given an election-cycle job exists and the municipality has at least one prior completed cycle When a client services user selects “Apply Prior-Cycle Defaults” Then the prior cycle's service configurations and key date offsets are pre-populated into the new job's fields

Given prior-cycle defaults are applied When pre-populated fields are displayed Then each inherited field is visibly marked as “Inherited from [cycle name/year]” to distinguish it from manually entered data

Given a user applies defaults and then manually edits an inherited field When the edit is saved Then the “Inherited” marker is removed from that field and it is treated as a manually entered value going forward

Given a municipality has multiple prior cycles When applying defaults Then the user can select which prior cycle to use as the source from a list ordered most-recent first

Given a municipality has no prior cycles When the defaults action is viewed Then the option is disabled with a clear “No prior cycle available” message — no error state is triggered


Story 2.5: Election-Cycle Readiness Status & Publication

As a client services staff member, I want to see required-field readiness status for my election-cycle job and publish it to production readiness through a pre-commit validation rail, So that I can confirm the plan is complete and provide the team with a verified production-ready job.

Acceptance Criteria:

Given an election-cycle job has missing required fields (as defined by seeded rules from Story 1.9) When a client services user views readiness status Then each missing required field is identified by name with a jump-link that navigates directly to the field

Given all required fields are complete When readiness status is evaluated Then the job shows a “Ready to Publish” state and the Publish action becomes enabled

Given a user initiates the Publish action When the SafeCommitRail activates Then it runs dependency and policy checks and displays: overall pass/fail status, a list of any blocking reasons with one-click corrective action links, and a reason-code selector where audit policy requires it (UX-DR4)

Given the SafeCommitRail shows all checks passed When the user confirms the publish with a required reason code Then the job status transitions to “Production Ready” and actor, timestamp, and reason code are captured in the audit log

Given the SafeCommitRail shows one or more blocking issues When displayed Then the Publish confirm button remains disabled until all blocking issues are resolved

Given the publish action succeeds When the confirmation is shown Then a “Next Best Action” prompt guides the user to the recommended following step (e.g., configure services) (UX-DR11)

And the SafeCommitRail is built as a reusable shared module — it is independently consumable by Epic 3 service configuration commits and Epic 5 production status commits without duplication or modification


Story 2.6: Spreadsheet Import & Column Mapping

As a client services or operations user, I want to import approved election-cycle spreadsheet data and map it to the extension model, So that key schedule and service fields can be staged and reviewed without manual re-entry.

Acceptance Criteria:

Given an approved import file is provided When the import workflow starts Then the system parses required columns and validates expected template headers before staging data

Given staged rows include jurisdiction references When mapping runs Then each row is matched to legacy-linked identifiers (ID, JCode/JurisCode, KitID where applicable) or flagged as unresolved

Given a staged row fails validation When the review screen is displayed Then deterministic error output identifies the row, failing field, and corrective action needed before publish

Given a staged row passes validation When it is included in publish Then provenance metadata is recorded: source file identifier, source row reference, import timestamp, and importing user


Epic 3: Service Configuration

Client services staff can configure all election services on a job — addressing, envelopes, sorting, office copies, and transportation events — with inline editing in the operational workspace grid and SafeCommitRail validation on commits.

Story 3.1: Addressing Service Configuration

As a client services staff member, I want to configure addressing service for an election-cycle job including quantities and dependency fields, So that the addressing workflow has all required production parameters before execution begins.

Acceptance Criteria:

Given an election-cycle job exists When a client services user opens the addressing service section Then they can enter addressing quantity, addressing type, dependency fields, and addressing-specific notes

Given an addressing field is edited inline in the workspace grid When the cell is activated Then it enters edit mode with explicit commit and cancel controls visible and keyboard-accessible (UX-DR3)

Given addressing configuration is ready to commit When the user saves via the SafeCommitRail Then dependency and policy checks run, the configuration is stored against the election-cycle job on pass, and actor and timestamp are captured in the audit log

Given the MunicipalityCycleWorkspaceGrid renders a service configuration row When displayed Then a status chip shows current configuration completeness state (e.g., incomplete, configured, confirmed)

And the MunicipalityCycleWorkspaceGrid is built as a reusable shared component with: sticky column header, column visibility controls, inline editable cells, row status chips, and provenance quick-view trigger — consumable across all service configuration stories in this epic (UX-DR3)


Story 3.2: Envelope Service Configuration — Purple & Blue

As a client services staff member, I want to configure purple and blue envelope service options with quantities and scenario details, So that production teams know exactly what envelope materials and quantities to prepare for the election.

Acceptance Criteria:

Given an election-cycle job exists When a client services user opens envelope service configuration Then purple envelope and blue envelope scenarios are presented as independently configurable sections each with quantity and service-specific option fields

Given both envelope types are configured When saved via SafeCommitRail Then purple and blue configurations are stored as separate service records against the election-cycle job

Given a purple or blue envelope scenario is not applicable to this election When the user marks it as “Not Used” Then the service is recorded as Not Used, no quantity validation is required, and no downstream transportation events are generated for that envelope type

Given envelope configuration is committed When confirmed Then actor, timestamp, and any reason code are captured in the audit log

Given envelope proof workflow fields are tracked for the election-cycle job When the user updates proof status values Then Proof Sent and Proof Approved values are persisted with actor/timestamp provenance and surfaced to downstream reporting


Story 3.3: Office-Copy Service Configuration

As a client services staff member, I want to configure office-copy requirements and related production details for an election-cycle job, So that office copy preparation is tracked and visible alongside other election services.

Acceptance Criteria:

Given an election-cycle job exists When a client services user opens office-copy configuration Then they can enter office copy quantity, production details, and any special handling requirements

Given office-copy configuration is saved When committed via SafeCommitRail Then the configuration is stored against the election-cycle job and appears in the service summary view

Given office copies are not required for this election When the user marks the service as “Not Required” Then it is recorded as Not Required with no quantity validation triggered and the service is clearly labelled as excluded in the service summary

Given office-copy configuration is committed When confirmed Then actor, timestamp, and reason code are captured in the audit log


Story 3.4: Sorting Service Configuration

As a client services staff member, I want to configure sorting service options including quantity, mail class, permit or meter designation, and daily-sort flags, So that the sort team has all parameters needed to plan and execute sorting operations.

Acceptance Criteria:

Given an election-cycle job exists When a client services user opens sorting service configuration Then they can enter: sort quantity, mail class, permit or meter designation, and a daily-sort flag toggle

Given sorting configuration is saved via SafeCommitRail When committed Then all sort parameters are stored against the election-cycle job and the sort service appears as configured in the service summary

Given the daily-sort flag is enabled When configuration is saved Then the sort service is marked for daily sort operations and this flag is visible in Epic 4 milestone scheduling for sort milestone generation

Given sorting is not applicable to this election When the user marks it as “Not Used” Then sorting is excluded from service summary and no sort milestones are generated in Epic 4

Given sorting configuration is committed When confirmed Then actor, timestamp, and reason code are captured in the audit log

Given sorting configuration includes permit/meter and mail-date-sensitive settings When the user commits the configuration Then deterministic validation checks ensure daily-sort and mail-date dependencies are coherent before save is allowed


Story 3.5: Transportation Service Events

As a client services staff member, I want to record transportation-relevant service events tied to configured election services, So that transportation coordinators have accurate event data to build dispatch plans in Epic 5.

Acceptance Criteria:

Given at least one service is configured on an election-cycle job (addressing, envelopes, sorting, or office copies) When a client services user opens transportation events Then they can record pickup and delivery events linked to each configured service type

Given a transportation event is created When saved Then it stores: event type (pickup or delivery), service reference, expected date, quantity, and pickup/delivery location

Given a transportation event is linked to a service configuration When that service configuration is subsequently updated Then related transportation events are flagged as “Needs Review” rather than silently deleted or auto-updated

Given multiple services are configured When the transportation events list is viewed Then events from all service types are consolidated in a single list sortable by date and filterable by service type

Given a transportation event is saved When confirmed Then actor and timestamp are captured in the audit log and the event is available to Epic 5 report generation


Epic 4: Milestone Scheduling & Timeline Management

Operations teams can schedule and update milestone dates across all configured services, view timelines by municipality and date, detect missing or conflicting milestones before cutoffs, and assign or reassign ownership — with a persistent risk queue surfacing deadline pressure in real time.

Story 4.1: Schedule & Update Milestone Dates

As an operations user, I want to schedule and update milestone dates for all configured service events on an election-cycle job, So that each service has a date-driven execution plan tied to the election timeline.

Acceptance Criteria:

Given an election-cycle job has configured services When an operations user opens milestone scheduling Then milestone date fields are presented for each active service type (addressing, envelopes, sorting, office copies, transportation events)

Given a service was marked “Not Used” in Epic 3 When milestones are displayed Then that service's milestone fields are excluded from the scheduling view entirely

Given the daily-sort flag is set on a sorting service (Story 3.4) When sort milestones are generated Then daily sort milestone entries are created for each day within the configured sort date range

Given a milestone date is entered and saved When the job is reloaded Then the date persists and is visible in the milestone timeline view

Given a milestone date is updated When saved Then the change is captured in the audit log with actor identity and timestamp


Story 4.2: Milestone Timeline Views & CutoffRiskQueuePanel

As an operations user, I want to view milestone timelines by municipality and by date across active election-cycle jobs with at-risk and overdue items surfaced in a persistent right-pane risk queue, So that I can see the full operational schedule and identify where urgent attention is needed before cutoffs.

Acceptance Criteria:

Given active election-cycle jobs have scheduled milestones When an operations user opens the timeline view Then milestones are displayed organized by municipality with date-sorted order and filterable by date range, county, and municipality

Given the timeline view is filtered When two users apply identical filters Then both see the same deterministic sort order — no per-user result variation (UX-DR13)

Given multiple municipalities share milestones on the same date When viewed in date mode Then milestones are grouped by date then sorted by county then municipality name

Given the CutoffRiskQueuePanel renders in the right pane When it loads Then it displays prioritized urgency cards each showing: milestone name, job reference, due date countdown, severity badge (on-track/at-risk/overdue/critical), and assigned owner name (UX-DR5)

Given a milestone transitions to at-risk or overdue status When the queue re-evaluates Then it reorders with the most urgent items at the top and each severity badge is accompanied by a text label — never color alone (UX-DR12)

Given a user selects a card in the risk queue When clicked or activated via keyboard Then the center pane navigates to the relevant job and milestone without losing queue context

And the CutoffRiskQueuePanel is built as a reusable shared component — consumable by Epic 5 production tracking without modification


Story 4.3: Missing & Conflicting Milestone Detection

As an operations user, I want the system to detect missing required milestones and logically conflicting date sequences before execution cutoffs, So that I can resolve gaps before they block production operations.

Acceptance Criteria:

Given an election-cycle job has required milestones not yet scheduled When an operations user views the job or runs detection Then each missing required milestone is identified by name with its service context displayed

Given two milestone dates create a logical conflict (e.g., delivery date before pickup date, mail date before sort date) When the conflict is detected Then both conflicting milestones are flagged with a plain-language explanation identifying the conflict type and the affected dates

Given a missing or conflicting milestone is flagged When the flag is displayed Then a one-click jump link navigates directly to the scheduling field for that specific milestone

Given all required milestones are scheduled without conflicts When the job is evaluated Then it displays a “Milestones Complete” status and this clears any related items from the CutoffRiskQueuePanel

Given a user resolves flagged issues and re-evaluates When detection re-runs Then resolved items are cleared from the detection list and a Next Best Action prompt guides the user to the recommended following step (UX-DR11)


Story 4.4: Milestone Ownership & Reassignment

As an operations user, I want to assign and reassign milestone ownership and due dates across teams, So that each milestone has a clear accountable owner responsible for its timely completion.

Acceptance Criteria:

Given a milestone exists on an election-cycle job When an operations user opens milestone details Then they can assign an owner from the list of active application users and set or update the milestone due date

Given a milestone is reassigned to a new owner When saved Then the previous owner, new owner, reassigning actor identity, and timestamp are all captured in the audit log

Given a milestone due date is updated When saved Then the CutoffRiskQueuePanel re-evaluates the milestone's urgency and reorders the queue to reflect the new due date

Given a user is assigned as milestone owner When they access their role workspace Then their assigned milestones appear in their workspace prioritized by due date with severity indicators

Given a milestone is reassigned to a new owner When they next view their workspace Then newly assigned milestones are visually distinguished (e.g., “New Assignment” badge) until acknowledged


Epic 5: Production Tracking, Exception Management, Audit History & Transportation Report

Production teams can update job statuses, log and resolve exceptions, view complete timestamped status history, and see current and historical process state. Transportation coordinators receive the first external-facing report — a date-sorted dispatch report — as an early municipality proof point.

Story 5.1: Production Status Updates at Checkpoints

As a production user, I want to update election-cycle job status at defined process checkpoints, So that the team has an accurate current view of where each job stands in the production workflow.

Acceptance Criteria:

Given an election-cycle job is in production When a production user opens the status panel Then available status transitions from the current checkpoint are presented (e.g., In Setup → Configured → Scheduled → In Production → Complete) — only valid next states are selectable

Given a status update is initiated When the SafeCommitRail activates (reused from Story 2.5) Then it validates the transition is permitted from the current status and all required fields for the new status are present before enabling the commit action

Given a valid status transition passes all SafeCommitRail checks When the user confirms with a reason code Then the new status is saved with actor identity, timestamp, and reason code captured in the audit log

Given an invalid status transition is attempted (e.g., skipping a required checkpoint) When the SafeCommitRail evaluates Then the commit is blocked with a plain-language explanation identifying the constraint and the required preceding step

Given a status update is committed When confirmed Then the change is immediately reflected in the CutoffRiskQueuePanel and milestone timeline views


Story 5.2: Exception & Blocker Logging

As a support or operations user, I want to log exceptions, blockers, and resolution notes against an election-cycle job, So that issues are tracked with accountability and visible to all relevant team members without leaving the operations workspace.

Acceptance Criteria:

Given an election-cycle job exists When a user creates an exception record Then they can enter: exception type, description, blocking impact, assigned owner, and due-by timestamp

Given an exception is logged with blocking impact When saved Then it appears in the CutoffRiskQueuePanel with a severity badge matching its impact level (reused from Epic 4, UX-DR5)

Given an open exception passes its due-by timestamp without resolution When the CutoffRiskQueuePanel evaluates urgency Then the exception's severity escalates automatically and the updated priority is reflected immediately in the queue ordering

Given an exception is resolved When the resolution note is saved Then the exception status transitions to Resolved with resolution note, resolving actor identity, and timestamp captured in the audit log

And exception records are available as input to the BlockerResolutionDrawer in Story 5.3 for in-context resolution workflows


Story 5.3: Blocked-Job Resolution with BlockerResolutionDrawer

As a production or operations user, I want to resolve blocked election-cycle jobs through an in-context recovery drawer without losing my current workspace position, So that I can address blockers quickly and maintain operational momentum under deadline pressure.

Acceptance Criteria:

Given a blocked job or open exception exists When a user opens the BlockerResolutionDrawer from the risk queue, a blocked status indicator, or a validation failure Then a right-side drawer opens in context — the user's current workspace view remains visible and no navigation occurs

Given the BlockerResolutionDrawer is open When displayed Then it shows: blocker details, dependency links to affected milestones, assignee field, due-by date control, resolution note field, and save and escalate actions (UX-DR6)

Given a user updates assignment and due-by date and saves When committed Then the exception history is updated with the new values, actor identity, and timestamp, and the drawer closes returning keyboard focus to the previous context

Given a blocker cannot be resolved in the available time When the user selects Escalate Then the exception's severity escalates in the CutoffRiskQueuePanel and the escalation event is appended to the exception audit trail

Given the drawer has unsaved changes When the user attempts to close it Then a confirmation prompt prevents accidental data loss before dismissal

And the BlockerResolutionDrawer is built as a reusable shared component with standard and escalation mode variants — consumable across all operational views without modification (UX-DR6)


Story 5.4: Status Transition History & ProvenanceTimelinePanel

As any operational user, I want to view a complete timestamped history of status transitions and key operational events on an election-cycle job, So that I can trace what changed, when, by whom, and why at any point in the job lifecycle.

Acceptance Criteria:

Given any status transition or key operational event occurs on an election-cycle job When committed Then previous value, new value, actor identity, timestamp, event type, and reason code are appended to the immutable event history

Given the ProvenanceTimelinePanel is opened for a job When loaded Then it displays a chronological timeline of events each showing: actor, timestamp, event type, changed field, previous value, new value, and reason code (UX-DR8)

Given a user filters the timeline by event type (status change, exception logged, milestone updated) When the filter is applied Then the timeline updates deterministically showing only matching events in the same chronological order

Given the timeline renders event type indicators When displayed Then each event type is conveyed with both a text label and an icon — never color alone (UX-DR12)

And the ProvenanceTimelinePanel is built as a reusable shared component with compact inline preview and full audit view variants — consumable by Epic 6 traceability features without modification (UX-DR8)


Story 5.5: Current & Historical Process State View

As any operational user, I want to view current and historical process state for a municipality's election-cycle jobs, So that I can understand where each job stands today and how it progressed through the full production lifecycle.

Acceptance Criteria:

Given a municipality has one or more election-cycle jobs When a user opens the process state view Then the current job displays: status, milestone completion summary, count of open exceptions, and last-updated timestamp

Given the current job has open blockers When the process state view is displayed Then a BlockerResolutionDrawer quick-launch action is available directly from the view for immediate in-context resolution (reused from Story 5.3)

Given prior completed election-cycle jobs exist for the municipality When the user accesses job history Then historical jobs are listed with final status, completion date, and a link to their full ProvenanceTimelinePanel audit view

Given a user navigates to a historical job's provenance timeline When the timeline loads Then the complete event history for that cycle is displayed in chronological order with all actor, timestamp, and reason code data intact


Story 5.6: Transportation Report — Date-Sorted Dispatch

As a transportation coordinator, I want to generate a date-sorted transportation report grouped by county and municipality, So that I can prepare accurate next-day and week-lookahead dispatch runs tied directly to election job milestones.

Acceptance Criteria:

Given active election-cycle jobs have transportation events and milestones scheduled When a transportation coordinator generates the report Then pickup and delivery events are aggregated from extension records joined to legacy identifiers and sorted by date then county then municipality (FR22)

Given the report is generated When displayed Then each row shows: event date, county, municipality name, event type (pickup or delivery), service type, quantity, and location

Given a filter is applied (date range, county, municipality, or service status) When the report refreshes Then only matching events are shown in the same deterministic sort order for all users applying identical filters (UX-DR13)

Given a report row has missing critical event data When detected during generation Then the row is flagged with a data-gap indicator and a direct deep-link to the source job record for correction

Given the report is ready for dispatch planning When the user exports Then a spreadsheet-compatible file (CSV or XLSX-equivalent) is generated preserving all visible columns and sort order (FR25)

And report generation completes in 30 seconds or less for standard daily and weekly date range filters under normal operating load (NFR3)


Epic 6: Full Reporting Suite, Admin Management UIs & Governance

All remaining operational reports with deterministic filtering and export. Admin management UIs complete the FR28/FR29/FR30 configuration layer from seed-only to fully managed. Support analysts get report-to-source traceability and data correction tools. Parity governance closes the brownfield migration with a defined sunset gate.

Story 6.1: Sorting Report by Municipality

As an operations user, I want to generate a sorting report organized by municipality for all election-cycle jobs with sorting enabled, So that the sort team can review all sorting requirements per municipality in a single operational view.

Acceptance Criteria:

Given active election-cycle jobs have sorting services configured and enabled When a user generates the sorting report by municipality Then all jobs with sorting enabled are aggregated and displayed grouped by municipality name

Given the report is generated When displayed Then each row shows: municipality name, jurisdiction code, sort quantity, mail class, permit or meter designation, daily-sort flag, and current job status

Given filters are applied (date range, county, service status) When the report refreshes Then only matching jobs are shown in deterministic municipality-sorted order

Given the report is exported When downloaded Then a spreadsheet-compatible file is generated preserving all visible columns, sort order, and active filter context (FR25)

And report generation completes in 30 seconds or less for standard filter ranges (NFR3)


Story 6.2: Sorting Report by Mail Date

As an operations user, I want to generate a sorting report organized chronologically by mail date for all election-cycle jobs with sorting enabled, So that the sort team can plan operations across all active municipalities in date-priority order.

Acceptance Criteria:

Given active election-cycle jobs have sorting enabled and mail dates scheduled When a user generates the sorting report by mail date Then jobs are displayed sorted by mail date ascending then by municipality name within each date group

Given the report is generated When displayed Then each row shows: mail date, municipality name, sort quantity, mail class, permit or meter designation, and daily-sort flag

Given multiple municipalities share the same mail date When grouped Then they appear together under the shared date header in municipality-sorted order

Given the report is exported When downloaded Then a spreadsheet-compatible file is generated preserving all columns, grouping, and sort order (FR25)

And report generation completes in 30 seconds or less for standard filter ranges (NFR3)


Story 6.3: Report Filtering, Saved Presets & Unified Export

As an operations user, I want to apply consistent filters across all operational reports and save presets for recurring use, So that I can reproduce the same report view instantly without re-entering filter criteria each session.

Acceptance Criteria:

Given any operational report is open (transportation, sorting by municipality, sorting by mail date) When a user applies filters (date range, municipality, county, service status) Then only matching records are shown in deterministic sort order identical for all users with the same active filters (UX-DR13, FR26)

Given a user configures a useful filter set When they save it as a named preset Then the preset is stored per user role and available from a preset selector dropdown in future sessions

Given a saved preset is selected When applied Then all filter values are restored exactly and the report regenerates with the same deterministic output

Given any report is ready for export When the user triggers export Then a spreadsheet-compatible file (CSV or XLSX-equivalent) is generated preserving column labels, sort order, grouping, and all applied filter values (FR25)

And exported files preserve required field parity for existing operational consumers — column names and data types match the legacy report output schema where mandated (NFR14)


Story 6.4: Report-to-Source Traceability

As a support analyst, I want to trace any report value back to its source records across legacy and extension datasets, So that I can investigate and resolve report discrepancies with full visibility into how the value was produced.

Acceptance Criteria:

Given a report row or field value is under investigation When a support analyst activates the trace action for that row Then the system displays the source extension record(s) and legacy join record(s) that produced the value, including join path and field-level mapping (FR33)

Given the trace is opened When displayed using the ProvenanceTimelinePanel (reused from Story 5.4) Then source record identifiers, field values, last-updated actor, timestamp, and join keys are all visible in the audit view

Given a discrepancy exists between a report output value and its source record When the trace is reviewed Then the analyst can identify the exact field, record, and value mismatch causing the discrepancy

Given a trace is run on any operational report When the result is shown Then traceability is available for transportation reports and all sorting reports — not limited to a single report type

Given a traced value originated from spreadsheet import When trace details are expanded Then source file identifier, source row reference, import timestamp, and importing user are visible in the provenance panel


Story 6.5: Extension-Layer Data Correction

As an authorized support or admin user, I want to correct erroneous extension-layer data with a mandatory reason and full audit trail, So that data issues can be resolved with accountability while preserving immutable legacy schema integrity.

Acceptance Criteria:

Given an extension record contains erroneous data When an authorized user (Support or Admin role) opens the correction workflow Then they can edit the extension record fields with a mandatory correction reason field that must be completed before saving

Given a correction is submitted When saved Then the corrected values, previous values, correction reason, actor identity, and timestamp are all captured in the audit log as an immutable correction event (FR34)

Given the correction workflow displays a record that joins to legacy data When legacy fields are shown Then they are rendered read-only with no edit affordance — no modification path to legacy tables exists in this workflow (NFR12)

Given a user without the Support or Admin role attempts to access the correction workflow When they navigate to it Then they receive 403 Forbidden and the unauthorized access attempt is captured in the audit log (NFR6)

Given a correction saves successfully When the corrected record is used in a subsequent report Then the report reflects the corrected value and the correction event is visible via report-to-source traceability (Story 6.4)


Story 6.6: Admin Configuration UIs — Reference Values, Required-Field Rules & Escalation Rules

As an administrator, I want management interfaces for extension-layer reference values, required-field rules, and escalation rule configurations, So that operational defaults established in Epic 1 can be updated as business needs evolve without requiring code changes.

Acceptance Criteria:

Given an administrator navigates to reference value management When the UI loads Then they can view, add, edit, and deactivate status sets, service template defaults, and other extension-layer reference values across all operational domains (FR28)

Given a reference value is updated When saved Then the change is immediately available to all operational workflows and captured in the audit log with actor and timestamp

Given an administrator navigates to required-field rules management When the UI loads Then they can view and modify which fields are required for election-cycle readiness checks and set effective dates for rule changes (FR29)

Given an administrator navigates to escalation rule configuration When the UI loads Then they can configure notification triggers, escalation thresholds, due-date offsets, and recipient rules for missed or at-risk milestones (FR30)

Given any admin configuration change is about to be committed When the SafeCommitRail activates (reused from Story 2.5) Then it validates the change does not break active workflows or produce orphaned records before enabling the save action


Story 6.7: Parity Governance & Legacy Report Sunset

As an operations administrator and parity governance owner, I want a structured parity validation workflow with a defined sunset checklist, So that the legacy report stack can be formally decommissioned only after proven equivalence is documented and signed off.

Acceptance Criteria:

Given modern reports are generating output alongside legacy reports When a parity validation run is initiated Then modern and legacy report outputs are compared field-by-field across a defined validation set of active election jobs and a comparison report is produced

Given a parity comparison report is generated When discrepancies are found Then the report identifies: affected report type, field name, legacy value, modern value, discrepancy severity, and an assignable owner field for triage

Given a discrepancy is assigned to an owner When the owner resolves it and updates closure status Then the resolution is recorded with actor identity, timestamp, and resolution notes in the parity audit trail

Given parity validation shows zero critical discrepancies across the full validation set When reviewed by the named parity governance owner Then the sunset criteria checklist becomes available for formal sign-off review

Given all sunset criteria are satisfied (zero critical discrepancies, named parity owner sign-off, municipality client acknowledgment) When the final gate is passed and recorded Then the legacy report stack is eligible for decommission and the gate completion event is captured with all sign-off actors and timestamps

And the named parity governance owner is a required system configuration field — parity validation cannot be initiated until this field is populated


Story 6.8: Source Reconciliation & Data Quality Queue

As a support analyst or operations owner, I want a reconciliation queue for imported source data versus report output, So that data mismatches are triaged with clear ownership before they impact operational decisions.

Acceptance Criteria:

Given imported spreadsheet-origin records and report outputs exist When a reconciliation run is executed Then mismatches are surfaced with report type, affected field, source value, system value, and severity

Given a mismatch is identified When triage begins Then an owner can be assigned with due date, status, and resolution notes tracked in an auditable trail

Given a reconciliation issue is resolved When the resolution is saved Then closure metadata (actor, timestamp, reason) is captured and linked to report traceability records

Given unresolved high-severity mismatches remain When operational export is attempted for affected scope Then the system displays a blocking warning with a direct link to the reconciliation queue

Powered by TurnKey Linux.