Status: done
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.
Campaign_Tracker.Server/campaign-tracker-client/_bmad-output/implementation-artifacts/_bmad-output/planning-artifacts/epics.md (Epic 1 / Story 1.10)_bmad-output/planning-artifacts/architecture.md_bmad-output/planning-artifacts/ux-design-specification.mdclaude-sonnet-4-6
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).ILegacyLinkedRecordProvider so integrity check covers municipality profiles.municipalityContracts.ts — typed fetch functions with MunicipalityValidationError for 422 responses (AC #4).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.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)_lock object added; duplicate-check+insert atomic in CreateAsync; read-modify-write atomic in UpdateAsync [Campaign_Tracker.Server/Municipalities/InMemoryMunicipalityProfileRepository.cs]MunicipalityProfileSaveResult.ProfileNotFound factory added; controller checks result.IsNotFound and returns 404 [Campaign_Tracker.Server/Controllers/MunicipalityProfileController.cs]jurisdictionsLoadError state added; “New” button disabled when jurisdictions unavailable; distinct warning alert shown [campaign-tracker-client/src/municipalities/MunicipalityProfilePanel.tsx]catch (Exception ex) with Console.Error.WriteLine added [Campaign_Tracker.Server/LegacyData/InMemoryLegacyDataAccess.cs]CreateProfile_WrongRoleToken_Returns403, GetJurisdictions_NoToken_Returns401, and UpdateProfile_UnknownId_Returns404 tests added [Campaign_Tracker.Server.Tests/MunicipalityProfileControllerTests.cs]normalizedJCode computed before validator call; stored and validated forms are now consistent [Campaign_Tracker.Server/Municipalities/InMemoryMunicipalityProfileRepository.cs].DistinctBy(r => r.JCode!.Trim(), StringComparer.OrdinalIgnoreCase) added before projection [Campaign_Tracker.Server/LegacyData/InMemoryLegacyDataAccess.cs]CreateProfile_RecordsAuditEvent_AC3 and UpdateProfile_RecordsAuditEvent_AC3 tests added [Campaign_Tracker.Server.Tests/MunicipalityProfileControllerTests.cs]problem.error ?? 'Validation failed.' fallback added in both create and update functions [campaign-tracker-client/src/municipalities/municipalityContracts.ts]Powered by TurnKey Linux.