# Story 1.10: Municipality Account Profile Status: review ## Story As a 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 1. **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) 2. **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 3. **Given** a profile field is updated **When** saved **Then** the change is recorded in the audit log with actor identity and timestamp 4. **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 ## Tasks / Subtasks - [x] Implement story behavior in aligned backend/frontend modules (AC: #1) - [x] Add or update API/service/UI components required by the story scope - [x] Keep legacy Access entities read-only and route writes to extension-layer structures - [x] Cover acceptance criteria #2 in implementation and tests (AC: #2) - [x] Add validation/error handling and UX state updates as needed - [x] Cover acceptance criteria #3 in implementation and tests (AC: #3) - [x] Add validation/error handling and UX state updates as needed - [x] Cover acceptance criteria #4 in implementation and tests (AC: #4) - [x] Add validation/error handling and UX state updates as needed - [x] Validate and document completion evidence - [x] Verify build/tests for touched modules - [x] Capture changed files and any migration/config implications ## Dev Notes - Follow Epic 1 architecture constraints: ASP.NET Core + React separation, RBAC-aware patterns, and immutable legacy tables. - Reuse shared component and workflow patterns defined in UX and architecture docs; avoid parallel custom implementations. - Keep changes scoped to this story; do not pull forward Epic 2+ features. ### Project Structure Notes - Backend: `Campaign_Tracker.Server/` - Frontend: `campaign-tracker-client/` - Story artifacts: `_bmad-output/implementation-artifacts/` ### References - Story source: `_bmad-output/planning-artifacts/epics.md` (Epic 1 / Story 1.10) - Architecture constraints: `_bmad-output/planning-artifacts/architecture.md` - UX patterns: `_bmad-output/planning-artifacts/ux-design-specification.md` ## Dev Agent Record ### Agent Model Used claude-sonnet-4-6 ### Debug Log References - 133/133 backend tests pass; 36/36 frontend tests pass. No regressions. ### Completion Notes List - Introduced `Campaign_Tracker.Server/Municipalities/` namespace with domain entity and repository. - `MunicipalityProfile` record implements `ILegacyLinkedRecord` — participates in Story 1.8 nightly integrity check automatically. - `InMemoryMunicipalityProfileRepository` validates JCode via `ILegacyLinkValidator` before save (AC #4). Resolves legacy jurisdiction fields via `ILegacyDataAccess` for combined views (AC #2). Returns `MunicipalityProfileView` combining both layers. - `MunicipalityProfileController` (`/api/municipalities/profiles`) — POST/GET/PUT with `ClientServicesAccess` policy (Admin bypass via `HasAny`). Records audit events on create and update (AC #3). - Repository registered as singleton + as `ILegacyLinkedRecordProvider` so integrity check covers municipality profiles. - Frontend: `municipalityContracts.ts` — typed fetch functions with `MunicipalityValidationError` for 422 responses (AC #4). - Frontend: `MunicipalityProfilePanel.tsx` — table of profiles with combined legacy data (AC #2), modal form for create with JCode field and error display. - `WorkspaceShell.tsx` updated: selecting "Municipalities" nav item now renders `MunicipalityProfilePanel` for users with `canViewMunicipalityProfile` permission. - 16 backend unit tests (11 repository + 5 controller integration) + 9 frontend contract tests. ### File List - `Campaign_Tracker.Server/Municipalities/MunicipalityProfile.cs` (new) - `Campaign_Tracker.Server/Municipalities/MunicipalityProfileView.cs` (new) - `Campaign_Tracker.Server/Municipalities/MunicipalityProfileSaveResult.cs` (new) - `Campaign_Tracker.Server/Municipalities/IMunicipalityProfileRepository.cs` (new) - `Campaign_Tracker.Server/Municipalities/InMemoryMunicipalityProfileRepository.cs` (new) - `Campaign_Tracker.Server/Controllers/MunicipalityProfileController.cs` (new) - `Campaign_Tracker.Server/Program.cs` (modified — added Municipalities using + repository registrations) - `Campaign_Tracker.Server.Tests/MunicipalityProfileRepositoryTests.cs` (new — 11 tests) - `Campaign_Tracker.Server.Tests/MunicipalityProfileControllerTests.cs` (new — 5 tests) - `campaign-tracker-client/src/municipalities/municipalityContracts.ts` (new) - `campaign-tracker-client/src/municipalities/MunicipalityProfilePanel.tsx` (new) - `campaign-tracker-client/src/municipalities/municipalityContracts.test.ts` (new — 9 tests) - `campaign-tracker-client/src/workspace/WorkspaceShell.tsx` (modified — municipalities view wired) - `_bmad-output/implementation-artifacts/1-10-municipality-account-profile.md` (this file) - `_bmad-output/implementation-artifacts/sprint-status.yaml` (modified — status updated) ## Change Log - 2026-05-06: Story 1.10 implemented — municipality account profile domain, repository, REST API, and React panel with legacy join resolution. 25 tests added. All 4 ACs satisfied. (claude-sonnet-4-6)