Skip to main content

RFC-0011: Policy-Driven "Landing" Architecture

  • Status: Implemented
  • Author(s): @revant.one
  • Created: 2026-04-14

Context

Standard application frameworks often hardcode user landing pages (e.g., redirecting all users to /dashboard after login). In multi-app environments like Framework M, landing needs to be dynamic, role-aware, and attribute-aware (e.g., a Supplier landing on a Portal vs. an Admin landing on a Desk). "Redirect hacks" often interfere with SPA routing and API fetches.

Proposed Architecture

1. The Landing Port (Backend)

Landing resolution is moved from imperative code (hardcoded redirects) to a declarative Protocol:

  • Protocol: LandingProtocol.
  • Contract: resolve_landing(user_context: UserContext) -> LandingDescriptor.

2. Specialized Adapters

Different implementation patterns can be swapped without changing the framework's core auth flow:

AdapterLogicUse Case
RBAC (Standard)Role -> Route mappingBasic internal apps.
ABAC (Attribute)User.attributes -> RouteLand users based on Branch, Department, or Type.
ReBAC (Relation)User -[member_of]-> WarehouseLand users based on their relationship to a specific entity.

3. The Resolution Hierarchy

Redirection is handled statelessly in the "Post-Auth Handshake":

  1. Explicit Override: If ?to=/path is present in the URL, the framework honors it immediately (Standard Redirect respect).
  2. Entitlement Filtering: Before resolution, the framework queries the FeatureEntitlementProtocol to ensure the target module/route is enabled for the tenant.
  3. User Preference: If the User has a personal_landing_page set in their metadata (and is entitled to it), it takes priority.
  4. Protocol Resolution: Query the LandingProtocol for the "Best Match" route based on active Roles/Permissions.
  5. System Fallback: Redirect to the global default (e.g., /dashboard).

4. Decoupling Logic (No-Cliff)

By treating the landing page as a Data Object rather than a HTTP Header (302):

  • Single-Page Applications (SPAs) can resolve landing routes without page reloads.
  • Mobile apps can interpret the LandingDescriptor to deep-link into a native screen.
  • Business logic for "Where should this user go?" is centralized in the active adapter, making it easily testable via TDD.

5. Progressive Decomposition (Data Sovereignty)

To adhere to progressive-decomposition.md (Part 14), the landing architecture ensures that the "Home" experience survives service isolation by moving resolution logic to the Adapter Layer:

  • Resolution Autonomy (Adapters): While the LandingProtocol is pure, its implementations can vary by deployment mode.
    • In Enterprise Mode, a domain-aware Adapter may resolve the landing page using Pattern A (RPC) to maintain absolute consistency.
    • In Indie Mode, a simpler Adapter may use Pattern B (Projection) or local DB lookups.
  • Survivability: If a primary domain Adapter (e.g., Supplier Domain) is unreachable, a fallback Middleware-Adapter can resolve a "safe" system route, preventing a total shell failure.

6. SaaS Entitlements (The Control Plane)

Landing pages are often restricted by subscription tiers (e.g., a "Premium Dashboard").

  • Entitlement Check: The LandingProtocol implementation must verify feature enablement via the shared FeatureEntitlementProtocol.
  • Downgrade Handling: If a user's personal_landing_page is no longer entitled (due to a subscription downgrade), the hierarchy automatically falls back to the next valid match in Step 4 or 5.

Implementation Details

  1. Backend: Add a landing_protocol field to the SystemConfig.
  2. Entitlements: Integrate FeatureEntitlementProtocol into the resolve_landing service logic.
  3. Frontend: The AuthHandler component triggers the resolve_landing API call upon successful login and updates the local router state.

Unresolved Questions

  • Session Management: Should the resolved landing page be cached in the session to avoid re-calculation on every refresh?
  • Multiple Matches: If an ABAC adapter returns multiple valid landing pages, how does the UI present a "Choice" to the user?