create-tigra 1.1.0 → 2.0.1
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 -21
- package/README.md +80 -87
- package/bin/create-tigra.js +259 -308
- package/package.json +49 -41
- package/template/_claude/QUICK_REFERENCE.md +193 -0
- package/template/_claude/README.md +53 -0
- package/template/_claude/commands/create-client.md +881 -0
- package/template/_claude/commands/create-server.md +383 -0
- package/template/_claude/rules/client/01-project-structure.md +133 -0
- package/template/_claude/rules/client/02-components-and-types.md +146 -0
- package/template/_claude/rules/client/03-data-and-state.md +156 -0
- package/template/_claude/rules/client/04-design-system.md +185 -0
- package/template/_claude/rules/client/05-security.md +55 -0
- package/template/_claude/rules/client/06-ux-checklist.md +81 -0
- package/template/_claude/rules/client/core.md +42 -0
- package/template/_claude/rules/global/core.md +77 -0
- package/template/_claude/rules/server/core.md +50 -0
- package/template/_claude/rules/server/database.md +124 -0
- package/template/_claude/rules/server/project-conventions.md +150 -0
- package/template/_claude/rules/server/response-handling.md +144 -0
- package/template/client/.env.example +5 -0
- package/template/client/README.md +36 -0
- package/template/client/components.json +23 -0
- package/template/client/eslint.config.mjs +18 -0
- package/template/client/next.config.ts +34 -0
- package/template/client/package.json +44 -0
- package/template/client/postcss.config.mjs +7 -0
- package/template/client/src/app/(auth)/layout.tsx +18 -0
- package/template/client/src/app/(auth)/login/page.tsx +13 -0
- package/template/client/src/app/(auth)/register/page.tsx +13 -0
- package/template/client/src/app/(main)/dashboard/page.tsx +22 -0
- package/template/client/src/app/(main)/layout.tsx +11 -0
- package/template/client/src/app/error.tsx +27 -0
- package/template/client/src/app/favicon.ico +0 -0
- package/template/client/src/app/globals.css +145 -0
- package/template/client/src/app/layout.tsx +36 -0
- package/template/client/src/app/loading.tsx +11 -0
- package/template/client/src/app/not-found.tsx +23 -0
- package/template/client/src/app/page.tsx +45 -0
- package/template/client/src/app/providers.tsx +43 -0
- package/template/client/src/components/common/ConfirmDialog.tsx +56 -0
- package/template/client/src/components/common/EmptyState.tsx +31 -0
- package/template/client/src/components/common/LoadingSpinner.tsx +30 -0
- package/template/client/src/components/common/Pagination.tsx +55 -0
- package/template/client/src/components/layout/Footer.tsx +17 -0
- package/template/client/src/components/layout/Header.tsx +173 -0
- package/template/client/src/components/layout/MainLayout.tsx +18 -0
- package/template/client/src/components/ui/alert-dialog.tsx +196 -0
- package/template/client/src/components/ui/badge.tsx +48 -0
- package/template/client/src/components/ui/button.tsx +64 -0
- package/template/client/src/components/ui/card.tsx +92 -0
- package/template/client/src/components/ui/input.tsx +21 -0
- package/template/client/src/components/ui/label.tsx +24 -0
- package/template/client/src/components/ui/select.tsx +190 -0
- package/template/client/src/components/ui/skeleton.tsx +13 -0
- package/template/client/src/components/ui/table.tsx +116 -0
- package/template/client/src/features/auth/components/AuthInitializer.tsx +55 -0
- package/template/client/src/features/auth/components/LoginForm.tsx +107 -0
- package/template/client/src/features/auth/components/RegisterForm.tsx +178 -0
- package/template/client/src/features/auth/hooks/useAuth.ts +84 -0
- package/template/client/src/features/auth/services/auth.service.ts +52 -0
- package/template/client/src/features/auth/store/authSlice.ts +38 -0
- package/template/client/src/features/auth/types/auth.types.ts +32 -0
- package/template/client/src/hooks/useDebounce.ts +14 -0
- package/template/client/src/hooks/useLocalStorage.ts +55 -0
- package/template/client/src/hooks/useMediaQuery.ts +27 -0
- package/template/client/src/lib/api/api.types.ts +34 -0
- package/template/client/src/lib/api/axios.config.ts +98 -0
- package/template/client/src/lib/constants/api-endpoints.ts +18 -0
- package/template/client/src/lib/constants/app.constants.ts +12 -0
- package/template/client/src/lib/constants/routes.ts +9 -0
- package/template/client/src/lib/utils/error.ts +32 -0
- package/template/client/src/lib/utils/format.ts +37 -0
- package/template/client/src/lib/utils/security.ts +34 -0
- package/template/client/src/lib/utils.ts +6 -0
- package/template/client/src/middleware.ts +57 -0
- package/template/client/src/store/hooks.ts +7 -0
- package/template/client/src/store/index.ts +12 -0
- package/template/client/src/types/index.ts +3 -0
- package/template/client/tsconfig.json +34 -0
- package/template/gitignore +34 -0
- package/template/server/.dockerignore +66 -0
- package/template/server/.env.example +96 -69
- package/template/server/.env.production.example +90 -0
- package/template/server/Dockerfile +94 -0
- package/template/server/docker-compose.yml +82 -111
- package/template/server/docs/logging.md +62 -0
- package/template/server/eslint.config.mjs +17 -0
- package/template/server/package.json +68 -81
- package/template/server/phpmyadmin-config.php +26 -0
- package/template/server/postman_collection.json +666 -0
- package/template/server/prisma/schema.prisma +77 -93
- package/template/server/prisma/seed.ts +46 -142
- package/template/server/scripts/flush-redis.ts +41 -0
- package/template/server/src/app.ts +243 -71
- package/template/server/src/config/env.ts +67 -94
- package/template/server/src/libs/auth.ts +88 -0
- package/template/server/src/libs/cleanup.ts +35 -0
- package/template/server/src/libs/cookies.ts +46 -0
- package/template/server/src/libs/logger.ts +33 -60
- package/template/server/src/libs/monitoring.ts +205 -0
- package/template/server/src/libs/password.ts +38 -0
- package/template/server/src/libs/prisma.ts +68 -0
- package/template/server/src/libs/redis.ts +60 -79
- package/template/server/src/libs/requestLogger.ts +66 -0
- package/template/server/src/libs/storage/file-storage.service.ts +211 -0
- package/template/server/src/libs/storage/file-validator.ts +97 -0
- package/template/server/src/libs/storage/filename-sanitizer.ts +71 -0
- package/template/server/src/libs/storage/image-optimizer.service.ts +144 -0
- package/template/server/src/modules/auth/__tests__/auth.service.test.ts +365 -0
- package/template/server/src/modules/auth/auth.controller.ts +90 -141
- package/template/server/src/modules/auth/auth.repo.ts +120 -218
- package/template/server/src/modules/auth/auth.routes.ts +96 -83
- package/template/server/src/modules/auth/auth.schemas.ts +35 -137
- package/template/server/src/modules/auth/auth.service.ts +286 -329
- package/template/server/src/modules/auth/session.repo.ts +110 -0
- package/template/server/src/modules/users/users.controller.ts +120 -0
- package/template/server/src/modules/users/users.repo.ts +77 -0
- package/template/server/src/modules/users/users.routes.ts +89 -0
- package/template/server/src/modules/users/users.schemas.ts +21 -0
- package/template/server/src/modules/users/users.service.ts +169 -0
- package/template/server/src/server.ts +58 -139
- package/template/server/src/shared/errors/AppError.ts +21 -0
- package/template/server/src/shared/errors/errors.ts +43 -0
- package/template/server/src/shared/responses/paginatedResponse.ts +38 -0
- package/template/server/src/shared/responses/successResponse.ts +17 -0
- package/template/server/src/shared/schemas/pagination.schema.ts +12 -0
- package/template/server/src/shared/types/index.ts +26 -0
- package/template/server/src/test/setup.ts +74 -38
- package/template/server/tsconfig.json +27 -89
- package/template/server/uploads/avatars/.gitkeep +1 -0
- package/template/server/vitest.config.ts +43 -98
- package/template/.agent/rules/client/01-project-structure.md +0 -326
- package/template/.agent/rules/client/02-component-patterns.md +0 -249
- package/template/.agent/rules/client/03-typescript-rules.md +0 -226
- package/template/.agent/rules/client/04-state-management.md +0 -474
- package/template/.agent/rules/client/05-api-integration.md +0 -129
- package/template/.agent/rules/client/06-forms-validation.md +0 -129
- package/template/.agent/rules/client/07-common-patterns.md +0 -150
- package/template/.agent/rules/client/08-color-system.md +0 -93
- package/template/.agent/rules/client/09-security-rules.md +0 -97
- package/template/.agent/rules/client/10-testing-strategy.md +0 -370
- package/template/.agent/rules/global/ai-edit-safety.md +0 -38
- package/template/.agent/rules/server/01-db-and-migrations.md +0 -242
- package/template/.agent/rules/server/02-general-rules.md +0 -111
- package/template/.agent/rules/server/03-migrations.md +0 -20
- package/template/.agent/rules/server/04-pagination.md +0 -130
- package/template/.agent/rules/server/05-project-conventions.md +0 -71
- package/template/.agent/rules/server/06-response-handling.md +0 -173
- package/template/.agent/rules/server/07-testing-strategy.md +0 -506
- package/template/.agent/rules/server/08-observability.md +0 -180
- package/template/.agent/rules/server/10-background-jobs-v2.md +0 -185
- package/template/.agent/rules/server/11-rate-limiting-v2.md +0 -210
- package/template/.agent/rules/server/12-performance-optimization.md +0 -567
- package/template/.claude/rules/client-01-project-structure.md +0 -327
- package/template/.claude/rules/client-02-component-patterns.md +0 -250
- package/template/.claude/rules/client-03-typescript-rules.md +0 -227
- package/template/.claude/rules/client-04-state-management.md +0 -475
- package/template/.claude/rules/client-05-api-integration.md +0 -130
- package/template/.claude/rules/client-06-forms-validation.md +0 -130
- package/template/.claude/rules/client-07-common-patterns.md +0 -151
- package/template/.claude/rules/client-08-color-system.md +0 -94
- package/template/.claude/rules/client-09-security-rules.md +0 -98
- package/template/.claude/rules/client-10-testing-strategy.md +0 -371
- package/template/.claude/rules/global-ai-edit-safety.md +0 -39
- package/template/.claude/rules/server-01-db-and-migrations.md +0 -243
- package/template/.claude/rules/server-02-general-rules.md +0 -112
- package/template/.claude/rules/server-03-migrations.md +0 -21
- package/template/.claude/rules/server-04-pagination.md +0 -131
- package/template/.claude/rules/server-05-project-conventions.md +0 -72
- package/template/.claude/rules/server-06-response-handling.md +0 -174
- package/template/.claude/rules/server-07-testing-strategy.md +0 -507
- package/template/.claude/rules/server-08-observability.md +0 -181
- package/template/.claude/rules/server-10-background-jobs-v2.md +0 -186
- package/template/.claude/rules/server-11-rate-limiting-v2.md +0 -211
- package/template/.claude/rules/server-12-performance-optimization.md +0 -568
- package/template/.cursor/rules/client-01-project-structure.mdc +0 -327
- package/template/.cursor/rules/client-02-component-patterns.mdc +0 -250
- package/template/.cursor/rules/client-03-typescript-rules.mdc +0 -227
- package/template/.cursor/rules/client-04-state-management.mdc +0 -475
- package/template/.cursor/rules/client-05-api-integration.mdc +0 -130
- package/template/.cursor/rules/client-06-forms-validation.mdc +0 -130
- package/template/.cursor/rules/client-07-common-patterns.mdc +0 -151
- package/template/.cursor/rules/client-08-color-system.mdc +0 -94
- package/template/.cursor/rules/client-09-security-rules.mdc +0 -98
- package/template/.cursor/rules/client-10-testing-strategy.mdc +0 -371
- package/template/.cursor/rules/global-ai-edit-safety.mdc +0 -39
- package/template/.cursor/rules/server-01-db-and-migrations.mdc +0 -243
- package/template/.cursor/rules/server-02-general-rules.mdc +0 -112
- package/template/.cursor/rules/server-03-migrations.mdc +0 -21
- package/template/.cursor/rules/server-04-pagination.mdc +0 -131
- package/template/.cursor/rules/server-05-project-conventions.mdc +0 -72
- package/template/.cursor/rules/server-06-response-handling.mdc +0 -174
- package/template/.cursor/rules/server-07-testing-strategy.mdc +0 -507
- package/template/.cursor/rules/server-08-observability.mdc +0 -181
- package/template/.cursor/rules/server-09-api-documentation-v2.mdc +0 -169
- package/template/.cursor/rules/server-10-background-jobs-v2.mdc +0 -186
- package/template/.cursor/rules/server-11-rate-limiting-v2.mdc +0 -211
- package/template/.cursor/rules/server-12-performance-optimization.mdc +0 -568
- package/template/CLAUDE.md +0 -207
- package/template/server/.tsc-aliasrc.json +0 -13
- package/template/server/IMPORT_FIX_CHECKLIST.md +0 -98
- package/template/server/IMPORT_FIX_COMPLETE.md +0 -89
- package/template/server/README.md +0 -183
- package/template/server/REMAINING_IMPORT_FIXES.md +0 -150
- package/template/server/SECURITY.md +0 -190
- package/template/server/Tigra-API.postman_collection.json +0 -733
- package/template/server/biome.json +0 -42
- package/template/server/scripts/fix-all-imports.ps1 +0 -52
- package/template/server/scripts/fix-imports-reference.ps1 +0 -16
- package/template/server/scripts/fix-imports.mjs +0 -55
- package/template/server/scripts/setup-env.js +0 -50
- package/template/server/scripts/wait-for-db.js +0 -60
- package/template/server/src/hooks/request-timing.hook.ts +0 -26
- package/template/server/src/libs/auth/authenticate.middleware.ts +0 -22
- package/template/server/src/libs/auth/rbac.middleware.test.ts +0 -134
- package/template/server/src/libs/auth/rbac.middleware.ts +0 -147
- package/template/server/src/libs/db.ts +0 -76
- package/template/server/src/libs/error-handler.ts +0 -89
- package/template/server/src/libs/queue.ts +0 -79
- package/template/server/src/modules/admin/admin.controller.ts +0 -122
- package/template/server/src/modules/admin/admin.routes.ts +0 -62
- package/template/server/src/modules/admin/admin.schemas.ts +0 -35
- package/template/server/src/modules/admin/admin.service.ts +0 -167
- package/template/server/src/modules/auth/auth.integration.test.ts +0 -150
- package/template/server/src/modules/auth/auth.service.test.ts +0 -119
- package/template/server/src/modules/auth/auth.types.ts +0 -97
- package/template/server/src/modules/resources/resources.controller.ts +0 -218
- package/template/server/src/modules/resources/resources.repo.ts +0 -253
- package/template/server/src/modules/resources/resources.routes.ts +0 -116
- package/template/server/src/modules/resources/resources.schemas.ts +0 -146
- package/template/server/src/modules/resources/resources.service.ts +0 -218
- package/template/server/src/modules/resources/resources.types.ts +0 -73
- package/template/server/src/plugins/rate-limit.plugin.ts +0 -21
- package/template/server/src/plugins/security.plugin.ts +0 -21
- package/template/server/src/routes/health.routes.ts +0 -31
- package/template/server/src/types/fastify.d.ts +0 -36
- package/template/server/src/utils/errors.ts +0 -108
- package/template/server/src/utils/pagination.ts +0 -120
- package/template/server/src/utils/response.ts +0 -110
- package/template/server/src/workers/file.worker.ts +0 -106
- package/template/server/tsconfig.build.json +0 -30
- package/template/server/tsconfig.test.json +0 -22
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
> **SCOPE**: These rules apply specifically to the **client** directory (Next.js App Router).
|
|
2
|
+
|
|
3
|
+
# Data, State & API Integration
|
|
4
|
+
|
|
5
|
+
## State Decision Matrix
|
|
6
|
+
|
|
7
|
+
| State Type | Tool | When |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Server data (initial page load) | Server Components | SEO-critical, page-level data |
|
|
10
|
+
| Server data (client-triggered) | React Query | User actions, real-time updates, mutations |
|
|
11
|
+
| Global client state | Redux | Auth user + init/logout state — **nothing else** |
|
|
12
|
+
| Local UI state | `useState` / `useReducer` | Modals, hover, form inputs |
|
|
13
|
+
| URL-shareable state | `useSearchParams` | Filters, pagination, search query |
|
|
14
|
+
|
|
15
|
+
### Anti-patterns
|
|
16
|
+
|
|
17
|
+
- **No server state in Redux.** Use Server Components or React Query.
|
|
18
|
+
- **No UI state in Redux** (modals, loading). Use local state.
|
|
19
|
+
- **Prefer Server Component fetch** over client-side `useQuery` when the data is available at page level.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## React Query Config
|
|
24
|
+
|
|
25
|
+
Defaults in `app/providers.tsx`:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
staleTime: 5 * 60 * 1000 // 5 min
|
|
29
|
+
gcTime: 10 * 60 * 1000 // 10 min
|
|
30
|
+
refetchOnWindowFocus: false
|
|
31
|
+
retry: 1
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Query Key Factory Pattern
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
export const itemKeys = {
|
|
38
|
+
all: ['items'] as const,
|
|
39
|
+
lists: () => [...itemKeys.all, 'list'] as const,
|
|
40
|
+
list: (filters: ItemFilters) => [...itemKeys.lists(), filters] as const,
|
|
41
|
+
details: () => [...itemKeys.all, 'detail'] as const,
|
|
42
|
+
detail: (id: string) => [...itemKeys.details(), id] as const,
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Mutations
|
|
47
|
+
|
|
48
|
+
On success: invalidate related queries, show toast, navigate if needed.
|
|
49
|
+
On error: `toast.error(getErrorMessage(error))`.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Redux
|
|
54
|
+
|
|
55
|
+
**Scope**: Auth only. Single slice: `authSlice` with actions: `setUser`, `setInitialized`, `setLoggingOut`, `logout`.
|
|
56
|
+
|
|
57
|
+
Typed hooks in `store/hooks.ts`: `useAppDispatch`, `useAppSelector`.
|
|
58
|
+
|
|
59
|
+
State shape:
|
|
60
|
+
```typescript
|
|
61
|
+
{ user: IUser | null; isAuthenticated: boolean; isInitializing: boolean; isLoggingOut: boolean }
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Not persisted to localStorage** — auth state is hydrated on page load by `AuthInitializer` calling `getMe()`. Tokens are stored in httpOnly cookies (not accessible from JS).
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Axios Config
|
|
69
|
+
|
|
70
|
+
`lib/api/axios.config.ts` — singleton `apiClient`:
|
|
71
|
+
|
|
72
|
+
- **Base URL**: `process.env.NEXT_PUBLIC_API_BASE_URL` (fallback `http://localhost:8000/api/v1`)
|
|
73
|
+
- **Timeout**: 30s
|
|
74
|
+
- **`withCredentials: true`**: Sends httpOnly cookies automatically with every request.
|
|
75
|
+
- **No request interceptor** — cookies handle auth, no `Authorization` header needed.
|
|
76
|
+
- **Response interceptor**: On 401, attempts token refresh via `/auth/refresh` (cookie sent automatically). Queues concurrent 401s to avoid multiple refresh attempts. If refresh fails, dispatches `logout()` and redirects to `/login`.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Service Pattern
|
|
81
|
+
|
|
82
|
+
Services are **classes**, singleton-exported, using `apiClient` and `API_ENDPOINTS`.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
class ItemService {
|
|
86
|
+
async getItems(params?: ItemFilters & PaginationParams): Promise<PaginatedData<Item>>
|
|
87
|
+
async getItem(id: string): Promise<Item>
|
|
88
|
+
async createItem(data: CreateItemRequest): Promise<Item>
|
|
89
|
+
async updateItem(id: string, data: UpdateItemRequest): Promise<Item>
|
|
90
|
+
async deleteItem(id: string): Promise<void>
|
|
91
|
+
}
|
|
92
|
+
export const itemService = new ItemService();
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Auth service methods: `register`, `login`, `logout`, `refreshToken`, `getMe`, `verifyEmail`, `requestPasswordReset`, `resetPassword`.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Error Handling
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// lib/utils/error.ts
|
|
103
|
+
export const getErrorMessage = (error: unknown): string => {
|
|
104
|
+
// Checks: axios error → ApiError shape → network error → generic Error → fallback string
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Toast library**: `sonner`. Use `toast.success()`, `toast.error(getErrorMessage(error))`.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Next.js Caching Defaults
|
|
113
|
+
|
|
114
|
+
| Data type | Strategy | Example |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| General content | `next: { revalidate: 60 }` | Items list |
|
|
117
|
+
| User-specific | `cache: 'no-store'` | User profile |
|
|
118
|
+
| Static lookups | `cache: 'force-cache'` | Categories, settings |
|
|
119
|
+
|
|
120
|
+
Use `revalidatePath()` / `revalidateTag()` in Server Actions after mutations.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Forms
|
|
125
|
+
|
|
126
|
+
**Approach**: Hybrid — React Hook Form + Zod for client-side validation, Server Action for submission.
|
|
127
|
+
|
|
128
|
+
### Password Schema Requirements
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
z.string()
|
|
132
|
+
.min(8, 'Min 8 characters')
|
|
133
|
+
.regex(/[A-Z]/, 'Must contain uppercase')
|
|
134
|
+
.regex(/[a-z]/, 'Must contain lowercase')
|
|
135
|
+
.regex(/[0-9]/, 'Must contain number')
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### File Upload Validation
|
|
139
|
+
|
|
140
|
+
- Allowed types: `image/jpeg`, `image/png`, `image/webp`
|
|
141
|
+
- Max size: 5MB
|
|
142
|
+
- Validate extension AND MIME type
|
|
143
|
+
|
|
144
|
+
### Form Rules
|
|
145
|
+
|
|
146
|
+
- Show field-level errors below the field (red text + red border).
|
|
147
|
+
- Disable submit button during submission.
|
|
148
|
+
- Never clear the form on error — preserve user input.
|
|
149
|
+
- Use `useFormStatus` for pending states in Server Action forms.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Utility Defaults
|
|
154
|
+
|
|
155
|
+
- **Default currency**: `USD` for `formatCurrency`.
|
|
156
|
+
- **Date format**: `Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric' })`.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
> **SCOPE**: These rules apply specifically to the **client** directory (Next.js App Router).
|
|
2
|
+
|
|
3
|
+
# Design System
|
|
4
|
+
|
|
5
|
+
## Philosophy: "Neuro-Minimalism"
|
|
6
|
+
|
|
7
|
+
Clean, airy, "expensive" look inspired by Linear, Vercel, Stripe, Arc. Every visual decision reduces cognitive load.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## CSS Architecture (Source of Truth)
|
|
12
|
+
|
|
13
|
+
This project uses **Tailwind CSS v4** with **OKLCH color space** and the `@theme inline` directive (not the legacy `tailwind.config.ts`).
|
|
14
|
+
|
|
15
|
+
```css
|
|
16
|
+
/* app/globals.css */
|
|
17
|
+
@import "tailwindcss";
|
|
18
|
+
@import "tw-animate-css";
|
|
19
|
+
@import "shadcn/tailwind.css";
|
|
20
|
+
|
|
21
|
+
@custom-variant dark (&:is(.dark *));
|
|
22
|
+
|
|
23
|
+
@theme inline {
|
|
24
|
+
--color-background: var(--background);
|
|
25
|
+
--color-foreground: var(--foreground);
|
|
26
|
+
--font-sans: var(--font-geist-sans);
|
|
27
|
+
--font-mono: var(--font-geist-mono);
|
|
28
|
+
/* ... maps all semantic tokens to Tailwind */
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:root {
|
|
32
|
+
--radius: 0.625rem;
|
|
33
|
+
--background: oklch(1 0 0);
|
|
34
|
+
--foreground: oklch(0.145 0 0);
|
|
35
|
+
--primary: oklch(0.45 0.2 260);
|
|
36
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
37
|
+
--secondary: oklch(0.97 0 0);
|
|
38
|
+
--secondary-foreground: oklch(0.205 0 0);
|
|
39
|
+
--muted: oklch(0.97 0 0);
|
|
40
|
+
--muted-foreground: oklch(0.556 0 0);
|
|
41
|
+
--accent: oklch(0.97 0 0);
|
|
42
|
+
--accent-foreground: oklch(0.205 0 0);
|
|
43
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
44
|
+
--border: oklch(0.922 0 0);
|
|
45
|
+
--input: oklch(0.922 0 0);
|
|
46
|
+
--ring: oklch(0.45 0.2 260);
|
|
47
|
+
--success: oklch(0.52 0.17 155);
|
|
48
|
+
--success-foreground: oklch(1 0 0);
|
|
49
|
+
--warning: oklch(0.75 0.18 75);
|
|
50
|
+
--warning-foreground: oklch(0.2 0 0);
|
|
51
|
+
--info: oklch(0.55 0.15 240);
|
|
52
|
+
--info-foreground: oklch(1 0 0);
|
|
53
|
+
--chart-1 through --chart-5 /* Data visualization colors */
|
|
54
|
+
--sidebar, --sidebar-foreground, etc. /* Sidebar-specific tokens */
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.dark {
|
|
58
|
+
--background: oklch(0.145 0 0);
|
|
59
|
+
--foreground: oklch(0.985 0 0);
|
|
60
|
+
/* ... dark mode overrides for all tokens */
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Key differences from Tailwind v3:**
|
|
65
|
+
- No `tailwind.config.ts` — all config is CSS-based via `@theme inline`
|
|
66
|
+
- Colors use **OKLCH** (perceptually uniform) not HSL
|
|
67
|
+
- `@custom-variant dark` replaces `darkMode: 'class'`
|
|
68
|
+
- No `@layer base { :root { } }` — variables defined directly on `:root`
|
|
69
|
+
|
|
70
|
+
## Color Usage
|
|
71
|
+
|
|
72
|
+
| Token | Purpose | Example use |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| `primary` | Main CTAs, links, active states | "Get started" button |
|
|
75
|
+
| `secondary` | Secondary actions | Cancel, back |
|
|
76
|
+
| `destructive` | Delete, errors | Delete button, error alert |
|
|
77
|
+
| `success` | Success states | "Action completed" |
|
|
78
|
+
| `warning` | Warnings | "Pending approval" |
|
|
79
|
+
| `info` | Information | "New feature" badge |
|
|
80
|
+
| `muted` | Disabled, placeholders | Disabled input |
|
|
81
|
+
| `accent` | Highlights | "Featured" badge |
|
|
82
|
+
| `card` | Card backgrounds | Content card |
|
|
83
|
+
| `border` | Borders, dividers | Card border |
|
|
84
|
+
|
|
85
|
+
### Color Rules
|
|
86
|
+
|
|
87
|
+
1. **Never hardcode**: No `bg-blue-500`, no `bg-[#3b82f6]`, no `style={{ color }}`. Always semantic tokens.
|
|
88
|
+
2. **Semantic names by purpose**: `bg-destructive` not `bg-red`.
|
|
89
|
+
3. **Always pair bg + foreground**: `bg-primary text-primary-foreground` for contrast.
|
|
90
|
+
4. **Single source of truth**: Change colors only in `globals.css` variables.
|
|
91
|
+
5. **90% monochrome**: 90% of UI uses `background`, `foreground`, `muted`, `border`. Color is the exception.
|
|
92
|
+
6. **Opacity for hierarchy**: Use `bg-primary/10`, `bg-primary/5` for tinted backgrounds.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Surfaces & Depth
|
|
97
|
+
|
|
98
|
+
- **Border radius**: `rounded-xl` (12px) or `rounded-2xl` (16px) for cards, modals, containers.
|
|
99
|
+
- **Shadows** (layered by elevation):
|
|
100
|
+
- Resting cards: `shadow-sm`
|
|
101
|
+
- Hovered/elevated: `shadow-md` to `shadow-lg`
|
|
102
|
+
- Modals/popovers: `shadow-xl`
|
|
103
|
+
- **Glassmorphism**: Only on sticky headers, floating toolbars, modal backdrops. Never on content cards.
|
|
104
|
+
`backdrop-filter: blur(12px) saturate(1.5); background: oklch(from var(--background) l c h / 0.8);`
|
|
105
|
+
- **No pure black/white**: Use `--background` and `--foreground` tokens (already off-pure).
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Typography
|
|
110
|
+
|
|
111
|
+
- **Font**: Inter v4 (variable) or Geist Sans via `next/font`.
|
|
112
|
+
- **Headings**: `text-wrap: balance`, `leading-tight`. H1: `text-3xl`–`text-4xl`, H2: `text-2xl`.
|
|
113
|
+
- **Body**: `text-base`, `leading-relaxed`. Max reading width: `max-w-prose` (~65ch).
|
|
114
|
+
- **Data/numbers**: Always `tabular-nums` for alignment.
|
|
115
|
+
- **Captions/meta**: `text-sm text-muted-foreground`.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Spacing
|
|
120
|
+
|
|
121
|
+
- **Whitespace IS the divider.** Prefer spacing over visible borders/lines.
|
|
122
|
+
- **Section gap = 2x internal gap**: `space-y-16` between sections, `space-y-6` within.
|
|
123
|
+
- **Stick to scale**: `4, 6, 8, 12, 16, 20, 24` from Tailwind. Avoid arbitrary values.
|
|
124
|
+
- **Container**: `container mx-auto px-4 md:px-6 lg:px-8`.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Motion & Interactions
|
|
129
|
+
|
|
130
|
+
Every interactive element MUST have visible `:hover`, `:active`, and `:focus-visible` states.
|
|
131
|
+
|
|
132
|
+
### Standard Patterns
|
|
133
|
+
```
|
|
134
|
+
Button: transition-all duration-200 ease-out hover:brightness-110 active:scale-[0.98]
|
|
135
|
+
Card: transition-all duration-300 ease-out hover:shadow-lg hover:-translate-y-0.5
|
|
136
|
+
Link: transition-colors duration-150 hover:text-primary
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Rules
|
|
140
|
+
- **Transform + opacity only** — never animate layout properties (`width`, `height`, `top`).
|
|
141
|
+
- **Respect `prefers-reduced-motion`**: Use `motion-safe:` / `motion-reduce:` variants.
|
|
142
|
+
- **Motion budget**: Max 2-3 animated elements in viewport at once.
|
|
143
|
+
- **Zero CLS**: Animations must never cause layout shift.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Images
|
|
148
|
+
|
|
149
|
+
- **Format priority**: AVIF > WebP > JPEG (Next.js `<Image>` handles this).
|
|
150
|
+
- **LCP image**: Always add `priority` prop.
|
|
151
|
+
- **Blur placeholder**: Use `placeholder="blur"` with `blurDataURL`.
|
|
152
|
+
- **Always set** explicit `width`/`height` or use `aspect-ratio` to prevent CLS.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Modern CSS Features (Use Where Appropriate)
|
|
157
|
+
|
|
158
|
+
| Feature | Use for |
|
|
159
|
+
|---|---|
|
|
160
|
+
| `@container` | Component-level responsive behavior |
|
|
161
|
+
| CSS Subgrid | Child alignment with parent grid |
|
|
162
|
+
| `dvh` | Full-height layouts (avoids mobile browser bar) |
|
|
163
|
+
| `<dialog>` | Modals (with glassmorphism backdrop) |
|
|
164
|
+
| Popover API | Dropdowns, tooltips |
|
|
165
|
+
| `:has()` | Parent-based styling without JS |
|
|
166
|
+
| `content-visibility: auto` | Long lists/pages performance |
|
|
167
|
+
| `@starting-style` | Entry animations |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Component Visual Patterns
|
|
172
|
+
|
|
173
|
+
- **Cards**: `rounded-xl border border-border/50 bg-card shadow-sm transition-all duration-300 hover:shadow-md hover:-translate-y-0.5`
|
|
174
|
+
- **Empty states**: Centered, muted icon, 2-line text max, one clear CTA.
|
|
175
|
+
- **Loading**: Skeleton loaders matching content shape. Show immediately, no delay.
|
|
176
|
+
- **Modals**: Max `max-w-lg`. Dismissible with Escape + backdrop click. Glassmorphism backdrop.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Dark Mode
|
|
181
|
+
|
|
182
|
+
- Use `next-themes` with `attribute="class"`, `defaultTheme="system"`.
|
|
183
|
+
- Reduce shadow visibility in dark mode (use subtle light borders instead).
|
|
184
|
+
- Consider `brightness-90` on images in dark mode.
|
|
185
|
+
- Add `suppressHydrationWarning` to `<html>` tag.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
> **SCOPE**: These rules apply specifically to the **client** directory (Next.js App Router).
|
|
2
|
+
|
|
3
|
+
# Security
|
|
4
|
+
|
|
5
|
+
## Token Storage
|
|
6
|
+
|
|
7
|
+
- **httpOnly cookies** (`access_token` + `refresh_token`) set by the server via `Set-Cookie` headers.
|
|
8
|
+
- Tokens are **never accessible from JavaScript** — no localStorage, no Redux token state.
|
|
9
|
+
- Axios sends cookies automatically via `withCredentials: true`.
|
|
10
|
+
- `AuthInitializer` hydrates user state on page load by calling `getMe()` (cookie sent automatically).
|
|
11
|
+
- On logout: call logout API endpoint (server clears cookies), dispatch `logout()` action, redirect to `/login`.
|
|
12
|
+
|
|
13
|
+
## Environment Variables
|
|
14
|
+
|
|
15
|
+
- **Never prefix secrets with `NEXT_PUBLIC_`** — only public values (API URL, app name) get the prefix.
|
|
16
|
+
- Server-only secrets (DB URL, JWT secret) have no prefix and are only accessible in Server Components / Server Actions.
|
|
17
|
+
- Validate env with Zod at startup.
|
|
18
|
+
|
|
19
|
+
## File Upload Validation
|
|
20
|
+
|
|
21
|
+
- Allowed types: `image/jpeg`, `image/png`, `image/webp`
|
|
22
|
+
- Max size: 5MB
|
|
23
|
+
- Validate both MIME type AND file extension.
|
|
24
|
+
|
|
25
|
+
## Security Headers (`next.config.ts`)
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
X-Frame-Options: DENY
|
|
29
|
+
X-Content-Type-Options: nosniff
|
|
30
|
+
Referrer-Policy: origin-when-cross-origin
|
|
31
|
+
X-XSS-Protection: 1; mode=block
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Content Security Policy
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
default-src 'self';
|
|
38
|
+
script-src 'self' 'unsafe-eval' 'unsafe-inline';
|
|
39
|
+
style-src 'self' 'unsafe-inline';
|
|
40
|
+
img-src 'self' blob: data: https:;
|
|
41
|
+
font-src 'self';
|
|
42
|
+
object-src 'none';
|
|
43
|
+
base-uri 'self';
|
|
44
|
+
form-action 'self';
|
|
45
|
+
frame-ancestors 'none';
|
|
46
|
+
connect-src 'self' ${NEXT_PUBLIC_API_BASE_URL};
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Rules
|
|
50
|
+
|
|
51
|
+
1. **Never inject raw HTML** without sanitizing it first (use DOMPurify with allowed tags/attrs).
|
|
52
|
+
2. **Never log sensitive data** (tokens, passwords, full user objects). Dev-only: log IDs at most.
|
|
53
|
+
3. **Validate all inputs** with Zod — client-side (UX) AND server-side (security).
|
|
54
|
+
4. **External links**: Always `target="_blank" rel="noopener noreferrer"`.
|
|
55
|
+
5. **Sanitize URLs**: Only allow `http:`, `https:`, `mailto:` protocols before rendering as links.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
> **SCOPE**: These rules apply specifically to the **client** directory (Next.js App Router).
|
|
2
|
+
|
|
3
|
+
# Neuro-UX Checklist
|
|
4
|
+
|
|
5
|
+
## Cognitive Load — Miller's Law
|
|
6
|
+
|
|
7
|
+
- **Max 5-7 interactive elements** per viewport section. Use progressive disclosure (tabs, accordions, "Show more") for more.
|
|
8
|
+
|
|
9
|
+
## Gestalt Principles
|
|
10
|
+
|
|
11
|
+
- **Proximity**: Related items close together. Gap between groups = 2x gap within groups.
|
|
12
|
+
- **Grid alignment**: All elements on a strict grid. No floating/misaligned elements.
|
|
13
|
+
- **Similarity**: Same action = same visual style across all pages.
|
|
14
|
+
- **Common region**: Group related controls in a visual container (`bg-muted/50` or subtle border).
|
|
15
|
+
|
|
16
|
+
## Instant Feedback
|
|
17
|
+
|
|
18
|
+
| User action | Required feedback | Timing |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Click button | Press state (`active:scale-[0.98]`) | Instant |
|
|
21
|
+
| Submit form | Loading state on button + disable | Instant |
|
|
22
|
+
| Successful action | Toast notification | <500ms |
|
|
23
|
+
| Failed action | Inline error OR toast | <500ms |
|
|
24
|
+
| Navigate | Skeleton or page transition | Instant |
|
|
25
|
+
| Hover interactive | Color/shadow/scale change | <100ms |
|
|
26
|
+
|
|
27
|
+
- **Optimistic UI**: Update UI immediately before server confirms. Revert on error.
|
|
28
|
+
- **Skeletons over spinners. Always.** Spinners only inside buttons during submission.
|
|
29
|
+
|
|
30
|
+
## Nielsen's 10 Heuristics
|
|
31
|
+
|
|
32
|
+
1. **System status**: Show loading, toast on completion, inline validation as user types.
|
|
33
|
+
2. **Real-world match**: Human language ("Sign in" not "Authenticate"). Locale-formatted dates/currencies.
|
|
34
|
+
3. **User control**: Every modal dismissible with Escape + backdrop. Undo for destructive actions. Back always works.
|
|
35
|
+
4. **Consistency**: Same action = same button style, position, label everywhere.
|
|
36
|
+
5. **Error prevention**: Real-time validation. Disable submit until valid. Type-appropriate inputs. Confirm destructive actions.
|
|
37
|
+
6. **Recognition > recall**: Visible labels (not placeholder-only). Show recent searches. Visible nav on desktop.
|
|
38
|
+
7. **Flexibility**: Keyboard shortcuts (Cmd+K). Preserve filters in URL. Bulk actions where appropriate.
|
|
39
|
+
8. **Minimalist design**: Every element earns its place. Prefer whitespace over separators.
|
|
40
|
+
9. **Error recovery**: Say what went wrong + how to fix it. Highlight the field. Never clear form on error.
|
|
41
|
+
10. **Help**: Contextual tooltips on complex features. Dismissible onboarding hints.
|
|
42
|
+
|
|
43
|
+
## Performance Targets
|
|
44
|
+
|
|
45
|
+
| Metric | Target |
|
|
46
|
+
|---|---|
|
|
47
|
+
| Lighthouse Performance | 98+ |
|
|
48
|
+
| Lighthouse Accessibility | 98+ |
|
|
49
|
+
| LCP | <2.5s |
|
|
50
|
+
| CLS | 0 |
|
|
51
|
+
| INP | <200ms |
|
|
52
|
+
|
|
53
|
+
## Accessibility
|
|
54
|
+
|
|
55
|
+
- All interactive elements reachable via Tab in logical order.
|
|
56
|
+
- Focus rings: `:focus-visible` only (not `:focus`). Style: `ring-2 ring-primary/50`.
|
|
57
|
+
- Icon-only buttons: must have `aria-label`.
|
|
58
|
+
- One `h1` per page. No skipped heading levels.
|
|
59
|
+
- Dynamic content updates: `aria-live="polite"`.
|
|
60
|
+
- All animations in `motion-safe:` variant.
|
|
61
|
+
- WCAG AA contrast: 4.5:1 for text, 3:1 for large text/UI.
|
|
62
|
+
|
|
63
|
+
## Microcopy
|
|
64
|
+
|
|
65
|
+
- **Buttons**: Action verbs — "Save changes", "Create item", "Delete account". Never "Submit" or "OK".
|
|
66
|
+
- **Toasts**: Under 10 words. Success: confirm. Error: what happened + what to do.
|
|
67
|
+
- **Empty states**: Explain what this area is for + CTA to fill it. ("No items yet. Create your first one.")
|
|
68
|
+
- **Form errors**: Specific to the field. Below the field. Red text + red border.
|
|
69
|
+
|
|
70
|
+
## Page Audit Checklist
|
|
71
|
+
|
|
72
|
+
1. Interactive elements per section ≤ 7?
|
|
73
|
+
2. All elements on grid?
|
|
74
|
+
3. Every button/link has hover + active + focus-visible?
|
|
75
|
+
4. Skeletons for all async content?
|
|
76
|
+
5. Inline field-level errors on forms?
|
|
77
|
+
6. Every modal dismissible with Escape?
|
|
78
|
+
7. Tab through all elements in logical order?
|
|
79
|
+
8. Text passes WCAG AA contrast?
|
|
80
|
+
9. All animation in `motion-safe:`?
|
|
81
|
+
10. LCP image has `priority`?
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
> **SCOPE**: These rules apply specifically to the **client** directory (Next.js App Router).
|
|
2
|
+
|
|
3
|
+
# Client Rules — Core Index
|
|
4
|
+
|
|
5
|
+
**Read only the file relevant to your current task.**
|
|
6
|
+
|
|
7
|
+
| You are doing... | Read this |
|
|
8
|
+
|---|---|
|
|
9
|
+
| Creating files, folders, feature modules | `01-project-structure.md` |
|
|
10
|
+
| Building components, writing types/interfaces | `02-components-and-types.md` |
|
|
11
|
+
| Fetching data, managing state, calling APIs, forms | `03-data-and-state.md` |
|
|
12
|
+
| Choosing colors, styling, typography, spacing, motion | `04-design-system.md` |
|
|
13
|
+
| Auth tokens, env vars, security headers | `05-security.md` |
|
|
14
|
+
| UX psychology, cognitive load, a11y, performance | `06-ux-checklist.md` |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Architecture
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
Page (Server Component — fetches data)
|
|
22
|
+
→ Feature Components (Server or Client)
|
|
23
|
+
→ UI (shadcn/ui + Tailwind)
|
|
24
|
+
|
|
25
|
+
State: Server data (SSR) → Server Components
|
|
26
|
+
Server data (client) → React Query
|
|
27
|
+
Global client state → Redux (auth only)
|
|
28
|
+
Local state → useState / useReducer
|
|
29
|
+
URL state → useSearchParams
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Non-negotiable rules
|
|
35
|
+
|
|
36
|
+
1. **Server Components by default.** Only add `'use client'` when you need hooks, state, or event handlers.
|
|
37
|
+
2. **Component limits**: Max 250 lines, max 5 props, max 3 JSX nesting levels.
|
|
38
|
+
3. **No hardcoded colors**: Use Tailwind semantic tokens (`bg-primary`, `text-foreground`). Never hex/rgb.
|
|
39
|
+
4. **No inline styles**: Tailwind only. Use `cn()` for conditional classes.
|
|
40
|
+
5. **Import order**: React/Next → third-party → UI → local → hooks → services → types → utils.
|
|
41
|
+
6. **Forms**: Validate with Zod. Always validate client-side AND server-side.
|
|
42
|
+
7. **Security**: Never inject raw HTML without sanitization. Never prefix secrets with `NEXT_PUBLIC_`.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
> **SCOPE**: These rules apply to the **entire workspace** (server + client). Always active.
|
|
2
|
+
|
|
3
|
+
# Global Rules
|
|
4
|
+
|
|
5
|
+
These rules are always in effect regardless of which directory you are working in.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## New Project Setup
|
|
10
|
+
|
|
11
|
+
When the user asks to create, scaffold, or start a new server or client project, **always run `/create-server` or `/create-client` first** before writing any code. These commands contain the full scaffolding templates, dependency lists, and boilerplate that match our architecture. Do not attempt to scaffold a project from memory.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Safe Editing
|
|
16
|
+
|
|
17
|
+
1. **Small, focused changes**: Only modify what's necessary. Don't restructure code unless asked.
|
|
18
|
+
2. **Preserve signatures**: Don't change existing function signatures, exports, or imports unless explicitly requested.
|
|
19
|
+
3. **Extend, don't rewrite**: Add to existing modules. Don't gut and rebuild.
|
|
20
|
+
4. **Protect critical flows**: Never break existing auth, core business flows, or payment logic.
|
|
21
|
+
5. **No half-done work**: If something is incomplete, add a `// TODO:` with explanation.
|
|
22
|
+
6. **No noisy logs**: No debug logs in production code. Mark temporary ones with `// TODO: remove debug log`.
|
|
23
|
+
7. **Call out breaking changes**: If a breaking change is unavoidable, state it clearly in your explanation.
|
|
24
|
+
8. **Assume production**: Treat this as a real production project. Avoid destructive or experimental changes.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## TypeScript
|
|
29
|
+
|
|
30
|
+
- **Strict mode ON** in both client and server. No exceptions.
|
|
31
|
+
- **No `any`** — use `unknown` if the type is truly unknown.
|
|
32
|
+
- **Explicit return types** on all functions.
|
|
33
|
+
- **Always `import type`** for type-only imports.
|
|
34
|
+
- **Validate all inputs with Zod** — client-side for UX, server-side for security.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Git & Branching
|
|
39
|
+
|
|
40
|
+
- **Branch naming**: `feature/<name>`, `fix/<name>`, `chore/<name>`, `hotfix/<name>`.
|
|
41
|
+
- **Commit messages**: Use conventional commits — `feat:`, `fix:`, `chore:`, `refactor:`, `docs:`, `test:`.
|
|
42
|
+
- Keep the subject line under 72 characters.
|
|
43
|
+
- Use imperative mood: "Add search filter" not "Added search filter".
|
|
44
|
+
- **Never commit**: `.env` files, secrets, `node_modules`, build artifacts, OS files (`.DS_Store`, `Thumbs.db`).
|
|
45
|
+
- **One logical change per commit**. Don't mix unrelated changes.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Environment & Configuration
|
|
50
|
+
|
|
51
|
+
- **`.env` files are never committed.** Use `.env.example` as the template with placeholder values.
|
|
52
|
+
- **Adding a new env var**: Add it to `.env.example` with a comment, and document where it's used.
|
|
53
|
+
- **Secrets** (DB URLs, JWT secrets, API keys) must never be prefixed with `NEXT_PUBLIC_` and must never appear in client-side code.
|
|
54
|
+
- **Public values only** (API base URL, app name) get the `NEXT_PUBLIC_` prefix.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Testing
|
|
59
|
+
|
|
60
|
+
- **New features and bug fixes should include tests** unless the change is trivial (copy, config, styling).
|
|
61
|
+
- **Test naming**: `describe('<ModuleName>')` → `it('should <expected behavior>')`.
|
|
62
|
+
- **Tests must be deterministic**: No reliance on real time, network, or random values. Mock external dependencies.
|
|
63
|
+
- **Don't test implementation details** — test behavior and outputs.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Code Review Checklist
|
|
68
|
+
|
|
69
|
+
Before considering work done, verify:
|
|
70
|
+
|
|
71
|
+
- [ ] No `any` types.
|
|
72
|
+
- [ ] No hardcoded values (URLs, colors, magic numbers) — use constants and tokens.
|
|
73
|
+
- [ ] No `console.log` left in code.
|
|
74
|
+
- [ ] No commented-out code without a `// TODO:` explaining why.
|
|
75
|
+
- [ ] Inputs validated with Zod.
|
|
76
|
+
- [ ] Error cases handled (not just the happy path).
|
|
77
|
+
- [ ] Existing tests still pass.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
> **SCOPE**: These rules apply specifically to the **server** directory (Fastify backend).
|
|
2
|
+
|
|
3
|
+
# Server Rules — Core Index
|
|
4
|
+
|
|
5
|
+
**Do NOT read every rule file upfront.** Use this index to find the right rules for your current task.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## When to read which file
|
|
10
|
+
|
|
11
|
+
| You are doing... | Read this |
|
|
12
|
+
|------------------|-----------|
|
|
13
|
+
| Setting up a module, organizing code, understanding the stack | `project-conventions.md` |
|
|
14
|
+
| Creating or modifying a route / controller | `project-conventions.md` + `response-handling.md` |
|
|
15
|
+
| Returning data (success, error, or paginated) | `response-handling.md` |
|
|
16
|
+
| Handling or throwing errors | `response-handling.md` |
|
|
17
|
+
| Writing service or business logic | `project-conventions.md` (Layer Responsibilities) |
|
|
18
|
+
| Changing DB schema, migrations, indexes | `database.md` |
|
|
19
|
+
| Adding or changing API endpoints | `project-conventions.md` (Postman Collection) |
|
|
20
|
+
| Unsure where to start | This file |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Architecture at a glance
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
Request
|
|
28
|
+
-> Route (Fastify plugin, defines HTTP method + path)
|
|
29
|
+
-> Controller (validates input with Zod, calls service, returns response)
|
|
30
|
+
-> Service (business logic, throws typed errors)
|
|
31
|
+
-> Repository (Prisma queries, returns raw data)
|
|
32
|
+
-> Database
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Three strict boundaries:**
|
|
36
|
+
1. **Controllers** — parse input, call services, format responses. No business logic. No direct DB access.
|
|
37
|
+
2. **Services** — all business logic. No Fastify concepts (request, reply). Throw typed `AppError` instances.
|
|
38
|
+
3. **Repositories** — Prisma queries only. No business logic. No error formatting.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Non-negotiable rules (always apply)
|
|
43
|
+
|
|
44
|
+
1. **Response format**: All controllers use `successResponse()` / `paginatedResponse()`. No custom shapes.
|
|
45
|
+
2. **Error handling**: Only throw `AppError` subclasses. Never raw `Error` or strings. Global error handler formats all errors.
|
|
46
|
+
3. **Validation**: All input validated with Zod schemas before reaching services.
|
|
47
|
+
4. **Database changes**: Always via Prisma migrations. Never raw DDL.
|
|
48
|
+
5. **Logging**: Use `logger` from `src/libs/logger`. Never `console.log`.
|
|
49
|
+
6. **Routes**: All prefixed with `/api/v1`. Registered as Fastify plugins.
|
|
50
|
+
7. **Postman**: Every new or modified endpoint must be reflected in `postman/collection.json`. Create the collection if it doesn't exist.
|