create-tigra 3.0.5 → 3.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.
Files changed (83) hide show
  1. package/README.md +4 -2
  2. package/bin/create-tigra.js +5 -19
  3. package/modules/email-verification/client/hooks/useVerification.ts +3 -3
  4. package/package.json +1 -1
  5. package/template/.agents/skills/security-audit/AI-AND-LLM.md +83 -0
  6. package/template/.agents/skills/security-audit/ATTACK-CLASSES.md +130 -0
  7. package/template/.agents/skills/security-audit/CLIENT-SIDE.md +83 -0
  8. package/template/.agents/skills/security-audit/CLOUD-AND-DEPLOYMENT.md +86 -0
  9. package/template/.agents/skills/security-audit/DATA-ISOLATION-AND-LIFECYCLE.md +84 -0
  10. package/template/.agents/skills/security-audit/DESKTOP-MOBILE-AND-LOCAL-IPC.md +89 -0
  11. package/template/.agents/skills/security-audit/HUNTING.md +251 -0
  12. package/template/.agents/skills/security-audit/LICENSE +21 -0
  13. package/template/.agents/skills/security-audit/MEMORY-SAFETY-AND-BINARY.md +101 -0
  14. package/template/.agents/skills/security-audit/PROTOCOLS-RPC-AND-MESSAGING.md +81 -0
  15. package/template/.agents/skills/security-audit/RECONNAISSANCE.md +156 -0
  16. package/template/.agents/skills/security-audit/RESOURCE-EXHAUSTION-AND-AVAILABILITY.md +78 -0
  17. package/template/.agents/skills/security-audit/SKILL.md +192 -0
  18. package/template/.agents/skills/security-audit/SOURCE.md +5 -0
  19. package/template/.agents/skills/security-audit/SUPPLY-CHAIN-AND-RELEASE.md +73 -0
  20. package/template/.agents/skills/security-audit/VALIDATION-AND-REPORTING.md +186 -0
  21. package/template/.agents/skills/security-audit/WEB-PROTOCOL-AND-AUTH.md +105 -0
  22. package/template/.agents/skills/security-audit/report-schema.json +461 -0
  23. package/template/.agents/skills/security-audit/validate-coverage-ledger.cjs +872 -0
  24. package/template/.agents/skills/security-audit/validate-coverage-ledger.test.cjs +740 -0
  25. package/template/.agents/skills/security-audit/validate-findings.cjs +773 -0
  26. package/template/.agents/skills/security-audit/validate-findings.test.cjs +652 -0
  27. package/template/AGENTS.md +45 -0
  28. package/template/client/AGENTS.md +22 -0
  29. package/template/client/package-lock.json +410 -324
  30. package/template/client/package.json +3 -3
  31. package/template/client/src/app/(auth)/layout.tsx +9 -0
  32. package/template/client/src/app/(auth)/loading.tsx +7 -0
  33. package/template/client/src/app/(main)/layout.tsx +11 -0
  34. package/template/client/src/app/(main)/loading.tsx +7 -0
  35. package/template/client/src/app/globals.css +4 -0
  36. package/template/client/src/app/loading.tsx +2 -6
  37. package/template/client/src/app/not-found.tsx +2 -3
  38. package/template/client/src/app/providers.tsx +6 -3
  39. package/template/client/src/components/common/AppLink.tsx +84 -0
  40. package/template/client/src/components/common/EmptyState.tsx +2 -2
  41. package/template/client/src/components/common/Pagination.tsx +3 -2
  42. package/template/client/src/components/common/RouteLoadingShell.tsx +21 -0
  43. package/template/client/src/components/common/SmoothNavigationProvider.tsx +151 -0
  44. package/template/client/src/components/layout/Header.tsx +12 -12
  45. package/template/client/src/features/admin/hooks/useAdminSessions.ts +2 -2
  46. package/template/client/src/features/admin/hooks/useAdminUsers.ts +3 -3
  47. package/template/client/src/features/auth/components/AuthInitializer.tsx +3 -2
  48. package/template/client/src/features/auth/components/LoginForm.tsx +3 -3
  49. package/template/client/src/features/auth/components/RegisterForm.tsx +3 -3
  50. package/template/client/src/features/auth/hooks/useAuth.ts +2 -2
  51. package/template/client/src/features/auth/hooks/usePasswordReset.ts +2 -2
  52. package/template/client/src/hooks/useAppRouter.ts +40 -0
  53. package/template/client/src/styles/themes/default.css +1 -1
  54. package/template/gitignore +0 -6
  55. package/template/server/AGENTS.md +28 -0
  56. package/template/server/package-lock.json +671 -522
  57. package/template/server/package.json +8 -8
  58. package/template/_claude/QUICK_REFERENCE.md +0 -193
  59. package/template/_claude/README.md +0 -53
  60. package/template/_claude/commands/create-client.md +0 -878
  61. package/template/_claude/commands/create-server.md +0 -388
  62. package/template/_claude/hooks/restrict-paths.sh +0 -51
  63. package/template/_claude/rules/client/01-project-structure.md +0 -147
  64. package/template/_claude/rules/client/02-components-and-types.md +0 -146
  65. package/template/_claude/rules/client/03-data-and-state.md +0 -195
  66. package/template/_claude/rules/client/04-design-system.md +0 -408
  67. package/template/_claude/rules/client/05-security.md +0 -55
  68. package/template/_claude/rules/client/06-ux-checklist.md +0 -111
  69. package/template/_claude/rules/client/07-deployment.md +0 -99
  70. package/template/_claude/rules/client/08-lockfile-cross-platform.md +0 -79
  71. package/template/_claude/rules/client/core.md +0 -46
  72. package/template/_claude/rules/global/completion-reports.md +0 -178
  73. package/template/_claude/rules/global/core.md +0 -104
  74. package/template/_claude/rules/global/investigation-before-conclusions.md +0 -57
  75. package/template/_claude/rules/server/core.md +0 -52
  76. package/template/_claude/rules/server/database.md +0 -124
  77. package/template/_claude/rules/server/deployment.md +0 -78
  78. package/template/_claude/rules/server/project-conventions.md +0 -254
  79. package/template/_claude/rules/server/response-handling.md +0 -144
  80. package/template/_claude/settings.json +0 -15
  81. package/template/_claude/skills/clean-ui/SKILL.md +0 -63
  82. package/template/_claude/skills/role/SKILL.md +0 -39
  83. package/template/_claude/skills/theme/SKILL.md +0 -109
