Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
16 KiB
PRD — Advanced Authorization Kernel and Premium ABAC Bundles
- Slug:
premium-abac-authorization-kernel - Date:
2026-04-21 - Status: Draft
Summary
Build a shared authorization kernel that centralizes the codebase's existing ABAC-like access rules in both CE and EE, then add an EE-only, tier-gated control plane for configurable authorization bundles. The new system keeps RBAC as the prerequisite, preserves built-in security invariants, normalizes relationship-driven access patterns such as own / assigned / managed / same client / client portfolio / selected boards, and lets entitled EE tenants apply narrowing-only premium restrictions through reusable bundles attached to roles, teams, users, and API keys.
The immediate product value is better differentiation for larger MSPs that need fine-grained segmentation across tickets, documents, time, projects, assets, and billing. The immediate engineering value is replacing today's fragmented mix of RBAC, inline ownership checks, board filters, and API/UI drift with one coherent authorization path.
Problem
Authorization in the current codebase is split across three layers that do not compose cleanly:
- RBAC is relatively simple and stable: role → permission(
resource,action) with tenant and portal gating. - Relationship- and attribute-driven rules already exist in many features, but are scattered inline:
- client-portal board scoping
- manager/delegation checks for time
- document ownership/client visibility rules
- client admin / same-client guards
- assorted own/assigned/manage checks in projects and other domains
- A legacy policy/DSL scaffold exists, but it is not the authoritative runtime path and has drifted from production behavior.
This creates several problems:
- enterprise MSP segmentation is difficult to express consistently
- UI/server-action and API-key paths can diverge
- own/manage/assigned/client-portfolio logic is reimplemented repeatedly
- there is no single place to explain why access was allowed or denied
- the existing policy DSL is not the right abstraction for how the product actually works
Goals
- Introduce a shared authorization kernel in CE and EE that centralizes relationship-driven access evaluation, list scoping, single-record authorization, mutation guards, and optional field redaction hooks.
- Preserve RBAC as the first authorization gate; the new system must narrow or shape access after RBAC, not replace it.
- Normalize the most important built-in relationship semantics already present in the product, especially:
- own
- assigned
- managed
- same client
- client portfolio
- selected boards
- Converge UI/server-action and API/programmatic paths toward one effective authorization model for the migrated resource families.
- Ship an EE-only configurable control plane that lets entitled tenants create reusable authorization bundles and attach them to roles, teams, users, and API keys.
- Make configurable premium ABAC narrowing-only. Configured bundles may further restrict access, but may not broaden RBAC or built-in baseline behavior.
- Replace the legacy policy DSL direction with typed relationship-first templates and bundle-based management.
- Deliver strong baseline validation by documenting current behavior before migration and verifying parity after cutover.
Non-goals
- Replacing RBAC with pure ABAC.
- Supporting arbitrary custom expressions, a general-purpose policy DSL, or user-authored boolean logic in v1.
- Allowing EE-configured policies to widen access beyond RBAC or built-in kernel behavior.
- Introducing allow/deny precedence trees, explicit negative policies, or exception systems in v1.
- Covering every product resource family in the first configurable rollout.
- Implementing multi-step human approval workflows for bundle publication in v1.
- Moving all historical authorization behavior into tenant-configurable policies. Some baseline invariants must remain built in.
- Solving every extension/integration authorization seam in the first milestone, although the kernel should be designed for later adoption.
Users and Primary Flows
Security / platform administrator (EE)
- Opens the Advanced Authorization area.
- Creates or edits an authorization bundle such as "Field Technician" or "Assigned Client Delivery Team".
- Adds narrowing rules across one or more resource families.
- Simulates the draft bundle against real users/records or synthetic scenarios.
- Publishes the revision.
- Assigns the bundle to roles, teams, users, or API keys.
MSP operations admin / team lead (EE)
- Needs to segment access by client portfolio, team, assignment, board, or management chain.
- Uses shipped system bundles or clones them into custom bundles.
- Applies bundles to operational roles and teams.
- Uses explainability tooling to understand why a technician can or cannot access a record.
Support / engineering staff (CE + EE)
- Uses the shared kernel's decision traces and common behavior model to debug access issues.
- Confirms that migrated resource families now apply one normalized authorization path.
Integration administrator (EE)
- Assigns a narrowing bundle to an API key.
- Ensures programmatic access is an intersection of user access and API-key restrictions.
- Validates the effective scope before enabling integrations in production.
UX / UI Notes
EE bundle-management experience
- Primary artifacts are bundles, not raw policy rows.
- Main EE surfaces:
- Bundle Library
- Bundle Editor
- Assignment Manager
- Access Simulator / Explainability
- Bundle editing should be organized by resource sections (Tickets, Documents, Time, Projects, Assets, Billing), not generic condition grids.
- All rules should show natural-language summaries.
- Bundle changes must follow a draft → publish model. Published revisions are enforced; draft revisions are not.
- Assignments attach to the stable bundle, not directly to a draft revision.
- The simulator should support:
- real principals + real existing records
- synthetic scenarios
- draft-vs-published comparison
CE / non-entitled EE behavior
- CE uses the shared kernel for built-in behavior but has no configurable bundle management UI.
- EE tenants below the required tier should see an upgrade path using the existing tier-gating patterns.
- Built-in relationship behavior must remain active even when the premium management UI is unavailable.
Requirements
Functional Requirements
- Introduce a shared authorization kernel that exposes common entry points for:
- single-resource authorization
- list/query scoping
- mutation authorization
- field redaction hooks
- explainability traces
- Keep RBAC as a prerequisite. If RBAC denies a
resource:action, configured ABAC must not restore that access. - Normalize built-in relationship resolvers for the most important relationship types used in current product behavior, including own, assigned, managed, same-client, client-portfolio, and selected-board semantics where applicable.
- Preserve product-defined baseline invariants in CE and EE, even when tenant-configurable premium ABAC is unavailable.
- Ensure configurable premium ABAC is narrowing-only.
- Provide an EE-only configurable control plane that lets tenants define reusable authorization bundles.
- Bundles must support rules spanning at least the v1 resource families:
- tickets
- documents
- time
- projects
- assets
- billing
- Bundles must attach to:
- roles
- teams
- users
- API keys
- API-key bundle restrictions must always be an intersection with the impersonated user's effective access.
- Bundles must be versioned with a draft/publish lifecycle.
- Editing an active bundle must create or modify a draft revision rather than mutating the enforced revision in place.
- Publishing a draft revision must atomically make it the enforced revision for all active assignments of that bundle.
- Bundles must support archive semantics without deleting historical revisions.
- Bundle assignments must use one generic assignment model keyed by
target_type + target_id. - Assignment creation must validate that the target exists in the same tenant and is compatible with the chosen attachment type.
- Bundles must compose as narrowing intersections, not widening unions.
- The configurable rule catalog must use typed templates rather than arbitrary expressions.
- The v1 template catalog must support relationship-first scope templates such as:
- own
- assigned
- managed
- own_or_assigned
- own_or_managed
- client_portfolio / selected_clients
- same_team
- selected_boards
- The v1 constraint catalog must support at least the high-value narrowing guards needed for migrated resource families, including concepts such as:
- not-self-approver
- client-visible-only
- hide-sensitive-fields
- Provide shipped system bundles / starter bundles for common enterprise MSP scenarios.
- Replace use of the legacy policy DSL as the primary runtime direction. The new control plane must not depend on end-user DSL authoring.
- Migrate ticket authorization to the shared kernel for the selected v1 access paths, including list/detail and premium narrowing support where applicable.
- Migrate document authorization to the shared kernel while preserving current relationship and visibility semantics.
- Migrate time / timesheet delegation and approval-related authorization to the shared kernel.
- Migrate project authorization for the selected v1 project/task/comment access paths into the shared kernel.
- Migrate asset authorization for the selected v1 access paths into the shared kernel, including client/team/assignment segmentation hooks.
- Migrate billing authorization for the selected quote/invoice/approval visibility and mutation guards into the shared kernel.
- Normalize migrated API/programmatic paths to use the same effective authorization kernel as UI/server-action paths.
- Provide explainability output that identifies the builtin rule path and any configured bundle-based narrowing that contributed to a decision.
- Create and maintain a plan-local current-behavior baseline artifact so the migration can validate end-state behavior against today's real semantics.
- Treat current-behavior parity as part of the deliverable, not as optional follow-up.
Non-functional Requirements
- The shared authorization runtime must work in CE and EE through an edition-aware, pluggable implementation seam.
- The configurable control plane must be EE-only and tier-gated using the same tenant-tier system already used elsewhere in the product (for example Teams integration support), with Premium as the default required tenant tier.
- The shared runtime interface should avoid scattering
isEnterprise()branches through feature code; callers should rely on the common authorization contract. - The system must fail closed when authorization context or required resource attributes cannot be resolved safely.
- The new runtime should be designed for request-local caching to avoid repeated relationship and bundle resolution within a request.
- Runtime cutovers must not silently broaden access for any migrated resource family.
- Decision traces should be detailed enough to support simulator output, support debugging, and later auditability.
- The migration must not require immediate removal of every legacy policy/DSL artifact, but the new runtime must not depend on them.
- The implementation must include database-backed regression coverage for migrated resource families and at least one failure/guard case per high-risk domain.
- API/UI parity should be validated explicitly for migrated resource families where both channels exist.
Data / API / Integrations
Recommended shared runtime shape
The kernel should expose stable entry points such as:
- authorize one resource/action
- resolve effective scope for list/search queries
- assert mutation authorization
- resolve field redactions
- explain why access was allowed or denied
Recommended configurable control-plane model
Use new, typed authorization tables rather than extending the old policy-DSL model:
authorization_bundlesauthorization_bundle_revisionsauthorization_bundle_rulesauthorization_bundle_assignments
Assignments should key on:
target_typetarget_id
Current baseline artifact
Maintain a plan-local baseline artifact, currently seeded as:
CURRENT_AUTHORIZATION_BASELINE.md
That artifact is the source of truth for current behavior validation during rollout.
Security / Permissions
- RBAC remains mandatory.
- Built-in kernel invariants remain mandatory in both CE and EE.
- Configured premium ABAC may only narrow access after RBAC and built-in kernel rules have been applied.
- Programmatic/API key restrictions must never broaden access beyond the impersonated user.
- Bundle, revision, assignment, publish, and simulator actions must themselves be permission-gated.
- Assignment validation must be tenant-scoped.
- Simulator access should expose enough explanation to support governance while avoiding disclosure of unrelated tenant data.
- Migrated resource families must preserve fail-closed behavior when relationship resolution is incomplete or invalid.
Observability
Default operational telemetry does not need to expand beyond normal server logs unless implementation reveals a clear operational gap. However, the authorization kernel and EE simulator should provide structured decision reasons that can be surfaced in debugging and governance workflows.
Rollout / Migration
- Treat this as a comprehensive authorization-kernel overhaul rather than a one-off feature bolt-on.
- Start by documenting current behavior and locking in regression expectations before large-scale cutovers.
- Introduce the shared kernel with built-in behavior only first so CE and EE can migrate onto one runtime path.
- Migrate prioritized resource families onto the kernel while preserving existing behavior.
- Converge API and UI/server-action behavior during resource-family migration rather than leaving parity for later.
- Add the EE configurable control plane once the shared kernel contract is stable enough to support bundle overlays.
- Roll configurable narrowing onto the selected v1 resource families after the built-in kernel path is in place.
- Prefer resource-family cutovers within the comprehensive architecture over a single all-at-once runtime switch.
Open Questions
- Which exact project and asset actions are in the first migrated cutover versus a later follow-up inside the same kernel architecture?
- Which billing fields should participate in v1 redaction, and which should remain out of scope until a later phase?
- Which existing API surfaces are explicitly in the first parity wave versus a second wave after the shared kernel is established?
Acceptance Criteria (Definition of Done)
- A shared authorization kernel exists and is used by migrated CE and EE flows.
- RBAC remains the prerequisite gate, and configured premium ABAC cannot widen access.
- The new runtime centrally supports relationship-driven access evaluation for the v1 relationship templates.
- EE tenants on the Premium tier or above can create, revise, publish, and assign narrowing bundles.
- Bundles can attach to roles, teams, users, and API keys through one generic assignment model.
- Active bundle enforcement uses only the current published revision; draft revisions are not enforced.
- The simulator supports both real principals/records and synthetic scenarios.
- Tickets, documents, time, projects, assets, and billing are migrated onto the shared kernel for the selected v1 paths.
- API/UI parity is validated for the migrated resource families where both channels exist.
CURRENT_AUTHORIZATION_BASELINE.mdor its updated equivalent captures the real pre-migration behavior needed to validate the rollout.- The legacy DSL/policy runtime is no longer the primary runtime direction for the migrated authorization paths.
- Regression coverage demonstrates that migrated behavior preserves baseline security semantics while allowing entitled EE tenants to add narrowing restrictions through bundles.