express-js/skills/skills/crud-resource-scaffolder/SKILL.md
Scaffold a complete CRUD resource for an Express.js + MongoDB API. Generates all files — model, validation schema, filter, controllers, routes, and barrel exports — in one shot. Use this skill whenever the user wants to add a new resource, create CRUD endpoints, scaffold an entity, add a new model, or says things like "I need a new collection for X" or "create endpoints for X". Even if the user only mentions a model or a single endpoint, this skill ensures the full resource is scaffolded correctly.
npx skillsauth add spuneiartur/claude-agent-specs crud-resource-scaffolderInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Scaffolds a complete CRUD admin resource following the project's Express.js + MongoDB patterns. One resource = ~12 files across 7 directories + updates to 6 barrel index files and the main router.
Any time the user wants to add a new entity/resource/collection to the API. This includes requests like:
Gather from the user:
review, blog-comment, faq-item)name or slug)tag): no refs to other models, basic fields. Read references/simple-resource-example.md.product): has embedded refs to other models, needs normalizeDropdownValues middleware. Read references/relational-resource-example.md.Generate ALL files below. Read references/coding-standards.md for rules that apply to every file.
For a resource named {resource} (singular, kebab-case) with PascalCase name {Resource}:
models/{resource}.jsimport { validate } from 'express-goodies/middleware';
import { paginate, softDelete } from 'express-goodies/mongoose';
import trails from 'express-goodies/mongoose/trails';
import { model, Schema } from 'mongoose';
const name = '{resource}';
const schema = new Schema(
{
// fields here
},
{ timestamps: true }
);
schema.plugin(paginate);
schema.plugin(validate);
schema.plugin(softDelete);
schema.plugin(trails);
export default model(name, schema);
schemas/schema-{resource}.jsimport * as yup from 'yup';
import safeSchema from './safe-schema';
const {resource}Schema = safeSchema({
// field validations here using yup
});
export default {resource}Schema;
Use yup.string(), yup.number(), yup.boolean(), yup.date(), yup.array(), yup.object(). Add .required('Field is required') for required fields. Add .trim() for strings. Use camelCase for the schema variable name.
filters/apply-filters-{resource}.jsconst applyFilters{Resource} = (query) => {
const { search = '', created_from, created_to } = query;
const filter = {};
if (search) {
filter.{searchField} = { $regex: search, $options: 'i' };
}
if (created_from) {
filter.createdAt = { $gte: created_from };
}
if (created_to) {
filter.createdAt = { ...filter.createdAt, $lt: created_to };
}
return filter;
};
export default applyFilters{Resource};
Replace {searchField} with the primary searchable field (usually name or title).
controllers/{resource}/Create 5 files + 1 barrel index. See references/simple-resource-example.md for exact templates.
create.js — Check duplicate on unique field, Model.create(req.body), return { data, message }read-one.js — Model.findById(id), throw 404 if not found, return documentread-many.js — Model.find(applyFilters(req.query)).paginate(req.query), return documentsupdate.js — Check duplicate (excluding self with $ne: id), findByIdAndUpdate(id, req.body, { new: true }), return { data, message }delete.js — Model.findByIdAndDelete(id), return { data: req.model, message }index.js — Barrel file exporting all controllersThe delete controller export name should be delete{Resource} (e.g. deleteReview) since delete is a reserved word.
routes/{resource}.jsSimple resource:
import { {Resource} } from '@controllers';
import { validate } from '@middleware';
import {resource}Schema from '@schemas/schema-{resource}';
import { Router } from 'express';
const router = Router();
export default router;
router.get('/admin/{resources}', {Resource}.readMany);
router.get('/admin/{resources}/:id', {Resource}.readOne);
router.post('/admin/{resources}', validate({resource}Schema), {Resource}.create);
router.put('/admin/{resources}/:id', validate({resource}Schema), {Resource}.update);
router.delete('/admin/{resources}/:id', {Resource}.delete{Resource});
Relational resource (has refs): additionally import diacriticInsensitive, normalizeDropdownValues, and referenced models. See references/relational-resource-example.md.
Read references/barrel-exports-guide.md for the exact export patterns. Update these files maintaining A-Z alphabetical order:
controllers/index.js — export * as {Resource} from './{resource}';models/index.js — export { default as {Resource} } from './{resource}';routes/index.js — export { default as {resource} } from './{resource}';filters/index.js — export { default as applyFilters{Resource} } from './apply-filters-{resource}';schemas/index.js — Add under // ===== VALIDATION SCHEMAS ===== section: export { default as {resource}Schema } from './schema-{resource}';In router.js, add router.use(routes.{resource}); in A-Z order among the other router.use(routes.xxx) lines, before router.use(routes.public) and router.use(exampleRoutes.todo).
Only if this resource will be embedded as a ref in other models:
models/schemas/ref-{resource}.js — Mongoose embedded ref schema. See references/simple-resource-example.md for the pattern.schemas/ref-{resource}.js — Yup ref validation schema.schemas/index.js under // ===== REFERENCE SCHEMAS =====.'{Resource} created successfully!', '{Resource} not found', 'A {resource} with this {field} already exists'@aliases for imports (@models, @controllers, @functions, @filters, @schemas, @middleware)index.js files)try/catch in controllers — the app uses express-async-errors200 on success for all operationsreturn statementerror() from @functions for throwing errorsreferences/simple-resource-example.md — Complete tag resource as template (all 12 files)references/relational-resource-example.md — Complete product resource showing relational patternsreferences/coding-standards.md — All coding rules for generated filesreferences/barrel-exports-guide.md — How each barrel index.js uses different export patternstools
Replace with description of the skill and when Claude should use it.
tools
Comprehensive website performance audit and optimization skill. Identifies and automatically fixes performance issues including image optimization, video compression, lazy loading, Core Web Vitals, bundle size, and rendering strategy. Uses Lighthouse (via CLI or MCP when available), ffmpeg for media processing, and the project's existing Image component with blur-up lazy loading. Use this skill whenever the user mentions: website speed, page load time, performance audit, Core Web Vitals, Lighthouse, optimize images, compress videos, lazy loading, LCP, CLS, FID, INP, slow website, speed up, performance optimization, image compression, video optimization, blur placeholder, WebP conversion, media audit, bundle size, or wants to improve their website's loading performance. Also trigger when the user says "my site is slow", "optimize for speed", "reduce load time", "improve performance", or asks about image/video optimization in any context.
tools
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
tools
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.