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.
Files changed (243) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +80 -87
  3. package/bin/create-tigra.js +259 -308
  4. package/package.json +49 -41
  5. package/template/_claude/QUICK_REFERENCE.md +193 -0
  6. package/template/_claude/README.md +53 -0
  7. package/template/_claude/commands/create-client.md +881 -0
  8. package/template/_claude/commands/create-server.md +383 -0
  9. package/template/_claude/rules/client/01-project-structure.md +133 -0
  10. package/template/_claude/rules/client/02-components-and-types.md +146 -0
  11. package/template/_claude/rules/client/03-data-and-state.md +156 -0
  12. package/template/_claude/rules/client/04-design-system.md +185 -0
  13. package/template/_claude/rules/client/05-security.md +55 -0
  14. package/template/_claude/rules/client/06-ux-checklist.md +81 -0
  15. package/template/_claude/rules/client/core.md +42 -0
  16. package/template/_claude/rules/global/core.md +77 -0
  17. package/template/_claude/rules/server/core.md +50 -0
  18. package/template/_claude/rules/server/database.md +124 -0
  19. package/template/_claude/rules/server/project-conventions.md +150 -0
  20. package/template/_claude/rules/server/response-handling.md +144 -0
  21. package/template/client/.env.example +5 -0
  22. package/template/client/README.md +36 -0
  23. package/template/client/components.json +23 -0
  24. package/template/client/eslint.config.mjs +18 -0
  25. package/template/client/next.config.ts +34 -0
  26. package/template/client/package.json +44 -0
  27. package/template/client/postcss.config.mjs +7 -0
  28. package/template/client/src/app/(auth)/layout.tsx +18 -0
  29. package/template/client/src/app/(auth)/login/page.tsx +13 -0
  30. package/template/client/src/app/(auth)/register/page.tsx +13 -0
  31. package/template/client/src/app/(main)/dashboard/page.tsx +22 -0
  32. package/template/client/src/app/(main)/layout.tsx +11 -0
  33. package/template/client/src/app/error.tsx +27 -0
  34. package/template/client/src/app/favicon.ico +0 -0
  35. package/template/client/src/app/globals.css +145 -0
  36. package/template/client/src/app/layout.tsx +36 -0
  37. package/template/client/src/app/loading.tsx +11 -0
  38. package/template/client/src/app/not-found.tsx +23 -0
  39. package/template/client/src/app/page.tsx +45 -0
  40. package/template/client/src/app/providers.tsx +43 -0
  41. package/template/client/src/components/common/ConfirmDialog.tsx +56 -0
  42. package/template/client/src/components/common/EmptyState.tsx +31 -0
  43. package/template/client/src/components/common/LoadingSpinner.tsx +30 -0
  44. package/template/client/src/components/common/Pagination.tsx +55 -0
  45. package/template/client/src/components/layout/Footer.tsx +17 -0
  46. package/template/client/src/components/layout/Header.tsx +173 -0
  47. package/template/client/src/components/layout/MainLayout.tsx +18 -0
  48. package/template/client/src/components/ui/alert-dialog.tsx +196 -0
  49. package/template/client/src/components/ui/badge.tsx +48 -0
  50. package/template/client/src/components/ui/button.tsx +64 -0
  51. package/template/client/src/components/ui/card.tsx +92 -0
  52. package/template/client/src/components/ui/input.tsx +21 -0
  53. package/template/client/src/components/ui/label.tsx +24 -0
  54. package/template/client/src/components/ui/select.tsx +190 -0
  55. package/template/client/src/components/ui/skeleton.tsx +13 -0
  56. package/template/client/src/components/ui/table.tsx +116 -0
  57. package/template/client/src/features/auth/components/AuthInitializer.tsx +55 -0
  58. package/template/client/src/features/auth/components/LoginForm.tsx +107 -0
  59. package/template/client/src/features/auth/components/RegisterForm.tsx +178 -0
  60. package/template/client/src/features/auth/hooks/useAuth.ts +84 -0
  61. package/template/client/src/features/auth/services/auth.service.ts +52 -0
  62. package/template/client/src/features/auth/store/authSlice.ts +38 -0
  63. package/template/client/src/features/auth/types/auth.types.ts +32 -0
  64. package/template/client/src/hooks/useDebounce.ts +14 -0
  65. package/template/client/src/hooks/useLocalStorage.ts +55 -0
  66. package/template/client/src/hooks/useMediaQuery.ts +27 -0
  67. package/template/client/src/lib/api/api.types.ts +34 -0
  68. package/template/client/src/lib/api/axios.config.ts +98 -0
  69. package/template/client/src/lib/constants/api-endpoints.ts +18 -0
  70. package/template/client/src/lib/constants/app.constants.ts +12 -0
  71. package/template/client/src/lib/constants/routes.ts +9 -0
  72. package/template/client/src/lib/utils/error.ts +32 -0
  73. package/template/client/src/lib/utils/format.ts +37 -0
  74. package/template/client/src/lib/utils/security.ts +34 -0
  75. package/template/client/src/lib/utils.ts +6 -0
  76. package/template/client/src/middleware.ts +57 -0
  77. package/template/client/src/store/hooks.ts +7 -0
  78. package/template/client/src/store/index.ts +12 -0
  79. package/template/client/src/types/index.ts +3 -0
  80. package/template/client/tsconfig.json +34 -0
  81. package/template/gitignore +34 -0
  82. package/template/server/.dockerignore +66 -0
  83. package/template/server/.env.example +96 -69
  84. package/template/server/.env.production.example +90 -0
  85. package/template/server/Dockerfile +94 -0
  86. package/template/server/docker-compose.yml +82 -111
  87. package/template/server/docs/logging.md +62 -0
  88. package/template/server/eslint.config.mjs +17 -0
  89. package/template/server/package.json +68 -81
  90. package/template/server/phpmyadmin-config.php +26 -0
  91. package/template/server/postman_collection.json +666 -0
  92. package/template/server/prisma/schema.prisma +77 -93
  93. package/template/server/prisma/seed.ts +46 -142
  94. package/template/server/scripts/flush-redis.ts +41 -0
  95. package/template/server/src/app.ts +243 -71
  96. package/template/server/src/config/env.ts +67 -94
  97. package/template/server/src/libs/auth.ts +88 -0
  98. package/template/server/src/libs/cleanup.ts +35 -0
  99. package/template/server/src/libs/cookies.ts +46 -0
  100. package/template/server/src/libs/logger.ts +33 -60
  101. package/template/server/src/libs/monitoring.ts +205 -0
  102. package/template/server/src/libs/password.ts +38 -0
  103. package/template/server/src/libs/prisma.ts +68 -0
  104. package/template/server/src/libs/redis.ts +60 -79
  105. package/template/server/src/libs/requestLogger.ts +66 -0
  106. package/template/server/src/libs/storage/file-storage.service.ts +211 -0
  107. package/template/server/src/libs/storage/file-validator.ts +97 -0
  108. package/template/server/src/libs/storage/filename-sanitizer.ts +71 -0
  109. package/template/server/src/libs/storage/image-optimizer.service.ts +144 -0
  110. package/template/server/src/modules/auth/__tests__/auth.service.test.ts +365 -0
  111. package/template/server/src/modules/auth/auth.controller.ts +90 -141
  112. package/template/server/src/modules/auth/auth.repo.ts +120 -218
  113. package/template/server/src/modules/auth/auth.routes.ts +96 -83
  114. package/template/server/src/modules/auth/auth.schemas.ts +35 -137
  115. package/template/server/src/modules/auth/auth.service.ts +286 -329
  116. package/template/server/src/modules/auth/session.repo.ts +110 -0
  117. package/template/server/src/modules/users/users.controller.ts +120 -0
  118. package/template/server/src/modules/users/users.repo.ts +77 -0
  119. package/template/server/src/modules/users/users.routes.ts +89 -0
  120. package/template/server/src/modules/users/users.schemas.ts +21 -0
  121. package/template/server/src/modules/users/users.service.ts +169 -0
  122. package/template/server/src/server.ts +58 -139
  123. package/template/server/src/shared/errors/AppError.ts +21 -0
  124. package/template/server/src/shared/errors/errors.ts +43 -0
  125. package/template/server/src/shared/responses/paginatedResponse.ts +38 -0
  126. package/template/server/src/shared/responses/successResponse.ts +17 -0
  127. package/template/server/src/shared/schemas/pagination.schema.ts +12 -0
  128. package/template/server/src/shared/types/index.ts +26 -0
  129. package/template/server/src/test/setup.ts +74 -38
  130. package/template/server/tsconfig.json +27 -89
  131. package/template/server/uploads/avatars/.gitkeep +1 -0
  132. package/template/server/vitest.config.ts +43 -98
  133. package/template/.agent/rules/client/01-project-structure.md +0 -326
  134. package/template/.agent/rules/client/02-component-patterns.md +0 -249
  135. package/template/.agent/rules/client/03-typescript-rules.md +0 -226
  136. package/template/.agent/rules/client/04-state-management.md +0 -474
  137. package/template/.agent/rules/client/05-api-integration.md +0 -129
  138. package/template/.agent/rules/client/06-forms-validation.md +0 -129
  139. package/template/.agent/rules/client/07-common-patterns.md +0 -150
  140. package/template/.agent/rules/client/08-color-system.md +0 -93
  141. package/template/.agent/rules/client/09-security-rules.md +0 -97
  142. package/template/.agent/rules/client/10-testing-strategy.md +0 -370
  143. package/template/.agent/rules/global/ai-edit-safety.md +0 -38
  144. package/template/.agent/rules/server/01-db-and-migrations.md +0 -242
  145. package/template/.agent/rules/server/02-general-rules.md +0 -111
  146. package/template/.agent/rules/server/03-migrations.md +0 -20
  147. package/template/.agent/rules/server/04-pagination.md +0 -130
  148. package/template/.agent/rules/server/05-project-conventions.md +0 -71
  149. package/template/.agent/rules/server/06-response-handling.md +0 -173
  150. package/template/.agent/rules/server/07-testing-strategy.md +0 -506
  151. package/template/.agent/rules/server/08-observability.md +0 -180
  152. package/template/.agent/rules/server/10-background-jobs-v2.md +0 -185
  153. package/template/.agent/rules/server/11-rate-limiting-v2.md +0 -210
  154. package/template/.agent/rules/server/12-performance-optimization.md +0 -567
  155. package/template/.claude/rules/client-01-project-structure.md +0 -327
  156. package/template/.claude/rules/client-02-component-patterns.md +0 -250
  157. package/template/.claude/rules/client-03-typescript-rules.md +0 -227
  158. package/template/.claude/rules/client-04-state-management.md +0 -475
  159. package/template/.claude/rules/client-05-api-integration.md +0 -130
  160. package/template/.claude/rules/client-06-forms-validation.md +0 -130
  161. package/template/.claude/rules/client-07-common-patterns.md +0 -151
  162. package/template/.claude/rules/client-08-color-system.md +0 -94
  163. package/template/.claude/rules/client-09-security-rules.md +0 -98
  164. package/template/.claude/rules/client-10-testing-strategy.md +0 -371
  165. package/template/.claude/rules/global-ai-edit-safety.md +0 -39
  166. package/template/.claude/rules/server-01-db-and-migrations.md +0 -243
  167. package/template/.claude/rules/server-02-general-rules.md +0 -112
  168. package/template/.claude/rules/server-03-migrations.md +0 -21
  169. package/template/.claude/rules/server-04-pagination.md +0 -131
  170. package/template/.claude/rules/server-05-project-conventions.md +0 -72
  171. package/template/.claude/rules/server-06-response-handling.md +0 -174
  172. package/template/.claude/rules/server-07-testing-strategy.md +0 -507
  173. package/template/.claude/rules/server-08-observability.md +0 -181
  174. package/template/.claude/rules/server-10-background-jobs-v2.md +0 -186
  175. package/template/.claude/rules/server-11-rate-limiting-v2.md +0 -211
  176. package/template/.claude/rules/server-12-performance-optimization.md +0 -568
  177. package/template/.cursor/rules/client-01-project-structure.mdc +0 -327
  178. package/template/.cursor/rules/client-02-component-patterns.mdc +0 -250
  179. package/template/.cursor/rules/client-03-typescript-rules.mdc +0 -227
  180. package/template/.cursor/rules/client-04-state-management.mdc +0 -475
  181. package/template/.cursor/rules/client-05-api-integration.mdc +0 -130
  182. package/template/.cursor/rules/client-06-forms-validation.mdc +0 -130
  183. package/template/.cursor/rules/client-07-common-patterns.mdc +0 -151
  184. package/template/.cursor/rules/client-08-color-system.mdc +0 -94
  185. package/template/.cursor/rules/client-09-security-rules.mdc +0 -98
  186. package/template/.cursor/rules/client-10-testing-strategy.mdc +0 -371
  187. package/template/.cursor/rules/global-ai-edit-safety.mdc +0 -39
  188. package/template/.cursor/rules/server-01-db-and-migrations.mdc +0 -243
  189. package/template/.cursor/rules/server-02-general-rules.mdc +0 -112
  190. package/template/.cursor/rules/server-03-migrations.mdc +0 -21
  191. package/template/.cursor/rules/server-04-pagination.mdc +0 -131
  192. package/template/.cursor/rules/server-05-project-conventions.mdc +0 -72
  193. package/template/.cursor/rules/server-06-response-handling.mdc +0 -174
  194. package/template/.cursor/rules/server-07-testing-strategy.mdc +0 -507
  195. package/template/.cursor/rules/server-08-observability.mdc +0 -181
  196. package/template/.cursor/rules/server-09-api-documentation-v2.mdc +0 -169
  197. package/template/.cursor/rules/server-10-background-jobs-v2.mdc +0 -186
  198. package/template/.cursor/rules/server-11-rate-limiting-v2.mdc +0 -211
  199. package/template/.cursor/rules/server-12-performance-optimization.mdc +0 -568
  200. package/template/CLAUDE.md +0 -207
  201. package/template/server/.tsc-aliasrc.json +0 -13
  202. package/template/server/IMPORT_FIX_CHECKLIST.md +0 -98
  203. package/template/server/IMPORT_FIX_COMPLETE.md +0 -89
  204. package/template/server/README.md +0 -183
  205. package/template/server/REMAINING_IMPORT_FIXES.md +0 -150
  206. package/template/server/SECURITY.md +0 -190
  207. package/template/server/Tigra-API.postman_collection.json +0 -733
  208. package/template/server/biome.json +0 -42
  209. package/template/server/scripts/fix-all-imports.ps1 +0 -52
  210. package/template/server/scripts/fix-imports-reference.ps1 +0 -16
  211. package/template/server/scripts/fix-imports.mjs +0 -55
  212. package/template/server/scripts/setup-env.js +0 -50
  213. package/template/server/scripts/wait-for-db.js +0 -60
  214. package/template/server/src/hooks/request-timing.hook.ts +0 -26
  215. package/template/server/src/libs/auth/authenticate.middleware.ts +0 -22
  216. package/template/server/src/libs/auth/rbac.middleware.test.ts +0 -134
  217. package/template/server/src/libs/auth/rbac.middleware.ts +0 -147
  218. package/template/server/src/libs/db.ts +0 -76
  219. package/template/server/src/libs/error-handler.ts +0 -89
  220. package/template/server/src/libs/queue.ts +0 -79
  221. package/template/server/src/modules/admin/admin.controller.ts +0 -122
  222. package/template/server/src/modules/admin/admin.routes.ts +0 -62
  223. package/template/server/src/modules/admin/admin.schemas.ts +0 -35
  224. package/template/server/src/modules/admin/admin.service.ts +0 -167
  225. package/template/server/src/modules/auth/auth.integration.test.ts +0 -150
  226. package/template/server/src/modules/auth/auth.service.test.ts +0 -119
  227. package/template/server/src/modules/auth/auth.types.ts +0 -97
  228. package/template/server/src/modules/resources/resources.controller.ts +0 -218
  229. package/template/server/src/modules/resources/resources.repo.ts +0 -253
  230. package/template/server/src/modules/resources/resources.routes.ts +0 -116
  231. package/template/server/src/modules/resources/resources.schemas.ts +0 -146
  232. package/template/server/src/modules/resources/resources.service.ts +0 -218
  233. package/template/server/src/modules/resources/resources.types.ts +0 -73
  234. package/template/server/src/plugins/rate-limit.plugin.ts +0 -21
  235. package/template/server/src/plugins/security.plugin.ts +0 -21
  236. package/template/server/src/routes/health.routes.ts +0 -31
  237. package/template/server/src/types/fastify.d.ts +0 -36
  238. package/template/server/src/utils/errors.ts +0 -108
  239. package/template/server/src/utils/pagination.ts +0 -120
  240. package/template/server/src/utils/response.ts +0 -110
  241. package/template/server/src/workers/file.worker.ts +0 -106
  242. package/template/server/tsconfig.build.json +0 -30
  243. package/template/server/tsconfig.test.json +0 -22
