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,326 @@
|
|
|
1
|
+
---
|
|
2
|
+
trigger: always_on
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
> **SCOPE**: These rules apply specifically to the **client** directory.
|
|
6
|
+
|
|
7
|
+
# Project Structure & File Naming
|
|
8
|
+
|
|
9
|
+
## Folder Structure
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
src/
|
|
13
|
+
├── app/ # App configuration
|
|
14
|
+
│ ├── App.tsx
|
|
15
|
+
│ ├── router.tsx
|
|
16
|
+
│ └── providers.tsx
|
|
17
|
+
├── components/
|
|
18
|
+
│ ├── layout/ # Header, Footer, MainLayout
|
|
19
|
+
│ │ ├── Header.tsx
|
|
20
|
+
│ │ ├── Footer.tsx
|
|
21
|
+
│ │ ├── Sidebar.tsx
|
|
22
|
+
│ │ └── MainLayout.tsx
|
|
23
|
+
│ └── common/ # Shared components
|
|
24
|
+
│ ├── LoadingSpinner.tsx
|
|
25
|
+
│ ├── ErrorBoundary.tsx
|
|
26
|
+
│ ├── ProtectedRoute.tsx
|
|
27
|
+
│ ├── Pagination.tsx
|
|
28
|
+
│ └── EmptyState.tsx
|
|
29
|
+
├── features/ # Feature modules (domain-driven)
|
|
30
|
+
│ ├── auth/
|
|
31
|
+
│ │ ├── components/ # LoginForm, RegisterForm
|
|
32
|
+
│ │ ├── hooks/ # useAuth, useLogin, useRegister
|
|
33
|
+
│ │ ├── pages/ # LoginPage, RegisterPage
|
|
34
|
+
│ │ ├── services/ # auth.service.ts
|
|
35
|
+
│ │ ├── store/ # authSlice.ts (Redux)
|
|
36
|
+
│ │ ├── types/ # auth.types.ts
|
|
37
|
+
│ │ └── utils/ # auth.utils.ts
|
|
38
|
+
│ ├── resources/ # Example feature
|
|
39
|
+
│ │ ├── components/
|
|
40
|
+
│ │ ├── hooks/
|
|
41
|
+
│ │ ├── pages/
|
|
42
|
+
│ │ ├── services/
|
|
43
|
+
│ │ ├── types/
|
|
44
|
+
│ │ └── utils/
|
|
45
|
+
│ └── users/
|
|
46
|
+
├── hooks/ # Global custom hooks
|
|
47
|
+
│ ├── useDebounce.ts
|
|
48
|
+
│ ├── useLocalStorage.ts
|
|
49
|
+
│ └── useMediaQuery.ts
|
|
50
|
+
├── lib/
|
|
51
|
+
│ ├── api/
|
|
52
|
+
│ │ ├── axios.config.ts
|
|
53
|
+
│ │ └── api.types.ts
|
|
54
|
+
│ ├── constants/
|
|
55
|
+
│ │ ├── routes.ts
|
|
56
|
+
│ │ ├── api-endpoints.ts
|
|
57
|
+
│ │ └── app.constants.ts
|
|
58
|
+
│ └── utils/
|
|
59
|
+
│ ├── format.ts
|
|
60
|
+
│ ├── validation.ts
|
|
61
|
+
│ └── error.ts
|
|
62
|
+
├── store/ # Redux store
|
|
63
|
+
│ ├── index.ts
|
|
64
|
+
│ └── hooks.ts
|
|
65
|
+
├── types/ # Global types
|
|
66
|
+
│ ├── index.ts
|
|
67
|
+
│ └── api.types.ts
|
|
68
|
+
└── styles/
|
|
69
|
+
├── globals.css # Global CSS
|
|
70
|
+
└── theme.css # Ant Design custom theme (if needed)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## File Naming Rules
|
|
74
|
+
|
|
75
|
+
### Components
|
|
76
|
+
- **PascalCase**: `ResourceCard.tsx`, `LoginForm.tsx`
|
|
77
|
+
- **Pattern**: `<ComponentName>.tsx`
|
|
78
|
+
- **CSS**: If using CSS Modules, name as `<ComponentName>.module.css`
|
|
79
|
+
|
|
80
|
+
### Pages
|
|
81
|
+
- **PascalCase + Page suffix**: `ResourcesPage.tsx`, `LoginPage.tsx`
|
|
82
|
+
- **Pattern**: `<FeatureName>Page.tsx`
|
|
83
|
+
|
|
84
|
+
### Hooks
|
|
85
|
+
- **camelCase + use prefix**: `useAuth.ts`, `useResources.ts`
|
|
86
|
+
- **Pattern**: `use<HookName>.ts`
|
|
87
|
+
|
|
88
|
+
### Services
|
|
89
|
+
- **camelCase + .service suffix**: `auth.service.ts`, `resource.service.ts`
|
|
90
|
+
- **Pattern**: `<domain>.service.ts`
|
|
91
|
+
|
|
92
|
+
### Types
|
|
93
|
+
- **camelCase + .types suffix**: `auth.types.ts`, `resource.types.ts`
|
|
94
|
+
- **Pattern**: `<domain>.types.ts`
|
|
95
|
+
|
|
96
|
+
### Store (Redux)
|
|
97
|
+
- **camelCase + Slice suffix**: `authSlice.ts`, `resourceSlice.ts`
|
|
98
|
+
- **Pattern**: `<domain>Slice.ts`
|
|
99
|
+
|
|
100
|
+
### Utils
|
|
101
|
+
- **camelCase + .utils suffix**: `auth.utils.ts`, `date.utils.ts`
|
|
102
|
+
- **Pattern**: `<purpose>.utils.ts`
|
|
103
|
+
|
|
104
|
+
### Constants
|
|
105
|
+
- **camelCase**: `routes.ts`, `api-endpoints.ts`, `app.constants.ts`
|
|
106
|
+
|
|
107
|
+
## Module Structure Pattern
|
|
108
|
+
|
|
109
|
+
Every feature module follows this pattern:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
features/<domain>/
|
|
113
|
+
├── components/ # Feature-specific components
|
|
114
|
+
├── hooks/ # Feature-specific hooks
|
|
115
|
+
├── pages/ # Feature pages (routes)
|
|
116
|
+
├── services/ # API service
|
|
117
|
+
├── store/ # Redux slice (if needed)
|
|
118
|
+
├── types/ # TypeScript types
|
|
119
|
+
└── utils/ # Feature utilities
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Import Path Aliases
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
// tsconfig.json & vite.config.ts
|
|
126
|
+
{
|
|
127
|
+
"paths": {
|
|
128
|
+
"@/*": ["./src/*"],
|
|
129
|
+
"@/components/*": ["./src/components/*"],
|
|
130
|
+
"@/features/*": ["./src/features/*"],
|
|
131
|
+
"@/lib/*": ["./src/lib/*"],
|
|
132
|
+
"@/hooks/*": ["./src/hooks/*"],
|
|
133
|
+
"@/store/*": ["./src/store/*"],
|
|
134
|
+
"@/types/*": ["./src/types/*"],
|
|
135
|
+
"@/styles/*": ["./src/styles/*"]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Import Order
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
// 1. React and framework
|
|
144
|
+
import { useState, useEffect } from 'react';
|
|
145
|
+
import { useNavigate } from 'react-router-dom';
|
|
146
|
+
|
|
147
|
+
// 2. Third-party libraries (Ant Design first)
|
|
148
|
+
import { Button, Card, Input } from 'antd';
|
|
149
|
+
import { useQuery } from '@tanstack/react-query';
|
|
150
|
+
|
|
151
|
+
// 3. Styles
|
|
152
|
+
import './ResourceCard.css'; // or .module.css
|
|
153
|
+
|
|
154
|
+
// 4. Local components
|
|
155
|
+
import { ResourceCard } from '../components/ResourceCard';
|
|
156
|
+
|
|
157
|
+
// 5. Hooks
|
|
158
|
+
import { useAuth } from '@/features/auth/hooks/useAuth';
|
|
159
|
+
import { useResources } from '../hooks/useResources';
|
|
160
|
+
|
|
161
|
+
// 6. Services
|
|
162
|
+
import { resourceService } from '../services/resource.service';
|
|
163
|
+
|
|
164
|
+
// 7. Types (always use 'type' keyword)
|
|
165
|
+
import type { Resource } from '../types/resource.types';
|
|
166
|
+
|
|
167
|
+
// 8. Utils
|
|
168
|
+
import { formatDate } from '@/lib/utils/format';
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Constants Structure
|
|
172
|
+
|
|
173
|
+
### API Endpoints
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
// lib/constants/api-endpoints.ts
|
|
177
|
+
export const API_ENDPOINTS = {
|
|
178
|
+
AUTH: {
|
|
179
|
+
REGISTER: '/auth/register',
|
|
180
|
+
LOGIN: '/auth/login',
|
|
181
|
+
LOGOUT: '/auth/logout',
|
|
182
|
+
REFRESH: '/auth/refresh',
|
|
183
|
+
ME: '/auth/me',
|
|
184
|
+
VERIFY_EMAIL: '/auth/verify-email',
|
|
185
|
+
RESEND_VERIFICATION: '/auth/resend-verification',
|
|
186
|
+
REQUEST_PASSWORD_RESET: '/auth/request-password-reset',
|
|
187
|
+
RESET_PASSWORD: '/auth/reset-password',
|
|
188
|
+
},
|
|
189
|
+
USERS: {
|
|
190
|
+
ME: '/users/me',
|
|
191
|
+
UPDATE_ME: '/users/me',
|
|
192
|
+
DELETE_ME: '/users/me',
|
|
193
|
+
},
|
|
194
|
+
RESOURCES: {
|
|
195
|
+
LIST: '/resources',
|
|
196
|
+
MY_RESOURCES: '/resources/my',
|
|
197
|
+
CREATE: '/resources',
|
|
198
|
+
GET: (id: string) => `/resources/${id}`,
|
|
199
|
+
UPDATE: (id: string) => `/resources/${id}`,
|
|
200
|
+
DELETE: (id: string) => `/resources/${id}`,
|
|
201
|
+
},
|
|
202
|
+
} as const;
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Routes
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
// lib/constants/routes.ts
|
|
209
|
+
export const ROUTES = {
|
|
210
|
+
HOME: '/',
|
|
211
|
+
LOGIN: '/login',
|
|
212
|
+
REGISTER: '/register',
|
|
213
|
+
VERIFY_EMAIL: '/verify-email',
|
|
214
|
+
RESET_PASSWORD: '/reset-password',
|
|
215
|
+
DASHBOARD: '/dashboard',
|
|
216
|
+
PROFILE: '/profile',
|
|
217
|
+
RESOURCES: {
|
|
218
|
+
LIST: '/resources',
|
|
219
|
+
DETAILS: (id: string) => `/resources/${id}`,
|
|
220
|
+
MY_RESOURCES: '/my-resources',
|
|
221
|
+
CREATE: '/resources/create',
|
|
222
|
+
EDIT: (id: string) => `/resources/${id}/edit`,
|
|
223
|
+
},
|
|
224
|
+
} as const;
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### App Constants
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
// lib/constants/app.constants.ts
|
|
231
|
+
export const APP_NAME = 'My Application';
|
|
232
|
+
|
|
233
|
+
export const PAGINATION = {
|
|
234
|
+
DEFAULT_PAGE: 1,
|
|
235
|
+
DEFAULT_LIMIT: 10,
|
|
236
|
+
MAX_LIMIT: 100,
|
|
237
|
+
} as const;
|
|
238
|
+
|
|
239
|
+
export const USER_ROLES = {
|
|
240
|
+
USER: 'USER',
|
|
241
|
+
ORG: 'ORGANIZATION',
|
|
242
|
+
ADMIN: 'ADMIN',
|
|
243
|
+
} as const;
|
|
244
|
+
|
|
245
|
+
export const CURRENCIES = {
|
|
246
|
+
GEL: 'GEL',
|
|
247
|
+
USD: 'USD',
|
|
248
|
+
EUR: 'EUR',
|
|
249
|
+
} as const;
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Naming Conventions
|
|
253
|
+
|
|
254
|
+
### Variables
|
|
255
|
+
- **camelCase**: `userName`, `resourceList`, `isLoading`
|
|
256
|
+
|
|
257
|
+
### Functions
|
|
258
|
+
- **camelCase**: `getUserData()`, `handleSubmit()`, `formatPrice()`
|
|
259
|
+
|
|
260
|
+
### Constants
|
|
261
|
+
- **UPPER_SNAKE_CASE**: `API_BASE_URL`, `MAX_FILE_SIZE`
|
|
262
|
+
|
|
263
|
+
### Types/Interfaces
|
|
264
|
+
- **PascalCase**: `User`, `Resource`, `ResourceFilters`
|
|
265
|
+
- **Interface prefix**: `IUser`, `IResource` (optional, be consistent)
|
|
266
|
+
|
|
267
|
+
### Enums/Type Unions
|
|
268
|
+
- **PascalCase**: `UserRole`, `ResourceStatus`
|
|
269
|
+
|
|
270
|
+
## Export Patterns
|
|
271
|
+
|
|
272
|
+
### Named Exports (Preferred)
|
|
273
|
+
```tsx
|
|
274
|
+
// ✅ GOOD
|
|
275
|
+
export const ResourceCard = () => {};
|
|
276
|
+
export const ResourceList = () => {};
|
|
277
|
+
|
|
278
|
+
// Import
|
|
279
|
+
import { ResourceCard, ResourceList } from './components';
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Default Export (Only for app.ts)
|
|
283
|
+
```tsx
|
|
284
|
+
// ❌ AVOID for components
|
|
285
|
+
export default ResourceCard;
|
|
286
|
+
|
|
287
|
+
// ✅ OK for App
|
|
288
|
+
export default App;
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Barrel Exports
|
|
292
|
+
```tsx
|
|
293
|
+
// features/resources/index.ts
|
|
294
|
+
export { ResourceCard } from './components/ResourceCard';
|
|
295
|
+
export { ResourceList } from './components/ResourceList';
|
|
296
|
+
export { useResources } from './hooks/useResources';
|
|
297
|
+
export { resourceService } from './services/resource.service';
|
|
298
|
+
export type * from './types/resource.types';
|
|
299
|
+
|
|
300
|
+
// Usage
|
|
301
|
+
import { ResourceCard, useResources, resourceService } from '@/features/resources';
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Environment Variables
|
|
305
|
+
|
|
306
|
+
```env
|
|
307
|
+
# .env.development
|
|
308
|
+
VITE_API_BASE_URL=http://localhost:3000/api/v1
|
|
309
|
+
VITE_APP_NAME=My Application
|
|
310
|
+
|
|
311
|
+
# .env.production
|
|
312
|
+
VITE_API_BASE_URL=https://api.myapplication.com/api/v1
|
|
313
|
+
VITE_APP_NAME=My Application
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Rules:**
|
|
317
|
+
- Prefix with `VITE_` to expose to client
|
|
318
|
+
- Never commit `.env` files
|
|
319
|
+
- Always provide `.env.example`
|
|
320
|
+
|
|
321
|
+
```tsx
|
|
322
|
+
// Accessing env variables
|
|
323
|
+
const apiUrl = import.meta.env.VITE_API_BASE_URL;
|
|
324
|
+
const isDev = import.meta.env.DEV;
|
|
325
|
+
const isProd = import.meta.env.PROD;
|
|
326
|
+
```
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
---
|
|
2
|
+
trigger: always_on
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
> **SCOPE**: These rules apply specifically to the **client** directory.
|
|
6
|
+
|
|
7
|
+
# Component Patterns & Rules
|
|
8
|
+
|
|
9
|
+
## Component Structure Template
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
// 1. IMPORTS (grouped and ordered)
|
|
13
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
14
|
+
import { useNavigate } from 'react-router-dom';
|
|
15
|
+
import { Button, Card } from 'antd'; // Ant Design
|
|
16
|
+
import { useResources } from '../hooks/useResources';
|
|
17
|
+
import type { Resource } from '../types/resource.types';
|
|
18
|
+
|
|
19
|
+
// Import CSS (Vanilla or Module)
|
|
20
|
+
import './ResourceCard.css';
|
|
21
|
+
|
|
22
|
+
// 2. TYPES (component-specific only)
|
|
23
|
+
interface ResourceCardProps {
|
|
24
|
+
resource: Resource;
|
|
25
|
+
onEdit?: (id: string) => void;
|
|
26
|
+
className?: string; // Standard className prop for custom styles
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 3. COMPONENT
|
|
30
|
+
export const ResourceCard = ({ resource, onEdit, className }: ResourceCardProps) => {
|
|
31
|
+
// 3a. HOOKS (router → Redux → React Query → state → custom)
|
|
32
|
+
const navigate = useNavigate();
|
|
33
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
34
|
+
|
|
35
|
+
// 3b. EVENT HANDLERS
|
|
36
|
+
const handleClick = useCallback(() => {
|
|
37
|
+
navigate(`/resources/${resource.id}`);
|
|
38
|
+
}, [navigate, resource.id]);
|
|
39
|
+
|
|
40
|
+
// 3c. EFFECTS
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
// Side effects
|
|
43
|
+
}, []);
|
|
44
|
+
|
|
45
|
+
// 3d. EARLY RETURNS
|
|
46
|
+
if (!resource) return null;
|
|
47
|
+
|
|
48
|
+
// 3e. RENDER
|
|
49
|
+
return (
|
|
50
|
+
<Card
|
|
51
|
+
className={`resource-card ${className || ''}`}
|
|
52
|
+
onClick={handleClick}
|
|
53
|
+
hoverable
|
|
54
|
+
>
|
|
55
|
+
<h3>{resource.title}</h3>
|
|
56
|
+
{/* JSX */}
|
|
57
|
+
</Card>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Component Types
|
|
63
|
+
|
|
64
|
+
### 1. Presentational Components
|
|
65
|
+
**Location**: `components/common/` or `features/*/components/`
|
|
66
|
+
|
|
67
|
+
**Rules**:
|
|
68
|
+
- NO business logic
|
|
69
|
+
- NO API calls
|
|
70
|
+
- NO Redux/Context (except theme)
|
|
71
|
+
- Receive ALL data via props
|
|
72
|
+
- Focus ONLY on UI
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
// ✅ GOOD - Pure presentation
|
|
76
|
+
interface ResourceCardProps {
|
|
77
|
+
resource: Resource;
|
|
78
|
+
onClick: (id: string) => void;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const ResourceCard = ({ resource, onClick }: ResourceCardProps) => {
|
|
82
|
+
return (
|
|
83
|
+
<div className="card-container" onClick={() => onClick(resource.id)}>
|
|
84
|
+
<h3>{resource.title}</h3>
|
|
85
|
+
<p>{resource.price}</p>
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 2. Container Components
|
|
92
|
+
**Location**: `features/*/pages/` or `features/*/components/`
|
|
93
|
+
|
|
94
|
+
**Rules**:
|
|
95
|
+
- Contains business logic
|
|
96
|
+
- Makes API calls via hooks
|
|
97
|
+
- Manages state
|
|
98
|
+
- Passes data to presentational components
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
// ✅ GOOD - Container component
|
|
102
|
+
export const ResourcesPage = () => {
|
|
103
|
+
const [filters, setFilters] = useState<ResourceFilters>({});
|
|
104
|
+
const { resources, isLoading } = useResources(filters);
|
|
105
|
+
const navigate = useNavigate();
|
|
106
|
+
|
|
107
|
+
const handleResourceClick = (id: string) => {
|
|
108
|
+
navigate(`/resources/${id}`);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
if (isLoading) return <LoadingSpinner />;
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<div className="page-container">
|
|
115
|
+
<ResourceFilters value={filters} onChange={setFilters} />
|
|
116
|
+
<div className="resource-list">
|
|
117
|
+
{resources.map(res => (
|
|
118
|
+
<ResourceCard key={res.id} resource={res} onClick={handleResourceClick} />
|
|
119
|
+
))}
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Styling Rules
|
|
127
|
+
|
|
128
|
+
### CSS Architecture
|
|
129
|
+
Instead of Tailwind, use Vanilla CSS or CSS Modules.
|
|
130
|
+
|
|
131
|
+
**Vanilla CSS Pattern**:
|
|
132
|
+
```css
|
|
133
|
+
/* ResourceCard.css */
|
|
134
|
+
.resource-card {
|
|
135
|
+
padding: 16px;
|
|
136
|
+
border: 1px solid var(--border-color);
|
|
137
|
+
transition: all 0.3s ease;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.resource-card:hover {
|
|
141
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**CSS Modules Pattern**:
|
|
146
|
+
```tsx
|
|
147
|
+
import styles from './ResourceCard.module.css';
|
|
148
|
+
|
|
149
|
+
<div className={styles.cardContainer}>...</div>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Rules**:
|
|
153
|
+
1. **NO Inline styles**: Avoid `<div style={{...}}>`.
|
|
154
|
+
2. **Use Variables**: Use CSS variables for theme colors (defined in `globals.css`).
|
|
155
|
+
3. **Consistency**: Use Ant Design's built-in props for standard spacing and layout where possible.
|
|
156
|
+
4. **Responsive**: Use media queries in CSS files.
|
|
157
|
+
|
|
158
|
+
```css
|
|
159
|
+
/* ✅ GOOD - Responsive in CSS */
|
|
160
|
+
.page-container {
|
|
161
|
+
padding: 20px;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@media (min-width: 768px) {
|
|
165
|
+
.page-container {
|
|
166
|
+
padding: 40px;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Component Size Rules
|
|
172
|
+
|
|
173
|
+
### Limits
|
|
174
|
+
- **Max 250 lines** per component
|
|
175
|
+
- **Max 5 props** (use object if more)
|
|
176
|
+
- **Max 3 levels** of JSX nesting
|
|
177
|
+
|
|
178
|
+
### When to Split
|
|
179
|
+
Split when:
|
|
180
|
+
1. Component exceeds 250 lines
|
|
181
|
+
2. JSX nesting exceeds 3 levels
|
|
182
|
+
3. Multiple responsibilities
|
|
183
|
+
4. Part is reusable elsewhere
|
|
184
|
+
|
|
185
|
+
## Props Rules
|
|
186
|
+
|
|
187
|
+
### Props Interface
|
|
188
|
+
```tsx
|
|
189
|
+
// ✅ GOOD - Group related props
|
|
190
|
+
interface ResourceCardProps {
|
|
191
|
+
resource: Resource;
|
|
192
|
+
actions?: ResourceActions;
|
|
193
|
+
className?: string;
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Children Prop
|
|
198
|
+
```tsx
|
|
199
|
+
interface LayoutProps {
|
|
200
|
+
children: React.ReactNode;
|
|
201
|
+
headerContent?: React.ReactNode;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export const Layout = ({ children, headerContent }: LayoutProps) => {
|
|
205
|
+
return (
|
|
206
|
+
<div className="layout">
|
|
207
|
+
{headerContent && <div className="header">{headerContent}</div>}
|
|
208
|
+
{children}
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
211
|
+
};
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Performance Optimization
|
|
215
|
+
|
|
216
|
+
### React.memo
|
|
217
|
+
```tsx
|
|
218
|
+
// ✅ Use for components in lists
|
|
219
|
+
export const ResourceCard = React.memo(({ resource }: ResourceCardProps) => {
|
|
220
|
+
return <div>{resource.title}</div>;
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
ResourceCard.displayName = 'ResourceCard';
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### useCallback
|
|
227
|
+
```tsx
|
|
228
|
+
// ✅ For handlers passed to children
|
|
229
|
+
const handleClick = useCallback((id: string) => {
|
|
230
|
+
navigate(`/resources/${id}`);
|
|
231
|
+
}, [navigate]);
|
|
232
|
+
|
|
233
|
+
<ResourceCard resource={resource} onClick={handleClick} />
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Accessibility Rules
|
|
237
|
+
- Use semantic HTML tags.
|
|
238
|
+
- Use `aria-*` attributes when standard elements aren't enough.
|
|
239
|
+
- Ensure Ant Design components are used with proper labels.
|
|
240
|
+
|
|
241
|
+
## Component Checklist
|
|
242
|
+
- [ ] Under 250 lines
|
|
243
|
+
- [ ] Props interface defined (max 5)
|
|
244
|
+
- [ ] Event handlers use useCallback
|
|
245
|
+
- [ ] Expensive computations use useMemo
|
|
246
|
+
- [ ] Early returns for error/loading
|
|
247
|
+
- [ ] CSS files used (no inline styles, no Tailwind)
|
|
248
|
+
- [ ] Accessibility attributes
|
|
249
|
+
- [ ] Named export (not default)
|