qualia-framework 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/bin/cli.js +519 -0
- package/framework/agents/architecture-strategist.md +53 -0
- package/framework/agents/backend-agent.md +150 -0
- package/framework/agents/code-simplicity-reviewer.md +86 -0
- package/framework/agents/frontend-agent.md +111 -0
- package/framework/agents/kieran-typescript-reviewer.md +96 -0
- package/framework/agents/performance-oracle.md +111 -0
- package/framework/agents/qualia-codebase-mapper.md +760 -0
- package/framework/agents/qualia-debugger.md +1203 -0
- package/framework/agents/qualia-executor.md +881 -0
- package/framework/agents/qualia-integration-checker.md +423 -0
- package/framework/agents/qualia-phase-researcher.md +453 -0
- package/framework/agents/qualia-plan-checker.md +699 -0
- package/framework/agents/qualia-planner.md +1241 -0
- package/framework/agents/qualia-project-researcher.md +602 -0
- package/framework/agents/qualia-research-synthesizer.md +236 -0
- package/framework/agents/qualia-roadmapper.md +605 -0
- package/framework/agents/qualia-verifier.md +685 -0
- package/framework/agents/team-orchestrator.md +228 -0
- package/framework/agents/teams/full-stack-team.md +48 -0
- package/framework/agents/teams/optimize-team.md +53 -0
- package/framework/agents/teams/review-team.md +62 -0
- package/framework/agents/teams/ship-team.md +86 -0
- package/framework/agents/test-agent.md +182 -0
- package/framework/askpass.sh +2 -0
- package/framework/commands/design.md +53 -0
- package/framework/commands/quick-db.md +22 -0
- package/framework/config/retention.json +35 -0
- package/framework/core/PRINCIPLES.md +77 -0
- package/framework/hooks/auto-format.sh +45 -0
- package/framework/hooks/block-env-edit.sh +42 -0
- package/framework/hooks/branch-guard.sh +46 -0
- package/framework/hooks/confirm-delete.sh +56 -0
- package/framework/hooks/migration-validate.sh +68 -0
- package/framework/hooks/notification-speak.sh +15 -0
- package/framework/hooks/pre-commit.sh +80 -0
- package/framework/hooks/pre-compact.sh +55 -0
- package/framework/hooks/pre-deploy-gate.sh +151 -0
- package/framework/hooks/qualia-colors.sh +32 -0
- package/framework/hooks/retention-cleanup.sh +43 -0
- package/framework/hooks/save-session-state.sh +153 -0
- package/framework/hooks/session-context-loader.sh +28 -0
- package/framework/hooks/session-learn.sh +30 -0
- package/framework/knowledge/claudecode-bible.md +1384 -0
- package/framework/knowledge/client-prefs.md +22 -0
- package/framework/knowledge/common-fixes.md +25 -0
- package/framework/knowledge/deployment-map.md +35 -0
- package/framework/knowledge/email-signature.html +1 -0
- package/framework/knowledge/employees.md +8 -0
- package/framework/knowledge/learned-patterns.md +51 -0
- package/framework/knowledge/optimization-research-2026.md +137 -0
- package/framework/knowledge/qualia-context.md +67 -0
- package/framework/knowledge/supabase-patterns.md +50 -0
- package/framework/knowledge/voice-agent-patterns.md +46 -0
- package/framework/qualia-engine/VERSION +1 -0
- package/framework/qualia-engine/bin/qualia-tools.js +2160 -0
- package/framework/qualia-engine/bin/qualia-tools.test.js +1054 -0
- package/framework/qualia-engine/references/checkpoints.md +775 -0
- package/framework/qualia-engine/references/continuation-format.md +249 -0
- package/framework/qualia-engine/references/decimal-phase-calculation.md +65 -0
- package/framework/qualia-engine/references/design-quality.md +56 -0
- package/framework/qualia-engine/references/git-integration.md +254 -0
- package/framework/qualia-engine/references/git-planning-commit.md +50 -0
- package/framework/qualia-engine/references/model-profile-resolution.md +32 -0
- package/framework/qualia-engine/references/model-profiles.md +73 -0
- package/framework/qualia-engine/references/phase-argument-parsing.md +61 -0
- package/framework/qualia-engine/references/planning-config.md +195 -0
- package/framework/qualia-engine/references/questioning.md +141 -0
- package/framework/qualia-engine/references/tdd.md +263 -0
- package/framework/qualia-engine/references/ui-brand.md +160 -0
- package/framework/qualia-engine/references/verification-patterns.md +612 -0
- package/framework/qualia-engine/templates/DEBUG.md +159 -0
- package/framework/qualia-engine/templates/DESIGN.md +81 -0
- package/framework/qualia-engine/templates/UAT.md +247 -0
- package/framework/qualia-engine/templates/codebase/architecture.md +255 -0
- package/framework/qualia-engine/templates/codebase/concerns.md +310 -0
- package/framework/qualia-engine/templates/codebase/conventions.md +307 -0
- package/framework/qualia-engine/templates/codebase/integrations.md +280 -0
- package/framework/qualia-engine/templates/codebase/stack.md +186 -0
- package/framework/qualia-engine/templates/codebase/structure.md +285 -0
- package/framework/qualia-engine/templates/codebase/testing.md +480 -0
- package/framework/qualia-engine/templates/config.json +35 -0
- package/framework/qualia-engine/templates/context.md +283 -0
- package/framework/qualia-engine/templates/continue-here.md +78 -0
- package/framework/qualia-engine/templates/debug-subagent-prompt.md +91 -0
- package/framework/qualia-engine/templates/discovery.md +146 -0
- package/framework/qualia-engine/templates/milestone-archive.md +123 -0
- package/framework/qualia-engine/templates/milestone.md +115 -0
- package/framework/qualia-engine/templates/phase-prompt.md +567 -0
- package/framework/qualia-engine/templates/planner-subagent-prompt.md +117 -0
- package/framework/qualia-engine/templates/project.md +184 -0
- package/framework/qualia-engine/templates/projects/ai-agent.md +156 -0
- package/framework/qualia-engine/templates/projects/mobile-app.md +181 -0
- package/framework/qualia-engine/templates/projects/voice-agent.md +134 -0
- package/framework/qualia-engine/templates/projects/website.md +137 -0
- package/framework/qualia-engine/templates/requirements.md +231 -0
- package/framework/qualia-engine/templates/research-project/ARCHITECTURE.md +204 -0
- package/framework/qualia-engine/templates/research-project/FEATURES.md +147 -0
- package/framework/qualia-engine/templates/research-project/PITFALLS.md +200 -0
- package/framework/qualia-engine/templates/research-project/STACK.md +120 -0
- package/framework/qualia-engine/templates/research-project/SUMMARY.md +170 -0
- package/framework/qualia-engine/templates/research.md +552 -0
- package/framework/qualia-engine/templates/roadmap.md +202 -0
- package/framework/qualia-engine/templates/state.md +176 -0
- package/framework/qualia-engine/templates/summary-complex.md +59 -0
- package/framework/qualia-engine/templates/summary-minimal.md +41 -0
- package/framework/qualia-engine/templates/summary-standard.md +48 -0
- package/framework/qualia-engine/templates/summary.md +246 -0
- package/framework/qualia-engine/templates/user-setup.md +311 -0
- package/framework/qualia-engine/templates/verification-report.md +322 -0
- package/framework/qualia-engine/workflows/add-phase.md +179 -0
- package/framework/qualia-engine/workflows/add-todo.md +157 -0
- package/framework/qualia-engine/workflows/audit-milestone.md +241 -0
- package/framework/qualia-engine/workflows/check-todos.md +176 -0
- package/framework/qualia-engine/workflows/complete-milestone.md +858 -0
- package/framework/qualia-engine/workflows/diagnose-issues.md +219 -0
- package/framework/qualia-engine/workflows/discovery-phase.md +289 -0
- package/framework/qualia-engine/workflows/discuss-phase.md +534 -0
- package/framework/qualia-engine/workflows/execute-phase.md +559 -0
- package/framework/qualia-engine/workflows/execute-plan.md +438 -0
- package/framework/qualia-engine/workflows/help.md +470 -0
- package/framework/qualia-engine/workflows/insert-phase.md +220 -0
- package/framework/qualia-engine/workflows/list-phase-assumptions.md +178 -0
- package/framework/qualia-engine/workflows/map-codebase.md +327 -0
- package/framework/qualia-engine/workflows/new-milestone.md +363 -0
- package/framework/qualia-engine/workflows/new-project.md +1037 -0
- package/framework/qualia-engine/workflows/pause-work.md +122 -0
- package/framework/qualia-engine/workflows/plan-milestone-gaps.md +256 -0
- package/framework/qualia-engine/workflows/plan-phase.md +422 -0
- package/framework/qualia-engine/workflows/progress.md +354 -0
- package/framework/qualia-engine/workflows/quick.md +252 -0
- package/framework/qualia-engine/workflows/remove-phase.md +326 -0
- package/framework/qualia-engine/workflows/research-phase.md +74 -0
- package/framework/qualia-engine/workflows/resume-project.md +306 -0
- package/framework/qualia-engine/workflows/set-profile.md +80 -0
- package/framework/qualia-engine/workflows/settings.md +145 -0
- package/framework/qualia-engine/workflows/transition.md +556 -0
- package/framework/qualia-engine/workflows/update.md +197 -0
- package/framework/qualia-engine/workflows/verify-phase.md +195 -0
- package/framework/qualia-engine/workflows/verify-work.md +625 -0
- package/framework/rules/context7.md +11 -0
- package/framework/rules/deployment.md +29 -0
- package/framework/rules/frontend.md +33 -0
- package/framework/rules/security.md +12 -0
- package/framework/rules/speed.md +20 -0
- package/framework/scripts/__pycache__/say.cpython-314.pyc +0 -0
- package/framework/scripts/apply-retention.sh +120 -0
- package/framework/scripts/bootstrap-pop-os.sh +354 -0
- package/framework/scripts/claude-voice +13 -0
- package/framework/scripts/cleanup.sh +131 -0
- package/framework/scripts/cowork-mode.sh +141 -0
- package/framework/scripts/generate-project-claude-md.sh +153 -0
- package/framework/scripts/load-test-webhook.js +172 -0
- package/framework/scripts/say.py +236 -0
- package/framework/scripts/showcase-video-recorder/ffmpeg-builder.js +167 -0
- package/framework/scripts/showcase-video-recorder/playwright-helpers.js +216 -0
- package/framework/scripts/speak.py +55 -0
- package/framework/scripts/speak.sh +18 -0
- package/framework/scripts/status.sh +138 -0
- package/framework/scripts/sync-to-framework.sh +65 -0
- package/framework/scripts/voice-hotkey.py +227 -0
- package/framework/scripts/voice-input.sh +51 -0
- package/framework/skills/animate/SKILL.md +202 -0
- package/framework/skills/bolder/SKILL.md +144 -0
- package/framework/skills/browser-qa/SKILL.md +536 -0
- package/framework/skills/clarify/SKILL.md +179 -0
- package/framework/skills/colorize/SKILL.md +170 -0
- package/framework/skills/critique/SKILL.md +126 -0
- package/framework/skills/deep-research/SKILL.md +271 -0
- package/framework/skills/delight/SKILL.md +329 -0
- package/framework/skills/deploy/SKILL.md +261 -0
- package/framework/skills/deploy-verify/SKILL.md +377 -0
- package/framework/skills/deploy-verify/scripts/canary-check.sh +206 -0
- package/framework/skills/deploy-verify/scripts/check-console-errors.js +147 -0
- package/framework/skills/deploy-verify/scripts/check-cwv.js +139 -0
- package/framework/skills/deploy-verify/scripts/project-detect.sh +84 -0
- package/framework/skills/deploy-verify/scripts/verify.sh +548 -0
- package/framework/skills/design-quieter/SKILL.md +130 -0
- package/framework/skills/distill/SKILL.md +149 -0
- package/framework/skills/docs-lookup/SKILL.md +78 -0
- package/framework/skills/fcm-notifications/SKILL.md +125 -0
- package/framework/skills/financial-ledger/SKILL.md +1039 -0
- package/framework/skills/frontend-master/NOTICE.md +4 -0
- package/framework/skills/frontend-master/SKILL.md +127 -0
- package/framework/skills/frontend-master/reference/color-and-contrast.md +132 -0
- package/framework/skills/frontend-master/reference/interaction-design.md +123 -0
- package/framework/skills/frontend-master/reference/motion-design.md +99 -0
- package/framework/skills/frontend-master/reference/responsive-design.md +114 -0
- package/framework/skills/frontend-master/reference/spatial-design.md +100 -0
- package/framework/skills/frontend-master/reference/typography.md +131 -0
- package/framework/skills/frontend-master/reference/ux-writing.md +107 -0
- package/framework/skills/harden/SKILL.md +357 -0
- package/framework/skills/i18n-rtl/SKILL.md +752 -0
- package/framework/skills/learn/SKILL.md +71 -0
- package/framework/skills/memory/SKILL.md +50 -0
- package/framework/skills/mobile-expo/SKILL.md +864 -0
- package/framework/skills/mobile-expo/references/store-checklist.md +550 -0
- package/framework/skills/nestjs-backend/README.md +73 -0
- package/framework/skills/nestjs-backend/SKILL.md +446 -0
- package/framework/skills/nestjs-backend/references/templates.md +1173 -0
- package/framework/skills/normalize/SKILL.md +79 -0
- package/framework/skills/onboard/SKILL.md +242 -0
- package/framework/skills/polish/SKILL.md +209 -0
- package/framework/skills/pr/SKILL.md +66 -0
- package/framework/skills/qualia/SKILL.md +153 -0
- package/framework/skills/qualia-add-todo/SKILL.md +68 -0
- package/framework/skills/qualia-audit-milestone/SKILL.md +92 -0
- package/framework/skills/qualia-check-todos/SKILL.md +55 -0
- package/framework/skills/qualia-complete-milestone/SKILL.md +108 -0
- package/framework/skills/qualia-debug/SKILL.md +149 -0
- package/framework/skills/qualia-design/SKILL.md +203 -0
- package/framework/skills/qualia-discuss-phase/SKILL.md +72 -0
- package/framework/skills/qualia-execute-phase/SKILL.md +86 -0
- package/framework/skills/qualia-help/SKILL.md +67 -0
- package/framework/skills/qualia-idk/SKILL.md +352 -0
- package/framework/skills/qualia-list-phase-assumptions/SKILL.md +67 -0
- package/framework/skills/qualia-new-milestone/SKILL.md +72 -0
- package/framework/skills/qualia-new-project/SKILL.md +92 -0
- package/framework/skills/qualia-optimize/SKILL.md +417 -0
- package/framework/skills/qualia-pause-work/SKILL.md +96 -0
- package/framework/skills/qualia-plan-milestone-gaps/SKILL.md +57 -0
- package/framework/skills/qualia-plan-phase/SKILL.md +101 -0
- package/framework/skills/qualia-progress/SKILL.md +53 -0
- package/framework/skills/qualia-quick/SKILL.md +89 -0
- package/framework/skills/qualia-research-phase/SKILL.md +88 -0
- package/framework/skills/qualia-resume-work/SKILL.md +62 -0
- package/framework/skills/qualia-review/SKILL.md +263 -0
- package/framework/skills/qualia-start/SKILL.md +182 -0
- package/framework/skills/qualia-verify-work/SKILL.md +105 -0
- package/framework/skills/qualia-workflow/SKILL.md +130 -0
- package/framework/skills/rag/SKILL.md +750 -0
- package/framework/skills/responsive/SKILL.md +231 -0
- package/framework/skills/retro/SKILL.md +284 -0
- package/framework/skills/sakani-conventions/SKILL.md +136 -0
- package/framework/skills/sakani-conventions/evals/evals.json +23 -0
- package/framework/skills/sakani-conventions/references/entities.md +365 -0
- package/framework/skills/sakani-conventions/references/error-codes.md +95 -0
- package/framework/skills/seo-master/SKILL.md +490 -0
- package/framework/skills/seo-master/references/checklist.md +199 -0
- package/framework/skills/seo-master/references/structured-data.md +609 -0
- package/framework/skills/ship/SKILL.md +202 -0
- package/framework/skills/stack-researcher/SKILL.md +215 -0
- package/framework/skills/status/SKILL.md +154 -0
- package/framework/skills/status/scripts/health-check.sh +562 -0
- package/framework/skills/subscription-payments/SKILL.md +250 -0
- package/framework/skills/supabase/SKILL.md +973 -0
- package/framework/skills/supabase/references/templates.md +159 -0
- package/framework/skills/team/SKILL.md +67 -0
- package/framework/skills/test-runner/SKILL.md +202 -0
- package/framework/skills/voice-agent/SKILL.md +407 -0
- package/framework/skills/zoho-workflow/SKILL.md +51 -0
- package/framework/statusline-command.sh +117 -0
- package/package.json +24 -0
- package/profiles/fawzi.json +16 -0
- package/profiles/hasan.json +16 -0
- package/profiles/moayad.json +16 -0
- package/templates/CLAUDE-owner.md +52 -0
- package/templates/CLAUDE.md.hbs +58 -0
- package/templates/env.claude.template +12 -0
- package/templates/settings.json +141 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nestjs-backend
|
|
3
|
+
description: "NestJS backend development patterns — module/controller/service architecture, guards, interceptors, DTOs with Zod, error handling, database integration, and API design. Use whenever building or modifying a NestJS API server, creating endpoints, services, guards, middleware, or any backend logic in a NestJS application. Triggers on: NestJS, API endpoint, controller, service, guard, interceptor, DTO, middleware, backend module, REST API server."
|
|
4
|
+
tags: [nestjs, backend, api, typescript]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# NestJS Backend Skill
|
|
8
|
+
|
|
9
|
+
## Project Structure
|
|
10
|
+
|
|
11
|
+
Standard NestJS modular structure with feature modules:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
src/
|
|
15
|
+
├── main.ts
|
|
16
|
+
├── app.module.ts
|
|
17
|
+
├── common/
|
|
18
|
+
│ ├── decorators/ # Custom decorators (@CurrentUser, @Roles, @IdempotencyKey)
|
|
19
|
+
│ ├── filters/ # Exception filters (global error handler)
|
|
20
|
+
│ ├── guards/ # Auth guard, Role guard, Subscription guard
|
|
21
|
+
│ ├── interceptors/ # Request ID, Logging, Transform response
|
|
22
|
+
│ ├── middleware/ # Correlation ID middleware
|
|
23
|
+
│ ├── pipes/ # Zod validation pipe
|
|
24
|
+
│ └── types/ # Shared interfaces
|
|
25
|
+
├── modules/
|
|
26
|
+
│ ├── auth/ # Auth module (OTP, tokens, sessions)
|
|
27
|
+
│ ├── building/ # Building CRUD + verification
|
|
28
|
+
│ ├── unit/ # Unit CRUD + claims
|
|
29
|
+
│ └── [feature]/ # Feature modules
|
|
30
|
+
├── config/ # Configuration module with validation
|
|
31
|
+
└── database/ # Supabase client and RLS utilities
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Module Pattern
|
|
35
|
+
|
|
36
|
+
Every feature module follows a consistent structure:
|
|
37
|
+
|
|
38
|
+
- **module.ts**: Registers controllers and providers
|
|
39
|
+
- **controller.ts**: HTTP layer — validates input, delegates to service, returns response
|
|
40
|
+
- **service.ts**: Business logic — domain operations, database queries, validation
|
|
41
|
+
- **dto/**: Data Transfer Objects with Zod schemas
|
|
42
|
+
- **entities/**: TypeScript interfaces for database tables
|
|
43
|
+
- **spec.ts**: Unit and integration tests
|
|
44
|
+
|
|
45
|
+
Controllers are thin (validate + delegate). Services contain all business logic and are testable in isolation.
|
|
46
|
+
|
|
47
|
+
## Controller Pattern
|
|
48
|
+
|
|
49
|
+
Controllers handle HTTP concerns only — request validation, response formatting, and delegation.
|
|
50
|
+
|
|
51
|
+
**Guidelines:**
|
|
52
|
+
- Validate input using Zod validation pipe
|
|
53
|
+
- Use decorators for authentication (@UseGuards, @Roles)
|
|
54
|
+
- Call service methods and return results
|
|
55
|
+
- Let global exception filter handle errors
|
|
56
|
+
- Response shape is always: `{ data: T }` for success, errors via exception filter
|
|
57
|
+
|
|
58
|
+
**Example structure:**
|
|
59
|
+
```typescript
|
|
60
|
+
@Controller('buildings')
|
|
61
|
+
export class BuildingController {
|
|
62
|
+
constructor(private readonly buildingService: BuildingService) {}
|
|
63
|
+
|
|
64
|
+
@Post()
|
|
65
|
+
@UseGuards(AuthGuard)
|
|
66
|
+
async create(
|
|
67
|
+
@Body() dto: CreateBuildingDto,
|
|
68
|
+
@CurrentUser() user: JwtPayload,
|
|
69
|
+
) {
|
|
70
|
+
return {
|
|
71
|
+
data: await this.buildingService.create(dto, user.id),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@Get(':id')
|
|
76
|
+
@UseGuards(AuthGuard)
|
|
77
|
+
async findOne(@Param('id') id: string) {
|
|
78
|
+
return {
|
|
79
|
+
data: await this.buildingService.findById(id),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Service Pattern
|
|
86
|
+
|
|
87
|
+
Services contain all business logic, database operations, and domain-specific validation.
|
|
88
|
+
|
|
89
|
+
**Guidelines:**
|
|
90
|
+
- Inject dependencies (database client, other services)
|
|
91
|
+
- All queries and mutations happen here
|
|
92
|
+
- Throw domain exceptions, never HTTP exceptions
|
|
93
|
+
- Services are testable in isolation with mocked dependencies
|
|
94
|
+
- Use transactions for multi-step operations
|
|
95
|
+
- Validate business rules before state changes
|
|
96
|
+
|
|
97
|
+
**Example structure:**
|
|
98
|
+
```typescript
|
|
99
|
+
@Injectable()
|
|
100
|
+
export class BuildingService {
|
|
101
|
+
constructor(
|
|
102
|
+
private readonly supabase: SupabaseService,
|
|
103
|
+
private readonly logger: LoggerService,
|
|
104
|
+
) {}
|
|
105
|
+
|
|
106
|
+
async create(dto: CreateBuildingDto, userId: string) {
|
|
107
|
+
// Validate business rules
|
|
108
|
+
const existingCount = await this.supabase
|
|
109
|
+
.from('buildings')
|
|
110
|
+
.select('id')
|
|
111
|
+
.eq('owner_id', userId)
|
|
112
|
+
.count('exact');
|
|
113
|
+
|
|
114
|
+
if (existingCount >= 10) {
|
|
115
|
+
throw new DomainException('MAX_BUILDINGS_EXCEEDED', {
|
|
116
|
+
limit: 10,
|
|
117
|
+
current: existingCount,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Create record
|
|
122
|
+
const { data, error } = await this.supabase
|
|
123
|
+
.from('buildings')
|
|
124
|
+
.insert([{ ...dto, owner_id: userId }])
|
|
125
|
+
.select()
|
|
126
|
+
.single();
|
|
127
|
+
|
|
128
|
+
if (error) {
|
|
129
|
+
this.logger.error('Failed to create building', { error, dto });
|
|
130
|
+
throw new DomainException('BUILDING_CREATE_FAILED');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return data;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async findById(id: string, userId?: string) {
|
|
137
|
+
const query = this.supabase
|
|
138
|
+
.from('buildings')
|
|
139
|
+
.select('*')
|
|
140
|
+
.eq('id', id);
|
|
141
|
+
|
|
142
|
+
if (userId) {
|
|
143
|
+
query.eq('owner_id', userId);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const { data, error } = await query.single();
|
|
147
|
+
|
|
148
|
+
if (error || !data) {
|
|
149
|
+
throw new DomainException('BUILDING_NOT_FOUND');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return data;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## DTO Pattern with Zod
|
|
158
|
+
|
|
159
|
+
DTOs are derived from Zod schemas for type-safe validation across the stack.
|
|
160
|
+
|
|
161
|
+
**Guidelines:**
|
|
162
|
+
- Define Zod schemas in separate files
|
|
163
|
+
- Export both schema and inferred type
|
|
164
|
+
- Use shared DTO packages in monorepos (frontend + backend)
|
|
165
|
+
- Zod validates at controller layer via ZodValidationPipe
|
|
166
|
+
- DTOs are plain objects, not class-validator decorators
|
|
167
|
+
|
|
168
|
+
**Example DTO file:**
|
|
169
|
+
```typescript
|
|
170
|
+
// dtos/create-building.dto.ts
|
|
171
|
+
import { z } from 'zod';
|
|
172
|
+
|
|
173
|
+
export const CreateBuildingDtoSchema = z.object({
|
|
174
|
+
nameAr: z.string().min(1).max(200),
|
|
175
|
+
nameEn: z.string().min(1).max(200),
|
|
176
|
+
buildingType: z.enum(['RESIDENTIAL', 'COMMERCIAL', 'MIXED']),
|
|
177
|
+
unitCount: z.number().int().positive().max(1000),
|
|
178
|
+
address: z.string().optional(),
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
export type CreateBuildingDto = z.infer<typeof CreateBuildingDtoSchema>;
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Usage in controller:**
|
|
185
|
+
```typescript
|
|
186
|
+
@Post()
|
|
187
|
+
async create(
|
|
188
|
+
@Body(new ZodValidationPipe(CreateBuildingDtoSchema))
|
|
189
|
+
dto: CreateBuildingDto,
|
|
190
|
+
) {
|
|
191
|
+
return { data: await this.buildingService.create(dto) };
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Error Handling
|
|
196
|
+
|
|
197
|
+
A global exception filter standardizes all error responses.
|
|
198
|
+
|
|
199
|
+
**Guidelines:**
|
|
200
|
+
- Services throw DomainException (never HttpException)
|
|
201
|
+
- Global filter catches all exceptions and formats them
|
|
202
|
+
- Error responses include: HTTP status, error_code, message_key, request_id
|
|
203
|
+
- Never expose internal details (stack traces, SQL errors, database column names)
|
|
204
|
+
- Log errors server-side for debugging, send safe messages to client
|
|
205
|
+
|
|
206
|
+
**Error response shape:**
|
|
207
|
+
```typescript
|
|
208
|
+
{
|
|
209
|
+
http_status: 400,
|
|
210
|
+
error_code: "VALIDATION_FAILED",
|
|
211
|
+
message_key: "error.validation_failed",
|
|
212
|
+
request_id: "req_abc123",
|
|
213
|
+
details: { field: "nameAr", reason: "too_short" }
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Exception mapping:**
|
|
218
|
+
```
|
|
219
|
+
DomainException codes:
|
|
220
|
+
NOT_FOUND → 404
|
|
221
|
+
UNAUTHORIZED → 401
|
|
222
|
+
FORBIDDEN → 403
|
|
223
|
+
VALIDATION_FAILED → 400
|
|
224
|
+
CONFLICT → 409
|
|
225
|
+
INTERNAL_ERROR → 500
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Guards
|
|
229
|
+
|
|
230
|
+
Guards enforce authentication and authorization at the controller method level.
|
|
231
|
+
|
|
232
|
+
**AuthGuard:** Validates JWT token and attaches user to request.
|
|
233
|
+
|
|
234
|
+
**RolesGuard:** Checks user role against @Roles() decorator on method.
|
|
235
|
+
|
|
236
|
+
**SubscriptionGuard:** For gated features, validates subscription status before execution.
|
|
237
|
+
|
|
238
|
+
Usage:
|
|
239
|
+
```typescript
|
|
240
|
+
@Post()
|
|
241
|
+
@UseGuards(AuthGuard, RolesGuard)
|
|
242
|
+
@Roles('ADMIN', 'MANAGER')
|
|
243
|
+
async create(@Body() dto: CreateDto) {
|
|
244
|
+
// Only authenticated admins/managers reach here
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Interceptors
|
|
249
|
+
|
|
250
|
+
Interceptors handle cross-cutting concerns around request/response handling.
|
|
251
|
+
|
|
252
|
+
**RequestIdInterceptor:** Generates or propagates a unique request_id UUID for tracing.
|
|
253
|
+
|
|
254
|
+
**LoggingInterceptor:** Logs request and response details (timing, status) — no PII.
|
|
255
|
+
|
|
256
|
+
**TransformInterceptor:** Wraps all responses in `{ data: T }` envelope and adds metadata.
|
|
257
|
+
|
|
258
|
+
Usage:
|
|
259
|
+
```typescript
|
|
260
|
+
// In app.module.ts
|
|
261
|
+
providers: [
|
|
262
|
+
{
|
|
263
|
+
provide: APP_INTERCEPTOR,
|
|
264
|
+
useClass: RequestIdInterceptor,
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
provide: APP_INTERCEPTOR,
|
|
268
|
+
useClass: LoggingInterceptor,
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
provide: APP_INTERCEPTOR,
|
|
272
|
+
useClass: TransformInterceptor,
|
|
273
|
+
},
|
|
274
|
+
];
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Database Integration
|
|
278
|
+
|
|
279
|
+
Supabase is the primary database with RLS (Row-Level Security) policies enforced at the database layer.
|
|
280
|
+
|
|
281
|
+
**Guidelines:**
|
|
282
|
+
- Inject SupabaseService to access client
|
|
283
|
+
- Use `@supabase/supabase-js` for type-safe queries
|
|
284
|
+
- RLS enforced at DB level; service layer adds application-level checks
|
|
285
|
+
- Transactions via stored procedures or `.rpc()` for atomic operations
|
|
286
|
+
- Always handle errors gracefully and log server-side
|
|
287
|
+
|
|
288
|
+
**Example service:**
|
|
289
|
+
```typescript
|
|
290
|
+
async findByOwner(userId: string) {
|
|
291
|
+
const { data, error } = await this.supabase
|
|
292
|
+
.from('buildings')
|
|
293
|
+
.select('*')
|
|
294
|
+
.eq('owner_id', userId);
|
|
295
|
+
|
|
296
|
+
if (error) {
|
|
297
|
+
this.logger.error('Supabase query failed', { error, userId });
|
|
298
|
+
throw new DomainException('INTERNAL_ERROR');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return data ?? [];
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Testing
|
|
306
|
+
|
|
307
|
+
Tests are colocated with source files and follow NestJS testing patterns.
|
|
308
|
+
|
|
309
|
+
**Unit tests for services:**
|
|
310
|
+
- Mock Supabase client
|
|
311
|
+
- Test business logic in isolation
|
|
312
|
+
- Mock other service dependencies
|
|
313
|
+
|
|
314
|
+
**Integration tests for controllers:**
|
|
315
|
+
- Use `supertest` for HTTP testing
|
|
316
|
+
- Create test module with real/mocked dependencies
|
|
317
|
+
- Test full request/response cycle
|
|
318
|
+
|
|
319
|
+
**Test file naming:** `*.spec.ts` next to source file.
|
|
320
|
+
|
|
321
|
+
**Example service test:**
|
|
322
|
+
```typescript
|
|
323
|
+
describe('BuildingService', () => {
|
|
324
|
+
let service: BuildingService;
|
|
325
|
+
let mockSupabase: jest.Mocked<SupabaseService>;
|
|
326
|
+
|
|
327
|
+
beforeEach(async () => {
|
|
328
|
+
mockSupabase = {
|
|
329
|
+
from: jest.fn().mockReturnValue({
|
|
330
|
+
select: jest.fn().mockReturnThis(),
|
|
331
|
+
eq: jest.fn().mockReturnThis(),
|
|
332
|
+
single: jest.fn(),
|
|
333
|
+
}),
|
|
334
|
+
} as any;
|
|
335
|
+
|
|
336
|
+
const module = await Test.createTestingModule({
|
|
337
|
+
providers: [
|
|
338
|
+
BuildingService,
|
|
339
|
+
{ provide: SupabaseService, useValue: mockSupabase },
|
|
340
|
+
],
|
|
341
|
+
}).compile();
|
|
342
|
+
|
|
343
|
+
service = module.get(BuildingService);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should create a building', async () => {
|
|
347
|
+
mockSupabase.from().select().eq().single.mockResolvedValue({
|
|
348
|
+
data: { id: '1', nameAr: 'Test' },
|
|
349
|
+
error: null,
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const result = await service.create({ nameAr: 'Test' });
|
|
353
|
+
expect(result.id).toBe('1');
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Idempotency Pattern
|
|
359
|
+
|
|
360
|
+
For financial or state-changing operations, idempotency keys prevent duplicate processing.
|
|
361
|
+
|
|
362
|
+
**Implementation:**
|
|
363
|
+
```typescript
|
|
364
|
+
async createWithIdempotency(
|
|
365
|
+
dto: CreateDto,
|
|
366
|
+
idempotencyKey: string,
|
|
367
|
+
) {
|
|
368
|
+
// Check if request already processed
|
|
369
|
+
const existing = await this.findByIdempotencyKey(idempotencyKey);
|
|
370
|
+
if (existing) return existing; // Return original result
|
|
371
|
+
|
|
372
|
+
// Create new record with idempotency_key
|
|
373
|
+
const result = await this.create(dto);
|
|
374
|
+
await this.saveIdempotencyKey(idempotencyKey, result.id);
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
**Client usage:**
|
|
380
|
+
```typescript
|
|
381
|
+
@Post()
|
|
382
|
+
async create(
|
|
383
|
+
@Body() dto: CreateDto,
|
|
384
|
+
@IdempotencyKey() key: string,
|
|
385
|
+
) {
|
|
386
|
+
return {
|
|
387
|
+
data: await this.service.createWithIdempotency(dto, key),
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Configuration
|
|
393
|
+
|
|
394
|
+
Configuration is centralized in a Config module with Zod schema validation.
|
|
395
|
+
|
|
396
|
+
**Guidelines:**
|
|
397
|
+
- Validate all env vars at startup (fail fast on misconfiguration)
|
|
398
|
+
- Use Zod for schema validation
|
|
399
|
+
- Typed access via ConfigService
|
|
400
|
+
- Store sensitive values in environment only
|
|
401
|
+
|
|
402
|
+
**Example:**
|
|
403
|
+
```typescript
|
|
404
|
+
const envSchema = z.object({
|
|
405
|
+
PORT: z.string().pipe(z.coerce.number()).default('3000'),
|
|
406
|
+
DATABASE_URL: z.string(),
|
|
407
|
+
JWT_SECRET: z.string(),
|
|
408
|
+
SUPABASE_URL: z.string().url(),
|
|
409
|
+
SUPABASE_ANON_KEY: z.string(),
|
|
410
|
+
NODE_ENV: z.enum(['development', 'production']).default('development'),
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
export type Environment = z.infer<typeof envSchema>;
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Best Practices
|
|
417
|
+
|
|
418
|
+
**Code Organization:**
|
|
419
|
+
- One class per file
|
|
420
|
+
- Controllers handle HTTP only
|
|
421
|
+
- Services handle business logic
|
|
422
|
+
- DTOs in separate folder with Zod schemas
|
|
423
|
+
|
|
424
|
+
**Error Handling:**
|
|
425
|
+
- Never expose stack traces or internal errors to client
|
|
426
|
+
- Log errors server-side for debugging
|
|
427
|
+
- Use domain exceptions for business rule violations
|
|
428
|
+
- Map domain exceptions to HTTP status codes in filter
|
|
429
|
+
|
|
430
|
+
**Security:**
|
|
431
|
+
- Validate all inputs with Zod
|
|
432
|
+
- Use guards for authentication and authorization
|
|
433
|
+
- RLS policies enforced at database layer
|
|
434
|
+
- Never trust client data
|
|
435
|
+
|
|
436
|
+
**Performance:**
|
|
437
|
+
- Use request ID for tracing
|
|
438
|
+
- Log timing for slow queries
|
|
439
|
+
- Lazy-load modules with dynamic imports
|
|
440
|
+
- Use caching for read-heavy operations
|
|
441
|
+
|
|
442
|
+
**Testing:**
|
|
443
|
+
- Unit test services with mocked dependencies
|
|
444
|
+
- Integration test controllers with test database
|
|
445
|
+
- Aim for 70%+ coverage on business logic
|
|
446
|
+
- Test error paths, not just happy paths
|