Constraints
Hard rules, limitations, and .cursorrules for AI agents
Constraints
These are hard rules that must never be violated. AI assistants must respect these constraints without exception.
Version Requirements
MANDATORY VERSIONS:
| Package | Version | Notes |
|---|---|---|
| Prisma | 5.x | NOT 6.x (breaking changes) |
| Express | 4.x | NOT 5.x (beta) |
| Redis | 7.x | NOT 8.x |
| Zod | 3.x | Latest stable |
| PostgreSQL | 17.x | Latest stable |
| Node.js | 20.x LTS | Better AI training data |
| NestJS | 10.x | Stable release |
| Next.js | 15.x | App Router |
Why: These versions are tested, stable, and compatible. Using other versions breaks the stack.
Technology Restrictions
FORBIDDEN:
| Technology | Reason |
|---|---|
| GraphQL | Too complex for our scale |
| Microservices | Monolith is simpler |
| Event-driven architecture | Use direct calls |
| Custom frameworks | Use NestJS/Next.js |
| Alternative databases | PostgreSQL only |
| Redux/MobX | Use React Query |
Why: These add unnecessary complexity. The architecture is optimized for the target scale without them.
Architecture Boundaries
HRMS Core:
- Next.js frontend + NestJS backend + PostgreSQL
- Monolithic application
- REST APIs only
Web App Database Access:
apps/web/lib/prisma.tsexists ONLY for Auth.js- ALL other data access MUST go through
apps/api - DO NOT import prisma.ts in any other web app files
// WRONG - bypasses API layer
import { prisma } from '@/lib/prisma';
const employees = await prisma.employee.findMany(); // ❌
// CORRECT - use API
const response = await fetch('/api/v1/employees'); // ✅AI Service:
- Separate Express service
- MongoDB for vectors only
- No HRMS data in MongoDB
Org Structure Rules (CRITICAL)
Model Split
- EmployeeCore = WHO (identity, job info, employment)
- EmployeeOrgRelations = HOW (managers, teams, departments, roles)
Multi-Everything Support
primaryManagerId: string? // 0..1 (direct manager)
dottedLineManagerIds: string[] // 0..N (matrix reporting)
additionalManagerIds: string[] // 0..N (secondary real managers)
teamIds: string[] // 0..N (multi-team membership)
departmentIds: string[] // 0..N (cross-department)
roleIds: string[] // 0..N (multi-role)Org Rules
- Every manager IS an employee (no separate Manager table)
- Self-management BLOCKED (employeeId !== managerId)
- Circular management ALLOWED by default (startup flexibility)
- No limits on any relations
Valid Examples
// CTO with multiple responsibilities
CTO: {
primaryManagerId: "ceo-id",
dottedLineManagerIds: ["cfo-id"],
roleIds: ["cto", "sales-manager"],
teamIds: ["leadership", "sales"]
}
// Developer in multiple teams
Developer: {
primaryManagerId: "dev-lead-id",
additionalManagerIds: ["cto-id"],
teamIds: ["saas", "web"],
departmentIds: ["engineering", "product"]
}Complexity Limits
Per Module:
- Maximum 5 files
- Maximum 150 lines per service file
- Maximum 100 lines per controller file
Per Building Block:
- Complete one block before starting next
- No parallel work on multiple blocks
- All gates must pass before moving on
Pattern Enforcement
NO VARIATIONS:
- Use exact patterns from Patterns
- No "better" ways or "improvements"
- Copy-paste similar code (don't abstract)
.cursorrules Content
Use this as your .cursorrules file:
# Project Context
Multi-tenant HRMS SaaS with flexible org structure.
- Next.js 15 (App Router) + NestJS 10 + PostgreSQL 17 + Prisma 5
- Shadcn/ui + Tailwind CSS
- Auth.js for authentication
## Architecture Principles
1. SIMPLICITY FIRST - No premature optimization
2. Single PostgreSQL with Row-Level Security
3. REST APIs only (no GraphQL)
4. Feature modules in NestJS
## ORG STRUCTURE RULES (CRITICAL)
### Model Split
- EmployeeCore = WHO (identity, job info, employment)
- EmployeeOrgRelations = HOW (managers, teams, departments, roles)
### Multi-Everything
- primaryManagerId: 0..1 (direct manager)
- dottedLineManagerIds: 0..N (matrix reporting)
- additionalManagerIds: 0..N (secondary real managers)
- teamIds: 0..N (multi-team membership)
- departmentIds: 0..N (cross-department)
- roleIds: 0..N (multi-role)
### Rules
- Every manager IS an employee (no separate Manager table)
- Self-management BLOCKED (employeeId !== managerId)
- Circular management ALLOWED by default (startup flexibility)
- No limits on any relations
## Code Style
- TypeScript strict (no `any`)
- Functional components with hooks
- Early returns for guards
- Descriptive names (no abbreviations)
## Database
- All tables have tenantId
- Always filter by tenantId
- Use Prisma transactions for multi-table ops
- Junction tables for many-to-many
## API Design
- REST with proper HTTP methods
- Consistent response shapes
- Pagination for lists
## Security
- Never trust client input
- Verify tenant context always
- Use isManagerOf() for permission checks
- Log security actions
## DO NOT
- GraphQL or event sourcing
- Separate microservices
- Abstractions without 3+ implementations
- Redux/MobX (use React Query)
- Separate Manager table
- Limit org relationships
- Block circular management by default
## COMMIT MESSAGE FORMAT (ENFORCED)
All commits MUST use conventional commits:
- Format: <type>: <description>
- Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
- feat = minor bump, fix/others = patch bump
- Add ! after type for breaking changes (major bump)
Good: feat: add employee dashboard
Bad: update stuff (CI rejects)Exception Process
To Add Technology:
- Create ADR explaining why (See ADR Guide)
- Get approval
- Follow technology addition process
- Update boilerplate definition
To Change Pattern:
- Create ADR explaining why
- Get approval
- Update Patterns
- Update all affected code
UI Development Constraints
All UI work MUST follow the Design System:
Mandatory UI Rules
| # | Rule | Rationale |
|---|---|---|
| 1 | NEVER create plain white cards with gray borders | Looks like wireframe, not shipped product |
| 2 | ALWAYS use gradient backgrounds for stats cards | Visual hierarchy and polish |
| 3 | ALWAYS use shadow-lg on content cards | Soft, modern aesthetic |
| 4 | ALWAYS use rounded-2xl (16px) on cards | Apple/iOS design language |
| 5 | ALWAYS use CSS variables (bg-card, not bg-white) | Dark mode support |
| 6 | ALWAYS support dark mode with dark: variants | Required feature |
| 7 | NEVER use spacing less than p-6 on cards | Generous whitespace |
| 8 | NEVER create new button/component variants without updating design system | Prevents drift |
Before Writing UI Code
- Read Design Tokens
- Read AI Rules
- Check Validation Checklist
- Review UI Screenshots for visual reference
UI Code Review Criteria
REJECT if:
- Plain white cards with gray borders
- Hard-coded colors (
bg-whiteinstead ofbg-card) - Missing dark mode support
- Spacing below minimum (
p-4instead ofp-6) - Stats cards without gradient backgrounds
See Design System for complete specifications.
Enforcement
AI Must:
- Check constraints before suggesting changes
- Reject own suggestions that violate constraints
- Reference constraints when user asks for forbidden features
- Follow UI design system for all frontend work
User Must:
- Enforce constraints when AI suggests violations
- Create ADR for any exceptions
- Update constraints when decisions change
Platform Admin Constraints
Platform Admin functionality (Phase 10) has specific rules:
Authorization
| Rule | Requirement |
|---|---|
| Guard | ALL Platform Admin endpoints MUST use @PlatformAdminOnly() |
| Role | Only SYSTEM_ADMIN users can access Platform Admin features |
| Tenant Context | Platform Admin endpoints do NOT require X-Tenant-ID header |
| Cross-tenant | Platform Admin CAN access data across all tenants |
API Design
// CORRECT - Platform Admin endpoint pattern
@Controller('api/v1/admin/tenants')
@PlatformAdminOnly()
export class AdminTenantController { ... }
// WRONG - Missing guard
@Controller('api/v1/admin/tenants')
export class AdminTenantController { ... }Data Access
| Constraint | Reason |
|---|---|
| Tenant creation MUST validate unique tenant name | Prevent duplicates |
| Tenant status changes MUST be logged | Audit trail |
| Tenant Admin assignment creates user with null password | Forces password reset |
| Platform Admin CANNOT modify tenant-specific data directly | Use tenant-scoped endpoints |
UI Constraints
- Platform Admin sidebar section MUST only render for
SYSTEM_ADMINusers - Platform Admin pages MUST be under
/admin/*route - Platform Admin UI MUST follow the same design system as tenant UI
Domain Registration Rules
| Constraint | Reason |
|---|---|
| Domain format MUST be validated (lowercase, no protocol) | Prevent duplicates and normalize format |
| Domain MUST be unique across all tenants | One domain = one tenant ownership |
| Registration with unrecognized domain MUST be rejected | Enterprise-only mode |
| New users joining via domain MUST get EMPLOYEE role | Security - not admin by default |
| Cannot delete last domain if tenant has users | Prevents orphaned users |
| Primary domain MUST be settable per tenant | Display and identification |
Implementation Notes:
- Domain validation regex:
/^[a-z0-9]+([\-\.][a-z0-9]+)*\.[a-z]{2,}$/ - Always lowercase domains before storing
- Auth.js
createUserevent handles domain matching - Delete user record if domain not recognized (rollback)
Employee Management Constraints
Employee Status Rules
| Status | Usage |
|---|---|
| ACTIVE | Normal working employee |
| INACTIVE | Temporarily not working (sabbatical, long-term leave without pay) |
| ON_LEAVE | Currently on approved paid leave |
| TERMINATED | Employment ended, soft-deleted from active queries |
Status Transitions:
- ACTIVE → INACTIVE: Manual HR action (sabbatical, extended leave)
- ACTIVE → ON_LEAVE: Automatic when leave request approved
- ON_LEAVE → ACTIVE: Automatic when leave period ends
- Any → TERMINATED: Manual HR action (irreversible soft-delete)
Profile Picture Rules
| Constraint | Value | Reason |
|---|---|---|
| Max file size | 5MB | Performance and storage costs |
| Allowed formats | JPG, PNG, WebP | Browser compatibility |
| Storage path | /uploads/profile-pictures/{employeeId} | Organized storage |
| Image processing | Resize to 400x400 max | Consistent display, reduced storage |
Implementation:
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
const MAX_SIZE = 5 * 1024 * 1024; // 5MBValidation:
- MUST validate file type on server (don't trust client MIME type)
- MUST resize large images before storage
- MUST delete old picture when uploading new one
- SHOULD return 413 Payload Too Large for oversized files
Conventional Commits Constraint (ENFORCED)
CI ENFORCED
All commits MUST use conventional commit format. GitHub Actions rejects PRs with non-conforming commits.
Commit Message Format
<type>: <description>Allowed Types
| Type | Version Bump | When to Use |
|---|---|---|
feat | Minor (0.X.0) | New feature |
fix | Patch (0.0.X) | Bug fix |
docs | Patch | Documentation only |
style | Patch | Formatting, no code change |
refactor | Patch | Code restructuring |
perf | Patch | Performance improvement |
test | Patch | Adding/updating tests |
build | Patch | Build system changes |
ci | Patch | CI/CD changes |
chore | Patch | Maintenance tasks |
revert | Patch | Reverting previous commit |
Breaking Changes
Add ! after type for Major version bump (X.0.0):
feat!: redesign API endpoints
# Or use footer
feat: redesign API endpoints
BREAKING CHANGE: API endpoints have changedRules
| Rule | Enforcement |
|---|---|
| Type MUST be lowercase | CI validates |
| Type MUST be from allowed list | CI validates |
| Colon MUST follow type | CI validates |
| Description MUST not be empty | CI validates |
| Header MUST be ≤100 characters | CI validates |
Examples
# Correct
git commit -m "feat: add employee dashboard"
git commit -m "fix: resolve login timeout"
git commit -m "docs: update API guide"
git commit -m "refactor: simplify auth flow"
# Incorrect (CI will reject)
git commit -m "update stuff" # Missing type
git commit -m "Feature: add login" # Wrong case
git commit -m "feat add login" # Missing colon
git commit -m "FEAT: add login" # Uppercase type.cursorrules Addition for Commits
Add to your .cursorrules:
## COMMIT MESSAGE FORMAT (ENFORCED)
All commits MUST use conventional commits format:
- Format: <type>: <description>
- Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
- feat = minor version bump, fix/others = patch version bump
- Add ! after type for breaking changes (major version bump)
Examples:
- feat: add employee dashboard
- fix: resolve login timeout
- docs: update deployment guide
- feat!: redesign authentication API
NEVER commit with messages like "update stuff" or "WIP" - CI will reject.Deployment Checkpoint Constraints (MANDATORY)
ENFORCED BY GITHUB
These constraints are enforced at the GitHub level. Violations are technically impossible.
Hard Rules
| Rule | Enforcement |
|---|---|
| NEVER push directly to main | GitHub blocks direct pushes |
| NEVER merge without PR | PRs required for all changes |
| NEVER skip CI tests | Tests must pass before merge |
| NEVER bypass as admin | Enforce for admins enabled |
AI Agent Checkpoint Rules
| # | Rule | Consequence of Violation |
|---|---|---|
| 1 | NEVER push without human saying "OK to push" | Session restart required |
| 2 | NEVER merge without human verifying preview | PR rejected |
| 3 | NEVER deploy production without human verifying staging | Deployment blocked |
| 4 | ALWAYS stop and wait at each checkpoint | Trust broken |
Checkpoint Protocol
At each deployment gate, AI agents MUST:
- STOP - Halt all execution
- SHOW - Display relevant information (diff, URL, status)
- ASK - Request explicit confirmation
- WAIT - Do NOT proceed until human responds
- VERIFY - Check response before continuing
.cursorrules Addition
Add to your .cursorrules file:
## DEPLOYMENT CHECKPOINT RULES (CRITICAL)
AI MUST pause and ask for human confirmation at these 4 gates:
1. CHECKPOINT 1: After commit, before push
- Show diff, ask "OK to push?"
- WAIT for "OK to push"
2. CHECKPOINT 2: After preview deploys
- Show preview URL, ask "OK to merge?"
- WAIT for "OK to merge"
3. CHECKPOINT 3: After staging deploys
- Show staging URL, ask "OK to deploy production?"
- WAIT for "OK to deploy"
4. CHECKPOINT 4: After production deploys
- Show production URL, ask "Confirm complete?"
- WAIT for "Complete"
NEVER proceed past a checkpoint without explicit human confirmation.
This is non-negotiable. Violations require session restart.Agent Boundaries
File Modification Rules
Safe to Modify (within current task):
- Files explicitly mentioned in current building block
- New files being created for the task
- Test files for code being written
Requires Confirmation:
- Any file in
packages/database/prisma/ - Configuration files (
*.config.*,docker-compose.yml) - Files in
apps/*/src/lib/(shared utilities)
Never Modify Without ADR:
- Files marked as locked in previous phases
- Authentication/authorization code after Phase 1
- Core middleware and guards
Dependency Rules
Before Installing ANY New Package:
- Check if functionality exists in current stack
- Verify package is in Technology Stack
- If not listed, ASK before installing
- Never install alternative packages (e.g., moment.js when date-fns is standard)
Forbidden Without Approval:
- Any ORM except Prisma
- Any UI library except shadcn/ui
- Any state management except React Query
- Any new testing framework
Automatic Progression Forbidden
After completing any task:
- Report completion status
- Show gate verification result
- STOP and ASK: "Task complete. What's next?"
DO NOT:
- Automatically start the next step
- Suggest improvements to working code
- Refactor "while we're here"
- Add "nice to have" features
Anti-Improvement Pledge (CRITICAL)
MANDATORY
AI agents MUST NOT "improve" code beyond the current task scope.
Forbidden Actions
| Forbidden Action | Why It Causes Chaos |
|---|---|
| "Improve" working code | Creates inconsistency, breaks tests |
| Suggest "better" alternatives | Delays progress, scope creep |
| Refactor "while we're here" | Uncontrolled changes, harder reviews |
| Add "helpful" features | Not in specification, untested |
| "Clean up" unrelated code | Breaks what works, wasted effort |
| Premature optimization | YAGNI violation, complexity |
| Add extra error handling | Over-engineering, noise |
| Create abstractions for one use | Unnecessary complexity |
| Rename variables for "clarity" | Churn, diff noise |
| Add comments to existing code | Out of scope, opinion |
When Tempted to Improve
Instead of improving, ASK:
"I notice [X] could be improved. Is this in scope for the current step? If not, I'll add it to a future enhancement list and continue with the current task."
Valid Exceptions
Improvements are ONLY allowed when:
- Explicitly requested by user: "Please refactor this function"
- Required for current task: Can't implement feature without fixing bug
- Security vulnerability: Must fix immediately, document as blocker
- Build/test failure: Must fix to continue, document as blocker
Improvement Detection Self-Check
Before any edit, AI must verify:
□ Is this edit required for the current step?
□ Is this edit explicitly requested?
□ Does this file appear in the current task specification?
□ Am I changing MORE than what the task requires?
If any checkbox fails → STOP and ASKConsequence of Violation
If AI violates Anti-Improvement Pledge:
- User should reject the changes
- User should point to this document
- AI should revert to task-only changes
- Session may need to restart with clearer scope