9.6 KiB
9.6 KiB
Route Access Matrix
Date: 2026-03-29 Purpose: Explicit interim audience model for sensitive API read routes while the broader least-privilege refactor is still in progress.
Decision Rules
protectedProcedure: only for clearly personal or low-sensitivity reads.controllerProcedure: planning, financial, staffing, or portfolio-wide analytics that should only be visible toCONTROLLER,MANAGER, orADMIN.- Ownership checks: self-service routes stay user-accessible, but only for the caller's own linked resource unless elevated staff access applies.
Applied In This Pass
Dashboard
All routes in dashboard.ts are treated as portfolio analytics and now require controllerProcedure.
| Route | Classification | Reason |
|---|---|---|
getOverview |
controllerProcedure |
exposes global resource/project counts and budget context |
getPeakTimes |
controllerProcedure |
exposes portfolio-wide demand/utilization peaks |
getTopValueResources |
controllerProcedure |
exposes ranked value/cost-related resource data |
getDemand |
controllerProcedure |
exposes staffing demand by project/person/chapter |
getDetail |
controllerProcedure |
aggregates the above into assistant-facing strategic detail |
getChargeabilityOverview |
controllerProcedure |
already correctly scoped |
getBudgetForecast |
controllerProcedure |
exposes budget burn and exhaustion projections |
getSkillGaps |
controllerProcedure |
exposes org-wide capability shortfalls |
getSkillGapSummary |
controllerProcedure |
summary variant of strategic skill analytics |
getProjectHealth |
controllerProcedure |
exposes portfolio-level delivery risk indicators |
Vacation
Routes in vacation.ts now distinguish between self-service and staff oversight.
| Route | Classification | Reason |
|---|---|---|
previewRequest |
self-service | personal validation before request creation |
create |
self-service with ownership check | users may request only for their own resource |
cancel |
self-service with ownership check | users may cancel only their own requests |
list |
self-service scoped to own resource, or full staff view for manager/admin | broad vacation visibility is sensitive absence data |
getById |
self-service scoped to own vacation, or full staff view for manager/admin | direct object lookup should not bypass ownership |
getForResource |
self-service scoped to own resource, or full staff view for manager/admin | calculator support should not expose foreign absence data |
getTeamOverlap |
self-service scoped to own resource, or full staff view for manager/admin | overlap warnings are valid, but only for the caller's team context |
getPendingApprovals |
manager/admin | approval queue is supervisory data |
Resource
Routes in resource.ts remain partially deferred, but the clearest sensitive reads are now explicitly scoped.
| Route | Classification | Reason |
|---|---|---|
directory |
authenticated safe directory | dedicated low-sensitivity directory for generic pickers, filters, calendars, and lookups; returns only id, eid, displayName, chapter, and isActive, limits search to name/EID, and preserves anonymization behavior |
getMyResource |
self-service | explicit route for the caller's linked resource |
getChargeabilitySummary |
self-service scoped to own resource, or staff with VIEW_ALL_RESOURCES |
exposes detailed capacity, holiday, assignment, and target data for an individual resource |
getValueScores |
explicit permission gate VIEW_SCORES |
ranked score output should not depend on ad hoc session-role strings |
getById |
self-service scoped to own resource, or staff with VIEW_ALL_RESOURCES |
full resource detail page includes person-level operational and cost context |
getByEid |
self-service scoped to own resource, or staff with VIEW_ALL_RESOURCES |
direct identifier lookup should not bypass ownership |
getHoverCard |
self-service scoped to own resource, or staff with VIEW_ALL_RESOURCES |
hover card exposes rates, role, skills, and staffing targets |
getByIdentifier |
exact self lookup for regular users; broad lookup for staff with VIEW_ALL_RESOURCES |
lightweight identifier read returns only identity-safe fields (id, eid, displayName, chapter, isActive) |
getByIdentifierDetail |
exact self lookup for regular users; broad lookup for staff with VIEW_ALL_RESOURCES |
explicit detail route for assistant and UI flows that truly need rates, targets, org placement, and skill/count context |
resolveByIdentifier |
exact self lookup for regular users; broad lookup for staff with VIEW_ALL_RESOURCES |
minimal identity resolver used by tool chains to convert free-form names/EIDs into canonical IDs without leaking cost or location detail |
listSummaries |
staff with VIEW_ALL_RESOURCES |
staff-only org search that returns non-financial summary cards for discovery and candidate selection |
listSummariesDetail |
staff with VIEW_ALL_RESOURCES |
explicit richer search variant for assistant/staff workflows that need FTE, LCR, and chargeability context |
listStaff |
staff with VIEW_ALL_RESOURCES |
explicit staff-only list for cost-aware, role-aware, and estimate/planning workflows; supports email search, rates, roles, and dynamic field filters |
Resource Directory Split
This pass introduces an explicit audience split in resource.ts:
resource.directoryis the default route for generic UI selectors and org-directory style lookups.resource.listStaffis the explicit staff-only route for estimate, staffing, and scenario-planning screens that need cost-sensitive resource data.
The following web consumers now use resource.directory:
- generic resource comboboxes and assignment pickers
- vacation filters and team calendar selectors
- timeline quick filters, toolbar lookup, and project panel add-member search
- project responsible-person picker
- computation graph resource selector
- batch skill import resource matching
Project
Routes in project.ts now distinguish between lightweight project discovery and planning/commercial detail.
| Route | Classification | Reason |
|---|---|---|
resolveByIdentifier |
authenticated safe resolver | minimal project identity lookup for names/codes/IDs without commercial detail |
searchSummaries |
authenticated safe summary search | lightweight project discovery returns only code, name, status, dates, and client |
searchSummariesDetail |
controllerProcedure |
exposes budget, win probability, and staffing/estimate counts |
getByIdentifier |
authenticated safe identifier read | exact/fuzzy lookup returns only identity-safe project fields |
getByIdentifierDetail |
controllerProcedure |
exposes commercial and staffing detail, including budget, responsible person, category, and top allocations |
list |
controllerProcedure |
broad project listing can expose commercial/custom-field planning context |
getById |
controllerProcedure |
full project read model includes allocations, demands, and assignments |
getShoringRatio |
controllerProcedure |
derived staffing geography analytics should not be generally user-visible |
Timeline
Routes in timeline.ts now split personal self-service reads from broad planning views.
| Route | Classification | Reason |
|---|---|---|
getEntries |
controllerProcedure |
returns broad staffing allocations across projects/resources for a time window |
getEntriesView |
controllerProcedure |
exposes the full timeline read model, including demands and assignments |
getHolidayOverlays |
controllerProcedure |
org-wide absence overlays reveal staffing availability context |
getMyEntriesView |
self-service scoped to own linked resource | personal timeline view for USER/VIEWER; ignores foreign resource scoping and never broadens beyond the caller's linked resource |
getMyHolidayOverlays |
self-service scoped to own linked resource | personal holiday overlays for the caller's own timeline window without org-wide absence visibility |
getEntriesDetail |
controllerProcedure |
assistant-facing planning detail aggregates allocations, demands, assignments, and holiday summaries |
getHolidayOverlayDetail |
controllerProcedure |
detailed overlay summaries are planning-sensitive absence context |
getProjectContext |
controllerProcedure |
project-side planning context includes all allocations and cross-resource context |
getProjectContextDetail |
controllerProcedure |
detailed project timeline context exposes conflict and overlap analysis |
previewShift |
controllerProcedure |
shift preview computes operational and budget impacts before mutation |
getShiftPreviewDetail |
controllerProcedure |
detail variant includes project metadata plus cost/conflict preview |
getBudgetStatus |
controllerProcedure |
budget burn/remaining exposure is commercial data |
Review Standard
- Any new sensitive read route must document one of:
- personal self-service ownership
- explicit role gate
- explicit permission gate
- Any route returning portfolio-wide financial, staffing, scheduling, or HR absence data should not default to plain
protectedProcedure.