ADR-0011: Per-Portal Controller Isolation
Status: ACCEPTED Date: 2026-03-22 Supersedes: N/A Superseded by: N/A
Context
The original codebase used shared controllers with @GatewayValidation(portals={...}) annotations to serve multiple portals. This caused method-level portal override errors, ambiguous API surface per portal, and tight coupling between portal-specific endpoints. Five methods on InstitutionController had class-level S,T but overrode to S-only at the method level, creating audit risk.
Source: docs/archive/specs/2026-03-22-portal-controller-split-system-design.md, docs/archive/specs/2026-03-23-portal-controller-split-consumer-design.md, docs/archive/specs/2026-03-23-portal-controller-split-tenant-design.md
Decision
Each portal gets its own controller package (com.slaunchx.core.portal.{system,tenant,consumer,partner}.web) with dedicated controllers per domain. Portal scope is declared once at class level (@GatewayValidation(portals = {10010101})) with no method-level portals override. Each portal has its own URL prefix (/web/v1/system/, /web/v1/tenant/, etc.). Controllers are thin delegation shells that call existing Service/Facade beans.
Consequences
- Each portal's endpoint set is immediately visible from its package contents.
- No method-level portal override eliminates the class of annotation-mismatch bugs.
- Documentation generation (DevPortal) can enumerate endpoints per portal by scanning the corresponding package.
- Code duplication across portal controllers for similar endpoints (mitigated by thin delegation to shared services).
- Old shared controllers are marked
@Deprecatedand retained until all four portal phases complete.
Alternatives Considered
- Keep shared controllers with stricter annotation validation: Rejected because method-level overrides are inherently fragile and the audit surface remains ambiguous.
- Runtime portal filtering (single controller, response varies by portal): Rejected because it hides the endpoint contract in runtime logic rather than explicit source code declarations.