@@ -1,78 +0,0 @@
1
- > **SCOPE**: These rules apply specifically to the **server** directory.
2
-
3
- # Deployment & Docker
4
-
5
- This project is deployed via **Docker** on **Coolify** (or any Docker-based platform). The `Dockerfile` is the production deployment contract. Every code change must remain compatible with it.
6
-
7
- ---
8
-
9
- ## Dockerfile Architecture
10
-
11
- The server uses a **3-stage multi-stage build**:
12
-
13
- ```
14
- Stage 1 (dependencies) → Installs prod-only node_modules (cached layer)
15
- Stage 2 (builder) → Installs all deps, generates Prisma client, compiles TypeScript
16
- Stage 3 (production) → Alpine + dumb-init, non-root user, copies dist + prod node_modules + Prisma
17
- ```
18
-
19
- **Entry point**: the container `CMD` runs `npx prisma migrate deploy` and then starts `node dist/server.js` — pending migrations are applied automatically on every container boot (migrate-on-boot).
20
- **Health check**: `GET /api/v1/live` — this endpoint MUST always exist and return 200.
21
-
22
- ---
23
-
24
- ## When to Update the Dockerfile
25
-
26
- | You did this... | Update Dockerfile? | What to change |
27
- |---|---|---|
28
- | Added a new npm dependency | No | Automatic — `npm ci` installs from `package.json` |
29
- | Added a native/system dependency (e.g., `sharp`, `bcrypt`) | **Yes** | Add `apk add` in the production stage for required system libraries |
30
- | Changed the build command or output directory | **Yes** | Update the `RUN npm run build` or `COPY` paths in stage 2/3 |
31
- | Changed the entry point file (e.g., renamed `server.ts`) | **Yes** | Update the `CMD` to run `dist/<new-name>.js` (keep the `prisma migrate deploy` step before it) |
32
- | Changed the default port | **Yes** | Update `EXPOSE` and the `HEALTHCHECK` port |
33
- | Added/renamed a health check endpoint | **Yes** | Update the `HEALTHCHECK` URL path |
34
- | Added files needed at runtime (e.g., templates, static assets) | **Yes** | Add a `COPY` line in stage 3 |
35
- | Changed Prisma schema | No | Automatic — `npx prisma generate` runs in stage 2 |
36
- | Added a new env var | Maybe | If it's needed at **build time**, add `ARG` + `ENV` in the builder stage |
37
- | Added file upload functionality | **Yes** | Add a `VOLUME` directive or ensure the upload directory is writable |
38
-
39
- ---
40
-
41
- ## Critical Rules
42
-
43
- 1. **Health endpoint is sacred.** The route `GET /api/v1/live` must always exist and return HTTP 200. Coolify, Docker, and load balancers use it to determine if the container is alive. Never remove, rename, or gate it behind auth.
44
-
45
- 2. **Never break the build chain.** If you rename the build output directory, the entry file, or change `tsconfig.json` `outDir`, update the Dockerfile `COPY` paths and `CMD` accordingly.
46
-
47
- 3. **System dependencies must be explicit.** If a new npm package requires native binaries (e.g., `sharp` needs `libvips`, `bcrypt` needs `build-base`), add `apk add --no-cache <package>` in the production stage. The build will succeed locally but fail in Docker without this.
48
-
49
- 4. **Non-root user.** The app runs as `nodejs:nodejs` (UID 1001). Any files the app needs to write (uploads, logs) must be in directories owned by this user. Add `RUN mkdir -p /app/<dir> && chown nodejs:nodejs /app/<dir>` if needed.
50
-
51
- 5. **No secrets in the image.** Environment variables are injected at runtime via Coolify/Docker. Never hardcode secrets, never `COPY .env`, never use `ENV` for sensitive values. Only use `ARG`/`ENV` for non-secret build-time config.
52
-
53
- 6. **Keep `.dockerignore` in sync.** When adding new directories or file types that should NOT be in the Docker build context (test fixtures, docs, local scripts), add them to `.dockerignore`. When adding files that ARE needed at build time, make sure they're not ignored.
54
-
55
- 7. **Port consistency.** The default port is `8000`. If you change the port in `src/config/env.ts`, also update `EXPOSE` and the `HEALTHCHECK` in the Dockerfile.
56
-
57
- ---
58
-
59
- ## Coolify-Specific Notes
60
-
61
- - **Environment variables**: Set in Coolify's UI, injected at container runtime. No `.env` file needed.
62
- - **Build arguments**: For build-time vars, use Coolify's "Build Arguments" section → maps to `docker build --build-arg`.
63
- - **Persistent storage**: For file uploads, mount a volume in Coolify to `/app/uploads`. Add to Dockerfile: `RUN mkdir -p /app/uploads && chown nodejs:nodejs /app/uploads` before `USER nodejs`.
64
- - **Database migrations**: Applied automatically at container startup — the Dockerfile `CMD` runs `npx prisma migrate deploy` before starting the server, so no Coolify configuration is needed. (Alternative: remove the migrate step from the `CMD` and run `npx prisma migrate deploy` as a pre-deploy command in Coolify instead.)
65
-
66
- ---
67
-
68
- ## Files That Matter for Deployment
69
-
70
- | File | Purpose | Must exist? |
71
- |---|---|---|
72
- | `Dockerfile` | Production build instructions | Yes |
73
- | `.dockerignore` | Excludes files from Docker build context | Yes |
74
- | `package.json` | Dependencies and build script | Yes |
75
- | `tsconfig.json` | TypeScript compilation config | Yes |
76
- | `prisma/schema.prisma` | Database schema (copied to runtime) | Yes |
77
- | `prisma/migrations/` | Migration files (copied to runtime) | Yes |
78
- | `src/server.ts` | Entry point (compiled to `dist/server.js`) | Yes |
@@ -1,254 +0,0 @@
1
- > **SCOPE**: These rules apply specifically to the **server** directory.
2
-
3
- # Project Conventions
4
-
5
- ## Stack
6
-
7
- | Technology | Purpose |
8
- |------------|---------|
9
- | Node.js 20+ LTS | Runtime |
10
- | Fastify | HTTP framework (plugins, route prefixes, centralized error handling) |
11
- | TypeScript (strict) | Language — always type parameters and return types |
12
- | MySQL 8.0+ | Primary database |
13
- | Prisma 6.x | ORM, migrations, schema source of truth |
14
- | Redis | Caching (frequently accessed data, lookups), rate limiting, background task signaling |
15
- | Zod | Runtime validation and type inference |
16
- | JWT (HS256/RS256) | Auth — minimal token payload (id, role), role-based access control |
17
- | axios | Outbound HTTP client (external API calls) |
18
- | PM2 + Nginx | Production deployment (cluster mode) |
19
- | Jest / Vitest | Testing — deterministic, mock external APIs |
20
-
21
- ## Package Manager
22
-
23
- Detect from lockfile: `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, else → npm.
24
-
25
- ## Folder Structure
26
-
27
- ```
28
- src/
29
- ├── app.ts # Fastify instance and plugin registration
30
- ├── server.ts # listen() call only, no app logic
31
- ├── config/ # env, config, constants
32
- ├── libs/ # shared libraries (db, redis, logger, auth)
33
- └── modules/<domain>/ # domain modules
34
- ├── <domain>.routes.ts
35
- ├── <domain>.controller.ts
36
- ├── <domain>.service.ts
37
- ├── <domain>.repo.ts
38
- ├── <domain>.schemas.ts
39
- └── <domain>.types.ts (if needed)
40
- ```
41
-
42
- New modules MUST follow `src/modules/<name>/` with the exact naming pattern above.
43
-
44
- ## API Routes
45
-
46
- All routes prefixed with `/api/v1`. Grouped by domain: `/api/v1/<domain>/...`
47
-
48
- Register routes as Fastify plugins in `<domain>.routes.ts`.
49
-
50
- ## Coding Style
51
-
52
- - TypeScript `strict` mode ON
53
- - `async/await` over `.then()`
54
- - Named exports (except `src/app.ts` which default-exports the Fastify instance)
55
- - Relative imports within a module (`./user.service`), aliased imports cross-module (`@modules/users/...`)
56
- - Use `logger` from `src/libs/logger` — never `console.log`
57
-
58
- ## Layer Responsibilities
59
-
60
- | Layer | MUST | MUST NOT |
61
- |-------|------|----------|
62
- | **Routes** | Register Fastify plugins, define HTTP method + path | Contain any logic |
63
- | **Controllers** | Validate input (Zod), call services, return via `successResponse`/`paginatedResponse`, throw typed `AppError` | Business logic, direct DB access, manual error JSON, set HTTP status codes for errors |
64
- | **Services** | All business logic, throw `AppError` subclasses, call repos for DB ops, be stateless | Touch Fastify (request/reply), format responses, return HTTP status codes |
65
- | **Repositories** | Prisma queries, return raw data | Business logic, error formatting |
66
-
67
- ## Postman Collection
68
-
69
- When API endpoints are created or modified, **always update the Postman collection** (`postman/collection.json`). If the collection does not exist, create it.
70
-
71
- ### Collection Structure
72
-
73
- ```
74
- postman/
75
- ├── collection.json # Postman v2.1 collection
76
- └── environment.json # Environment variables template
77
- ```
78
-
79
- ### Environment Variables
80
-
81
- Use variables so requests are connected and portable:
82
-
83
- ```json
84
- {
85
- "variables": [
86
- { "key": "baseUrl", "value": "http://localhost:3000/api/v1" },
87
- { "key": "accessToken", "value": "" },
88
- { "key": "refreshToken", "value": "" },
89
- { "key": "userId", "value": "" }
90
- ]
91
- }
92
- ```
93
-
94
- - **`{{baseUrl}}`** — all request URLs use this prefix, never hardcoded hosts.
95
- - **`{{accessToken}}`** / **`{{refreshToken}}`** — set automatically via login/register test scripts.
96
- - **`{{userId}}`** and other IDs — captured from responses so subsequent requests can reference them.
97
-
98
- ### Auto-set Tokens via Test Scripts
99
-
100
- The **Login** and **Register** requests MUST include a `Tests` script that stores tokens and user data into collection variables:
101
-
102
- ```javascript
103
- if (pm.response.code === 200 || pm.response.code === 201) {
104
- const res = pm.response.json();
105
- pm.collectionVariables.set("accessToken", res.data.tokens.accessToken);
106
- pm.collectionVariables.set("refreshToken", res.data.tokens.refreshToken);
107
- pm.collectionVariables.set("userId", res.data.user.id);
108
- }
109
- ```
110
-
111
- ### Auth Header
112
-
113
- All authenticated requests use a collection-level or folder-level **Bearer Token** auth set to `{{accessToken}}`. Do not duplicate the auth header on every request — inherit from the parent folder.
114
-
115
- ### Folder Organization
116
-
117
- Organize requests into folders matching domain modules:
118
-
119
- ```
120
- Collection Root (Bearer Token: {{accessToken}})
121
- ├── Auth (No Auth)
122
- │ ├── Register → POST {{baseUrl}}/auth/register
123
- │ ├── Login → POST {{baseUrl}}/auth/login [sets tokens]
124
- │ ├── Refresh Token → POST {{baseUrl}}/auth/refresh
125
- │ └── Logout → POST {{baseUrl}}/auth/logout
126
- ├── Users
127
- │ ├── Get Me → GET {{baseUrl}}/users/me
128
- │ ├── Update Me → PATCH {{baseUrl}}/users/me
129
- │ └── Delete Me → DELETE {{baseUrl}}/users/me
130
- └── <Domain> → One folder per module
131
- ├── List → GET {{baseUrl}}/<domain>
132
- ├── Get by ID → GET {{baseUrl}}/<domain>/{{<domain>Id}}
133
- ├── Create → POST {{baseUrl}}/<domain>
134
- ├── Update → PATCH {{baseUrl}}/<domain>/{{<domain>Id}}
135
- └── Delete → DELETE {{baseUrl}}/<domain>/{{<domain>Id}}
136
- ```
137
-
138
- ### Rules
139
-
140
- 1. **Every route gets a request.** No endpoint should exist without a matching Postman request.
141
- 2. **Include example request bodies** for POST/PATCH/PUT with realistic placeholder data.
142
- 3. **Capture IDs from create responses** — add a `Tests` script that sets `{{<domain>Id}}` so Get/Update/Delete requests work without manual copy-paste.
143
- 4. **Auth folder uses "No Auth"** — login and register don't need tokens. All other folders inherit Bearer Token from the collection root.
144
- 5. **Keep it importable** — the collection must be valid Postman v2.1 JSON that anyone can import and run immediately after setting `baseUrl`.
145
-
146
- ## Security
147
-
148
- - Validate all inputs with Zod schemas
149
- - Never interpolate raw values into SQL — always use Prisma query builder
150
- - Rate limit public endpoints
151
- - Avoid N+1 queries — prefer joins or batched queries
152
-
153
- ## Outbound HTTP
154
-
155
- Use `httpClient` from `src/libs/http.ts` for ALL outbound HTTP calls. Never use native `fetch`, `node:http`, or a new `axios.create()` at the call site — the singleton provides consistent logging, 30s timeout, and automatic error conversion.
156
-
157
- ### Import
158
-
159
- ```typescript
160
- import { httpClient } from '@libs/http.js';
161
- ```
162
-
163
- ### Wrapping pattern (service layer)
164
-
165
- Outbound HTTP calls belong in the **service layer**. The interceptor converts `AxiosError` to `InternalError` automatically — services only deal with `AppError` subclasses:
166
-
167
- ```typescript
168
- class WeatherService {
169
- async getCurrentWeather(city: string): Promise<WeatherData> {
170
- const response = await httpClient.get<WeatherApiResponse>(
171
- `https://api.weather.example.com/v1/current`,
172
- { params: { q: city } },
173
- );
174
- return response.data.result;
175
- }
176
- }
177
- export const weatherService = new WeatherService();
178
- ```
179
-
180
- ### Auth headers
181
-
182
- Do NOT add auth headers to the `httpClient` singleton — it is shared. Pass per-request headers at the call site:
183
-
184
- ```typescript
185
- await httpClient.post(url, body, {
186
- headers: { Authorization: `Bearer ${token}` },
187
- });
188
- ```
189
-
190
- ### Fine-grained error mapping
191
-
192
- The interceptor always throws `InternalError`. If you need a more specific error (e.g., a 404 from an external API should surface as `NotFoundError`), catch and rethrow:
193
-
194
- ```typescript
195
- try {
196
- return await httpClient.get(url);
197
- } catch {
198
- throw new NotFoundError('External resource not found');
199
- }
200
- ```
201
-
202
- ### Fixed-base-URL services
203
-
204
- If a service always calls the same external API, create a private derived instance **inside the service file only** (never exported):
205
-
206
- ```typescript
207
- const apiClient = axios.create({ ...httpClient.defaults, baseURL: 'https://api.example.com/v2' });
208
- ```
209
-
210
- ### Rules
211
-
212
- - Always use `httpClient` — never `fetch`, `node:http`, or inline `axios.create()`.
213
- - Never add auth headers, cookies, or credentials to the singleton itself.
214
- - Never log response bodies (may contain PII or secrets).
215
-
216
- ## File Storage
217
-
218
- ### Directory Structure Principles
219
-
220
- Upload folders must be **scalable and manageable**. Never dump all files into a single flat directory (e.g., all product images under `/uploads/products/`). Instead, organize by **owner/entity ID** so each entity's files are isolated and easy to find, move, or delete.
221
-
222
- **Pattern**: `uploads/<domain>/{entityId}/<media-type>/`
223
-
224
- ### User Uploads
225
-
226
- Structure: `uploads/users/{userId}/<media-type>/`
227
-
228
- | Media type | Path | Example |
229
- |---|---|---|
230
- | Avatar | `uploads/users/{userId}/avatar/` | `uploads/users/abc123/avatar/john-doe-avatar.webp` |
231
-
232
- - All user media lives under `uploads/users/{userId}/` for easy per-user cleanup.
233
- - On account purge, delete the entire `uploads/users/{userId}/` directory via `deleteUserMedia()`.
234
- - Public URL pattern: `/uploads/users/{userId}/<media-type>/{filename}`
235
- - New media types follow the same pattern: add a subfolder under the user directory.
236
-
237
- ### Domain Entity Uploads (Products, Articles, etc.)
238
-
239
- Structure: `uploads/<domain>/{entityId}/<media-type>/`
240
-
241
- | Domain | Media type | Path | Example |
242
- |---|---|---|---|
243
- | Products | Images | `uploads/products/{productId}/images/` | `uploads/products/prod-456/images/front-view.webp` |
244
- | Products | Thumbnails | `uploads/products/{productId}/thumbnails/` | `uploads/products/prod-456/thumbnails/front-view-thumb.webp` |
245
- | Articles | Cover | `uploads/articles/{articleId}/cover/` | `uploads/articles/art-789/cover/hero.webp` |
246
- | Articles | Content images | `uploads/articles/{articleId}/content/` | `uploads/articles/art-789/content/diagram-1.webp` |
247
-
248
- ### Rules
249
-
250
- 1. **Never use flat directories** — `uploads/products/img1.jpg, img2.jpg, ...` is forbidden. Always namespace by entity ID.
251
- 2. **One folder per entity instance** — makes deletion, migration, and backup trivial (`rm -rf uploads/products/{id}/`).
252
- 3. **Separate media types into subfolders** — don't mix avatars, thumbnails, and full-size images in the same folder.
253
- 4. **Entity cleanup** — when an entity is deleted, remove its entire upload directory (e.g., `uploads/products/{productId}/`).
254
- 5. **Consistent naming** — use kebab-case for filenames, domain plural for top-level folders (`products`, `articles`, `users`).
@@ -1,144 +0,0 @@
1
- > **SCOPE**: These rules apply specifically to the **server** directory.
2
-
3
- # Response Handling
4
-
5
- All API responses follow a unified contract. No exceptions.
6
-
7
- ---
8
-
9
- ## Success Response
10
-
11
- ```json
12
- {
13
- "success": true,
14
- "message": "Human-readable message",
15
- "data": {}
16
- }
17
- ```
18
-
19
- - `data` can be an object, array, or null
20
- - Controllers MUST use the shared `successResponse()` helper
21
-
22
- ```typescript
23
- // Allowed
24
- return reply.send(successResponse("Item created successfully", item));
25
-
26
- // Forbidden — never send raw values or custom shapes
27
- reply.send(item);
28
- reply.send({ data: item });
29
- reply.send({ success: true, item });
30
- ```
31
-
32
- ---
33
-
34
- ## Error Response
35
-
36
- ```json
37
- {
38
- "success": false,
39
- "error": {
40
- "code": "MACHINE_READABLE_CODE",
41
- "message": "Human-readable, user-safe message"
42
- }
43
- }
44
- ```
45
-
46
- - `code`: stable machine-readable string (e.g. `RESOURCE_NOT_FOUND`, `VALIDATION_FAILED`)
47
- - Never expose internal details, stack traces, or SQL errors
48
- - Controllers MUST NOT manually construct error responses
49
-
50
- ---
51
-
52
- ## Paginated Response
53
-
54
- ```json
55
- {
56
- "success": true,
57
- "message": "string",
58
- "data": {
59
- "items": [],
60
- "pagination": {
61
- "page": 1,
62
- "limit": 10,
63
- "totalItems": 237,
64
- "totalPages": 24,
65
- "hasNextPage": true,
66
- "hasPreviousPage": false
67
- }
68
- }
69
- }
70
- ```
71
-
72
- Controllers MUST use the shared `paginatedResponse()` helper:
73
-
74
- ```typescript
75
- function paginatedResponse<T>(message: string, items: T[], page: number, limit: number, totalItems: number)
76
-
77
- // Allowed
78
- return reply.send(paginatedResponse("Items retrieved successfully", items, page, limit, totalCount));
79
- ```
80
-
81
- ### Pagination Input Validation
82
-
83
- All paginated endpoints MUST validate with this shared Zod schema:
84
-
85
- ```typescript
86
- const PaginationSchema = z.object({
87
- page: z.coerce.number().int().min(1).default(1),
88
- limit: z.coerce.number().int().min(1).max(100).default(10)
89
- });
90
- ```
91
-
92
- ### Service Return Pattern for Pagination
93
-
94
- Services return `{ items, totalItems }`. Controllers build the pagination metadata.
95
-
96
- ```typescript
97
- // Service returns:
98
- return { items, totalItems: count };
99
- // Offset calculation: (page - 1) * limit
100
- ```
101
-
102
- ### Filters with Pagination
103
-
104
- - Apply filters/sorting BEFORE `limit` and `offset`
105
- - Count total items AFTER filters but BEFORE pagination
106
- - Pages start at 1 (never 0)
107
-
108
- ---
109
-
110
- ## Error Architecture
111
-
112
- ONE global Fastify error handler via `fastify.setErrorHandler(...)`:
113
- - Maps `AppError` subclasses to HTTP status codes
114
- - Formats the unified error JSON structure
115
- - Logs internal details server-side only — never sends to client
116
-
117
- ### AppError Subclasses
118
-
119
- All errors MUST extend `AppError` (which defines `code`, `message`, `statusCode`). Only throw these typed subclasses — never raw `Error`, strings, or plain objects.
120
-
121
- | Class | Status | Example Code |
122
- |-------|--------|--------------|
123
- | `BadRequestError` | 400 | `INVALID_INPUT` |
124
- | `ValidationError` | 422 | `VALIDATION_FAILED` |
125
- | `UnauthorizedError` | 401 | `UNAUTHORIZED` |
126
- | `ForbiddenError` | 403 | `FORBIDDEN` |
127
- | `NotFoundError` | 404 | `RESOURCE_NOT_FOUND` |
128
- | `ConflictError` | 409 | `EMAIL_ALREADY_EXISTS` |
129
- | `InternalError` | 500 | `INTERNAL_ERROR` |
130
-
131
- ---
132
-
133
- ## Controller Response Rules
134
-
135
- **ALWAYS:**
136
- - Use `successResponse()` or `paginatedResponse()` for all responses
137
- - Validate input with Zod before calling services
138
- - Throw typed `AppError` subclasses on failure
139
-
140
- **NEVER:**
141
- - Send raw values or custom JSON shapes
142
- - Set HTTP status codes for errors (global handler does this)
143
- - Catch errors unless rethrowing as typed `AppError`
144
- - Manually construct error response JSON
@@ -1,15 +0,0 @@
1
- {
2
- "hooks": {
3
- "PreToolUse": [
4
- {
5
- "matcher": "Edit|Write",
6
- "hooks": [
7
- {
8
- "type": "command",
9
- "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/restrict-paths.sh\""
10
- }
11
- ]
12
- }
13
- ]
14
- }
15
- }
@@ -1,63 +0,0 @@
1
- ---
2
- name: clean-ui
3
- description: Remove the starter welcome page UI and replace with a blank canvas, preserving all client-side functionality (auth, hooks, services, store, middleware, utils)
4
- ---
5
-
6
- The user wants to remove the starter/welcome UI from the scaffolded client and start with a blank page.
7
-
8
- ## What this skill does
9
-
10
- Replaces the demo welcome page (`src/app/page.tsx`) with the absolute bare minimum — just a centered "Ready to build." text. **Nothing else is touched** — all functional infrastructure remains intact.
11
-
12
- ## What gets replaced
13
-
14
- | File | Action | Reason |
15
- |------|--------|--------|
16
- | `src/app/page.tsx` | **Replace** with blank canvas | Remove ALL demo content — hero, ambient glow, GitHub links, buttons, everything |
17
-
18
- ## What is NOT touched (preserved as-is)
19
-
20
- - `src/components/layout/` — Header, Footer, MainLayout
21
- - `src/app/layout.tsx` — root layout with providers
22
- - `src/app/providers.tsx` — Redux, React Query, themes, AuthInitializer
23
- - `src/app/error.tsx`, `src/app/not-found.tsx`, `src/app/loading.tsx`
24
- - `src/middleware.ts` — route protection
25
- - `src/features/auth/**` — entire auth system
26
- - `src/components/common/**` — ThemeToggle, EmptyState, LoadingSpinner, etc.
27
- - `src/components/ui/**` — all shadcn/ui components
28
- - `src/hooks/**`, `src/store/**`, `src/lib/**`, `src/styles/**`
29
- - All config files
30
-
31
- ## Steps
32
-
33
- 1. Read `src/app/page.tsx` to confirm it exists.
34
- 2. Replace its contents with the clean page below. Use the **exact** template — do not add anything.
35
- 3. Confirm to the user what was done.
36
-
37
- ## Clean page template
38
-
39
- Replace `src/app/page.tsx` with **exactly** this — no additions, no modifications:
40
-
41
- ```tsx
42
- import type React from 'react';
43
-
44
- export default function HomePage(): React.ReactElement {
45
- return (
46
- <main className="flex min-h-dvh items-center justify-center">
47
- <p className="text-sm text-muted-foreground">Ready to build.</p>
48
- </main>
49
- );
50
- }
51
- ```
52
-
53
- **CRITICAL**: Do NOT add anything beyond what is in the template above. No heading, no links, no buttons, no metadata, no imports beyond React. The entire point is a blank canvas.
54
-
55
- ## Response format
56
-
57
- After completing, respond with:
58
-
59
- ```
60
- Starter UI cleaned. `src/app/page.tsx` is now a blank canvas.
61
-
62
- Everything else is untouched — auth, hooks, services, store, middleware, components, and design system are all intact.
63
- ```
@@ -1,39 +0,0 @@
1
- ---
2
- name: role
3
- description: Switch developer role to restrict Claude's access to frontend-only, backend-only, or full access
4
- argument-hint: "[frontend | backend | fullstack]"
5
- disable-model-invocation: true
6
- allowed-tools: Read, Write
7
- ---
8
-
9
- The user wants to switch their developer role. The argument is: $ARGUMENTS
10
-
11
- Read the file `.developer-role` in the project root to see the current role.
12
-
13
- ## Rules
14
-
15
- - If the argument is `frontend`, `backend`, or `fullstack` — write that word to `.developer-role` and confirm the switch.
16
- - If no argument is given — read `.developer-role` and tell the user their current role, then ask which role they want.
17
- - If the argument is not one of the three valid roles — tell the user the valid options.
18
-
19
- ## What each role does
20
-
21
- Claude can always READ all files for full project context. Only WRITE access is restricted.
22
-
23
- | Role | Can edit |
24
- |------|---------|
25
- | `frontend` | `client/` only. Cannot edit `server/` files. |
26
- | `backend` | `server/` only. Cannot edit `client/` files. |
27
- | `fullstack` | Everything. No restrictions. |
28
-
29
- ## Response format
30
-
31
- After switching, confirm like this:
32
-
33
- ```
34
- Role switched to **{role}**.
35
-
36
- - frontend → can edit client/ only (can read everything)
37
- - backend → can edit server/ only (can read everything)
38
- - fullstack → can edit everything
39
- ```