Files
leo-claude-mktplace/plugins/saas-react-platform/skills/routing-conventions.md
lmiranda 2d51df7a42 feat(marketplace): command consolidation + 8 new plugins (v8.1.0 → v9.0.0) [BREAKING]
Phase 1b: Rename all ~94 commands across 12 plugins to /<noun> <action>
sub-command pattern. Git-flow consolidated from 8→5 commands (commit
variants absorbed into --push/--merge/--sync flags). Dispatch files,
name: frontmatter, and cross-reference updates for all plugins.

Phase 2: Design documents for 8 new plugins in docs/designs/.

Phase 3: Scaffold 8 new plugins — saas-api-platform, saas-db-migrate,
saas-react-platform, saas-test-pilot, data-seed, ops-release-manager,
ops-deploy-pipeline, debug-mcp. Each with plugin.json, commands, agents,
skills, README, and claude-md-integration. Marketplace grows from 12→20.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 14:52:11 -05:00

175 lines
4.8 KiB
Markdown

---
name: routing-conventions
description: File-based routing (Next.js), react-router conventions, dynamic routes, layouts, and middleware
---
# Routing Conventions
## Purpose
Define routing patterns for each supported framework. This skill ensures route scaffolding produces the correct file structure, naming conventions, and framework-specific boilerplate.
---
## Next.js App Router (v13.4+)
### File Conventions
| File | Purpose |
|------|---------|
| `page.tsx` | Route UI — required to make segment publicly accessible |
| `layout.tsx` | Shared layout wrapping child pages — persists across navigations |
| `loading.tsx` | Loading UI shown while page is loading (Suspense boundary) |
| `error.tsx` | Error UI shown when page throws (must be client component) |
| `not-found.tsx` | 404 UI for segment |
| `route.ts` | API route handler (GET, POST, etc.) |
### Route Patterns
```
app/
page.tsx # /
about/page.tsx # /about
blog/page.tsx # /blog
blog/[slug]/page.tsx # /blog/:slug (dynamic)
dashboard/
layout.tsx # Shared dashboard layout
page.tsx # /dashboard
settings/page.tsx # /dashboard/settings
(marketing)/ # Route group (no URL segment)
pricing/page.tsx # /pricing
```
### Dynamic Routes
| Pattern | File Path | URL Match |
|---------|-----------|-----------|
| Dynamic segment | `[id]/page.tsx` | `/users/123` |
| Catch-all | `[...slug]/page.tsx` | `/docs/a/b/c` |
| Optional catch-all | `[[...slug]]/page.tsx` | `/docs` or `/docs/a/b` |
### Server vs Client Components
- Pages are Server Components by default
- Add `'use client'` directive only when using: `useState`, `useEffect`, `onClick`, browser APIs
- Pass data from server to client via props, not through context
## Next.js Pages Router (Legacy)
### File Conventions
```
pages/
index.tsx # /
about.tsx # /about
blog/index.tsx # /blog
blog/[slug].tsx # /blog/:slug
_app.tsx # App wrapper (layouts)
_document.tsx # HTML document customization
404.tsx # Custom 404 page
api/users.ts # API route: /api/users
```
### Data Fetching
| Method | When | Use Case |
|--------|------|----------|
| `getServerSideProps` | Every request | Dynamic data, auth-gated pages |
| `getStaticProps` | Build time | Blog posts, marketing pages |
| `getStaticPaths` | Build time | Dynamic routes with static generation |
## React Router (v6+)
### Route Definition
```typescript
// router.tsx
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));
const router = createBrowserRouter([
{
path: '/',
element: <RootLayout />,
errorElement: <ErrorBoundary />,
children: [
{ index: true, element: <Home /> },
{
path: 'dashboard',
element: <Suspense fallback={<Loading />}><Dashboard /></Suspense>,
},
{
path: 'users/:id',
element: <UserProfile />,
loader: userLoader,
},
],
},
]);
```
### Layout Pattern
```typescript
// layouts/RootLayout.tsx
import { Outlet } from 'react-router-dom';
export function RootLayout() {
return (
<div>
<Header />
<main>
<Outlet />
</main>
<Footer />
</div>
);
}
```
## Protected Routes
### Pattern: Auth Guard Component
```typescript
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isLoading } = useAuth();
if (isLoading) return <LoadingSkeleton />;
if (!isAuthenticated) return <Navigate to="/login" replace />;
return <>{children}</>;
}
```
### App Router: Middleware
```typescript
// middleware.ts (project root)
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('session');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = { matcher: ['/dashboard/:path*'] };
```
## Error Boundaries
Every page route should have an error boundary:
- App Router: `error.tsx` file in route segment (automatically client component)
- React Router: `errorElement` prop on route definition
- Fallback: Generic `ErrorBoundary` component wrapping page content
Include retry functionality and user-friendly error message. Log error details to console (placeholder for error reporting service).