Skip to main content

RFC-0010: Regionalized "Rail & Drawer" Navigation Architecture

Context​

As Framework M moves towards a productized multi-app platform, the previous navigation models were limited by their flat structure and heavy focus on DocTypes. High-density platform applications require a navigation system that can handle hundreds of diverse resources (Reports, Pages, Kiosks) while remaining clean and extensible.

Proposed Architecture​

1. The Physical Model: "Rail & Drawer"​

Inspired by modern IDEs and high-density SaaS (e.g., Slack, VS Code), we transition from a single sidebar to a dual-layered navigation:

  • Primary Rail (The Switcher): A thin leftmost vertical bar containing App Icons (WMS, Finance, Studio, HR). Clicking an icon switches the Contextual Drawer.
  • Contextual Drawer (The Tree): A standard-width navigation drawer that displays a hierarchical resource tree for the active App.

2. The Resource Paradigm​

Navigation nodes are no longer strictly "DocTypes". The Navigation Manifest supports diverse Actionable Resources:

TypeDescriptionExample
DocTypeStandard List/Form viewsStock Entry
PageCustom React pagesPicking Dashboard
ReportGrid/Chart viewsInventory Aging
KioskSimplified terminal UIsQuick Pick Terminal
LinkInternal deep-links or external tools (with queries)/wms/stock?item={{ id }}
tip

Dynamic Interpolation: Link routes support template placeholders (e.g., {{ user_id }} or {{ branch_code }}). These are resolved by the Fidelity Port using the active UserContext or application state to ensure links remain contextual rather than hardcoded.

3. Dual-Layer Contract (Ports & Adapters)​

To maintain the "No-Cliff" promise, the navigation is governed by two distinct contracts:

A. The Context Port (Python)​

The Logical Source of Truth. This port resolves what the user is entitled to see and where they should go.

  • Protocol: NavigationProtocol.
  • Contract: get_navigation_manifest(user_context: UserContext) -> NavigationManifest.
  • Resolution Hierarchy:
    1. Entitlement Check: Query the FeatureEntitlementProtocol to see which apps are active for the tenant.
    2. Rail Discovery (Apps): Query only entitled apps' implementations of NavigationProtocol.
    3. Policy Filtering: Filter nodes via the NavigationPolicyEngine (RBAC/ABAC).
    4. Regional Augmentation: Apply decorators from NavigationDecoratorRegistry.
    5. User Personalization: Final merge with user-pinned or "Frequent" nodes.

B. The Fidelity Port (React)​

The Physical Execution Layer. This port resolves how the manifest is rendered to the user.

  • Adapter: Standard <Navigation /> component provided by framework-m-ui.
  • Rendering Logic: The UI consumes the NavigationManifest JSON. It maps resource types (DocType, Page, Report) to specific visual treatments.
  • Escapability: Advanced apps can provide their own React FidelityAdapter to override the standard navigation rendering while still consuming the systematic Python manifest.

4. Extensibility via Metadata Decorators​

Custom apps can augment productized navigation without editing the original codebase:

  • Registry: NavigationDecoratorRegistry.
  • Mechanism: A custom app can register a decorator that targets a specific AppID.
  • Example: An "India Compliance" app adds a GST Returns page to the Finance App's navigation manifest at runtime.
# Imperative Registration Example
def add_gst_module(manifest: NavigationManifest):
manifest.add_section("Compliance").add_node(type="Page", label="GST Portal")


NavigationDecoratorRegistry.register(target_app="finance", decorator=add_gst_module)

5. Progressive Decomposition (MFE Survival)​

To adhere to the progressive-decomposition.md principles (Part 13), the navigation architecture supports architectural decoupling:

  • Adapter-Driven Discovery: The NavigationProtocol remains agnostic to where metadata comes from. In decomposed environments, a specialized RemoteDiscoveryAdapter is injected to fetch manifests from FRAMEWORK_M_MFE_REMOTES over the network.
  • Logical Route Stability: All navigation nodes must use logical route strings (e.g., /wms/inventory) rather than hardcoded component references. This ensures the Core remains functional regardless of which Adapter (Local vs. Remote) resolves the UI.
  • Auto-Proxying: Connectivity issues are handled at the Adapter level (triggering FRAMEWORK_M_MFE_PROXY) rather than leaking into the navigation logic.

