From jaan-to
Generates production-ready backend code with routes, data models, service layers, and validation from API contracts, task breakdowns, and data models. Adapts to any tech stack.
How this skill is triggered — by the user, by Claude, or both
Slash command
/jaan-to:backend-scaffoldThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Generate production-ready backend code scaffolds from upstream specs — multi-stack, tech.md-adaptive.
Generate production-ready backend code scaffolds from upstream specs — multi-stack, tech.md-adaptive.
$JAAN_CONTEXT_DIR/tech.md - Tech stack context (CRITICAL — determines framework, DB, patterns)
#current-stack, #frameworks, #constraints, #patterns$JAAN_CONTEXT_DIR/config.md - Project configuration$JAAN_TEMPLATES_DIR/jaan-to-backend-scaffold.template.md - Output template$JAAN_LEARN_DIR/jaan-to-backend-scaffold.learn.md - Past lessons (loaded in Pre-Execution)${CLAUDE_PLUGIN_ROOT}/docs/extending/language-protocol.md - Language resolution protocolUpstream Artifacts: $ARGUMENTS
Accepts 1-3 file paths or descriptions:
/jaan-to:backend-api-contract output: api.yaml)/jaan-to:backend-task-breakdown output)/jaan-to:backend-data-model output)MANDATORY — Read and execute ALL steps in: ${CLAUDE_PLUGIN_ROOT}/docs/extending/pre-execution-protocol.md
Skill name: backend-scaffold
Execute: Step 0 (Init Guard) → A (Load Lessons) → B (Resolve Template) → C (Offer Template Seeding)
Also read context files if available:
$JAAN_CONTEXT_DIR/tech.md — Know the tech stack for framework-specific code generation$JAAN_CONTEXT_DIR/config.md — Project configurationRead and apply language protocol: ${CLAUDE_PLUGIN_ROOT}/docs/extending/language-protocol.md
Override field for this skill: language_backend-scaffold
Language exception: Generated code output (variable names, code blocks, schemas, SQL, API specs) is NOT affected by this setting and remains in the project's programming language.
ultrathink
Use extended reasoning for:
For each provided path:
Present input summary:
INPUT SUMMARY
─────────────
Sources Found: {list}
Sources Missing: {list with fallback suggestions}
Entities: {extracted entity names}
Endpoints: {count from API contract}
Tables: {count from data model}
Tasks: {count from task breakdown}
Read $JAAN_CONTEXT_DIR/tech.md:
#current-stack (default: Fastify v5+)#current-stack (default: PostgreSQL)#patterns (auth, error handling, logging)AskUserQuestion for items not in tech.md:
Present directory tree, file list, resource count:
SCAFFOLD PLAN
═════════════
STACK: {framework} + {database} + {orm}
PROJECT STRUCTURE
─────────────────
{directory tree showing all files to generate}
FILES ({count} total)
─────────────────────
{numbered list with file purpose}
RESOURCES ({count})
───────────────────
{resource list with operations}
Use AskUserQuestion:
Do NOT proceed to Phase 2 without explicit approval.
All files in $JAAN_OUTPUTS_DIR/backend/scaffold/{id}-{slug}/:
{id}-{slug}/
├── {id}-{slug}.md # Main doc (setup guide + architecture)
├── {id}-{slug}-routes.ts # Route handlers (all resources)
├── {id}-{slug}-services.ts # Service layer (business logic)
├── {id}-{slug}-schemas.ts # Validation schemas
├── {id}-{slug}-middleware.ts # Auth + error handling middleware
├── {id}-{slug}-prisma.prisma # ORM data model
├── {id}-{slug}-config.ts # Package.json + tsconfig content
└── {id}-{slug}-readme.md # Setup + run instructions
File extensions adapt to detected stack (.ts for Node.js, .php for PHP, .go for Go).
Read $JAAN_TEMPLATES_DIR/jaan-to-backend-scaffold.template.md and populate all sections based on Phase 1 analysis.
If tech stack needed, extract sections from tech.md:
#current-stack#frameworks#constraints#patternsValidate generated output against checklist:
If any check fails, fix before preview.
Present generated output summary. Use AskUserQuestion:
source "${CLAUDE_PLUGIN_ROOT}/scripts/lib/id-generator.sh"
SUBDOMAIN_DIR="$JAAN_OUTPUTS_DIR/backend/scaffold"
mkdir -p "$SUBDOMAIN_DIR"
NEXT_ID=$(generate_next_id "$SUBDOMAIN_DIR")
slug="{project-name-slug}"
OUTPUT_FOLDER="${SUBDOMAIN_DIR}/${NEXT_ID}-${slug}"
Preview output configuration:
Output Configuration
- ID: {NEXT_ID}
- Folder:
$JAAN_OUTPUTS_DIR/backend/scaffold/{NEXT_ID}-{slug}/- Main file:
{NEXT_ID}-{slug}.md
mkdir -p "$OUTPUT_FOLDER"$OUTPUT_FOLDERsource "${CLAUDE_PLUGIN_ROOT}/scripts/lib/index-updater.sh"
add_to_index \
"$SUBDOMAIN_DIR/README.md" \
"$NEXT_ID" \
"${NEXT_ID}-${slug}" \
"{Project Title}" \
"{Executive summary — 1-2 sentences}"
Scaffold written to:
$JAAN_OUTPUTS_DIR/backend/scaffold/{NEXT_ID}-{slug}/Index updated:$JAAN_OUTPUTS_DIR/backend/scaffold/README.md
Scaffold generated successfully!
Next Steps:
- Copy scaffold files to your project directory
- Run
npm install(or equivalent) to install dependencies- Run
/jaan-to:dev-integration-planto plan integration with existing code- Run
/jaan-to:dev-test-planto generate test plan
Use AskUserQuestion:
If "Learn from this": Run /jaan-to:learn-add backend-scaffold "{feedback}"
@fastify/autoload v6 for file-based route loading — register twice (plugins with encapsulate: false, routes encapsulated per resource); add ignorePattern: /.*\.(?:schema|service)\.ts/ to prevent non-plugin files from being auto-loaded as routesfastify-type-provider-zod v6.1+ with validatorCompiler/serializerCompiler set once at app level; must call withTypeProvider<ZodTypeProvider>() on each encapsulated context (type providers don't propagate across encapsulation boundaries)globalThis pattern to prevent connection pool exhaustion during hot-reload; conditional assignment based on NODE_ENV.schema.ts files, export z.infer<> types; derive from OpenAPI contract component schemassetErrorHandler (NOT Express-style middleware) — use hasZodFastifySchemaValidationErrors(error) for 400 (NOT instanceof ZodError which fails across module boundaries), use isResponseSerializationError(error) for 500 serialization errors; map PrismaClientKnownRequestError P2002 → 409 (unique constraint), P2003 → 409 (foreign key), P2025 → 404 (not found), all others → 500; always set Content-Type: application/problem+jsontype (URI), title, status, detail, instance; extension errors[] for validation detailsvi.mock(); callable from CRON jobs or queue consumers outside HTTP context; use Prisma $transaction for cross-service operationsindex.ts (routes) + {resource}.schema.ts (Zod) + {resource}.service.ts (logic) per resourcefastify-tsconfig v2 with target: "ES2023", module: "NodeNext", strict: true"type": "module" and moduleResolution: "NodeNext", all imports MUST include .js extensions — NodeNext mirrors Node.js runtime behavior; never use moduleResolution: "bundler" for backends (allows vague imports that fail at runtime)DATABASE_URL, PORT, HOST, NODE_ENV, LOG_LEVEL, CORS_ORIGIN--env-file=.env flag for loadingdev (tsx watch), build (tsc), start, lint, test, db:generate, db:migrate:dev, db:migrate:deploy, db:push, db:seed, db:studio, postinstall (prisma generate)The skill reads tech.md #current-stack to determine which stack to generate:
| tech.md value | Framework | ORM/DB | Validation | Output |
|---|---|---|---|---|
| Node.js / TypeScript | Fastify v5+ | Prisma | Zod + type-provider v6.1 | .ts files |
| PHP | Laravel 12 / Symfony 7 | Eloquent / Doctrine | Form Requests / Symfony Validator | .php files |
| Go | Chi / stdlib (Go 1.22+) | sqlc / GORM | go-playground/validator | .go files |
PHP Stack (Laravel) — Key Patterns:
public/index.php entry point$request->validated(), never $request->all())utf8mb4, BIGINT PKs, JSON columnsAppServiceProvider::boot(): preventLazyLoading() (catches N+1), preventSilentlyDiscardingAttributes() (catches mass assignment typos), preventAccessingMissingAttributes(); in production, lazy loading violations log instead of throwingwhenLoaded(), whenCounted(), conditional when() helpersSANCTUM_STATEFUL_DOMAINS and supports_credentials: truearch()->preset()->laravel()) and mutation testing (--mutate)crell/api-problem v3.8.0 (PHP ^8.3)daursu/laravel-zero-downtime-migration for large tablesPHP Stack (Symfony) — Key Patterns:
#[ApiResource] annotations for automatic CRUD REST APIs with OpenAPI documentation#[MapRequestPayload] and Symfony Validator constraint attributes (#[Assert\NotBlank], #[Assert\Positive])lexik/jwt-authentication-bundle v3.2.0 with RS256 signing + gesdinet/jwt-refresh-token-bundle for refresh tokensGo Stack — Generation Rules:
net/http.ServeMux with method+wildcard patterns (GET /users/{id}, r.PathValue("id")); use Chi v5.2.x only for middleware grouping/subrouters; avoid gorilla/mux (archived 2023), Gin/Fiber (diverge from net/http idioms)internal/ packages (internal/user/handler.go, service.go, repository.go); avoid layer-based internal/handlers/ anti-pattern (excessive cross-package imports); shallow hierarchies (1-2 levels)main.go; manual DI preferred over Wire/Dig except for very large projects-- name: GetUser :one); golang-migrate for sequential numbered up/down migration filesvalidate:"required,email"); single instance (caches struct info); WithRequiredStructEnabled() for v11 compatibility; RegisterTagNameFunc() for JSON field namesServerInterface; YAML config with Chi/stdlib backend supportProblemDetail struct; Content-Type: application/problem+jsonhttptest.NewRecorder() + httptest.NewRequest(); t.Run() subtests; t.Parallel() for concurrent executiondistroless/static-debian12; CGO_ENABLED=0 for static binaries; -ldflags="-s -w" to strip debug infosignal.NotifyContext with 10-second timeout, closing HTTP server and database connectionsWebSocket Support (Optional — all stacks):
ws://host/ws?ticket=abc123); 30-second TTL, consumed on first use to prevent log-exposure attacksWhen generating scaffold, include test framework and mutation tool recommendations based on detected stack:
| Stack | Test Framework | Mutation Tool | Config File |
|---|---|---|---|
| Node.js/TS | Vitest | StrykerJS | stryker.config.mjs |
| PHP/Laravel | Pest | Infection | infection.json5 |
| Go | testing + testify | go-mutesting | CLI flags |
| Python | pytest | mutmut | setup.cfg |
Add to generated README: "Run /jaan-to:qa-test-mutate to validate test suite effectiveness."
All Stacks: Business logic in route handlers, hardcoded secrets, missing .gitignore, no error handling
Node.js: Direct Prisma calls in handlers, multiple PrismaClient instances, any types, Express-style error middleware, missing response serialization schemas, instanceof ZodError (use v6 helpers), missing .js extensions in ESM imports, moduleResolution: "bundler" for backends
PHP: Fat controllers, N+1 queries, exposing raw Eloquent models, env() outside config files, utf8 instead of utf8mb4, missing Eloquent strictness modes
Go: Generic package names (utils/), global database connections, ignoring errors, unlimited connection pool, goroutine leaks, layer-based internal/handlers/ structure
Node.js/TypeScript:
fastify ^5.7, @fastify/autoload ^6, @fastify/cors ^10, @fastify/sensible ^6, @fastify/swagger ^9, @fastify/swagger-ui ^5, @prisma/client ^6, fastify-plugin ^5, fastify-type-provider-zod ^6.1, zod ^3.24typescript ^5.6, @types/node ^22, fastify-tsconfig ^2, prisma ^6, tsx ^4, vitest ^2, eslint ^9Go: chi v5.2.x (optional), go-playground/validator v10, golang-migrate, sqlc, oapi-codegen v2
PHP (Laravel): laravel/sanctum, crell/api-problem ^3.8, pestphp/pest ^3
PHP (Symfony): api-platform/core ^4, lexik/jwt-authentication-bundle ^3.2, gesdinet/jwt-refresh-token-bundle
tech.md detection$JAAN_OUTPUTS_DIR pathnpx claudepluginhub parhumm/jaan-to --plugin jaan-toGenerates backend service implementations with business logic from OpenAPI specs, data models, and scaffold stubs. Use when implementing service layers from TODO stubs.
Implements backend endpoints, business logic services, and third-party integrations with type safety, layered architecture, and explicit error handling.
Guides full-stack backend architecture and frontend-backend integration with patterns for API design, auth, error handling, real-time features, and production hardening.