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.0react-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' });
Link Component
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
NavLink Component
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 toexample.com/app/
Conformance Criteria
Functional Requirements
- F-ROUTE-01: Router SHALL render correct component for each defined route
- F-ROUTE-02: Router SHALL extract instance ID from URL parameters
- F-ROUTE-03: Navigation hooks SHALL update browser history
- F-ROUTE-04: Back/forward browser buttons SHALL work correctly
- F-ROUTE-05: Invalid routes SHALL display error boundary
- F-ROUTE-06: Instance routes SHALL validate instance existence
- F-ROUTE-07: Link components SHALL support keyboard navigation
- F-ROUTE-08: Routes SHALL support lazy loading of components
Non-Functional Requirements
- NF-ROUTE-01: Route transitions SHALL complete in < 200ms for cached routes
- NF-ROUTE-02: Router SHALL support browser back/forward without page reload
- NF-ROUTE-03: Navigation SHALL preserve scroll position when appropriate
- NF-ROUTE-04: Router SHALL be compatible with React 19.1+
- NF-ROUTE-05: Routes SHALL be defined declaratively in configuration
- NF-ROUTE-06: Router SHALL integrate with existing ErrorBoundary
- NF-ROUTE-07: Navigation SHALL work with InstanceContext
Integration Requirements
- I-ROUTE-01: Router SHALL integrate with InstanceContext
- I-ROUTE-02: AppSidebar SHALL use routing for navigation
- I-ROUTE-03: All page components SHALL be routed
- I-ROUTE-04: Router SHALL integrate with React Query for data loading
- 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:
- Instance ID exists in available instances
- 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 |