6. Policy-Driven Resolution (The "Conditional" Layer)​

To handle the challenge of "what to show" conditionally (similar to Landing Resolution), we implement a policy-driven engine that sits between the Manifest and the UI:

6.1 The Visibility Policy​

Navigation nodes can declare visibility requirements using a schema that the NavigationProtocol resolves:

{
"label": "GST Returns",
"route": "/finance/gst",
"visibility_policy": {
"roles": ["Accounts Manager"],
"attributes": { "country": "India" },
"feature_flag": "compliance_enabled"
}
}

6.2 Post-Login Handshake​

Similar to the resolve_landing API call, the frontend can fetch a "Resolved Navigation" post-authentication. This ensures that the UI doesn't just show a generic navigation and then "flicker" nodes away as permissions load.

  • Frontend Cache: The resolved manifest is stored in the App State (Redux/Zustand).
  • Hard Refresh: Manifests are re-validated on page refresh or context switch (e.g., switching companies).

6.3 Contextual Auto-Switching​

To reduce cognitive load, the navigation should automatically respond to the user's current route:

  • Route Tracking: If the user navigates to /wms/picking, the Primary Rail should automatically highlight the WMS icon.
  • Drawer Opening: If the drawer is collapsed, it should expand to reveal the active node's parent section.

7. SaaS Entitlements (The Control Plane)​

To support multi-tenant SaaS environments, we add an Entitlement Layer that governs the visibility of entire feature sets before user-level roles are checked.

7.1 The Entitlement Protocol​

The SaaS platform provider implements the FeatureEntitlementProtocol:

class FeatureEntitlementProtocol(Protocol):
def is_feature_enabled(self, tenant_id: str, feature_id: str) -> bool:
"""Checks if the tenant's subscription plan allows this feature."""
...

7.2 Entitlement-Aware Nodes​

Navigation nodes can optionally declare a feature_id. If the entitlement check fails for that ID, the node (and its children) are automatically pruned from the manifest at the Context Port level.

{
"label": "Advanced Forecasting",
"route": "/finance/forecast",
"feature_id": "finance_ai_pack",
"visibility_policy": { "roles": ["Finance Manager"] }
}

8. Interactive Extensions (Live State & Intents)​

To support high-engagement applications (Chat, Fitness, Real-time monitoring), navigation nodes transition from static links to Dynamic Interaction Points.

8.1 Live Badges & Status​

Navigation nodes can declare a badge property containing a logical path to a server-side query or a real-time status stream.

  • Example: badge: "wms.queries.get_pending_picks"
  • Behavior: The Fidelity Port (UI) resolves this path and renders a badge (e.g., "12") or status indicator (e.g., "● Active") next to the node label. Updates are pushed in real-time via the NATS-backed WebSocket stream defined in ADR-0003.

8.2 Hardware & OS Intents​

Nodes can be mapped to specialized hardware inputs or OS-level voice commands.

  • hardware_intent: Maps a node to physical buttons (e.g., crown_click, sos_button, f1_key).
  • voice_alias: A list of keywords for voice-activated navigation ("Hey Siri, open Store Inventory").

8.3 Interaction Hints​

Hints provided to the Fidelity Port to optimize rendering for specialized devices:

  • interaction_mode: touch_optimized (Kiosks), rotary_scrollable (Watches), dpad_navigable (TVs).

Implementation Strategy​

  1. Phase 1: Update NavigationManifest schema to include badge, hardware_intent, and interaction_mode.
  2. Phase 2: Implement the FeatureEntitlementProtocol in framework-m-core.
  3. Phase 3: Update the NavigationPolicyEngine to enforce hierarchy: Entitlement -> Policy -> Decoration.
  4. Phase 4: Implement the Primary Rail & Contextual Drawer components in framework-m-ui.

Unresolved Questions​

  • Mobile UX: Should the Rail become a Bottom Tab Bar on mobile?
  • State Persistence: Should the "Last Active App" be stored in User Preferences or LocalStorage?
  • Server-Side Rendering: How does policy resolution affect initial HTML generation for SEO/speed?