diff --git a/docs/audience-scoping-backlog.md b/docs/audience-scoping-backlog.md new file mode 100644 index 0000000..87be0ba --- /dev/null +++ b/docs/audience-scoping-backlog.md @@ -0,0 +1,176 @@ +# Audience Scoping Backlog + +**Date:** 2026-03-30 +**Purpose:** Collect the remaining audience-scoping work into a single batch backlog so the small auth-hardening slices can be finished before broader architecture work starts. + +## Status Snapshot + +### Done + +- `blueprint.listSummaries`: narrowed to `planning-read` +- `entitlement.getBalance`, `entitlement.getBalanceDetail`: narrowed to self-service with elevated cross-resource access for controller, manager, and admin +- `vacation.previewRequest`: now enforces owned-resource access for normal users +- `holidayCalendar.resolveResourceHolidays`, `holidayCalendar.resolveResourceHolidaysDetail`: now enforce self-service ownership with elevated manager/admin reads + +### Dirty Files To Avoid Mixing Into This Batch + +- `packages/api/src/router/assistant-tools.ts` +- `packages/api/src/router/notification.ts` +- `packages/api/src/__tests__/assistant-tools-import-export.test.ts` +- `packages/api/src/__tests__/notification-router.test.ts` + +These files already have unrelated local edits. Audience parity work that would normally touch them should be deferred or handled through adjacent files and dedicated follow-up tests. + +## Batch Categories + +### Ready Now + +These are small, well-bounded slices that should fit the existing hardening pattern: narrow the procedure, add router authorization tests, update docs, and commit separately. + +#### 1. `packages/api/src/router/blueprint.ts` -> `getGlobalFieldDefs` + +- Current state: `protectedProcedure` +- Likely target: `planning-read` +- Why it is ready: + - the route returns global blueprint field definitions across active blueprints + - that is broader than a low-risk lookup and belongs with other blueprint configuration reads + - the audience class already exists in [route-access-matrix.md](/home/hartmut/Documents/Copilot/capakraken/docs/route-access-matrix.md) +- Expected work: + - switch to `planningReadProcedure` + - add a focused auth test covering unauthenticated, plain user, and planning-enabled caller + - update matrix wording if needed + +#### 2. `packages/api/src/router/resource.ts` -> `chapters` + +- Current state: `protectedProcedure` +- Likely target: `authenticated-safe-lookup` +- Why it is ready: + - the route only returns distinct active `chapter` strings + - it does not expose resource records, counts, hierarchy, or staffing data + - it looks more like a shared filter/lookup helper than a resource-overview read +- Expected work: + - keep implementation shape, but make the intended audience explicit in docs + - add auth coverage proving normal authenticated access is allowed while unauthenticated access is blocked + - only tighten further if a concrete leak is found + +#### 3. `packages/api/src/router/project.ts` -> `isImageGenConfigured`, `isDalleConfigured` + +- Current state: `protectedProcedure` +- Likely target: keep as authenticated low-risk checks +- Why it is ready: + - these are explicit boolean readiness/configuration checks already called out in the matrix + - the main gap is CI-enforced audience intent, not router logic +- Expected work: + - add auth tests for authenticated vs unauthenticated callers + - assert the result shape stays narrow (`configured`, optional provider) + - document them explicitly in the backlog as `tests/docs only` + +#### 4. `packages/api/src/router/assistant.ts` -> `listPendingApprovals` + +- Current state: `protectedProcedure` +- Likely target: keep as self-service +- Why it is ready: + - the implementation reads approvals by `ctx.dbUser!.id` + - it is already effectively scoped to the current user + - this can be locked down by tests without touching dirty assistant tool files +- Expected work: + - add router-level auth coverage for self-only behavior + - document the route in the access matrix + +### Tests Or Docs Only + +These routes look conceptually acceptable already, but the classification is not yet enforced clearly enough. + +#### `packages/api/src/router/assistant.ts` -> `chat` + +- Current state: `protectedProcedure` +- Working model: + - chat session itself is authenticated + - actual tool visibility is permission-gated inside assistant selection +- Remaining gap: + - the matrix does not yet document this route explicitly + - parity expectations should remain in `assistant.ts` tests until `assistant-tools.ts` is safe to touch +- Follow-up: + - add matrix entry describing chat as an authenticated shell with tool-level audience enforcement + - avoid deeper changes until dirty assistant-tool files are clear + +#### `packages/api/src/router/resource.ts` -> `importSkillMatrix` + +- Current state: `protectedProcedure` +- Working model: + - the mutation resolves the linked resource from the current user and writes only to that resource +- Remaining gap: + - no explicit self-service classification in the matrix + - auth regression coverage should be verified +- Follow-up: + - document as self-service + - add or tighten tests only if coverage is missing + +#### `packages/api/src/router/project.ts` -> `isImageGenConfigured`, `isDalleConfigured` + +- The likely outcome is to keep the current procedure and add explicit tests/docs rather than re-architecting the route. + +### Needs Architecture Or Policy Design + +These routes should not be batch-edited as “small safe slices” until a visibility model exists. + +#### `packages/api/src/router/comment.ts` + +- Current state: all core routes are `protectedProcedure` +- Why this is not a small slice: + - reads and writes are keyed by generic `entityType` and `entityId` + - visibility depends on the backing entity, not on the comment record alone + - the current author/admin checks for resolve/delete are not enough to decide who may list or create comments on each entity class +- Design work needed: + - define which entity types can host comments + - map each entity type to its audience source of truth + - centralize entity visibility checks before any comment read/write +- Recommended path: + - treat comments as a separate architecture ticket, not part of the quick hardening batch + +### Blocked By Dirty Files + +#### `packages/api/src/router/assistant-tools.ts` + +- Why blocked: + - unrelated local edits are already present + - tool gating changes would mix poorly with concurrent work +- Interim rule: + - keep parity changes on the `assistant.ts` side where possible + - defer tool-level cleanups until the file is stable + +#### `packages/api/src/router/notification.ts` + +- Why blocked: + - unrelated local edits are already present + - TypeScript verification currently also reports a foreign issue in this file +- Interim rule: + - do not mix notification hardening into this batch unless the other worker clears the file first + +## Recommended Batch Order + +1. `blueprint.getGlobalFieldDefs` +2. `assistant.listPendingApprovals` plus matrix entry +3. `resource.chapters` classification and auth test +4. `project.isImageGenConfigured` and `project.isDalleConfigured` auth tests +5. `resource.importSkillMatrix` docs/test verification +6. `assistant.chat` matrix clarification and parity review +7. `comment` architecture design ticket + +## Slice Definition + +Each “ready now” slice should follow the same template: + +1. change the router audience only if the current procedure is too broad +2. add focused auth tests for unauthenticated, plain authenticated, and elevated callers as applicable +3. update [route-access-matrix.md](/home/hartmut/Documents/Copilot/capakraken/docs/route-access-matrix.md) +4. verify with targeted `vitest` +5. run `git diff --check` +6. commit in isolation + +## Exit Criteria For This Batch + +- every route in this document is classified as either `done`, `ready now`, `tests/docs only`, `needs architecture`, or `blocked` +- every `ready now` route has router-level authorization coverage +- the access matrix documents all low-risk exceptions explicitly +- larger architecture work starts only after this batch is either completed or intentionally deferred