git clone https://github.com/dcs-soni/awesome-claude-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/dcs-soni/awesome-claude-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/fullstack-feature-generator" ~/.claude/skills/dcs-soni-awesome-claude-skills-fullstack-feature-generator && rm -rf "$T"
fullstack-feature-generator/SKILL.mdFull Stack Feature Generator
A comprehensive skill for scaffolding complete features across the entire stack - from database schema to UI components - following clean architecture principles and your project's conventions.
Quick Start
When a user requests a new feature, follow this checklist:
Feature Generation Progress: - [ ] Step 1: Analyze requirements and existing patterns - [ ] Step 2: Design data model and schema - [ ] Step 3: Generate database layer (model + migration) - [ ] Step 4: Create API layer (routes + handlers + validation) - [ ] Step 5: Build service layer (business logic) - [ ] Step 6: Generate UI components (if applicable) - [ ] Step 7: Create tests for all layers - [ ] Step 8: Wire up imports and update indexes - [ ] Step 9: Verify and document
Workflow
Step 1: Analyze Requirements and Existing Patterns
Before generating any code, understand the context:
python .claude/skills/fullstack-feature-generator/scripts/analyze_project.py .
Gather:
- Feature name and description from user
- Existing project structure (see PATTERNS.md)
- Current ORM/database setup
- API framework in use
- Frontend framework (if applicable)
- Existing naming conventions
- Authentication/authorization patterns
Key Questions to Ask:
- What entities/data does this feature involve?
- Who can access this feature? (auth requirements)
- What CRUD operations are needed?
- Does it need real-time updates?
- Are there related features to integrate with?
Step 2: Design Data Model
Create the data model design before any code generation.
Output a schema proposal:
## Data Model: [FeatureName] ### Entities #### [EntityName] | Field | Type | Constraints | Description | | ----- | ---- | ----------- | ----------------- | | id | uuid | PK, auto | Unique identifier | | ... | ... | ... | ... | ### Relationships - [Entity A] has many [Entity B] - [Entity B] belongs to [Entity A] ### Indexes - idx*[entity]*[field] on [field] (for frequent queries)
Validation Questions:
- Are field names consistent with project conventions?
- Are relationships properly defined?
- Are indexes appropriate for expected queries?
Step 3: Generate Database Layer
Based on detected ORM, generate appropriate files:
For Prisma (Node.js)
// Add to prisma/schema.prisma model FeatureName { id String @id @default(cuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Add fields based on design }
Then run:
npx prisma migrate dev --name add_[feature_name] npx prisma generate
For Drizzle (Node.js)
// src/db/schema/[feature].ts import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"; export const featureName = pgTable("feature_name", { id: uuid("id").primaryKey().defaultRandom(), createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), // Add fields });
For SQLAlchemy (Python)
# src/models/feature_name.py from sqlalchemy import Column, String, DateTime from sqlalchemy.dialects.postgresql import UUID from src.db.base import Base import uuid from datetime import datetime class FeatureName(Base): __tablename__ = 'feature_name' id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Add fields
Step 4: Create API Layer
Generate routes, handlers, and validation.
Route Structure
Follow RESTful conventions:
| Method | Route | Handler | Description |
|---|---|---|---|
| GET | /api/[features] | list | List all with pagination |
| GET | /api/[features]/:id | getById | Get single by ID |
| POST | /api/[features] | create | Create new |
| PUT | /api/[features]/:id | update | Update existing |
| DELETE | /api/[features]/:id | delete | Delete by ID |
For Express/Node.js
// src/routes/[feature].routes.ts import { Router } from "express"; import { FeatureController } from "../controllers/[feature].controller"; import { validateRequest } from "../middleware/validate"; import { createFeatureSchema, updateFeatureSchema, } from "../schemas/[feature].schema"; const router = Router(); const controller = new FeatureController(); router.get("/", controller.list); router.get("/:id", controller.getById); router.post("/", validateRequest(createFeatureSchema), controller.create); router.put("/:id", validateRequest(updateFeatureSchema), controller.update); router.delete("/:id", controller.delete); export default router;
For FastAPI (Python)
# src/routes/[feature].py from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from src.schemas.[feature] import FeatureCreate, FeatureUpdate, FeatureResponse from src.services.[feature]_service import FeatureService from src.db.session import get_db router = APIRouter(prefix="/[features]", tags=["[features]"]) @router.get("/", response_model=list[FeatureResponse]) async def list_features(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): return FeatureService(db).list(skip=skip, limit=limit) @router.get("/{id}", response_model=FeatureResponse) async def get_feature(id: str, db: Session = Depends(get_db)): feature = FeatureService(db).get_by_id(id) if not feature: raise HTTPException(status_code=404, detail="Feature not found") return feature @router.post("/", response_model=FeatureResponse, status_code=201) async def create_feature(data: FeatureCreate, db: Session = Depends(get_db)): return FeatureService(db).create(data) @router.put("/{id}", response_model=FeatureResponse) async def update_feature(id: str, data: FeatureUpdate, db: Session = Depends(get_db)): return FeatureService(db).update(id, data) @router.delete("/{id}", status_code=204) async def delete_feature(id: str, db: Session = Depends(get_db)): FeatureService(db).delete(id)
Step 5: Build Service Layer
Encapsulate business logic separately from routes.
// src/services/[feature].service.ts import { db } from "../db"; import { featureTable } from "../db/schema"; import { eq } from "drizzle-orm"; import { CreateFeatureInput, UpdateFeatureInput, } from "../schemas/[feature].schema"; export class FeatureService { async list(options: { limit?: number; offset?: number } = {}) { const { limit = 50, offset = 0 } = options; return db.select().from(featureTable).limit(limit).offset(offset); } async getById(id: string) { const [result] = await db .select() .from(featureTable) .where(eq(featureTable.id, id)); return result ?? null; } async create(data: CreateFeatureInput) { const [result] = await db.insert(featureTable).values(data).returning(); return result; } async update(id: string, data: UpdateFeatureInput) { const [result] = await db .update(featureTable) .set({ ...data, updatedAt: new Date() }) .where(eq(featureTable.id, id)) .returning(); return result; } async delete(id: string) { await db.delete(featureTable).where(eq(featureTable.id, id)); } }
Step 6: Generate UI Components (if applicable)
For frontend features, create components following project conventions.
React Component Structure
src/features/[feature-name]/ ├── components/ │ ├── [Feature]List.tsx │ ├── [Feature]Card.tsx │ ├── [Feature]Form.tsx │ └── [Feature]Detail.tsx ├── hooks/ │ └── use[Feature].ts ├── api/ │ └── [feature].api.ts ├── types/ │ └── [feature].types.ts └── index.ts
See TEMPLATES.md for component templates.
Step 7: Create Tests
Generate tests for each layer:
API Tests
// tests/[feature].test.ts import { describe, it, expect, beforeAll, afterAll } from "vitest"; import request from "supertest"; import { app } from "../src/app"; import { db } from "../src/db"; describe("[Feature] API", () => { describe("POST /api/[features]", () => { it("should create a new [feature]", async () => { const response = await request(app) .post("/api/[features]") .send({ name: "Test Feature" }) .expect(201); expect(response.body).toHaveProperty("id"); expect(response.body.name).toBe("Test Feature"); }); it("should return 400 for invalid data", async () => { await request(app).post("/api/[features]").send({}).expect(400); }); }); describe("GET /api/[features]", () => { it("should return paginated list", async () => { const response = await request(app).get("/api/[features]").expect(200); expect(Array.isArray(response.body)).toBe(true); }); }); describe("GET /api/[features]/:id", () => { it("should return 404 for non-existent [feature]", async () => { await request(app).get("/api/[features]/non-existent-id").expect(404); }); }); });
Service Tests
// tests/services/[feature].service.test.ts import { describe, it, expect, beforeEach } from "vitest"; import { FeatureService } from "../../src/services/[feature].service"; describe("FeatureService", () => { let service: FeatureService; beforeEach(() => { service = new FeatureService(); }); describe("create", () => { it("should create and return new feature", async () => { const result = await service.create({ name: "Test" }); expect(result).toHaveProperty("id"); }); }); });
Step 8: Wire Up Imports
Update index files and register routes:
// src/routes/index.ts import featureRoutes from "./[feature].routes"; // Add to router registration app.use("/api/[features]", featureRoutes);
// src/db/schema/index.ts export * from "./[feature]";
Step 9: Verify and Document
Run verification checks:
# Type check npm run typecheck # Run tests npm test # Lint npm run lint
Create feature documentation:
## [Feature Name] ### Overview Brief description of what this feature does. ### API Endpoints | Method | Endpoint | Description | | ------ | --------------- | ----------- | | GET | /api/[features] | List all | | POST | /api/[features] | Create new | | ... | ... | ... | ### Data Model [Schema documentation] ### Usage Examples [Code examples]
Configuration
Feature Configuration File
Create
.claude/feature-config.yaml to customize generation:
# Feature generation preferences naming: style: camelCase # camelCase, snake_case, PascalCase plural: auto # auto-pluralize route names layers: database: true api: true service: true ui: true tests: true frameworks: api: express # express, fastify, fastapi, gin orm: prisma # prisma, drizzle, typeorm, sqlalchemy ui: react # react, vue, svelte, none test: vitest # vitest, jest, pytest templates: useCustom: false path: .claude/templates/
Examples
Example 1: Blog Posts Feature
User: "Add a blog posts feature with title, content, author, and published status"
Generated Files:
prisma/schema.prisma (updated) src/db/schema/posts.ts src/routes/posts.routes.ts src/controllers/posts.controller.ts src/services/posts.service.ts src/schemas/posts.schema.ts tests/posts.test.ts
Example 2: User Profiles Feature
User: "Create user profiles with avatar upload, bio, and social links"
Generated Files:
prisma/schema.prisma (updated) src/db/schema/profiles.ts src/routes/profiles.routes.ts src/services/profiles.service.ts src/services/upload.service.ts src/features/profile/components/ tests/profiles.test.ts
Anti-Patterns to Avoid
- Don't skip validation - Always generate input validation schemas
- Don't mix concerns - Keep routes thin, logic in services
- Don't forget auth - Add auth middleware where needed
- Don't ignore errors - Generate proper error handling
- Don't skip tests - At minimum, generate happy path tests
Related Skills
- codebase-onboarding - Understand project before generating
- api-documentation - Document generated endpoints
- verification-layer - Verify generated code works