create-tigra 1.0.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/LICENSE +21 -0
- package/README.md +87 -0
- package/bin/create-tigra.js +292 -0
- package/package.json +41 -0
- package/template/.agent/rules/client/01-project-structure.md +326 -0
- package/template/.agent/rules/client/02-component-patterns.md +249 -0
- package/template/.agent/rules/client/03-typescript-rules.md +226 -0
- package/template/.agent/rules/client/04-state-management.md +474 -0
- package/template/.agent/rules/client/05-api-integration.md +129 -0
- package/template/.agent/rules/client/06-forms-validation.md +129 -0
- package/template/.agent/rules/client/07-common-patterns.md +150 -0
- package/template/.agent/rules/client/08-color-system.md +93 -0
- package/template/.agent/rules/client/09-security-rules.md +97 -0
- package/template/.agent/rules/client/10-testing-strategy.md +370 -0
- package/template/.agent/rules/global/ai-edit-safety.md +38 -0
- package/template/.agent/rules/server/01-db-and-migrations.md +242 -0
- package/template/.agent/rules/server/02-general-rules.md +111 -0
- package/template/.agent/rules/server/03-migrations.md +20 -0
- package/template/.agent/rules/server/04-pagination.md +130 -0
- package/template/.agent/rules/server/05-project-conventions.md +71 -0
- package/template/.agent/rules/server/06-response-handling.md +173 -0
- package/template/.agent/rules/server/07-testing-strategy.md +506 -0
- package/template/.agent/rules/server/08-observability.md +180 -0
- package/template/.agent/rules/server/09-api-documentation-v2.md +168 -0
- package/template/.agent/rules/server/10-background-jobs-v2.md +185 -0
- package/template/.agent/rules/server/11-rate-limiting-v2.md +210 -0
- package/template/.agent/rules/server/12-performance-optimization.md +567 -0
- package/template/.claude/rules/client-01-project-structure.md +327 -0
- package/template/.claude/rules/client-02-component-patterns.md +250 -0
- package/template/.claude/rules/client-03-typescript-rules.md +227 -0
- package/template/.claude/rules/client-04-state-management.md +475 -0
- package/template/.claude/rules/client-05-api-integration.md +130 -0
- package/template/.claude/rules/client-06-forms-validation.md +130 -0
- package/template/.claude/rules/client-07-common-patterns.md +151 -0
- package/template/.claude/rules/client-08-color-system.md +94 -0
- package/template/.claude/rules/client-09-security-rules.md +98 -0
- package/template/.claude/rules/client-10-testing-strategy.md +371 -0
- package/template/.claude/rules/global-ai-edit-safety.md +39 -0
- package/template/.claude/rules/server-01-db-and-migrations.md +243 -0
- package/template/.claude/rules/server-02-general-rules.md +112 -0
- package/template/.claude/rules/server-03-migrations.md +21 -0
- package/template/.claude/rules/server-04-pagination.md +131 -0
- package/template/.claude/rules/server-05-project-conventions.md +72 -0
- package/template/.claude/rules/server-06-response-handling.md +174 -0
- package/template/.claude/rules/server-07-testing-strategy.md +507 -0
- package/template/.claude/rules/server-08-observability.md +181 -0
- package/template/.claude/rules/server-09-api-documentation-v2.md +169 -0
- package/template/.claude/rules/server-10-background-jobs-v2.md +186 -0
- package/template/.claude/rules/server-11-rate-limiting-v2.md +211 -0
- package/template/.claude/rules/server-12-performance-optimization.md +568 -0
- package/template/.cursor/rules/client-01-project-structure.mdc +327 -0
- package/template/.cursor/rules/client-02-component-patterns.mdc +250 -0
- package/template/.cursor/rules/client-03-typescript-rules.mdc +227 -0
- package/template/.cursor/rules/client-04-state-management.mdc +475 -0
- package/template/.cursor/rules/client-05-api-integration.mdc +130 -0
- package/template/.cursor/rules/client-06-forms-validation.mdc +130 -0
- package/template/.cursor/rules/client-07-common-patterns.mdc +151 -0
- package/template/.cursor/rules/client-08-color-system.mdc +94 -0
- package/template/.cursor/rules/client-09-security-rules.mdc +98 -0
- package/template/.cursor/rules/client-10-testing-strategy.mdc +371 -0
- package/template/.cursor/rules/global-ai-edit-safety.mdc +39 -0
- package/template/.cursor/rules/server-01-db-and-migrations.mdc +243 -0
- package/template/.cursor/rules/server-02-general-rules.mdc +112 -0
- package/template/.cursor/rules/server-03-migrations.mdc +21 -0
- package/template/.cursor/rules/server-04-pagination.mdc +131 -0
- package/template/.cursor/rules/server-05-project-conventions.mdc +72 -0
- package/template/.cursor/rules/server-06-response-handling.mdc +174 -0
- package/template/.cursor/rules/server-07-testing-strategy.mdc +507 -0
- package/template/.cursor/rules/server-08-observability.mdc +181 -0
- package/template/.cursor/rules/server-09-api-documentation-v2.mdc +169 -0
- package/template/.cursor/rules/server-10-background-jobs-v2.mdc +186 -0
- package/template/.cursor/rules/server-11-rate-limiting-v2.mdc +211 -0
- package/template/.cursor/rules/server-12-performance-optimization.mdc +568 -0
- package/template/CLAUDE.md +207 -0
- package/template/server/.env.example +148 -0
- package/template/server/.tsc-aliasrc.json +12 -0
- package/template/server/README.md +175 -0
- package/template/server/SECURITY.md +190 -0
- package/template/server/biome.json +42 -0
- package/template/server/docker-compose.yml +111 -0
- package/template/server/package.json +83 -0
- package/template/server/postman_collection.json +733 -0
- package/template/server/prisma/schema.prisma +92 -0
- package/template/server/prisma/seed.ts +142 -0
- package/template/server/scripts/wait-for-db.js +60 -0
- package/template/server/src/app.ts +74 -0
- package/template/server/src/config/env.ts +101 -0
- package/template/server/src/hooks/request-timing.hook.ts +26 -0
- package/template/server/src/libs/auth/authenticate.middleware.ts +22 -0
- package/template/server/src/libs/auth/rbac.middleware.test.ts +134 -0
- package/template/server/src/libs/auth/rbac.middleware.ts +147 -0
- package/template/server/src/libs/db.ts +76 -0
- package/template/server/src/libs/error-handler.ts +89 -0
- package/template/server/src/libs/logger.ts +60 -0
- package/template/server/src/libs/queue.ts +79 -0
- package/template/server/src/libs/redis.ts +79 -0
- package/template/server/src/libs/swagger-schemas.ts +16 -0
- package/template/server/src/modules/admin/admin.controller.ts +122 -0
- package/template/server/src/modules/admin/admin.routes.ts +100 -0
- package/template/server/src/modules/admin/admin.schemas.ts +35 -0
- package/template/server/src/modules/admin/admin.service.ts +167 -0
- package/template/server/src/modules/auth/auth.controller.ts +141 -0
- package/template/server/src/modules/auth/auth.integration.test.ts +150 -0
- package/template/server/src/modules/auth/auth.repo.ts +218 -0
- package/template/server/src/modules/auth/auth.routes.ts +204 -0
- package/template/server/src/modules/auth/auth.schemas.ts +137 -0
- package/template/server/src/modules/auth/auth.service.test.ts +119 -0
- package/template/server/src/modules/auth/auth.service.ts +329 -0
- package/template/server/src/modules/auth/auth.types.ts +97 -0
- package/template/server/src/modules/resources/resources.controller.ts +218 -0
- package/template/server/src/modules/resources/resources.repo.ts +253 -0
- package/template/server/src/modules/resources/resources.routes.ts +355 -0
- package/template/server/src/modules/resources/resources.schemas.ts +146 -0
- package/template/server/src/modules/resources/resources.service.ts +218 -0
- package/template/server/src/modules/resources/resources.types.ts +73 -0
- package/template/server/src/plugins/rate-limit.plugin.ts +21 -0
- package/template/server/src/plugins/security.plugin.ts +21 -0
- package/template/server/src/plugins/swagger.plugin.ts +41 -0
- package/template/server/src/routes/health.routes.ts +31 -0
- package/template/server/src/server.ts +142 -0
- package/template/server/src/test/setup.ts +38 -0
- package/template/server/src/types/fastify.d.ts +36 -0
- package/template/server/src/utils/errors.ts +108 -0
- package/template/server/src/utils/pagination.ts +120 -0
- package/template/server/src/utils/response.ts +110 -0
- package/template/server/src/workers/file.worker.ts +106 -0
- package/template/server/tsconfig.build.json +30 -0
- package/template/server/tsconfig.build.tsbuildinfo +1 -0
- package/template/server/tsconfig.json +89 -0
- package/template/server/tsconfig.test.json +22 -0
- package/template/server/vitest.config.ts +98 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
trigger: always_on
|
|
3
|
+
globs: "server/**/*"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **SCOPE**: These rules apply specifically to the **server** directory.
|
|
7
|
+
|
|
8
|
+
You are a senior backend engineer helping build a high-traffic API server.
|
|
9
|
+
|
|
10
|
+
### PROJECT CONTEXT
|
|
11
|
+
|
|
12
|
+
- Stack:
|
|
13
|
+
|
|
14
|
+
- Node.js (LTS, 20+)
|
|
15
|
+
- Fastify as HTTP framework
|
|
16
|
+
- TypeScript
|
|
17
|
+
- MySQL as the primary relational database
|
|
18
|
+
- Redis for caching, sessions, and rate limiting
|
|
19
|
+
- Zod for runtime validation and type inference
|
|
20
|
+
- Drizzle ORM (or Prisma) for DB access and migrations
|
|
21
|
+
- Jest/Vitest for tests
|
|
22
|
+
|
|
23
|
+
- Domain:
|
|
24
|
+
|
|
25
|
+
- Users & Roles
|
|
26
|
+
- Core Business Entities
|
|
27
|
+
- Locations & Mapping
|
|
28
|
+
- Media (images, galleries)
|
|
29
|
+
- Resources Availability & Pricing
|
|
30
|
+
- Transactions & Bookings
|
|
31
|
+
- Payments (integration with external providers)
|
|
32
|
+
- Messaging & Communications
|
|
33
|
+
|
|
34
|
+
- Goals:
|
|
35
|
+
- Clean, layered architecture: Routes → Controllers → Services → Repositories → DB
|
|
36
|
+
- High performance (Fastify, Redis, proper indexes)
|
|
37
|
+
- Easy to maintain and scale
|
|
38
|
+
- Secure (auth, input validation, rate limiting)
|
|
39
|
+
- Clear separation of concerns
|
|
40
|
+
|
|
41
|
+
### ARCHITECTURE & CODE STYLE
|
|
42
|
+
|
|
43
|
+
1. Use TypeScript everywhere. Always type function parameters and return types.
|
|
44
|
+
2. Organize by domain/module:
|
|
45
|
+
|
|
46
|
+
src/modules/<domain>/
|
|
47
|
+
|
|
48
|
+
- <domain>.routes.ts (Fastify route definitions)
|
|
49
|
+
- <domain>.controller.ts (HTTP handlers only; no business logic)
|
|
50
|
+
- <domain>.service.ts (business logic)
|
|
51
|
+
- <domain>.repo.ts (DB queries)
|
|
52
|
+
- <domain>.schemas.ts (Zod schemas for input/output)
|
|
53
|
+
|
|
54
|
+
3. Fastify:
|
|
55
|
+
|
|
56
|
+
- Use plugins and route registration with prefixes (e.g., /api/v1/<resource>).
|
|
57
|
+
- Use schemas for validation & serialization.
|
|
58
|
+
- Implement centralized error handling.
|
|
59
|
+
|
|
60
|
+
4. Database:
|
|
61
|
+
|
|
62
|
+
- Use migrations (via Drizzle/Prisma) for schema changes.
|
|
63
|
+
- Add proper indexes for search-heavy fields (identifiers, price, date, type).
|
|
64
|
+
- Avoid N+1 queries; prefer joins or batched queries.
|
|
65
|
+
|
|
66
|
+
5. Redis:
|
|
67
|
+
|
|
68
|
+
- Use for caching frequently accessed data.
|
|
69
|
+
- Use for rate limiting and potentially for background task signaling.
|
|
70
|
+
|
|
71
|
+
6. Auth:
|
|
72
|
+
|
|
73
|
+
- Use JWT with HS256 or RS256.
|
|
74
|
+
- Store only minimal user info in the token (id, role).
|
|
75
|
+
- Implement role-based access control.
|
|
76
|
+
|
|
77
|
+
7. Security:
|
|
78
|
+
|
|
79
|
+
- Validate all inputs with Zod and Fastify schemas.
|
|
80
|
+
- Never interpolate raw values into SQL; always use the ORM query builder.
|
|
81
|
+
- Implement sane rate limiting for public endpoints.
|
|
82
|
+
- Sanitize outputs where necessary.
|
|
83
|
+
|
|
84
|
+
8. Coding constraints:
|
|
85
|
+
|
|
86
|
+
- Do NOT break existing exports or types unless explicitly asked.
|
|
87
|
+
- When modifying existing files, keep changes focused and minimal.
|
|
88
|
+
- Reuse existing helpers (db, logger, env) instead of re-creating them.
|
|
89
|
+
- Add TODO comments for non-trivial follow-up tasks.
|
|
90
|
+
|
|
91
|
+
9. When asked to implement a feature:
|
|
92
|
+
|
|
93
|
+
- First, summarize what needs to be done.
|
|
94
|
+
- Then list files to be created/modified.
|
|
95
|
+
- Then provide code for each file in separate code blocks.
|
|
96
|
+
- Ensure imports between files are correct and consistent with the project structure.
|
|
97
|
+
|
|
98
|
+
10. Testing:
|
|
99
|
+
|
|
100
|
+
- For core logic (calculations, transactions, payment callbacks), provide Jest/Vitest tests.
|
|
101
|
+
- Tests should be deterministic and not hit external APIs directly (use mocks).
|
|
102
|
+
|
|
103
|
+
### RESPONSE FORMAT
|
|
104
|
+
|
|
105
|
+
Whenever you make changes:
|
|
106
|
+
|
|
107
|
+
1. Briefly explain the approach (1–2 paragraphs).
|
|
108
|
+
2. Show updated/created files with full content in code blocks.
|
|
109
|
+
3. Mention any migrations or environment variables that must be added.
|
|
110
|
+
4. If you are unsure, state your assumptions clearly.
|
|
111
|
+
|
|
112
|
+
If instructions from earlier parts of the prompt conflict with the user’s new message, follow the user’s latest explicit instructions.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
trigger: always_on
|
|
3
|
+
globs: "server/**/*"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **SCOPE**: These rules apply specifically to the **server** directory.
|
|
7
|
+
|
|
8
|
+
# Migration Rules for AI Agent
|
|
9
|
+
|
|
10
|
+
CRITICAL: When user asks for schema changes:
|
|
11
|
+
|
|
12
|
+
1. ALWAYS edit `prisma/schema.prisma` first
|
|
13
|
+
2. THEN run: `npm run prisma:migrate dev --name descriptive_name`
|
|
14
|
+
3. IF migration fails with conflicts:
|
|
15
|
+
- DON'T try to fix manually
|
|
16
|
+
- DO run: `npm run prisma:reset`
|
|
17
|
+
- Then: `npm run prisma:seed`
|
|
18
|
+
4. NEVER use `prisma db push` unless explicitly asked
|
|
19
|
+
|
|
20
|
+
Development = use prisma:reset freely
|
|
21
|
+
Production = ONLY use prisma:migrate deploy
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
trigger: always_on
|
|
3
|
+
globs: "server/**/*"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **SCOPE**: These rules apply specifically to the **server** directory.
|
|
7
|
+
|
|
8
|
+
## Pagination Contract (MANDATORY)
|
|
9
|
+
|
|
10
|
+
All paginated API responses MUST follow a unified structure. No exceptions are allowed.
|
|
11
|
+
|
|
12
|
+
### Paginated Response Format
|
|
13
|
+
|
|
14
|
+
Every paginated response MUST follow this exact structure:
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"success": true,
|
|
18
|
+
"message": "string",
|
|
19
|
+
"data": {
|
|
20
|
+
"items": [],
|
|
21
|
+
"pagination": {
|
|
22
|
+
"page": 1,
|
|
23
|
+
"limit": 10,
|
|
24
|
+
"totalItems": 237,
|
|
25
|
+
"totalPages": 24,
|
|
26
|
+
"hasNextPage": true,
|
|
27
|
+
"hasPreviousPage": false
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Response Rules
|
|
34
|
+
|
|
35
|
+
- `success` is always `true`
|
|
36
|
+
- `message` is REQUIRED and must be human-readable
|
|
37
|
+
- `data.items` contains the array of results (can be empty array)
|
|
38
|
+
- `data.pagination` is REQUIRED and contains:
|
|
39
|
+
- `page` – current page number (starts at 1)
|
|
40
|
+
- `limit` – items per page
|
|
41
|
+
- `totalItems` – total count of items across all pages
|
|
42
|
+
- `totalPages` – calculated as `Math.ceil(totalItems / limit)`
|
|
43
|
+
- `hasNextPage` – boolean, `true` if `page < totalPages`
|
|
44
|
+
- `hasPreviousPage` – boolean, `true` if `page > 1`
|
|
45
|
+
|
|
46
|
+
### Shared Pagination Helper (REQUIRED)
|
|
47
|
+
|
|
48
|
+
Controllers MUST use a shared `paginatedResponse` helper:
|
|
49
|
+
```typescript
|
|
50
|
+
function paginatedResponse<T>(
|
|
51
|
+
message: string,
|
|
52
|
+
items: T[],
|
|
53
|
+
page: number,
|
|
54
|
+
limit: number,
|
|
55
|
+
totalItems: number
|
|
56
|
+
)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Allowed example:**
|
|
60
|
+
```typescript
|
|
61
|
+
return reply.send(paginatedResponse("Resources retrieved successfully", items, page, limit, totalCount));
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Forbidden examples:**
|
|
65
|
+
```typescript
|
|
66
|
+
reply.send({ items, page, total });
|
|
67
|
+
reply.send({ success: true, data: items, pagination: {...} });
|
|
68
|
+
reply.send({ items: items, meta: {...} });
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Pagination Input Validation (REQUIRED)
|
|
72
|
+
|
|
73
|
+
All endpoints accepting pagination MUST validate using a shared Zod schema:
|
|
74
|
+
```typescript
|
|
75
|
+
const PaginationSchema = z.object({
|
|
76
|
+
page: z.coerce.number().int().min(1).default(1),
|
|
77
|
+
limit: z.coerce.number().int().min(1).max(100).default(10)
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Rules:**
|
|
82
|
+
- `page` defaults to `1`, must be positive integer
|
|
83
|
+
- `limit` defaults to `10`, must be between 1 and 100
|
|
84
|
+
- Use `z.coerce.number()` to handle query string conversion
|
|
85
|
+
- Controllers MUST validate pagination inputs before calling services
|
|
86
|
+
|
|
87
|
+
### Service Layer Requirements
|
|
88
|
+
|
|
89
|
+
Services handling pagination MUST:
|
|
90
|
+
- Accept `page` and `limit` as parameters
|
|
91
|
+
- Return both the `items` array AND `totalItems` count
|
|
92
|
+
- NOT construct pagination metadata (controller responsibility)
|
|
93
|
+
- Calculate offset as: `(page - 1) * limit`
|
|
94
|
+
|
|
95
|
+
**Service return pattern:**
|
|
96
|
+
```typescript
|
|
97
|
+
return {
|
|
98
|
+
items: results,
|
|
99
|
+
totalItems: count
|
|
100
|
+
};
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Filter & Sort with Pagination
|
|
104
|
+
|
|
105
|
+
When combining filters/sorting with pagination:
|
|
106
|
+
- Filters come BEFORE pagination in query parameters
|
|
107
|
+
- Pagination params (`page`, `limit`) are separate from filters
|
|
108
|
+
- Apply filters/sorting to query BEFORE applying `limit` and `offset`
|
|
109
|
+
- Count total items AFTER filters but BEFORE pagination
|
|
110
|
+
|
|
111
|
+
**Example query string:**
|
|
112
|
+
```
|
|
113
|
+
?category=active&minPrice=100&sortBy=price&order=asc&page=2&limit=20
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Strict Prohibitions
|
|
117
|
+
|
|
118
|
+
These patterns are NOT allowed:
|
|
119
|
+
- Multiple pagination formats across endpoints
|
|
120
|
+
- Returning raw arrays without pagination wrapper
|
|
121
|
+
- Custom pagination field names (e.g., `pageNumber`, `perPage`, `count`)
|
|
122
|
+
- Including pagination in query results instead of metadata
|
|
123
|
+
- Zero-indexed pages (always start at 1)
|
|
124
|
+
- Omitting `totalItems` or `totalPages`
|
|
125
|
+
|
|
126
|
+
### Enforcement Rule
|
|
127
|
+
|
|
128
|
+
If a user instruction conflicts with this pagination contract:
|
|
129
|
+
- Follow the user instruction ONLY if explicitly stated
|
|
130
|
+
- Otherwise, this pagination contract is non-negotiable
|
|
131
|
+
- Pagination structure MUST be consistent across ALL endpoints
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
trigger: always_on
|
|
3
|
+
globs: "server/**/*"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **SCOPE**: These rules apply specifically to the **server** directory.
|
|
7
|
+
|
|
8
|
+
# API Server – Project Conventions
|
|
9
|
+
|
|
10
|
+
## Package manager
|
|
11
|
+
|
|
12
|
+
- Detect the package manager from the lockfile:
|
|
13
|
+
- If `pnpm-lock.yaml` exists → use `pnpm`
|
|
14
|
+
- If `yarn.lock` exists → use `yarn`
|
|
15
|
+
- Else → use `npm`
|
|
16
|
+
|
|
17
|
+
## File & folder structure
|
|
18
|
+
|
|
19
|
+
- Keep everything under `src/`.
|
|
20
|
+
- Prefer this layout:
|
|
21
|
+
|
|
22
|
+
- `src/app.ts` → Fastify instance and plugin registration
|
|
23
|
+
- `src/server.ts` → actual `listen()` call, no app logic
|
|
24
|
+
- `src/config/` → env, config, constants
|
|
25
|
+
- `src/libs/` → shared libraries (db, redis, logger, auth)
|
|
26
|
+
- `src/modules/<domain>/` → domain modules:
|
|
27
|
+
- `<domain>.routes.ts`
|
|
28
|
+
- `<domain>.controller.ts`
|
|
29
|
+
- `<domain>.service.ts`
|
|
30
|
+
- `<domain>.repo.ts`
|
|
31
|
+
- `<domain>.schemas.ts`
|
|
32
|
+
- `<domain>.types.ts` (if needed)
|
|
33
|
+
|
|
34
|
+
- When adding new modules, stick to `src/modules/<name>/` and keep the exact naming pattern.
|
|
35
|
+
|
|
36
|
+
## Coding style
|
|
37
|
+
|
|
38
|
+
- Use TypeScript with `strict` mode ON.
|
|
39
|
+
- Prefer `async/await` over `.then()`.
|
|
40
|
+
- Prefer named exports over default exports, except for:
|
|
41
|
+
- `src/app.ts` → default export is the Fastify instance
|
|
42
|
+
- Frontend components (if any).
|
|
43
|
+
- Use consistent import paths:
|
|
44
|
+
- Use relative imports inside a module: `./user.service`
|
|
45
|
+
- Use aliased imports for cross-module paths if configured (e.g. `@modules/users/...`).
|
|
46
|
+
|
|
47
|
+
## Error handling
|
|
48
|
+
|
|
49
|
+
- Controllers must never throw raw errors; they should:
|
|
50
|
+
- Either use a shared error helper, or
|
|
51
|
+
- Let Fastify’s error handler handle typed errors.
|
|
52
|
+
- Never `console.log` for production logic:
|
|
53
|
+
- Use the shared `logger` from `src/libs/logger`.
|
|
54
|
+
|
|
55
|
+
## API versioning & routes
|
|
56
|
+
|
|
57
|
+
- All API routes must be prefixed with `/api/v1`.
|
|
58
|
+
- Group routes by domain:
|
|
59
|
+
- `/api/v1/auth/...`
|
|
60
|
+
- `/api/v1/users/...`
|
|
61
|
+
- `/api/v1/<domain_resource>/...`
|
|
62
|
+
- When adding new routes, register them in a Fastify plugin under `src/modules/<domain>/<domain>.routes.ts`.
|
|
63
|
+
|
|
64
|
+
## Service Layer Rules
|
|
65
|
+
|
|
66
|
+
- Every domain module must include a `<domain>.service.ts` file.
|
|
67
|
+
- Services contain all business logic and must NOT depend on Fastify, reply, request, or HTTP-specific concepts.
|
|
68
|
+
- Controllers must call services instead of performing logic directly.
|
|
69
|
+
- Services may call repositories for DB operations.
|
|
70
|
+
- Services must throw typed AppError instances for failures.
|
|
71
|
+
- Services must not return success or error responses; they only return data or throw errors.
|
|
72
|
+
- Services must be stateless and reusable.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
trigger: always_on
|
|
3
|
+
globs: "server/**/*"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **SCOPE**: These rules apply specifically to the **server** directory.
|
|
7
|
+
|
|
8
|
+
API Server – Error & Success Response Rules
|
|
9
|
+
|
|
10
|
+
These rules define the ONLY allowed way to return success and error responses from the API. All AI assistants MUST follow this contract strictly.
|
|
11
|
+
|
|
12
|
+
Unified Response Contract (MANDATORY)
|
|
13
|
+
The API uses a single, stable response structure for all endpoints. No exceptions are allowed.
|
|
14
|
+
|
|
15
|
+
Success Response Format
|
|
16
|
+
Every successful response MUST follow this exact structure:
|
|
17
|
+
|
|
18
|
+
{
|
|
19
|
+
"success": true,
|
|
20
|
+
"message": "string",
|
|
21
|
+
"data": {}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
Rules:
|
|
25
|
+
|
|
26
|
+
success is always true
|
|
27
|
+
|
|
28
|
+
message is REQUIRED and must be human-readable
|
|
29
|
+
|
|
30
|
+
data can be an object, array, or null
|
|
31
|
+
|
|
32
|
+
Controllers MUST use a shared success helper (for example successResponse)
|
|
33
|
+
|
|
34
|
+
Controllers MUST NOT return raw values or custom-shaped JSON
|
|
35
|
+
|
|
36
|
+
Allowed example:
|
|
37
|
+
return reply.send(successResponse("Resource created successfully", data));
|
|
38
|
+
|
|
39
|
+
Forbidden examples:
|
|
40
|
+
reply.send(data);
|
|
41
|
+
reply.send({ data: data });
|
|
42
|
+
reply.send({ success: true, data });
|
|
43
|
+
|
|
44
|
+
Error Response Format
|
|
45
|
+
Every error response MUST follow this exact structure:
|
|
46
|
+
|
|
47
|
+
{
|
|
48
|
+
"success": false,
|
|
49
|
+
"error": {
|
|
50
|
+
"code": "ERROR_CODE",
|
|
51
|
+
"message": "Human readable message"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Rules:
|
|
56
|
+
|
|
57
|
+
success is always false
|
|
58
|
+
|
|
59
|
+
code must be a stable machine-readable string (for example RESOURCE_NOT_FOUND)
|
|
60
|
+
|
|
61
|
+
message must be safe for end users
|
|
62
|
+
|
|
63
|
+
Internal details, stack traces, or SQL errors MUST NOT be exposed
|
|
64
|
+
|
|
65
|
+
Controllers MUST NOT manually send error responses
|
|
66
|
+
|
|
67
|
+
Global Error Handling Architecture
|
|
68
|
+
The server MUST define ONE global Fastify error handler using fastify.setErrorHandler(...).
|
|
69
|
+
This global handler is responsible for:
|
|
70
|
+
|
|
71
|
+
Mapping errors to HTTP status codes
|
|
72
|
+
|
|
73
|
+
Formatting the unified error response
|
|
74
|
+
|
|
75
|
+
Logging internal error details on server side only
|
|
76
|
+
|
|
77
|
+
Error Throwing Rules (CRITICAL)
|
|
78
|
+
Controllers and services MUST throw typed errors ONLY.
|
|
79
|
+
They MUST NOT throw:
|
|
80
|
+
|
|
81
|
+
raw Error
|
|
82
|
+
|
|
83
|
+
strings
|
|
84
|
+
|
|
85
|
+
unstructured objects
|
|
86
|
+
|
|
87
|
+
Required Error Base Class
|
|
88
|
+
All custom errors MUST extend a shared AppError class which defines:
|
|
89
|
+
|
|
90
|
+
code
|
|
91
|
+
|
|
92
|
+
message
|
|
93
|
+
|
|
94
|
+
statusCode
|
|
95
|
+
|
|
96
|
+
Allowed Error Types
|
|
97
|
+
Allowed subclasses:
|
|
98
|
+
|
|
99
|
+
BadRequestError
|
|
100
|
+
|
|
101
|
+
ValidationError
|
|
102
|
+
|
|
103
|
+
UnauthorizedError
|
|
104
|
+
|
|
105
|
+
ForbiddenError
|
|
106
|
+
|
|
107
|
+
NotFoundError
|
|
108
|
+
|
|
109
|
+
ConflictError
|
|
110
|
+
|
|
111
|
+
InternalError
|
|
112
|
+
|
|
113
|
+
Each subclass MUST:
|
|
114
|
+
|
|
115
|
+
extend AppError
|
|
116
|
+
|
|
117
|
+
set a meaningful code
|
|
118
|
+
|
|
119
|
+
set an appropriate statusCode
|
|
120
|
+
|
|
121
|
+
Controller Responsibilities
|
|
122
|
+
Controllers MUST:
|
|
123
|
+
|
|
124
|
+
Validate input using Zod schemas
|
|
125
|
+
|
|
126
|
+
Call service-layer logic only
|
|
127
|
+
|
|
128
|
+
Return success responses using the shared success helper
|
|
129
|
+
|
|
130
|
+
Throw typed errors when something fails
|
|
131
|
+
|
|
132
|
+
Controllers MUST NOT:
|
|
133
|
+
|
|
134
|
+
Set HTTP status codes for errors
|
|
135
|
+
|
|
136
|
+
Build custom error JSON structures
|
|
137
|
+
|
|
138
|
+
Catch errors unless rethrowing typed errors
|
|
139
|
+
|
|
140
|
+
Service Layer Responsibilities
|
|
141
|
+
Services MUST:
|
|
142
|
+
|
|
143
|
+
Contain business logic
|
|
144
|
+
|
|
145
|
+
Throw typed AppError errors when needed
|
|
146
|
+
|
|
147
|
+
NEVER depend on Fastify reply or HTTP objects
|
|
148
|
+
|
|
149
|
+
Logging Rules
|
|
150
|
+
Logging MUST occur only inside:
|
|
151
|
+
|
|
152
|
+
The global error handler
|
|
153
|
+
|
|
154
|
+
Shared logging utilities
|
|
155
|
+
|
|
156
|
+
Controllers MUST NOT log unless explicitly instructed. Internal logs MUST NOT be sent to the client.
|
|
157
|
+
|
|
158
|
+
Strict Prohibitions
|
|
159
|
+
These patterns are NOT allowed anywhere:
|
|
160
|
+
|
|
161
|
+
Multiple response formats
|
|
162
|
+
|
|
163
|
+
reply.send({ error: "text" })
|
|
164
|
+
|
|
165
|
+
throw new Error("message")
|
|
166
|
+
|
|
167
|
+
Returning raw errors from services
|
|
168
|
+
|
|
169
|
+
Leaking stack traces or database internals to users
|
|
170
|
+
|
|
171
|
+
Final Enforcement Rule
|
|
172
|
+
If a user instruction conflicts with this document:
|
|
173
|
+
Follow the user instruction ONLY if explicitly stated.
|
|
174
|
+
Otherwise, this response contract is non-negotiable.
|