Skip to content

Feature Scaffolding (/feature-scaffold)

In plain terms

Use this when building something brand new — a page, feature, or endpoint that doesn't exist yet.

What this skill does

Use when building anything new — a page, feature, module, entity, endpoint, component, or view that doesn't exist yet. Triggers on any request to create, build, add, implement, or introduce new functionality.

[!NOTE] Use this when creating anything new in the codebase — a feature, page, module, component, API endpoint, or entity that doesn't already exist. For extending an existing page, use /full-stack-extension instead.

Trigger Conditions

  • Any request to create, build, add, implement, or introduce new functionality
  • Keywords: "Create a new page", "Build a feature", "Add a module for X", "New view", "New endpoint", "Add a section", "Implement X", "I need a new...", "Set up...", "Make a..."
  • Also trigger when: the user describes desired behavior that doesn't map to any existing code

1. Planning

  • [ ] Architecture Check: Review docs/ARCHITECTURE.md for directory structure and naming conventions
  • [ ] Schema: Does this feature need new DB tables? If yes, run /db-migration first
  • [ ] OpenAPI: After backend changes, run /openapi-sync to regenerate frontend types

2. Backend Scaffold

  • [ ] Model: Add or update a SQLModel model in backend/app/models/[feature].py
  • [ ] Schema: Create Pydantic request/response schemas in backend/app/schemas/[feature].py
  • [ ] Router: Create route handlers in backend/app/api/[feature].py
from fastapi import APIRouter, Depends, HTTPException
from app.core.auth import require_auth, require_permission

router = APIRouter(prefix="/[feature]", tags=["[feature]"])

@router.get("/")
async def list_features(user=Depends(require_auth)):
    # Query logic here
    return data
  • [ ] Registration: Register the router in backend/app/api/__init__.py (or the main router file)
  • [ ] Migration: If schema changed, run Alembic: alembic revision --autogenerate -m "add [feature]" then alembic upgrade head
  • [ ] Validation: All inputs validated via Pydantic v2 schemas

3. Frontend Scaffold

  • [ ] Types: Run /openapi-sync — never manually define types that exist in @/types/api
  • [ ] Query/Mutation: Add TanStack Query hooks in frontend/src/hooks/use[Feature].ts:
    export function useFeature() {
        const query = useQuery({
            queryKey: ['[feature]'],
            queryFn: () => apiRequest('/api/[feature]'),
        });
    
        const createMutation = useMutation({
            mutationFn: (data: CreateFeatureInput) => apiRequest('/api/[feature]', { method: 'POST', body: data }),
            onSuccess: () => {
                queryClient.invalidateQueries({ queryKey: ['[feature]'] });
            },
        });
    
        return {
            features: query.data || [],
            isLoading: query.isLoading,
            createFeature: createMutation.mutateAsync,
        };
    }
    
  • [ ] Component: Create React page/components under frontend/src/app/ or frontend/src/components/
  • No window.alert() or window.confirm()
  • Use <FormattedCurrency /> for money, formatDateLocal() for dates
  • Empty states: never blank — use illustration or helpful text
  • Loading states: shimmer (animate-pulse on gray blocks)
  • [ ] Routing: Register the new page in the app router
  • [ ] Networking: All API calls must use apiRequest from @/lib/queryClient

4. Security

  • [ ] Auth: Every admin/protected route must declare require_auth and require_permission dependencies
  • [ ] Validation: Backend uses Pydantic v2; frontend uses Zod + React Hook Form

5. Tests (REQUIRED)

  • [ ] Run /test-sync to automatically create tests for all new/changed files
  • [ ] Verify: All tests pass before proceeding to verification

6. Verification

  • [ ] Integration: Frontend calls backend — verify in browser network tab
  • [ ] Design: Run /architecture-review to verify UI compliance
  • [ ] Types: Run cd frontend && npm run type-check && cd ../backend && python -m mypy app/

[!NOTE] Use this when creating anything new in the codebase — a feature, page, module, component, API endpoint, or entity that doesn't already exist. For extending an existing page, use /full-stack-extension instead.

Trigger Conditions

  • Any request to create, build, add, implement, or introduce new functionality
  • Keywords: "Create a new page", "Build a feature", "Add a module for X", "New view", "New endpoint", "Add a section", "Implement X", "I need a new...", "Set up...", "Make a..."
  • Also trigger when: the user describes desired behavior that doesn't map to any existing code

1. Planning

  • [ ] Architecture Check: Review docs/ARCHITECTURE.md for directory structure and naming conventions
  • [ ] Schema: Does this feature need new DB tables? If yes, run /db-migration first
  • [ ] Routing: Decide the URL path — SalesFocus uses Wouter (not React Router)

2. Backend Scaffold

  • [ ] Route file: Create backend/src/routes/[feature].ts
import { Router } from 'express';
import type { NextFunction, Response } from 'express';
import { db } from '../db/index.js';
import { authenticate } from '../middleware/auth.js';
import type { AuthRequest } from '../middleware/auth.js';

const router = Router();

router.get('/', authenticate, async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
        const data = await db.select().from(featureTable);
        res.json(data);
    } catch (error) {
        next(error); // ALWAYS use next(error) — never manual res.status(500)
    }
});

export default router;
  • [ ] Zod validation: Add validation schema to backend/src/validation/[feature].schema.ts
  • [ ] Register route: Add to backend/src/server.ts:
    import featureRouter from './routes/[feature].js';
    app.use('/api/[feature]', authenticate, featureRouter);
    
  • [ ] Explicit .js extensions: All local imports MUST use .js extension (TypeScript ESM requirement)

3. Frontend Scaffold

  • [ ] Service: Create services/domains/[feature]Service.ts (or add methods to services/apiClient.ts if small):

    import apiClient from '../apiClient';
    export const get[Feature]s = () => apiClient.get('/[feature]').then(r => r.data);
    

  • [ ] Hook: Create hooks/use[Feature].ts as a domain hook:

    export function use[Feature]() {
        const queryClient = useQueryClient();
        const toast = useToast();
    
        const query = useQuery({
            queryKey: ['[feature]'],
            queryFn: get[Feature]s,
        });
    
        const createMutation = useMutation({
            mutationFn: (data: Create[Feature]Input) => createFeature,
            onSuccess: () => {
                queryClient.invalidateQueries({ queryKey: ['[feature]'] });
                toast.success('[Feature] created');
            },
        });
    
        return {
            [feature]s: query.data || [],
            isLoading: query.isLoading,
            create[Feature]: createMutation.mutateAsync,
        };
    }
    

  • [ ] Component: Create components/[Feature]View.tsx or components/[Feature]Page.tsx

  • No window.alert() or window.confirm()
  • Use <FormattedCurrency /> for money, formatDateLocal() for dates
  • Empty states: never blank — use illustration or helpful text
  • Loading states: shimmer (animate-pulse on gray blocks)

  • [ ] Routing: Add to App.tsx using Wouter:

    import { Route } from 'wouter';
    <Route path="/[feature]" component={[Feature]View} />
    

  • [ ] Navigation: If it's a nav item, add to lib/navigation.ts

  • Admin-only pages: also add <AdminRoute> wrapper in App.tsx

4. Tests (REQUIRED)

  • [ ] Run /test-sync to automatically create tests for all new/changed files
  • [ ] Verify: All tests pass before proceeding to verification

5. Verification

  • [ ] Integration: Frontend calls backend — verify in browser network tab
  • [ ] Design: Run /architecture-review to verify UI compliance (Twycis colors, rounded buttons, etc.)
  • [ ] Types: Run cd backend && npm run type-check && npm run type-check