Install
npx skillscat add nvimer/plaet-server Install via the SkillsCat registry.
SKILL.md
Plaet Server Skill
Description
Specialized instructions for working with the Plaet backend API (Node.js + Express + Prisma).
Commands
Essential Commands
cd server
npm run dev # Start development server
npm run build # TypeScript compilation
npm run test # Run all tests
npm run test:watch # Watch mode
npm run lint # ESLint check
npm run prettier # Format code
npm run prisma:generate # Generate Prisma client
npm run prisma:migrate # Run migrationsTest Commands
npm run test -- src/api/users/user.service.test.ts # Single test file
npm run test:integration # Integration testsArchitecture
Layered Modular Pattern
src/api/{module}/
├── interfaces/ # Type contracts
├── {module}.controller.ts # Route handlers
├── {module}.service.ts # Business logic
├── {module}.repository.ts # Data access
├── {module}.validator.ts # Zod schemas
├── {module}.route.ts # Express routes
└── __tests__/ # TestsRequest Flow
HTTP Request → Middleware → Controller → Service → Repository → DatabaseMulti-Tenant Architecture
Automatic Tenant Isolation
- Prisma Client extended with tenant filter
- Models: User, MenuCategory, MenuItem, Table, Order, Expense, etc.
restaurantIdextracted from JWT token- NEVER manually filter by restaurantId in repositories
Authentication & Authorization
JWT Flow
- User logs in → receives access token
- Access token contains: userId, restaurantId, roles, permissions
- Middleware validates token and populates
req.user
RBAC Pattern
router.patch(
"/:id",
permissionMiddleware("users:update"),
controller.updateUser,
);Database (Prisma)
Multi-Tenant Models
Models with tenant isolation: User, MenuCategory, MenuItem, Table, Order, Expense, CashClosure, DailyMenu, Customer, Inventory, PurchaseOrder
Soft Delete
- Models: Permission, Role, MenuCategory, MenuItem, User, Table, Expense, Order
Validation (Zod)
Validator Pattern
export const createItemSchema = z.object({
body: z.object({
name: z.string().min(2).max(100),
price: z.number().positive(),
}),
});
export type CreateItemInput = z.infer<typeof createItemSchema>["body"];Error Handling
Custom Error Class
throw new CustomError("Error message", HttpStatus.BAD_REQUEST, "ERROR_CODE");Logging
Use Winston
import { logger } from "../config/logger";
logger.info("User created", { userId });- NEVER use console.log()
Best Practices
- Always use TypeScript - no
anyorunknown - Define interfaces for services and repositories
- Use Zod for all validation
- Centralize errors - throw CustomError
- Log with Winston - never console.log
- Write tests for services and critical paths