# Architecture Hardening Backlog **Date:** 2026-03-30 **Purpose:** Keep the remaining cleanup work for the current quality/security scope in a single prioritized list, so small hardening slices can be completed before larger redesign work. ## Recently Completed - SSE audience model narrowed to canonical `user:*`, `permission:*`, and `resource:*` scopes only - CI architecture guardrail added for SSE audience scoping - import boundaries hardened for server dispo workbooks and browser spreadsheet uploads - AI and SMTP runtime diagnostics sanitized before they reach logs or admin-facing error messages - transitive audit hotspots for `flatted` and `picomatch` pinned through root `pnpm.overrides` - `apps/web` export paths migrated from direct `xlsx` usage to a shared `exceljs` workbook export helper - `packages/application` workbook reading and `packages/engine` XLSX export serialization migrated from `xlsx` to `exceljs` - `pnpm audit --audit-level=high` no longer reports high-severity dependency findings - `apps/web` now has focused Vitest coverage for browser spreadsheet parsing and skill-matrix workbook parsing - cron routes, Redis helpers, reminder scheduling, webhook dispatching, and SSE fallback paths now use structured logger calls instead of raw `console.*` - `packages/api` now has focused Vitest coverage for reminder scheduler and webhook dispatcher logging failures - `apps/web` typecheck is now decoupled from generated `.next-e2e` artifacts via a dedicated `tsconfig.typecheck.json` - comment entity support is now centralized across shared constants, API registry policy, assistant tool metadata, and the web comment target API without pretending a second consumer exists - `resource` is now onboarded as the second real comment entity, reusing the same ownership and staff-visibility rules as the resource detail route - comment mention autocomplete now uses a dedicated entity-scoped API route instead of inheriting the narrower `user.listAssignable` audience - runtime secret handling is now environment-first end to end: admin updates no longer persist new operational secrets, runtime status is surfaced explicitly, and legacy database secret copies can be cleared through a dedicated cleanup path - `apps/web` system settings UI is now decomposed into section components with shared secret/runtime helpers, bringing all files in that slice back under the file-size guardrail - the first API-side `assistant-tools` extraction is in place: settings, system-role config, webhooks, audit log access, and shoring ratio now live in a dedicated domain module with shared assistant-tool types - the advanced timeline assistant toolset now lives in its own domain module, keeping the high-risk read/mutation pairings out of the monolithic router without changing the assistant contract - the adjacent allocation planning assistant helpers now live in their own domain module, covering allocation listing, budget status, and the core allocation create/cancel/status mutations without changing the assistant contract - the neighboring vacation and holiday assistant helpers now live in their own domain module, covering vacation-balance reads, regional/resource holiday inspection, and holiday calendar admin mutations without changing the assistant contract - the adjacent roles, skill-search, and lightweight analytics assistant helpers now live in their own domain module, covering role CRUD plus `search_by_skill`, `get_statistics`, and `get_chargeability` without changing the assistant contract - the neighboring client and org-unit admin mutations now live in their own domain module, keeping more CRUD wiring out of the monolithic router without changing the assistant contract - the adjacent chargeability/computation read helpers now live in their own domain module, keeping the advanced financial transparency read models out of the monolithic router without changing the assistant contract - the neighboring country and metro-city admin mutations now live in their own domain module, keeping more settings-side CRUD wiring out of the monolithic router without changing the assistant contract - the adjacent management-level, utilization, calculation-rule, effort-rule, and experience-multiplier read helpers now live in their own domain module, further shrinking the monolithic assistant router without changing the assistant contract - the remaining assistant user-admin helper cluster now lives in its own domain module, covering admin listing, user lifecycle mutations, permission overrides, resource linking, and MFA overrides without changing the assistant contract - the authenticated user self-service assistant helpers now live in their own domain module, covering assignable users, dashboard preferences, favorites, column preferences, and MFA self-service without changing the assistant contract ## Next Up Pin the next structural cleanup on the API side: continue splitting `packages/api/src/router/assistant-tools.ts` into domain-oriented tool modules without changing the public tool contract. The next clean slice should stay adjacent to the extracted domains and target one cohesive block such as the embedded notification/task helpers, or the remaining estimate and project admin helper clusters that are still in the monolithic router. ## Remaining Major Themes The small hardening slices are effectively exhausted. The remaining work is now structural rather than another quick batch: 1. secrets and runtime configuration policy 2. oversized router decomposition 3. production-grade rate limiting 4. canonical image-based production delivery 5. performance hotspot reduction ## Working Rule For the next batches, prefer work in this order: 1. remove or isolate known-risk runtime dependencies 2. add guardrails and tests around already-hardened code 3. only then expand architecture surface area