Files
wild-web-app/docs/specs/routing-contract.md
2025-10-12 17:44:54 +00:00

12 KiB

Wild Cloud Web App Routing Contract

Front Matter

Module Name: routing Module Type: Infrastructure Version: 1.0.0 Status: Draft Last Updated: 2025-10-12 Owner: Wild Cloud Development Team

Dependencies

  • react: ^19.1.0
  • react-router: ^7.0.0 (to be added)

Consumers

  • All page components within Wild Cloud Web App
  • Navigation components (AppSidebar)
  • Instance context management
  • External navigation links

Purpose

This module defines the routing system for the Wild Cloud web application, providing declarative navigation between pages, URL-based state management, and integration with the existing instance context system.

Public API

Router Configuration

The routing system provides a centralized router configuration that manages all application routes.

Primary Routes

interface RouteDefinition {
  path: string;
  element: React.ComponentType;
  loader?: () => Promise<unknown>;
  errorElement?: React.ComponentType;
}

Root Route:

  • Path: /
  • Purpose: Landing page and instance selector
  • Authentication: None required
  • Data Loading: None

Instance Routes:

  • Path Pattern: /instances/:instanceId/*
  • Purpose: All instance-specific pages
  • Authentication: Instance must exist
  • Data Loading: Instance configuration loaded at this level

Instance-Scoped Routes

All routes under /instances/:instanceId/:

Path Purpose Data Dependencies
dashboard Overview and quick status Instance config, cluster status
operations Operation monitoring and logs Active operations list
cluster/health Cluster health metrics Node status, etcd health
cluster/access Kubeconfig/Talosconfig download Instance credentials
secrets Secrets management interface Instance secrets (redacted)
services Base services management Installed services list
utilities Utilities panel Available utilities
cloud Cloud configuration Cloud settings
dns DNS management DNS configuration
dhcp DHCP management DHCP configuration
pxe PXE boot configuration PXE assets and config
infrastructure Cluster nodes Node list and status
cluster Cluster services Kubernetes services
apps Application management Installed apps
advanced Advanced settings System configuration

Navigation Hooks

useNavigate

function useNavigate(): NavigateFunction;

interface NavigateFunction {
  (to: string | number, options?: NavigateOptions): void;
}

interface NavigateOptions {
  replace?: boolean;
  state?: unknown;
}

Purpose: Programmatic navigation within the application.

Examples:

// Navigate to a specific instance dashboard
navigate('/instances/prod-cluster/dashboard');

// Navigate back
navigate(-1);

// Replace current history entry
navigate('/instances/prod-cluster/operations', { replace: true });

Error Conditions:

  • Invalid paths are handled by error boundary
  • Missing instance IDs redirect to root

useParams

function useParams<T extends Record<string, string>>(): T;

Purpose: Access URL parameters, primarily for extracting instance ID.

Example:

const { instanceId } = useParams<{ instanceId: string }>();

Error Conditions:

  • Returns undefined for missing parameters
  • Type safety through TypeScript generics

useLocation

interface Location {
  pathname: string;
  search: string;
  hash: string;
  state: unknown;
  key: string;
}

function useLocation(): Location;

Purpose: Access current location information for conditional rendering or analytics.

useSearchParams

function useSearchParams(): [
  URLSearchParams,
  (nextInit: URLSearchParams | ((prev: URLSearchParams) => URLSearchParams)) => void
];

Purpose: Read and write URL query parameters for filters, sorting, and view state.

Example:

const [searchParams, setSearchParams] = useSearchParams();
const view = searchParams.get('view') || 'grid';
setSearchParams({ view: 'list' });
interface LinkProps {
  to: string;
  replace?: boolean;
  state?: unknown;
  children: React.ReactNode;
  className?: string;
}

function Link(props: LinkProps): JSX.Element;

Purpose: Declarative navigation component for user-triggered navigation.

Example:

<Link to="/instances/prod-cluster/dashboard">
  Go to Dashboard
</Link>

Behavior:

  • Prevents default browser navigation
  • Supports keyboard navigation (Enter)
  • Maintains browser history
  • Supports Ctrl/Cmd+Click to open in new tab
interface NavLinkProps extends LinkProps {
  caseSensitive?: boolean;
  end?: boolean;
  className?: string | ((props: { isActive: boolean; isPending: boolean }) => string);
  style?: React.CSSProperties | ((props: { isActive: boolean; isPending: boolean }) => React.CSSProperties);
}

function NavLink(props: NavLinkProps): JSX.Element;

Purpose: Navigation links that are aware of their active state.

Example:

<NavLink
  to="/instances/prod-cluster/dashboard"
  className={({ isActive }) => isActive ? 'active-nav-link' : 'nav-link'}
>
  Dashboard
</NavLink>

Data Models

Route Parameters

interface InstanceRouteParams {
  instanceId: string;
}

Field Specifications:

  • instanceId: String identifier for the instance
    • Required: Yes
    • Format: Alphanumeric with hyphens, 1-64 characters
    • Validation: Must correspond to an existing instance
    • Example: "prod-cluster", "staging-env"

Navigation State

interface NavigationState {
  from?: string;
  returnTo?: string;
  [key: string]: unknown;
}

Purpose: Preserve state across navigation, such as return URLs or form data.

Example:

navigate('/instances/prod-cluster/secrets', {
  state: { returnTo: '/instances/prod-cluster/dashboard' }
});

Error Model

Route Errors

Error Code Condition User Impact Recovery Action
ROUTE_NOT_FOUND Path does not match any route 404 page displayed Redirect to root or show available routes
INSTANCE_NOT_FOUND Instance ID in URL does not exist Error boundary with message Redirect to instance selector at /
INVALID_INSTANCE_ID Instance ID format invalid Validation error displayed Show error message, redirect to /
NAVIGATION_CANCELLED User cancelled pending navigation No visible change Continue at current route
LOADER_ERROR Route data loader failed Error boundary with retry option Show error, allow retry or navigate away

Error Response Format

interface RouteError {
  code: string;
  message: string;
  status?: number;
  cause?: Error;
}

Example:

{
  code: "INSTANCE_NOT_FOUND",
  message: "Instance 'unknown-instance' does not exist",
  status: 404
}

Performance Characteristics

Route Transition Times

  • Static Routes: < 50ms (no data loading)
  • Instance Routes: < 200ms (with instance config loading)
  • Heavy Data Routes: < 500ms (with large data sets)

Bundle Size

  • Router Core: ~45KB (minified)
  • Navigation Components: ~5KB
  • Per-Route Code Splitting: Enabled by default

Memory Usage

  • History Stack: O(n) where n is number of navigation entries
  • Route Cache: Configurable, default 10 entries
  • Cleanup: Automatic on unmount

Configuration Requirements

Environment Variables

None required. All routing is handled client-side.

Route Configuration

interface RouterConfig {
  basename?: string;
  future?: {
    v7_startTransition?: boolean;
    v7_relativeSplatPath?: boolean;
  };
}

basename: Optional base path for deployment in subdirectories

  • Default: "/"
  • Example: "/app" if deployed to example.com/app/

Conformance Criteria

Functional Requirements

  1. F-ROUTE-01: Router SHALL render correct component for each defined route
  2. F-ROUTE-02: Router SHALL extract instance ID from URL parameters
  3. F-ROUTE-03: Navigation hooks SHALL update browser history
  4. F-ROUTE-04: Back/forward browser buttons SHALL work correctly
  5. F-ROUTE-05: Invalid routes SHALL display error boundary
  6. F-ROUTE-06: Instance routes SHALL validate instance existence
  7. F-ROUTE-07: Link components SHALL support keyboard navigation
  8. F-ROUTE-08: Routes SHALL support lazy loading of components

Non-Functional Requirements

  1. NF-ROUTE-01: Route transitions SHALL complete in < 200ms for cached routes
  2. NF-ROUTE-02: Router SHALL support browser back/forward without page reload
  3. NF-ROUTE-03: Navigation SHALL preserve scroll position when appropriate
  4. NF-ROUTE-04: Router SHALL be compatible with React 19.1+
  5. NF-ROUTE-05: Routes SHALL be defined declaratively in configuration
  6. NF-ROUTE-06: Router SHALL integrate with existing ErrorBoundary
  7. NF-ROUTE-07: Navigation SHALL work with InstanceContext

Integration Requirements

  1. I-ROUTE-01: Router SHALL integrate with InstanceContext
  2. I-ROUTE-02: AppSidebar SHALL use routing for navigation
  3. I-ROUTE-03: All page components SHALL be routed
  4. I-ROUTE-04: Router SHALL integrate with React Query for data loading
  5. I-ROUTE-05: Router SHALL support Vite code splitting

API Stability

Versioning Scheme: Semantic Versioning (SemVer)

Stability Level: Stable (1.0.0+)

Breaking Changes:

  • Route path changes require major version bump
  • Hook signature changes require major version bump
  • Added routes or optional parameters are minor version bumps

Deprecation Policy:

  • Deprecated routes supported for 2 minor versions
  • Console warnings for deprecated route usage
  • Migration guide provided for breaking changes

Security Considerations

Route Protection

Instance routes SHALL verify:

  1. Instance ID exists in available instances
  2. User has permission to access instance (future)

XSS Prevention

  • All route parameters SHALL be sanitized
  • User-provided navigation state SHALL be validated
  • No executable code in route parameters

CSRF Protection

Not applicable - all navigation is client-side without authentication tokens.

Browser Compatibility

Supported Browsers:

  • Chrome/Edge: Last 2 versions
  • Firefox: Last 2 versions
  • Safari: Last 2 versions

Required Browser APIs:

  • History API
  • URL API
  • ES6+ JavaScript features

Examples

Basic Navigation

// In a component
import { useNavigate } from 'react-router';

function InstanceCard({ instance }) {
  const navigate = useNavigate();

  const handleClick = () => {
    navigate(`/instances/${instance.id}/dashboard`);
  };

  return <button onClick={handleClick}>Open {instance.name}</button>;
}

Using Route Parameters

// In an instance page
import { useParams } from 'react-router';
import { useInstanceContext } from '../hooks';

function DashboardPage() {
  const { instanceId } = useParams<{ instanceId: string }>();
  const { setCurrentInstance } = useInstanceContext();

  useEffect(() => {
    setCurrentInstance(instanceId);
  }, [instanceId, setCurrentInstance]);

  return <div>Dashboard for {instanceId}</div>;
}

Sidebar Integration

// AppSidebar using NavLink
import { NavLink } from 'react-router';

function AppSidebar() {
  const { instanceId } = useParams();

  return (
    <nav>
      <NavLink
        to={`/instances/${instanceId}/dashboard`}
        className={({ isActive }) => isActive ? 'active' : ''}
      >
        Dashboard
      </NavLink>
    </nav>
  );
}

Version History

Version Date Changes
1.0.0 2025-10-12 Initial contract definition