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.
Files changed (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +87 -0
  3. package/bin/create-tigra.js +292 -0
  4. package/package.json +41 -0
  5. package/template/.agent/rules/client/01-project-structure.md +326 -0
  6. package/template/.agent/rules/client/02-component-patterns.md +249 -0
  7. package/template/.agent/rules/client/03-typescript-rules.md +226 -0
  8. package/template/.agent/rules/client/04-state-management.md +474 -0
  9. package/template/.agent/rules/client/05-api-integration.md +129 -0
  10. package/template/.agent/rules/client/06-forms-validation.md +129 -0
  11. package/template/.agent/rules/client/07-common-patterns.md +150 -0
  12. package/template/.agent/rules/client/08-color-system.md +93 -0
  13. package/template/.agent/rules/client/09-security-rules.md +97 -0
  14. package/template/.agent/rules/client/10-testing-strategy.md +370 -0
  15. package/template/.agent/rules/global/ai-edit-safety.md +38 -0
  16. package/template/.agent/rules/server/01-db-and-migrations.md +242 -0
  17. package/template/.agent/rules/server/02-general-rules.md +111 -0
  18. package/template/.agent/rules/server/03-migrations.md +20 -0
  19. package/template/.agent/rules/server/04-pagination.md +130 -0
  20. package/template/.agent/rules/server/05-project-conventions.md +71 -0
  21. package/template/.agent/rules/server/06-response-handling.md +173 -0
  22. package/template/.agent/rules/server/07-testing-strategy.md +506 -0
  23. package/template/.agent/rules/server/08-observability.md +180 -0
  24. package/template/.agent/rules/server/09-api-documentation-v2.md +168 -0
  25. package/template/.agent/rules/server/10-background-jobs-v2.md +185 -0
  26. package/template/.agent/rules/server/11-rate-limiting-v2.md +210 -0
  27. package/template/.agent/rules/server/12-performance-optimization.md +567 -0
  28. package/template/.claude/rules/client-01-project-structure.md +327 -0
  29. package/template/.claude/rules/client-02-component-patterns.md +250 -0
  30. package/template/.claude/rules/client-03-typescript-rules.md +227 -0
  31. package/template/.claude/rules/client-04-state-management.md +475 -0
  32. package/template/.claude/rules/client-05-api-integration.md +130 -0
  33. package/template/.claude/rules/client-06-forms-validation.md +130 -0
  34. package/template/.claude/rules/client-07-common-patterns.md +151 -0
  35. package/template/.claude/rules/client-08-color-system.md +94 -0
  36. package/template/.claude/rules/client-09-security-rules.md +98 -0
  37. package/template/.claude/rules/client-10-testing-strategy.md +371 -0
  38. package/template/.claude/rules/global-ai-edit-safety.md +39 -0
  39. package/template/.claude/rules/server-01-db-and-migrations.md +243 -0
  40. package/template/.claude/rules/server-02-general-rules.md +112 -0
  41. package/template/.claude/rules/server-03-migrations.md +21 -0
  42. package/template/.claude/rules/server-04-pagination.md +131 -0
  43. package/template/.claude/rules/server-05-project-conventions.md +72 -0
  44. package/template/.claude/rules/server-06-response-handling.md +174 -0
  45. package/template/.claude/rules/server-07-testing-strategy.md +507 -0
  46. package/template/.claude/rules/server-08-observability.md +181 -0
  47. package/template/.claude/rules/server-09-api-documentation-v2.md +169 -0
  48. package/template/.claude/rules/server-10-background-jobs-v2.md +186 -0
  49. package/template/.claude/rules/server-11-rate-limiting-v2.md +211 -0
  50. package/template/.claude/rules/server-12-performance-optimization.md +568 -0
  51. package/template/.cursor/rules/client-01-project-structure.mdc +327 -0
  52. package/template/.cursor/rules/client-02-component-patterns.mdc +250 -0
  53. package/template/.cursor/rules/client-03-typescript-rules.mdc +227 -0
  54. package/template/.cursor/rules/client-04-state-management.mdc +475 -0
  55. package/template/.cursor/rules/client-05-api-integration.mdc +130 -0
  56. package/template/.cursor/rules/client-06-forms-validation.mdc +130 -0
  57. package/template/.cursor/rules/client-07-common-patterns.mdc +151 -0
  58. package/template/.cursor/rules/client-08-color-system.mdc +94 -0
  59. package/template/.cursor/rules/client-09-security-rules.mdc +98 -0
  60. package/template/.cursor/rules/client-10-testing-strategy.mdc +371 -0
  61. package/template/.cursor/rules/global-ai-edit-safety.mdc +39 -0
  62. package/template/.cursor/rules/server-01-db-and-migrations.mdc +243 -0
  63. package/template/.cursor/rules/server-02-general-rules.mdc +112 -0
  64. package/template/.cursor/rules/server-03-migrations.mdc +21 -0
  65. package/template/.cursor/rules/server-04-pagination.mdc +131 -0
  66. package/template/.cursor/rules/server-05-project-conventions.mdc +72 -0
  67. package/template/.cursor/rules/server-06-response-handling.mdc +174 -0
  68. package/template/.cursor/rules/server-07-testing-strategy.mdc +507 -0
  69. package/template/.cursor/rules/server-08-observability.mdc +181 -0
  70. package/template/.cursor/rules/server-09-api-documentation-v2.mdc +169 -0
  71. package/template/.cursor/rules/server-10-background-jobs-v2.mdc +186 -0
  72. package/template/.cursor/rules/server-11-rate-limiting-v2.mdc +211 -0
  73. package/template/.cursor/rules/server-12-performance-optimization.mdc +568 -0
  74. package/template/CLAUDE.md +207 -0
  75. package/template/server/.env.example +148 -0
  76. package/template/server/.tsc-aliasrc.json +12 -0
  77. package/template/server/README.md +175 -0
  78. package/template/server/SECURITY.md +190 -0
  79. package/template/server/biome.json +42 -0
  80. package/template/server/docker-compose.yml +111 -0
  81. package/template/server/package.json +83 -0
  82. package/template/server/postman_collection.json +733 -0
  83. package/template/server/prisma/schema.prisma +92 -0
  84. package/template/server/prisma/seed.ts +142 -0
  85. package/template/server/scripts/wait-for-db.js +60 -0
  86. package/template/server/src/app.ts +74 -0
  87. package/template/server/src/config/env.ts +101 -0
  88. package/template/server/src/hooks/request-timing.hook.ts +26 -0
  89. package/template/server/src/libs/auth/authenticate.middleware.ts +22 -0
  90. package/template/server/src/libs/auth/rbac.middleware.test.ts +134 -0
  91. package/template/server/src/libs/auth/rbac.middleware.ts +147 -0
  92. package/template/server/src/libs/db.ts +76 -0
  93. package/template/server/src/libs/error-handler.ts +89 -0
  94. package/template/server/src/libs/logger.ts +60 -0
  95. package/template/server/src/libs/queue.ts +79 -0
  96. package/template/server/src/libs/redis.ts +79 -0
  97. package/template/server/src/libs/swagger-schemas.ts +16 -0
  98. package/template/server/src/modules/admin/admin.controller.ts +122 -0
  99. package/template/server/src/modules/admin/admin.routes.ts +100 -0
  100. package/template/server/src/modules/admin/admin.schemas.ts +35 -0
  101. package/template/server/src/modules/admin/admin.service.ts +167 -0
  102. package/template/server/src/modules/auth/auth.controller.ts +141 -0
  103. package/template/server/src/modules/auth/auth.integration.test.ts +150 -0
  104. package/template/server/src/modules/auth/auth.repo.ts +218 -0
  105. package/template/server/src/modules/auth/auth.routes.ts +204 -0
  106. package/template/server/src/modules/auth/auth.schemas.ts +137 -0
  107. package/template/server/src/modules/auth/auth.service.test.ts +119 -0
  108. package/template/server/src/modules/auth/auth.service.ts +329 -0
  109. package/template/server/src/modules/auth/auth.types.ts +97 -0
  110. package/template/server/src/modules/resources/resources.controller.ts +218 -0
  111. package/template/server/src/modules/resources/resources.repo.ts +253 -0
  112. package/template/server/src/modules/resources/resources.routes.ts +355 -0
  113. package/template/server/src/modules/resources/resources.schemas.ts +146 -0
  114. package/template/server/src/modules/resources/resources.service.ts +218 -0
  115. package/template/server/src/modules/resources/resources.types.ts +73 -0
  116. package/template/server/src/plugins/rate-limit.plugin.ts +21 -0
  117. package/template/server/src/plugins/security.plugin.ts +21 -0
  118. package/template/server/src/plugins/swagger.plugin.ts +41 -0
  119. package/template/server/src/routes/health.routes.ts +31 -0
  120. package/template/server/src/server.ts +142 -0
  121. package/template/server/src/test/setup.ts +38 -0
  122. package/template/server/src/types/fastify.d.ts +36 -0
  123. package/template/server/src/utils/errors.ts +108 -0
  124. package/template/server/src/utils/pagination.ts +120 -0
  125. package/template/server/src/utils/response.ts +110 -0
  126. package/template/server/src/workers/file.worker.ts +106 -0
  127. package/template/server/tsconfig.build.json +30 -0
  128. package/template/server/tsconfig.build.tsbuildinfo +1 -0
  129. package/template/server/tsconfig.json +89 -0
  130. package/template/server/tsconfig.test.json +22 -0
  131. package/template/server/vitest.config.ts +98 -0
@@ -0,0 +1,130 @@
1
+ ---
2
+ trigger: always_on
3
+ globs: "client/**/*"
4
+ ---
5
+
6
+ > **SCOPE**: These rules apply specifically to the **client** directory.
7
+
8
+ # API Integration & Error Handling
9
+
10
+ ## Axios Configuration
11
+ Standard pattern for interceptors and token management.
12
+
13
+ ```tsx
14
+ // lib/api/axios.config.ts
15
+ import axios from 'axios';
16
+ import { store } from '@/store';
17
+ import { logout, updateTokens } from '@/features/auth/store/authSlice';
18
+
19
+ export const apiClient = axios.create({
20
+ baseURL: import.meta.env.VITE_API_BASE_URL,
21
+ headers: { 'Content-Type': 'application/json' },
22
+ timeout: 30000,
23
+ });
24
+
25
+ apiClient.interceptors.request.use((config) => {
26
+ const token = store.getState().auth.tokens?.accessToken;
27
+ if (token) config.headers.Authorization = `Bearer ${token}`;
28
+ return config;
29
+ });
30
+ ```
31
+
32
+ ## Service Pattern
33
+ Use classes or plain objects to group API calls by domain.
34
+
35
+ ```tsx
36
+ // features/resources/services/resource.service.ts
37
+ class ResourceService {
38
+ async getResources(params = {}) {
39
+ const response = await apiClient.get('/resources', { params });
40
+ return response.data.data;
41
+ }
42
+ }
43
+ export const resourceService = new ResourceService();
44
+ ```
45
+
46
+ ## Error Handling Utilities
47
+
48
+ ```tsx
49
+ // lib/utils/error.ts
50
+ export const getErrorMessage = (error: unknown): string => {
51
+ if (axios.isAxiosError(error)) {
52
+ return error.response?.data?.error?.message || error.message;
53
+ }
54
+ return 'An unexpected error occurred';
55
+ };
56
+ ```
57
+
58
+ ## UI Feedback (Ant Design)
59
+
60
+ ### Error Components
61
+ ```tsx
62
+ // components/common/ErrorMessage.tsx
63
+ import { Alert } from 'antd';
64
+ import { getErrorMessage } from '@/lib/utils/error';
65
+
66
+ export const ErrorMessage = ({ error }: { error: any }) => (
67
+ <Alert
68
+ message="Error"
69
+ description={getErrorMessage(error)}
70
+ type="error"
71
+ showIcon
72
+ />
73
+ );
74
+ ```
75
+
76
+ ### Loading States
77
+ ```tsx
78
+ // components/common/LoadingSpinner.tsx
79
+ import { Spin } from 'antd';
80
+
81
+ export const LoadingSpinner = () => (
82
+ <div className="spinner-container">
83
+ <Spin size="large" />
84
+ </div>
85
+ );
86
+ ```
87
+
88
+ ### Skeleton (Ant Design)
89
+ ```tsx
90
+ // components/common/ResourceSkeleton.tsx
91
+ import { Skeleton, Card } from 'antd';
92
+
93
+ export const ResourceSkeleton = () => (
94
+ <Card>
95
+ <Skeleton active />
96
+ </Card>
97
+ );
98
+ ```
99
+
100
+ ## Notifications (Ant Design)
101
+ Use `message` or `notification` from Ant Design.
102
+
103
+ ```tsx
104
+ import { message } from 'antd';
105
+
106
+ // Success
107
+ message.success('Action completed!');
108
+
109
+ // Error
110
+ message.error(getErrorMessage(error));
111
+ ```
112
+
113
+ ## File Upload Pattern
114
+ ```tsx
115
+ // features/resources/hooks/useUploadFiles.ts
116
+ export const useUploadFiles = () => {
117
+ return useMutation({
118
+ mutationFn: async (files: File[]) => {
119
+ const formData = new FormData();
120
+ files.forEach((file) => formData.append('files', file));
121
+ return apiClient.post('/upload', formData, {
122
+ headers: { 'Content-Type': 'multipart/form-data' },
123
+ });
124
+ },
125
+ });
126
+ };
127
+ ```
128
+
129
+ ## Infinite Scroll Pattern
130
+ Standard React Query `useInfiniteQuery` implementation with Ant Design's `Button` for "Load More" or a custom observer.
@@ -0,0 +1,130 @@
1
+ ---
2
+ trigger: always_on
3
+ globs: "client/**/*"
4
+ ---
5
+
6
+ > **SCOPE**: These rules apply specifically to the **client** directory.
7
+
8
+ # Forms & Validation
9
+
10
+ ## Form Handling with React Hook Form + Zod + Ant Design
11
+
12
+ To maintain the project's logic and architecture while using Ant Design, use **React Hook Form (RHF)** for state management and **Zod** for validation, connecting them to **Ant Design** components via the `Controller` component.
13
+
14
+ ### Basic Form Pattern
15
+
16
+ ```tsx
17
+ // features/auth/components/LoginForm.tsx
18
+ import { useForm, Controller } from 'react-hook-form';
19
+ import { zodResolver } from '@hookform/resolvers/zod';
20
+ import { z } from 'zod';
21
+ import { Button, Input, Form } from 'antd';
22
+
23
+ const loginSchema = z.object({
24
+ email: z.string().email('Invalid email'),
25
+ password: z.string().min(8, 'Password must be at least 8 characters'),
26
+ });
27
+
28
+ type LoginFormData = z.infer<typeof loginSchema>;
29
+
30
+ export const LoginForm = ({ onSubmit, isSubmitting }) => {
31
+ const { control, handleSubmit, formState: { errors } } = useForm<LoginFormData>({
32
+ resolver: zodResolver(loginSchema),
33
+ });
34
+
35
+ return (
36
+ <Form layout="vertical" onFinish={handleSubmit(onSubmit)}>
37
+ <Form.Item
38
+ label="Email"
39
+ validateStatus={errors.email ? 'error' : ''}
40
+ help={errors.email?.message}
41
+ >
42
+ <Controller
43
+ name="email"
44
+ control={control}
45
+ render={({ field }) => <Input {...field} type="email" placeholder="Email" />}
46
+ />
47
+ </Form.Item>
48
+
49
+ <Form.Item
50
+ label="Password"
51
+ validateStatus={errors.password ? 'error' : ''}
52
+ help={errors.password?.message}
53
+ >
54
+ <Controller
55
+ name="password"
56
+ control={control}
57
+ render={({ field }) => <Input.Password {...field} placeholder="Password" />}
58
+ />
59
+ </Form.Item>
60
+
61
+ <Button type="primary" htmlType="submit" loading={isSubmitting} block>
62
+ Login
63
+ </Button>
64
+ </Form>
65
+ );
66
+ };
67
+ ```
68
+
69
+ ### Complete Form Example (Resources)
70
+
71
+ ```tsx
72
+ const resourceSchema = z.object({
73
+ title: z.string().min(1, 'Title is required'),
74
+ price: z.coerce.number().min(0, 'Price must be positive'),
75
+ category: z.string().min(1, 'Category is required'),
76
+ });
77
+
78
+ type ResourceFormData = z.infer<typeof resourceSchema>;
79
+
80
+ export const CreateResourceForm = ({ onSubmit, isSubmitting }) => {
81
+ const { control, handleSubmit, formState: { errors } } = useForm<ResourceFormData>({
82
+ resolver: zodResolver(resourceSchema),
83
+ });
84
+
85
+ return (
86
+ <Form layout="vertical" onFinish={handleSubmit(onSubmit)}>
87
+ <Form.Item label="Title" validateStatus={errors.title ? 'error' : ''} help={errors.title?.message}>
88
+ <Controller name="title" control={control} render={({ field }) => <Input {...field} />} />
89
+ </Form.Item>
90
+
91
+ <Form.Item label="Price" validateStatus={errors.price ? 'error' : ''} help={errors.price?.message}>
92
+ <Controller name="price" control={control} render={({ field }) => <Input type="number" {...field} />} />
93
+ </Form.Item>
94
+
95
+ <Button type="primary" htmlType="submit" loading={isSubmitting}>
96
+ Create Resource
97
+ </Button>
98
+ </Form>
99
+ );
100
+ };
101
+ ```
102
+
103
+ ## Form with Select (Ant Design)
104
+
105
+ ```tsx
106
+ import { Select } from 'antd';
107
+
108
+ <Form.Item label="Category" validateStatus={errors.category ? 'error' : ''} help={errors.category?.message}>
109
+ <Controller
110
+ name="category"
111
+ control={control}
112
+ render={({ field }) => (
113
+ <Select {...field} placeholder="Select Category">
114
+ <Select.Option value="cat1">Category 1</Select.Option>
115
+ <Select.Option value="cat2">Category 2</Select.Option>
116
+ </Select>
117
+ )}
118
+ />
119
+ </Form.Item>
120
+ ```
121
+
122
+ ## Form with File Upload (Ant Design)
123
+
124
+ Use Ant Design's `Upload` component, often manually handling the file list to sync with RHF if needed, or using a local state and calling an upload service.
125
+
126
+ ## Validation Best Practices
127
+ - ✅ **Consistent Schemas**: Keep Zod schemas in a dedicated `schemas/` folder within features.
128
+ - ✅ **Error Mapping**: Map API validation errors back to RHF fields using `setError`.
129
+ - ✅ **Loading States**: Use Ant Design's `loading` prop on buttons.
130
+ - ✅ **User Experience**: Don't show validation errors until the field is "touched" or the form is submitted.
@@ -0,0 +1,151 @@
1
+ ---
2
+ trigger: always_on
3
+ globs: "client/**/*"
4
+ ---
5
+
6
+ > **SCOPE**: These rules apply specifically to the **client** directory.
7
+
8
+ # Common Patterns & Utilities
9
+
10
+ ## Custom Hooks
11
+
12
+ ### useAuth Hook
13
+ Standard pattern for authentication state and methods.
14
+
15
+ ```tsx
16
+ // features/auth/hooks/useAuth.ts
17
+ export const useAuth = () => {
18
+ const dispatch = useAppDispatch();
19
+ const { user, isAuthenticated } = useAppSelector((state) => state.auth);
20
+
21
+ const login = async (data: LoginRequest) => {
22
+ const response = await authService.login(data);
23
+ dispatch(setCredentials(response));
24
+ };
25
+
26
+ const logout = () => {
27
+ dispatch(logoutAction());
28
+ };
29
+
30
+ return { user, isAuthenticated, login, logout };
31
+ };
32
+ ```
33
+
34
+ ## Common Components (Ant Design)
35
+
36
+ ### Pagination
37
+ Use Ant Design's `Pagination` component.
38
+
39
+ ```tsx
40
+ import { Pagination } from 'antd';
41
+
42
+ export const CustomPagination = ({ current, total, onChange }) => (
43
+ <Pagination
44
+ current={current}
45
+ total={total}
46
+ onChange={onChange}
47
+ showSizeChanger={false}
48
+ />
49
+ );
50
+ ```
51
+
52
+ ### Empty State
53
+ Use Ant Design's `Empty` component.
54
+
55
+ ```tsx
56
+ import { Empty, Button } from 'antd';
57
+
58
+ export const NoData = ({ message, onAction, actionText }) => (
59
+ <Empty
60
+ description={message}
61
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
62
+ >
63
+ {onAction && (
64
+ <Button type="primary" onClick={onAction}>
65
+ {actionText}
66
+ </Button>
67
+ )}
68
+ </Empty>
69
+ );
70
+ ```
71
+
72
+ ### Confirm Dialog
73
+ Use Ant Design's `Modal.confirm`.
74
+
75
+ ```tsx
76
+ import { Modal } from 'antd';
77
+
78
+ const showDeleteConfirm = (onConfirm: () => void) => {
79
+ Modal.confirm({
80
+ title: 'Are you sure you want to delete this resource?',
81
+ content: 'This action cannot be undone.',
82
+ okText: 'Yes, Delete',
83
+ okType: 'danger',
84
+ cancelText: 'No',
85
+ onOk() {
86
+ onConfirm();
87
+ },
88
+ });
89
+ };
90
+ ```
91
+
92
+ ## Utility Functions
93
+
94
+ ### Format Utils
95
+ Standard internationalization utils.
96
+
97
+ ```tsx
98
+ // lib/utils/format.ts
99
+ export const formatCurrency = (amount: number, currency = 'USD') => {
100
+ return new Intl.NumberFormat('en-US', {
101
+ style: 'currency',
102
+ currency,
103
+ }).format(amount);
104
+ };
105
+ ```
106
+
107
+ ## Router & App Setup
108
+
109
+ ### Router Configuration
110
+ ```tsx
111
+ // app/router.tsx
112
+ export const router = createBrowserRouter([
113
+ {
114
+ path: '/',
115
+ element: <MainLayout />,
116
+ children: [
117
+ { index: true, element: <HomePage /> },
118
+ { path: 'resources', element: <ResourcesPage /> },
119
+ { path: 'login', element: <LoginPage /> },
120
+ ],
121
+ },
122
+ ]);
123
+ ```
124
+
125
+ ## Table Pattern (Ant Design)
126
+ Use Ant Design's `Table` component for consistent data display.
127
+
128
+ ```tsx
129
+ // features/resources/components/ResourceTable.tsx
130
+ import { Table, Button, Space } from 'antd';
131
+
132
+ export const ResourceTable = ({ data, onEdit, onDelete, loading }) => {
133
+ const columns = [
134
+ { title: 'Title', dataIndex: 'title', key: 'title' },
135
+ { title: 'Category', dataIndex: 'category', key: 'category' },
136
+ {
137
+ title: 'Actions',
138
+ key: 'actions',
139
+ render: (_, record) => (
140
+ <Space size="middle">
141
+ <Button onClick={() => onEdit(record.id)}>Edit</Button>
142
+ <Button danger onClick={() => onDelete(record.id)}>Delete</Button>
143
+ </Space>
144
+ ),
145
+ },
146
+ ];
147
+
148
+ return <Table dataSource={data} columns={columns} loading={loading} rowKey="id" />;
149
+ };
150
+ ```
151
+ I use `Space` for horizontal layout and `Space.Compact` for grouped actions.
@@ -0,0 +1,94 @@
1
+ ---
2
+ trigger: always_on
3
+ globs: "client/**/*"
4
+ ---
5
+
6
+ > **SCOPE**: These rules apply specifically to the **client** directory.
7
+
8
+ # Color System & Theming
9
+
10
+ ## Color Architecture
11
+ All colors are defined as **CSS variables** in a global stylesheet and synchronized with **Ant Design's ConfigProvider** for component theming.
12
+
13
+ ## CSS Variables Setup
14
+
15
+ ```css
16
+ /* styles/theme.css */
17
+ :root {
18
+ --primary-color: #1677ff;
19
+ --success-color: #52c41a;
20
+ --warning-color: #faad14;
21
+ --error-color: #f5222d;
22
+ --text-color: rgba(0, 0, 0, 0.88);
23
+ --bg-color: #ffffff;
24
+ --border-color: #d9d9d9;
25
+ }
26
+
27
+ [data-theme='dark'] {
28
+ --primary-color: #1668dc;
29
+ --bg-color: #141414;
30
+ --text-color: rgba(255, 255, 255, 0.85);
31
+ }
32
+ ```
33
+
34
+ ## Ant Design Configuration
35
+
36
+ ```tsx
37
+ // app/providers.tsx
38
+ import { ConfigProvider, theme } from 'antd';
39
+
40
+ export const AppProviders = ({ children, isDarkMode }) => (
41
+ <ConfigProvider
42
+ theme={{
43
+ algorithm: isDarkMode ? theme.darkAlgorithm : theme.defaultAlgorithm,
44
+ token: {
45
+ colorPrimary: '#1677ff',
46
+ borderRadius: 4,
47
+ },
48
+ }}
49
+ >
50
+ {children}
51
+ </ConfigProvider>
52
+ );
53
+ ```
54
+
55
+ ## Usage Rules
56
+
57
+ ### ✅ CORRECT - Use CSS Variables in Vanilla CSS
58
+
59
+ ```css
60
+ /* features/resources/components/ResourceCard.css */
61
+ .resource-card {
62
+ background-color: var(--bg-color);
63
+ border: 1px solid var(--border-color);
64
+ color: var(--text-color);
65
+ }
66
+
67
+ .resource-card:hover {
68
+ border-color: var(--primary-color);
69
+ }
70
+ ```
71
+
72
+ ### ❌ NEVER Hardcode Colors in Components
73
+
74
+ ```tsx
75
+ // ❌ BAD
76
+ <div style={{ color: '#ff0000' }}>Error</div>
77
+
78
+ // ✅ GOOD
79
+ <div className="error-text">Error</div> /* defined in CSS using var(--error-color) */
80
+ ```
81
+
82
+ ## Dark Mode Implementation
83
+ Use the `data-theme` attribute on the `html` or `body` tag and sync it with Ant Design's algorithm.
84
+
85
+ ## AI Agent Rules
86
+
87
+ ### Rule 1: No Hardcoded Colors
88
+ Always use `var(--color-name)` in CSS files. Never use hex/rgb values directly in component files.
89
+
90
+ ### Rule 2: Semantic Naming
91
+ Use functional names like `--primary-color`, `--text-secondary`, not descriptive ones like `--blue`.
92
+
93
+ ### Rule 3: Single Source of Truth
94
+ Global theme variables must stay in `styles/theme.css`. Components should import their own `.css` files that reference these variables.
@@ -0,0 +1,98 @@
1
+ ---
2
+ trigger: always_on
3
+ globs: "client/**/*"
4
+ ---
5
+
6
+ > **SCOPE**: These rules apply specifically to the **client** directory.
7
+
8
+ # Frontend Security Rules
9
+
10
+ ## Core Security Principles
11
+
12
+ 1. **Never trust user input**: Always validate and sanitize data from users.
13
+ 2. **Never expose secrets**: API keys, database credentials, and secrets must never be in the client code.
14
+ 3. **Always validate and sanitize**: Even if the backend validates, client-side sanitization is essential for UX and defense-in-depth.
15
+ 4. **Defense in depth**: Multiple layers of security at every level of the stack.
16
+
17
+ ## XSS Prevention
18
+
19
+ ### React's Built-in Protection
20
+ React automatically escapes values to prevent XSS.
21
+
22
+ ```tsx
23
+ // ✅ SAFE - React escapes by default
24
+ <div>{userInput}</div>
25
+
26
+ // ❌ DANGEROUS - Avoid dangerouslySetInnerHTML unless strictly sanitized
27
+ <div dangerouslySetInnerHTML={{ __html: userInput }} />
28
+ ```
29
+
30
+ ### URL Sanitization
31
+ Always validate URLs before using them in `href` attributes.
32
+
33
+ ```tsx
34
+ export const isSafeUrl = (url: string): boolean => {
35
+ try {
36
+ const parsed = new URL(url);
37
+ return ['http:', 'https:', 'mailto:'].includes(parsed.protocol);
38
+ } catch {
39
+ return false;
40
+ }
41
+ };
42
+ ```
43
+
44
+ ## Authentication Token Security
45
+
46
+ ### Token Storage
47
+ Avoid storing sensitive tokens in `localStorage`. Use Redux for access tokens (in-memory) and `httpOnly` cookies or encrypted storage for long-lived tokens.
48
+
49
+ ### Token Transmission
50
+ Always use HTTPS and send tokens in the `Authorization` header.
51
+
52
+ ```tsx
53
+ axios.interceptors.request.use((config) => {
54
+ const token = store.getState().auth.tokens?.accessToken;
55
+ if (token) {
56
+ config.headers.Authorization = `Bearer ${token}`;
57
+ }
58
+ return config;
59
+ });
60
+ ```
61
+
62
+ ## Input & File Validation
63
+
64
+ ### Client + Server Validation
65
+ Use Zod for robust client-side validation, matching the backend's expectations.
66
+
67
+ ### File Upload Security
68
+ Validate file type, size, and extension before uploading.
69
+
70
+ ```tsx
71
+ const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
72
+ const MAX_SIZE = 5 * 1024 * 1024; // 5MB
73
+
74
+ export const validateFile = (file: File) => {
75
+ if (!ALLOWED_TYPES.includes(file.type)) return { valid: false, error: 'File type not allowed' };
76
+ if (file.size > MAX_SIZE) return { valid: false, error: 'File too large' };
77
+ return { valid: true };
78
+ };
79
+ ```
80
+
81
+ ## Environment Variables
82
+ - Prefix with `VITE_` for client availability.
83
+ - Never commit `.env` files.
84
+ - Validate environment variables at runtime using a Zod schema.
85
+
86
+ ## AI Agent Security Rules
87
+
88
+ ### Rule 1: Never Trust User Input
89
+ Never use `dangerouslySetInnerHTML` with raw user input.
90
+
91
+ ### Rule 2: Never Expose Secrets
92
+ Do not hardcode API keys or credentials. Use `import.meta.env`.
93
+
94
+ ### Rule 3: Secure Tokens
95
+ Do not recommend plain `localStorage` for sensitive authentication tokens.
96
+
97
+ ### Rule 4: Sanitize Content
98
+ Sanitize any HTML content with DOMPurify before rendering.