Updates mainPlan.md's Region Management table, 10_region_management.md's status/open-questions/implementation-notes sections, and BACKEND_API_REFERENCE.md's Regions section to reflect the newly added target/budget/agency-map/tax-rule/hierarchy/dashboard endpoints, and flags that the EF Core migration for the new tables is still pending. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.9 KiB
10 — Region Management (Beyond CRUD)
Status: Implemented (except assignAreaToRegion, blocked on the Area entity)
Depends On: 00 — Existing Gap Fixes
Goal
Region CRUD already exists (Features/Region). This step covers everything in
mainPlan.md §2 that isn't plain
CRUD: targets, budgets, agency mapping, tax rules, hierarchy, and dashboarding.
Background / Context
Region today has only a Name. Nothing points to it except Route.FK_RegionId. There is no
Area level (see Open Question in 00_existing_gaps.md).
Data Model Changes
Regional Target / Budget
Implemented as two separate entities, RegionalTarget and RegionalBudget
(Models/RegionalTarget.cs, Models/RegionalBudget.cs), each with FK_RegionId, Period
(string, yyyy-MM), and TargetValue/BudgetAmount respectively. A unique index on
(FK_RegionId, Period) means each region has at most one target and one budget row per period;
setting the same period again updates it in place rather than inserting a duplicate.
Agency-Region Map
Implemented as RegionAgencyMap (Models/RegionAgencyMap.cs): FK_RegionId, FK_AgencyUserId,
unique on the pair. "Regional Agency" stayed a Role, not a distinct entity (see Open Questions,
resolved) — FK_AgencyUserId points at an existing User who holds the RegionalAgency role,
the same convention already used by Claim.FK_AgencyUserId (§18).
Regional Tax Rule
Implemented as RegionalTaxRule (Models/RegionalTaxRule.cs): FK_RegionId (unique — one rule
per region), RuleConfig (raw JSON string). Nothing in pricing/tax calculation reads this yet;
it's stored for a future pricing-rule integration.
API Endpoints
| Function reference | Endpoint | Status |
|---|---|---|
assignAreaToRegion(areaId, regionId) |
— | Blocked — no Area entity exists (see 00_existing_gaps.md) |
setRegionalTarget(regionId, period, targetValue) |
PUT /api/regions/{id}/targets/{period} |
Implemented |
setRegionalBudget(regionId, period, budgetAmount) |
PUT /api/regions/{id}/budgets/{period} |
Implemented |
mapAgencyToRegion(agencyId, regionId) |
POST /api/regions/{id}/agencies |
Implemented |
setRegionalTaxRule(regionId, ruleConfig) |
PUT /api/regions/{id}/tax-rule |
Implemented |
getRegionHierarchy(regionId) |
GET /api/regions/{id}/hierarchy |
Implemented (region → routes → store ids; no Area level) |
getRegionDashboard(regionId, period) |
GET /api/regions/{id}/dashboard?period=... |
Implemented (real-time aggregation; see Open Questions, resolved) |
All request/response DTOs live in Features/Region/RegionDTOs.cs; routing and access checks are
in RegionController.cs and RegionService.cs.
Business Rules
- Only
RegionalManagerand above (per role level inData/Seed/RoleAndPermissionSeed.cs) can set targets/budgets/tax-rule for their own region; onlyRegionalAgencycan set them across regions. Implemented viaRegionService.CanManageRegionAsync: role level ≥ 60 (RegionalAgency) is allowed unconditionally, role level ≥ 50 (RegionalManager) requires a matchingUserRegionScoperow for that region, anything lower is rejected. The same gate is applied tomapAgencyToRegion. mapAgencyToRegionadditionally rejects the target user if their role level is below theRegionalAgencythreshold (60) — you can only map a user who actually holds (or outranks) that role.
Open Questions
Is "Regional Agency" a business entity distinct from theResolved: kept as aRegionalAgencyrole...?RoleonUser; no new agency entity, consistent withClaim.FK_AgencyUserId.DoesResolved: real-time aggregation fromgetRegionDashboardneed real-time aggregation, or a scheduled/cached rollup?Order/Store/Routefor now; revisit if/when region-wide dashboard queries become a performance concern at scale.
Implementation Notes
- Backend:
Models/RegionalTarget.cs,Models/RegionalBudget.cs,Models/RegionAgencyMap.cs,Models/RegionalTaxRule.cs,Data/AppDBContext.cs(DbSets + unique indexes),Features/Region/{IRegionRepository,RegionRepository,RegionService,RegionController,RegionDTOs}.cs. - Frontend:
distribution_fe/types/api.ts(response types),distribution_fe/lib/api/master.ts(regions.setTarget/setBudget/mapAgency/setTaxRule/hierarchy/dashboard), and a newRegionManageSheetdialog (distribution_fe/app/(dashboard)/network/regions/_components/region-manage-sheet.tsx) wired into the regions table's row actions. - Outstanding: an EF Core migration for the four new tables still needs to be generated and applied (blocked locally by the running dev server locking the build output) — no schema exists in the database yet even though the code is complete.