| name | add-feature |
| description | Scaffold a new frontend feature module with page, components, API service, and hooks. Use whenever the user wants to add a new page, dashboard section, UI module, or frontend feature to the React app. |
| allowed-tools | Read, Write, Edit, Glob, Grep, Bash, mcp__context7__resolve-library-id, mcp__context7__query-docs |
| user-invocable | true |
Add Frontend Feature
Scaffold a new feature module following the project's React + TypeScript conventions.
Arguments
{feature} — Feature name in kebab-case (e.g., alerts, rollouts)
Structure
Creates the following structure under web/src/features/{feature}/:
{feature}/
├── pages/
│ └── {feature}-page.tsx
└── components/
└── {feature}-overview.tsx
And adds an API service at web/src/api/services/{feature}.api.ts.
1. API Service (web/src/api/services/{feature}.api.ts)
import { apiRequest } from '../client'
import { appendTenantId } from './tenant'
import type { PaginatedResponse } from '../types'
export interface {Entity} {
id: string
}
const BASE_PATH = '/api/{feature}'
export const {feature}Api = {
async getAll(page = 1, pageSize = 20): Promise<PaginatedResponse<{Entity}>> {
const params = new URLSearchParams()
appendTenantId(params)
params.set('pageNumber', page.toString())
params.set('pageSize', pageSize.toString())
return apiRequest({ url: BASE_PATH, params })
},
async getById(id: string): Promise<{Entity}> {
const params = new URLSearchParams()
appendTenantId(params)
return apiRequest({ url: `${BASE_PATH}/${id}`, params })
},
}
2. Page (web/src/features/{feature}/pages/{feature}-page.tsx)
import { {Feature}Overview } from '../components/{feature}-overview'
export function {Feature}Page() {
return (
<div className="container mx-auto py-6">
<{Feature}Overview />
</div>
)
}
3. Overview Component (web/src/features/{feature}/components/{feature}-overview.tsx)
import { useQuery } from '@tanstack/react-query'
import { {feature}Api } from '@/api/services/{feature}.api'
export function {Feature}Overview() {
const { data, isLoading, error } = useQuery({
queryKey: ['{feature}'],
queryFn: () => {feature}Api.getAll(),
staleTime: 30_000,
})
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error loading {feature}</div>
return (
<div>
<h1 className="text-2xl font-bold mb-4">{Feature}</h1>
{/* Render data */}
</div>
)
}
4. Add Route
Find the router configuration file and add the route automatically:
grep -rl "createBrowserRouter\|RouteObject\|path:" web/src/routes/ web/src/App.tsx 2>/dev/null | head -1
Read the router file, then add the import and route entry:
import { {Feature}Page } from '@/features/{feature}/pages/{feature}-page'
{ path: '/{feature}', element: <{Feature}Page /> }
If the router structure is unclear or uses a pattern you don't recognize, show the user what to add and where instead of guessing.
Checklist
Guidelines
- Follow existing features (e.g.,
devices/, bundles/) as reference
- Keep components small and focused
- Use barrel exports where the project already does
- If using unfamiliar TanStack Query patterns (infinite queries, optimistic updates, prefetching), use context7 to look up the current API
Output
After scaffolding, report:
## Scaffolded: {Feature} frontend feature
Files created:
- `web/src/api/services/{feature}.api.ts`
- `web/src/features/{feature}/pages/{feature}-page.tsx`
- `web/src/features/{feature}/components/{feature}-overview.tsx`
- Route added to `{router-file}`
Next: Run `cd web && npm run dev` to preview, or `/verify-feature /{feature}` to verify.
Error Handling
- Router file not found: Show the route snippet and ask the user where to add it.
- API client (
apiRequest) doesn't exist: Check web/src/api/client.ts — if the pattern differs, adapt to the existing API client setup.
- Feature directory already exists: Warn the user and ask whether to overwrite or extend.
Related Skills
/add-query to create the backend API endpoint this feature calls
/add-command to create mutation endpoints