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>
This commit is contained in:
174
plugins/saas-react-platform/skills/routing-conventions.md
Normal file
174
plugins/saas-react-platform/skills/routing-conventions.md
Normal file
@@ -0,0 +1,174 @@
|
||||
---
|
||||
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).
|
||||
Reference in New Issue
Block a user