@@ -1,370 +0,0 @@
1
- ---
2
- trigger: always_on
3
- ---
4
-
5
- > **SCOPE**: These rules apply specifically to the **client** directory.
6
-
7
- # Client Testing Strategy
8
-
9
- ## Stack
10
-
11
- ```json
12
- {
13
- "devDependencies": {
14
- "vitest": "^1.0.0",
15
- "@testing-library/react": "^14.0.0",
16
- "@testing-library/user-event": "^14.5.0",
17
- "@testing-library/jest-dom": "^6.1.0",
18
- "msw": "^2.0.0"
19
- }
20
- }
21
- ```
22
-
23
- ## Setup
24
-
25
- ```typescript
26
- // src/test/setup.ts
27
- import { expect, afterEach } from 'vitest';
28
- import { cleanup } from '@testing-library/react';
29
- import matchers from '@testing-library/jest-dom/matchers';
30
-
31
- expect.extend(matchers);
32
- afterEach(() => cleanup());
33
-
34
- // Mock window.matchMedia
35
- Object.defineProperty(window, 'matchMedia', {
36
- writable: true,
37
- value: vi.fn().mockImplementation((query) => ({
38
- matches: false,
39
- media: query,
40
- addEventListener: vi.fn(),
41
- removeEventListener: vi.fn(),
42
- })),
43
- });
44
- ```
45
-
46
- ```typescript
47
- // vite.config.ts
48
- export default defineConfig({
49
- test: {
50
- globals: true,
51
- environment: 'jsdom',
52
- setupFiles: './src/test/setup.ts',
53
- },
54
- });
55
- ```
56
-
57
- ## Test Utilities
58
-
59
- ```typescript
60
- // src/test/utils.tsx
61
- import { render } from '@testing-library/react';
62
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
63
- import { BrowserRouter } from 'react-router-dom';
64
- import { Provider } from 'react-redux';
65
- import { store } from '@/store';
66
-
67
- const createTestQueryClient = () =>
68
- new QueryClient({
69
- defaultOptions: { queries: { retry: false } },
70
- });
71
-
72
- export function renderWithProviders(ui: React.ReactElement, options = {}) {
73
- const queryClient = createTestQueryClient();
74
-
75
- function Wrapper({ children }: { children: React.ReactNode }) {
76
- return (
77
- <Provider store={store}>
78
- <QueryClientProvider client={queryClient}>
79
- <BrowserRouter>{children}</BrowserRouter>
80
- </QueryClientProvider>
81
- </Provider>
82
- );
83
- }
84
-
85
- return { ...render(ui, { wrapper: Wrapper, ...options }), queryClient };
86
- }
87
-
88
- export * from '@testing-library/react';
89
- export { renderWithProviders as render };
90
- ```
91
-
92
- ## API Mocking (MSW)
93
-
94
- ```typescript
95
- // src/test/mocks/handlers.ts
96
- import { http, HttpResponse } from 'msw';
97
-
98
- export const handlers = [
99
- http.post('/api/v1/auth/login', async ({ request }) => {
100
- const { email, password } = await request.json();
101
-
102
- if (email === 'user@test.com' && password === 'password') {
103
- return HttpResponse.json({
104
- success: true,
105
- data: {
106
- user: { id: '1', email: 'user@test.com' },
107
- tokens: { accessToken: 'fake-token' },
108
- },
109
- });
110
- }
111
-
112
- return HttpResponse.json(
113
- { success: false, error: { code: 'INVALID_CREDENTIALS' } },
114
- { status: 401 }
115
- );
116
- }),
117
-
118
- http.get('/api/v1/resources', () => {
119
- return HttpResponse.json({
120
- success: true,
121
- data: {
122
- items: [
123
- { id: '1', title: 'Resource 1', price: 100 },
124
- { id: '2', title: 'Resource 2', price: 200 },
125
- ],
126
- pagination: { page: 1, totalPages: 1, hasNextPage: false },
127
- },
128
- });
129
- }),
130
- ];
131
- ```
132
-
133
- ```typescript
134
- // src/test/mocks/server.ts
135
- import { setupServer } from 'msw/node';
136
- import { handlers } from './handlers';
137
-
138
- export const server = setupServer(...handlers);
139
- ```
140
-
141
- ```typescript
142
- // src/test/setup.ts (add to existing)
143
- import { server } from './mocks/server';
144
-
145
- beforeAll(() => server.listen());
146
- afterEach(() => server.resetHandlers());
147
- afterAll(() => server.close());
148
- ```
149
-
150
- ## Testing Patterns
151
-
152
- ### 1. Component Tests
153
-
154
- ```typescript
155
- // ResourceCard.test.tsx
156
- import { describe, it, expect, vi } from 'vitest';
157
- import { render, screen } from '@/test/utils';
158
- import { ResourceCard } from './ResourceCard';
159
-
160
- describe('ResourceCard', () => {
161
- const mockResource = {
162
- id: '1',
163
- title: 'Test Resource',
164
- price: 99.99,
165
- };
166
-
167
- it('renders resource information', () => {
168
- render(<ResourceCard resource={mockResource} />);
169
-
170
- expect(screen.getByText('Test Resource')).toBeInTheDocument();
171
- expect(screen.getByText('$99.99')).toBeInTheDocument();
172
- });
173
-
174
- it('calls onClick when clicked', async () => {
175
- const handleClick = vi.fn();
176
- const { user } = render(
177
- <ResourceCard resource={mockResource} onClick={handleClick} />
178
- );
179
-
180
- await user.click(screen.getByRole('button'));
181
- expect(handleClick).toHaveBeenCalledWith('1');
182
- });
183
- });
184
- ```
185
-
186
- ### 2. Page/Container Tests
187
-
188
- ```typescript
189
- // ResourcesPage.test.tsx
190
- import { render, screen, waitFor } from '@/test/utils';
191
-
192
- describe('ResourcesPage', () => {
193
- it('displays loading state initially', () => {
194
- render(<ResourcesPage />);
195
- expect(screen.getByRole('status')).toBeInTheDocument();
196
- });
197
-
198
- it('renders resources after loading', async () => {
199
- render(<ResourcesPage />);
200
-
201
- await waitFor(() => {
202
- expect(screen.getByText('Resource 1')).toBeInTheDocument();
203
- });
204
- });
205
-
206
- it('handles API errors', async () => {
207
- server.use(
208
- http.get('/api/v1/resources', () => {
209
- return HttpResponse.json(
210
- { success: false, error: { message: 'Error' } },
211
- { status: 500 }
212
- );
213
- })
214
- );
215
-
216
- render(<ResourcesPage />);
217
-
218
- await waitFor(() => {
219
- expect(screen.getByText(/error/i)).toBeInTheDocument();
220
- });
221
- });
222
- });
223
- ```
224
-
225
- ### 3. Form Tests
226
-
227
- ```typescript
228
- // ResourceForm.test.tsx
229
- import userEvent from '@testing-library/user-event';
230
-
231
- describe('ResourceForm', () => {
232
- it('submits valid form data', async () => {
233
- const handleSubmit = vi.fn();
234
- const user = userEvent.setup();
235
-
236
- render(<ResourceForm onSubmit={handleSubmit} />);
237
-
238
- await user.type(screen.getByLabelText(/title/i), 'New Resource');
239
- await user.type(screen.getByLabelText(/price/i), '99.99');
240
- await user.click(screen.getByRole('button', { name: /submit/i }));
241
-
242
- await waitFor(() => {
243
- expect(handleSubmit).toHaveBeenCalledWith({
244
- title: 'New Resource',
245
- price: 99.99,
246
- });
247
- });
248
- });
249
-
250
- it('displays validation errors', async () => {
251
- const user = userEvent.setup();
252
- render(<ResourceForm onSubmit={vi.fn()} />);
253
-
254
- await user.click(screen.getByRole('button', { name: /submit/i }));
255
-
256
- await waitFor(() => {
257
- expect(screen.getByText(/title is required/i)).toBeInTheDocument();
258
- });
259
- });
260
- });
261
- ```
262
-
263
- ### 4. Hook Tests
264
-
265
- ```typescript
266
- // useResources.test.tsx
267
- import { renderHook, waitFor } from '@testing-library/react';
268
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
269
-
270
- const createWrapper = () => {
271
- const queryClient = new QueryClient({
272
- defaultOptions: { queries: { retry: false } },
273
- });
274
-
275
- return ({ children }) => (
276
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
277
- );
278
- };
279
-
280
- describe('useResources', () => {
281
- it('fetches resources successfully', async () => {
282
- const { result } = renderHook(() => useResources(), {
283
- wrapper: createWrapper(),
284
- });
285
-
286
- expect(result.current.isLoading).toBe(true);
287
-
288
- await waitFor(() => {
289
- expect(result.current.isSuccess).toBe(true);
290
- });
291
-
292
- expect(result.current.data).toHaveLength(2);
293
- });
294
- });
295
- ```
296
-
297
- ### 5. User Flow Tests
298
-
299
- ```typescript
300
- // login-flow.test.tsx
301
- describe('Login Flow', () => {
302
- it('allows user to login', async () => {
303
- const user = userEvent.setup();
304
- render(<App />, { initialRoute: '/login' });
305
-
306
- await user.type(screen.getByLabelText(/email/i), 'user@test.com');
307
- await user.type(screen.getByLabelText(/password/i), 'password');
308
- await user.click(screen.getByRole('button', { name: /login/i }));
309
-
310
- await waitFor(() => {
311
- expect(screen.getByText(/dashboard/i)).toBeInTheDocument();
312
- });
313
- });
314
- });
315
- ```
316
-
317
- ## Best Practices
318
-
319
- ### ✅ DO:
320
- ```typescript
321
- // Test what user sees
322
- expect(screen.getByText('Resource 1')).toBeInTheDocument();
323
-
324
- // Use user-event for interactions
325
- await user.click(screen.getByRole('button'));
326
-
327
- // Wait for async updates
328
- await waitFor(() => {
329
- expect(screen.getByText('Success')).toBeInTheDocument();
330
- });
331
- ```
332
-
333
- ### ❌ DON'T:
334
- ```typescript
335
- // Don't test implementation details
336
- expect(component.state.isLoading).toBe(false); // BAD
337
-
338
- // Don't use test IDs unnecessarily
339
- screen.getByTestId('card'); // Prefer semantic queries
340
-
341
- // Don't test third-party libraries
342
- expect(mockRouter.navigate).toHaveBeenCalled(); // BAD
343
- ```
344
-
345
- ## Coverage Requirements
346
-
347
- ```json
348
- {
349
- "scripts": {
350
- "test": "vitest run",
351
- "test:watch": "vitest",
352
- "test:coverage": "vitest run --coverage"
353
- }
354
- }
355
- ```
356
-
357
- **Minimum:**
358
- - Hooks: 80%
359
- - Components: 70%
360
- - Utils: 90%
361
- - Overall: 70%
362
-
363
- ## Checklist
364
-
365
- - [ ] Test setup configured (RTL + MSW)
366
- - [ ] All critical user flows tested
367
- - [ ] Forms validated and tested
368
- - [ ] API mocking for endpoints
369
- - [ ] 70%+ code coverage
370
- - [ ] Tests run in CI
@@ -1,38 +0,0 @@
1
- ---
2
- trigger: always_on
3
- ---
4
-
5
- > **SCOPE**: These rules apply to the entire workspace (**server** and **client**).
6
-
7
- # API Server – Safe Editing Rules
8
-
9
- ## General safety
10
-
11
- - Assume this is a real production project. Avoid destructive or experimental changes.
12
- - Never delete or radically restructure large parts of the codebase unless explicitly requested.
13
-
14
- ## When modifying existing code
15
-
16
- - Keep changes as **small and focused** as possible.
17
- - Do not change:
18
- - Existing function signatures unless explicitly asked.
19
- - Existing exports/imports that other modules depend on.
20
- - If you must introduce a breaking change, call it out clearly in the explanation.
21
-
22
- ## Backwards compatibility
23
-
24
- - When adding new features, prefer extending modules over rewiring everything.
25
- - Preserve existing behavior for:
26
- - Auth
27
- - Core business flows
28
- - Payment flows
29
-
30
- ## Comments & TODOs
31
-
32
- - If something is ambiguous, add a `// TODO:` comment with a short note.
33
- - Do NOT leave half-implemented features without a TODO or explanation.
34
-
35
- ## Logs & debugging
36
-
37
- - Do not add noisy debug logs.
38
- - If temporary logs are necessary, clearly mark them with `// TODO: remove debug log` so they can be cleaned up.
@@ -1,242 +0,0 @@
1
- ---
2
- trigger: always_on
3
- ---
4
-
5
- > **SCOPE**: These rules apply specifically to the **server** directory.
6
-
7
- # API Server – Database & Migrations Rules
8
-
9
- ## 🎯 Core Principles
10
-
11
- - **Primary Database**: MySQL 8.0+
12
- - **ORM**: Prisma (version 6.x - DO NOT upgrade to 7.x without testing)
13
- - **Migration Philosophy**:
14
- - Development: Fast iteration with resets
15
- - Production: Safe, forward-only migrations
16
- - **Schema Source of Truth**: `prisma/schema.prisma`
17
-
18
- ---
19
-
20
- ## 🚫 CRITICAL RULES - NEVER BREAK THESE
21
-
22
- ### Rule 1: NO Manual Schema Changes
23
- ❌ **NEVER** run raw SQL to change schema (CREATE TABLE, ALTER TABLE, etc.)
24
- ✅ **ALWAYS** use Prisma migrations for schema changes
25
- ✅ **EXCEPTION**: Data changes (INSERT, UPDATE, DELETE) can be raw SQL
26
-
27
- ### Rule 2: Development vs Production Workflows
28
- **Development** (when iterating on schema):
29
- ```bash
30
- npm run prisma:reset # Drops everything, reruns migrations
31
- npm run prisma:seed # Repopulate test data
32
- ```
33
-
34
- **Production** (deployed servers):
35
- ```bash
36
- npm run prisma:migrate deploy # Only applies new migrations, NEVER resets
37
- ```
38
-
39
- ### Rule 3: Migration Conflicts = Reset
40
- When you get migration errors in **development**:
41
- - ❌ DON'T try to fix migration files manually
42
- - ❌ DON'T delete migration folders
43
- - ✅ DO run `npm run prisma:reset` to start clean
44
-
45
- ### Rule 4: Never Use `prisma db push` in Production
46
- - `prisma db push` = Quick prototyping, no migration history
47
- - `prisma migrate dev` = Proper migrations with history
48
- - Use `db push` ONLY when rapidly prototyping new features
49
-
50
- ---
51
-
52
- ## 📁 Naming Conventions
53
-
54
- ### Tables
55
- - Format: `snake_case` plural
56
- - Examples: `users`, `posts`, `categories`
57
-
58
- ### Columns
59
- - Format: `snake_case`
60
- - Timestamps: `created_at`, `updated_at`, `deleted_at`
61
- - Foreign keys: `<table_singular>_id`
62
- - Example: `user_id`, `category_id`
63
-
64
- ### Prisma Models
65
- - Format: `PascalCase` singular
66
- - Example: `User`, `Post`, `Category`
67
-
68
- ---
69
-
70
- ## 🗄️ Required Fields for Every Table
71
-
72
- Every main entity table MUST have:
73
- ```prisma
74
- model EntityName {
75
- id String @id @default(uuid())
76
- createdAt DateTime @default(now())
77
- updatedAt DateTime @updatedAt
78
- }
79
- ```
80
-
81
- Optional but recommended:
82
- ```prisma
83
- deletedAt DateTime? // For soft deletes
84
- isActive Boolean @default(true) // For disabling without deleting
85
- ```
86
-
87
- ---
88
-
89
- ## 🔗 Architecture Relationships
90
-
91
- ### Core Entities (Example)
92
- ```
93
- users (1) ──→ (many) posts
94
- users (1) ──→ (1) profiles
95
- categories (1) ──→ (many) posts
96
- ```
97
-
98
- ### Media Attachments
99
- For images/files attached to multiple entity types:
100
- ```prisma
101
- model Media {
102
- id String @id @default(uuid())
103
- entityType String // 'post', 'user', 'product'
104
- entityId String // ID of the related entity
105
- url String
106
- type String // 'image', 'video', 'document'
107
- order Int // For sorting galleries
108
-
109
- @@index([entityType, entityId])
110
- }
111
- ```
112
-
113
- ---
114
-
115
- ## ⚡ Indexing Strategy
116
-
117
- ### Always Index These:
118
- 1. **Foreign Keys** - Prisma auto-indexes, but verify:
119
- ```prisma
120
- @@index([userId])
121
- ```
122
-
123
- 2. **Filter Columns** - Fields used in WHERE clauses:
124
- ```prisma
125
- @@index([isActive])
126
- @@index([status])
127
- ```
128
-
129
- 3. **Composite Indexes** - Multiple columns filtered together:
130
- ```prisma
131
- @@index([categoryId, isActive])
132
- ```
133
-
134
- 4. **Unique Constraints** - Business logic requirements:
135
- ```prisma
136
- @@unique([email])
137
- @@unique([slug])
138
- ```
139
-
140
- ### When NOT to Index:
141
- - Low-cardinality boolean fields used alone (e.g., `isActive` by itself)
142
- - Text/blob columns
143
- - Fields never used in WHERE/ORDER BY
144
-
145
- ---
146
-
147
- ## 🔄 Migration Workflow
148
-
149
- ### When Making Schema Changes:
150
-
151
- #### Step 1: Edit `prisma/schema.prisma`
152
- ```prisma
153
- model Resource {
154
- id String @id @default(uuid())
155
- title String
156
- description String? @db.Text // NEW FIELD
157
- // ... rest of fields
158
- }
159
- ```
160
-
161
- #### Step 2: Create Migration (Development)
162
- ```bash
163
- # Option A: With descriptive name
164
- npm run prisma:migrate dev --name add_resource_description
165
-
166
- # Option B: If migration conflicts occur
167
- npm run prisma:reset # Nuclear option - drops everything
168
- npm run prisma:seed # Repopulate test data
169
- ```
170
-
171
- ---
172
-
173
- ## 🚀 Production Deployment Workflow
174
-
175
- ### Pre-Deployment Checklist:
176
- 1. ✅ All migrations tested locally
177
- 2. ✅ Seed data runs successfully
178
- 3. ✅ No pending schema changes in `schema.prisma`
179
- 4. ✅ Migration files committed to git
180
-
181
- ### Deployment Commands:
182
- ```bash
183
- # On production server:
184
- npm run prisma:migrate deploy # Applies pending migrations only
185
- npm run prisma:generate # Regenerates client with new schema
186
- npm start # Restart application
187
- ```
188
-
189
- ---
190
-
191
- ## 📊 Data Integrity Rules
192
-
193
- ### Foreign Keys
194
- - ✅ **USE** foreign keys for core relationships
195
- - ✅ **USE** `onDelete: Cascade` for dependent data
196
- ```prisma
197
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
198
- ```
199
-
200
- ### Soft Deletes
201
- Prefer soft deletes for user-generated content:
202
- ```prisma
203
- model Resource {
204
- deletedAt DateTime?
205
- // Query helper: where: { deletedAt: null }
206
- }
207
- ```
208
-
209
- ---
210
-
211
- ## 🛠️ Troubleshooting Guide
212
-
213
- ### Issue: "Environment variable not found: DATABASE_URL"
214
- **Solution:**
215
- ```bash
216
- # Verify .env exists and has:
217
- DATABASE_URL="mysql://user:pass@localhost:3306/dbname"
218
- ```
219
-
220
- ### Issue: "Prisma Client is not generated"
221
- **Solution:**
222
- ```bash
223
- npm run prisma:generate
224
- ```
225
-
226
- ---
227
-
228
- ## 🎯 Best Practices Summary
229
-
230
- ### ✅ DO:
231
- - Use Prisma migrations for ALL schema changes
232
- - Reset database freely in development
233
- - Test migrations in staging before production
234
- - Add indexes for frequently queried fields
235
- - Use soft deletes for user content
236
- - Commit migration files to git
237
-
238
- ### ❌ DON'T:
239
- - Manually edit database schema
240
- - Use `prisma:reset` in production
241
- - Skip migrations and use `db push` in production
242
- - Delete migration files