@famgia/omnify-ai-guides 2.0.15

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 (91) hide show
  1. package/README.md +105 -0
  2. package/dist/chunk-RCTEXK7C.js +549 -0
  3. package/dist/chunk-RCTEXK7C.js.map +1 -0
  4. package/dist/config/rules.yaml +524 -0
  5. package/dist/index.cjs +587 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.cts +55 -0
  8. package/dist/index.d.ts +55 -0
  9. package/dist/index.js +26 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/knowledge/agents/architect.md.stub +150 -0
  12. package/dist/knowledge/agents/developer.md.stub +190 -0
  13. package/dist/knowledge/agents/reviewer.md.stub +134 -0
  14. package/dist/knowledge/agents/tester.md.stub +196 -0
  15. package/dist/knowledge/checklists/backend.md.stub +112 -0
  16. package/dist/knowledge/checklists/react.md.stub +108 -0
  17. package/dist/knowledge/claude-rules/laravel-controllers.md.stub +57 -0
  18. package/dist/knowledge/claude-rules/laravel-migrations.md.stub +47 -0
  19. package/dist/knowledge/claude-rules/laravel-tests.md.stub +52 -0
  20. package/dist/knowledge/claude-rules/naming.md.stub +369 -0
  21. package/dist/knowledge/claude-rules/performance.md.stub +256 -0
  22. package/dist/knowledge/claude-rules/php-standards.md.stub +305 -0
  23. package/dist/knowledge/claude-rules/react-components.md.stub +67 -0
  24. package/dist/knowledge/claude-rules/schema-yaml.md.stub +83 -0
  25. package/dist/knowledge/claude-rules/security.md.stub +164 -0
  26. package/dist/knowledge/cursor-rules/antd-deprecations.mdc.stub +62 -0
  27. package/dist/knowledge/cursor-rules/basemodel-readonly.mdc.stub +66 -0
  28. package/dist/knowledge/cursor-rules/baserequest-readonly.mdc.stub +74 -0
  29. package/dist/knowledge/cursor-rules/baseresource-readonly.mdc.stub +78 -0
  30. package/dist/knowledge/cursor-rules/laravel-controller.mdc.stub +421 -0
  31. package/dist/knowledge/cursor-rules/laravel-request.mdc.stub +112 -0
  32. package/dist/knowledge/cursor-rules/laravel-resource.mdc.stub +73 -0
  33. package/dist/knowledge/cursor-rules/laravel-review.mdc.stub +69 -0
  34. package/dist/knowledge/cursor-rules/laravel-testing.mdc.stub +138 -0
  35. package/dist/knowledge/cursor-rules/laravel.mdc.stub +138 -0
  36. package/dist/knowledge/cursor-rules/migrations-workflow.mdc.stub +224 -0
  37. package/dist/knowledge/cursor-rules/model-editable.mdc.stub +120 -0
  38. package/dist/knowledge/cursor-rules/omnify-migrations.mdc.stub +109 -0
  39. package/dist/knowledge/cursor-rules/omnify-schema.mdc.stub +358 -0
  40. package/dist/knowledge/cursor-rules/omnify.mdc.stub +58 -0
  41. package/dist/knowledge/cursor-rules/react-design.mdc.stub +693 -0
  42. package/dist/knowledge/cursor-rules/react-form.mdc.stub +292 -0
  43. package/dist/knowledge/cursor-rules/react-services.mdc.stub +304 -0
  44. package/dist/knowledge/cursor-rules/react.mdc.stub +336 -0
  45. package/dist/knowledge/cursor-rules/request-editable.mdc.stub +111 -0
  46. package/dist/knowledge/cursor-rules/resource-editable.mdc.stub +125 -0
  47. package/dist/knowledge/cursor-rules/schema-create.mdc.stub +440 -0
  48. package/dist/knowledge/cursor-rules/validation-rules.mdc.stub +181 -0
  49. package/dist/knowledge/laravel/README.md.stub +59 -0
  50. package/dist/knowledge/laravel/architecture.md.stub +424 -0
  51. package/dist/knowledge/laravel/authentication.md.stub +588 -0
  52. package/dist/knowledge/laravel/controller.md.stub +484 -0
  53. package/dist/knowledge/laravel/datetime.md.stub +334 -0
  54. package/dist/knowledge/laravel/migrations-team.md.stub +376 -0
  55. package/dist/knowledge/laravel/openapi.md.stub +449 -0
  56. package/dist/knowledge/laravel/request.md.stub +450 -0
  57. package/dist/knowledge/laravel/resource.md.stub +516 -0
  58. package/dist/knowledge/laravel/service.md.stub +503 -0
  59. package/dist/knowledge/laravel/testing.md.stub +1504 -0
  60. package/dist/knowledge/omnify/antdesign-guide.md.stub +401 -0
  61. package/dist/knowledge/omnify/config-guide.md.stub +405 -0
  62. package/dist/knowledge/omnify/japan-guide.md.stub +186 -0
  63. package/dist/knowledge/omnify/laravel-guide.md.stub +61 -0
  64. package/dist/knowledge/omnify/partial-schema-guide.md.stub +353 -0
  65. package/dist/knowledge/omnify/react-form-guide.md.stub +225 -0
  66. package/dist/knowledge/omnify/schema-guide.md.stub +144 -0
  67. package/dist/knowledge/omnify/typescript-guide.md.stub +337 -0
  68. package/dist/knowledge/react/README.md.stub +221 -0
  69. package/dist/knowledge/react/antd-guide.md +528 -0
  70. package/dist/knowledge/react/antd-guide.md.stub +528 -0
  71. package/dist/knowledge/react/checklist.md.stub +108 -0
  72. package/dist/knowledge/react/datetime-guide.md.stub +137 -0
  73. package/dist/knowledge/react/design-philosophy.md.stub +363 -0
  74. package/dist/knowledge/react/i18n-guide.md.stub +211 -0
  75. package/dist/knowledge/react/laravel-integration.md.stub +181 -0
  76. package/dist/knowledge/react/service-pattern.md.stub +180 -0
  77. package/dist/knowledge/react/tanstack-query.md.stub +339 -0
  78. package/dist/knowledge/react/types-guide.md +669 -0
  79. package/dist/knowledge/react/types-guide.md.stub +669 -0
  80. package/dist/knowledge/workflows/bug-fix.md.stub +201 -0
  81. package/dist/knowledge/workflows/code-review.md.stub +164 -0
  82. package/dist/knowledge/workflows/new-feature.md.stub +327 -0
  83. package/dist/plugin-M95GyBll.d.cts +191 -0
  84. package/dist/plugin-M95GyBll.d.ts +191 -0
  85. package/dist/plugin.cjs +573 -0
  86. package/dist/plugin.cjs.map +1 -0
  87. package/dist/plugin.d.cts +2 -0
  88. package/dist/plugin.d.ts +2 -0
  89. package/dist/plugin.js +15 -0
  90. package/dist/plugin.js.map +1 -0
  91. package/package.json +53 -0
@@ -0,0 +1,528 @@
1
+ # Ant Design Guide
2
+
3
+ > **Related:** [README](./README.md) | [i18n](./i18n-guide.md)
4
+
5
+ ## ⚠️ IMPORTANT: Use Ant Design First
6
+
7
+ **ALWAYS check if Ant Design has a component before creating your own.**
8
+
9
+ Ant Design provides 60+ components: https://ant.design/components/overview
10
+
11
+ ```typescript
12
+ // ✅ DO: Use Ant Design components
13
+ import { Table, Form, Input, Button, Modal, Card, Descriptions } from "antd";
14
+
15
+ // ❌ DON'T: Create custom components that Ant Design already has
16
+ // DON'T create: CustomTable, CustomModal, CustomForm, CustomButton
17
+ // DON'T create: DataGrid, Popup, FormInput
18
+
19
+ // ✅ DO: Extend Ant Design if needed
20
+ function UserTable(props: { users: User[] }) {
21
+ return <Table dataSource={props.users} columns={...} />; // Wraps AntD Table
22
+ }
23
+
24
+ // ❌ DON'T: Build from scratch
25
+ function UserTable(props: { users: User[] }) {
26
+ return <table><tbody>{users.map(...)}</tbody></table>; // WRONG!
27
+ }
28
+ ```
29
+
30
+ ---
31
+
32
+ ## ⚠️ No New Libraries Without Permission
33
+
34
+ **DO NOT install new npm packages without explicit user approval.**
35
+
36
+ ```bash
37
+ # ❌ DON'T: Install without asking
38
+ npm install lodash
39
+ npm install moment
40
+ npm install react-table
41
+
42
+ # ✅ DO: Ask first
43
+ "Do you want to install library X for Y?"
44
+ ```
45
+
46
+ **Already installed libraries (use these):**
47
+ - UI: `antd`, `@ant-design/icons`
48
+ - HTTP: `axios`
49
+ - State: `@tanstack/react-query`
50
+ - Styling: `tailwindcss`
51
+ - i18n: `next-intl`
52
+
53
+ ---
54
+
55
+ ## When to Create a Component
56
+
57
+ | Create Component | Don't Create |
58
+ | ------------------------------- | ----------------------------- |
59
+ | Used in 2+ places | Used only once |
60
+ | Has own state/logic (>50 lines) | Simple markup (<30 lines) |
61
+ | Needs unit testing | Trivial display |
62
+ | Complex props interface | Few inline props |
63
+ | **Ant Design doesn't have it** | **Ant Design already has it** |
64
+
65
+ ---
66
+
67
+ ## Container vs Presentational
68
+
69
+ ```typescript
70
+ // ============================================================================
71
+ // CONTAINER COMPONENT (Smart) - pages or complex components
72
+ // - Fetches data
73
+ // - Handles mutations
74
+ // - Contains business logic
75
+ // ============================================================================
76
+
77
+ // app/(dashboard)/users/page.tsx
78
+ "use client";
79
+
80
+ import { useState } from "react";
81
+ import { useQuery } from "@tanstack/react-query";
82
+ import { userService, UserListParams } from "@/services/users";
83
+ import { queryKeys } from "@/lib/queryKeys";
84
+ import { UserTable } from "@/components/tables/UserTable";
85
+
86
+ export default function UsersPage() {
87
+ const [filters, setFilters] = useState<UserListParams>({ page: 1 });
88
+
89
+ const { data, isLoading } = useQuery({
90
+ queryKey: queryKeys.users.list(filters),
91
+ queryFn: () => userService.list(filters),
92
+ });
93
+
94
+ return (
95
+ <UserTable
96
+ users={data?.data ?? []}
97
+ loading={isLoading}
98
+ pagination={data?.meta}
99
+ onPageChange={(page) => setFilters({ ...filters, page })}
100
+ />
101
+ );
102
+ }
103
+
104
+ // ============================================================================
105
+ // PRESENTATIONAL COMPONENT (Dumb) - reusable UI
106
+ // - Receives data via props
107
+ // - No data fetching
108
+ // - No business logic
109
+ // ============================================================================
110
+
111
+ // components/tables/UserTable.tsx
112
+ import { Table } from "antd";
113
+ import type { User } from "@omnify/schemas";
114
+ import type { PaginatedResponse } from "@/lib/api";
115
+
116
+ interface UserTableProps {
117
+ users: User[];
118
+ loading: boolean;
119
+ pagination?: PaginatedResponse<User>["meta"];
120
+ onPageChange: (page: number) => void;
121
+ }
122
+
123
+ export function UserTable({ users, loading, pagination, onPageChange }: UserTableProps) {
124
+ return (
125
+ <Table
126
+ dataSource={users}
127
+ loading={loading}
128
+ rowKey="id"
129
+ pagination={{
130
+ current: pagination?.current_page,
131
+ total: pagination?.total,
132
+ onChange: onPageChange,
133
+ }}
134
+ columns={[
135
+ { title: "ID", dataIndex: "id" },
136
+ { title: "Name", dataIndex: "name" },
137
+ { title: "Email", dataIndex: "email" },
138
+ ]}
139
+ />
140
+ );
141
+ }
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Form Pattern with Laravel Validation
147
+
148
+ ```typescript
149
+ "use client";
150
+
151
+ import { Form, Input, Button, message } from "antd";
152
+ import { useMutation, useQueryClient } from "@tanstack/react-query";
153
+ import { useTranslations } from "next-intl";
154
+ import { getFormErrors } from "@/lib/api";
155
+ import { queryKeys } from "@/lib/queryKeys";
156
+ import { userService } from "@/services/users";
157
+
158
+ export default function UserForm() {
159
+ const t = useTranslations();
160
+ const [form] = Form.useForm();
161
+ const queryClient = useQueryClient();
162
+
163
+ const mutation = useMutation({
164
+ mutationFn: userService.create,
165
+ onSuccess: () => {
166
+ queryClient.invalidateQueries({ queryKey: queryKeys.users.all });
167
+ message.success(t("messages.created"));
168
+ form.resetFields();
169
+ },
170
+ onError: (error) => {
171
+ // This maps Laravel's 422 { errors: { email: ["Already exists"] } }
172
+ // to Ant Design's form.setFields format
173
+ form.setFields(getFormErrors(error));
174
+ },
175
+ });
176
+
177
+ return (
178
+ <Form
179
+ form={form}
180
+ layout="vertical"
181
+ onFinish={(values) => mutation.mutate(values)}
182
+ >
183
+ <Form.Item
184
+ name="name"
185
+ label={t("common.name")}
186
+ rules={[{ required: true }]}
187
+ >
188
+ <Input />
189
+ </Form.Item>
190
+
191
+ <Form.Item
192
+ name="email"
193
+ label={t("auth.email")}
194
+ rules={[{ required: true }, { type: "email" }]}
195
+ >
196
+ <Input />
197
+ </Form.Item>
198
+
199
+ <Form.Item>
200
+ <Button
201
+ type="primary"
202
+ htmlType="submit"
203
+ loading={mutation.isPending}
204
+ >
205
+ {t("common.save")}
206
+ </Button>
207
+ </Form.Item>
208
+ </Form>
209
+ );
210
+ }
211
+ ```
212
+
213
+ ---
214
+
215
+ ## ⚠️ Ant Design Breaking Changes & Deprecated Props
216
+
217
+ > **IMPORTANT**: Check your `package.json` to determine which Ant Design version you're using:
218
+ > - **Ant Design 5.x**: Use `visible`, `valueStyle`, `bodyStyle`, `headStyle` (deprecated but still work)
219
+ > - **Ant Design 6.x**: Use `open`, `styles={{ ... }}` (semantic DOM API)
220
+
221
+ ### Deprecated Props Reference Table
222
+
223
+ | Component | ❌ Deprecated (v6+) | ✅ Use Instead (v6+) | Notes |
224
+ | ----------------------- | -------------------------- | -------------------------- | -------------------------------------- |
225
+ | **Statistic** | `valueStyle` | `styles={{ content: {} }}` | ⚠️ v6.0.0+ only! Use `valueStyle` in v5 |
226
+ | **Card** | `bodyStyle` | `styles={{ body: {} }}` | ⚠️ v6.0.0+ only! Use `bodyStyle` in v5 |
227
+ | **Card** | `headStyle` | `styles={{ header: {} }}` | ⚠️ v6.0.0+ only! Use `headStyle` in v5 |
228
+ | **Divider** | `orientation` | `titlePlacement` | `orientation` is for direction only |
229
+ | Modal | `visible` | `open` | v5.0.0+ |
230
+ | Drawer | `visible` | `open` | v5.0.0+ |
231
+ | Dropdown | `visible` | `open` | v5.0.0+ |
232
+ | Tooltip | `visible` | `open` | v5.0.0+ |
233
+ | Popover | `visible` | `open` | v5.0.0+ |
234
+ | Popconfirm | `visible` | `open` | v5.0.0+ |
235
+ | Select | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` | v5.0.0+ |
236
+ | TreeSelect | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` | v5.0.0+ |
237
+ | Cascader | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` | v5.0.0+ |
238
+ | AutoComplete | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` | v5.0.0+ |
239
+ | Table | `filterDropdownVisible` | `filterDropdownOpen` | v5.0.0+ |
240
+ | DatePicker | `dropdownClassName` | `popupClassName` | v5.0.0+ |
241
+ | TimePicker | `dropdownClassName` | `popupClassName` | v5.0.0+ |
242
+ | Mentions | `dropdownClassName` | `popupClassName` | v5.0.0+ |
243
+ | Tag | `closable` | `closeIcon={false}` | Use `closeIcon={false}` to hide |
244
+ | **List** | (component) | Use `Table` or custom | DEPRECATED in v6.0.0 |
245
+ | **Statistic.Countdown** | (component) | `Statistic.Timer` | Use `Statistic.Timer` (v5.25.0+) |
246
+
247
+ ```typescript
248
+ // ❌ DON'T: Use deprecated props (causes console warnings)
249
+ <Statistic value={100} valueStyle={{ color: 'green' }} />
250
+ <Card bodyStyle={{ padding: 0 }} headStyle={{ background: '#f5f5f5' }}>
251
+ <Divider orientation="left">Title</Divider>
252
+ <Modal visible={isOpen}>
253
+
254
+ // ✅ DO: Use new props (Ant Design 6+)
255
+ <Statistic value={100} styles={{ content: { color: 'green' } }} />
256
+ <Card styles={{ body: { padding: 0 }, header: { background: '#f5f5f5' } }}>
257
+ <Divider titlePlacement="left">Title</Divider>
258
+ <Modal open={isOpen}>
259
+ ```
260
+
261
+ ---
262
+
263
+ ## 🎨 Ant Design 6.0 Semantic DOM API (NEW!)
264
+
265
+ **Version 6.0.0** introduced a new **Semantic DOM** pattern for styling. Instead of single style props, use `styles` and `classNames` objects:
266
+
267
+ ### Statistic - Semantic Structure
268
+
269
+ ```typescript
270
+ // Semantic keys: root, header, title, prefix, content, suffix
271
+
272
+ // ❌ OLD (deprecated in v6)
273
+ <Statistic
274
+ value={112893}
275
+ valueStyle={{ color: token.colorSuccess }}
276
+ prefix={<ArrowUpOutlined />}
277
+ />
278
+
279
+ // ✅ NEW (v6.0.0+)
280
+ <Statistic
281
+ value={112893}
282
+ styles={{
283
+ content: { color: token.colorSuccess },
284
+ prefix: { marginRight: 8 },
285
+ }}
286
+ classNames={{
287
+ root: 'my-statistic',
288
+ content: 'my-statistic-value',
289
+ }}
290
+ prefix={<ArrowUpOutlined />}
291
+ />
292
+ ```
293
+
294
+ ### Card - Semantic Structure
295
+
296
+ ```typescript
297
+ // Semantic keys: root, header, title, extra, body, actions, cover
298
+
299
+ // ❌ OLD (deprecated)
300
+ <Card bodyStyle={{ padding: 0 }} headStyle={{ background: '#fafafa' }}>
301
+
302
+ // ✅ NEW (v6.0.0+)
303
+ <Card styles={{ body: { padding: 0 }, header: { background: '#fafafa' } }}>
304
+ ```
305
+
306
+ ### Common Components with Semantic DOM (v6.0.0+)
307
+
308
+ | Component | Semantic Keys |
309
+ | ------------ | ------------------------------------------------------------- |
310
+ | Statistic | `root`, `header`, `title`, `prefix`, `content`, `suffix` |
311
+ | Card | `root`, `header`, `title`, `extra`, `body`, `actions` |
312
+ | Modal | `root`, `header`, `title`, `body`, `footer`, `mask` |
313
+ | Drawer | `root`, `header`, `title`, `body`, `footer`, `mask` |
314
+ | Table | `root`, `header`, `body`, `footer`, `cell` |
315
+ | Form | `root`, `item`, `label`, `input`, `feedback` |
316
+ | Descriptions | `root`, `header`, `title`, `body`, `item`, `label`, `content` |
317
+
318
+ ```typescript
319
+ // General pattern for semantic styling
320
+ <Component
321
+ styles={{ [semanticKey]: { /* CSSProperties */ } }}
322
+ classNames={{ [semanticKey]: 'my-class' }}
323
+ />
324
+ ```
325
+
326
+ ---
327
+
328
+ ## 🚨 Common Ant Design 6+ Mistakes
329
+
330
+ ### 1. Divider - `orientation` vs `titlePlacement`
331
+
332
+ ```typescript
333
+ // ❌ WRONG: This will show a deprecation warning!
334
+ <Divider orientation="left">Section Title</Divider>
335
+ // Warning: [antd: Divider] `orientation` is used for direction, please use `titlePlacement` replace this
336
+
337
+ // ✅ CORRECT: Use titlePlacement for title position
338
+ <Divider titlePlacement="left">Section Title</Divider>
339
+ <Divider titlePlacement="center">Section Title</Divider>
340
+ <Divider titlePlacement="right">Section Title</Divider>
341
+
342
+ // For horizontal/vertical dividers, use `type`:
343
+ <Divider type="horizontal" /> // default
344
+ <Divider type="vertical" />
345
+ ```
346
+
347
+ ### 2. Modal/Drawer - `visible` vs `open`
348
+
349
+ ```typescript
350
+ // ❌ WRONG
351
+ const [visible, setVisible] = useState(false);
352
+ <Modal visible={visible} onCancel={() => setVisible(false)}>
353
+
354
+ // ✅ CORRECT
355
+ const [open, setOpen] = useState(false);
356
+ <Modal open={open} onCancel={() => setOpen(false)}>
357
+ ```
358
+
359
+ ### 3. Form.Item - `dependencies` must be array
360
+
361
+ ```typescript
362
+ // ❌ WRONG: dependencies as string
363
+ <Form.Item dependencies="password">
364
+
365
+ // ✅ CORRECT: dependencies as array
366
+ <Form.Item dependencies={['password']}>
367
+ ```
368
+
369
+ ### 4. Table - Column `render` function signature
370
+
371
+ ```typescript
372
+ // ❌ WRONG: Using wrong parameter order
373
+ columns={[{
374
+ render: (record, text) => <span>{text}</span> // WRONG ORDER!
375
+ }]}
376
+
377
+ // ✅ CORRECT: (text, record, index)
378
+ columns={[{
379
+ render: (text, record, index) => <span>{text}</span>
380
+ }]}
381
+ ```
382
+
383
+ ### 5. Select/TreeSelect - Option rendering
384
+
385
+ ```typescript
386
+ // ❌ WRONG: Using children in v6+
387
+ <Select>
388
+ <Select.Option value="1">Option 1</Select.Option>
389
+ </Select>
390
+
391
+ // ✅ PREFERRED: Use options prop (better performance)
392
+ <Select options={[
393
+ { value: '1', label: 'Option 1' },
394
+ { value: '2', label: 'Option 2' },
395
+ ]} />
396
+ ```
397
+
398
+ ### 6. DatePicker - Dayjs instead of Moment
399
+
400
+ ```typescript
401
+ // ❌ WRONG: Ant Design 6+ uses dayjs, not moment
402
+ import moment from 'moment';
403
+ <DatePicker value={moment(date)} />
404
+
405
+ // ✅ CORRECT: Use dayjs
406
+ import dayjs from 'dayjs';
407
+ <DatePicker value={dayjs(date)} />
408
+ ```
409
+
410
+ ### 7. ConfigProvider - Theme customization
411
+
412
+ ```typescript
413
+ // ❌ WRONG: Old less variable approach
414
+ @primary-color: #1890ff;
415
+
416
+ // ✅ CORRECT: Use ConfigProvider theme token
417
+ <ConfigProvider
418
+ theme={{
419
+ token: {
420
+ colorPrimary: '#1890ff',
421
+ borderRadius: 6,
422
+ },
423
+ }}
424
+ >
425
+ <App />
426
+ </ConfigProvider>
427
+ ```
428
+
429
+ ### 8. App Component - message/notification/modal
430
+
431
+ ```typescript
432
+ // ❌ WRONG: Direct import (won't respect ConfigProvider)
433
+ import { message } from 'antd';
434
+ message.success('Done!');
435
+
436
+ // ✅ CORRECT: Use App.useApp() hook
437
+ import { App } from 'antd';
438
+
439
+ function MyComponent() {
440
+ const { message, notification, modal } = App.useApp();
441
+
442
+ const handleClick = () => {
443
+ message.success('Done!'); // Respects ConfigProvider theme
444
+ };
445
+ }
446
+
447
+ // Wrap your app with App component
448
+ <ConfigProvider theme={...}>
449
+ <App>
450
+ <YourApp />
451
+ </App>
452
+ </ConfigProvider>
453
+ ```
454
+
455
+ ### 9. Icons - Named imports required
456
+
457
+ ```typescript
458
+ // ❌ WRONG: Default import
459
+ import Icon from '@ant-design/icons';
460
+ <Icon type="user" />
461
+
462
+ // ✅ CORRECT: Named imports
463
+ import { UserOutlined, EditOutlined } from '@ant-design/icons';
464
+ <UserOutlined />
465
+ <EditOutlined />
466
+ ```
467
+
468
+ ### 10. Grid - `xs`, `sm`, etc. as objects
469
+
470
+ ```typescript
471
+ // ❌ CAREFUL: Mixing number and object syntax
472
+ <Col xs={24} sm={{ span: 12, offset: 6 }}>
473
+
474
+ // ✅ PREFERRED: Be consistent
475
+ <Col xs={{ span: 24 }} sm={{ span: 12, offset: 6 }}>
476
+ // OR
477
+ <Col xs={24} sm={12}>
478
+ ```
479
+
480
+ ---
481
+
482
+ ## Anti-Patterns
483
+
484
+ ```typescript
485
+ // ❌ Creating components that Ant Design already has
486
+ function CustomButton({ children }) { ... } // Use <Button> from antd
487
+ function CustomModal({ visible }) { ... } // Use <Modal> from antd
488
+ function CustomTable({ data }) { ... } // Use <Table> from antd
489
+ function DataGrid({ rows }) { ... } // Use <Table> from antd
490
+
491
+ // ❌ Installing libraries without permission
492
+ npm install lodash // Ask first!
493
+ npm install react-icons // Use @ant-design/icons
494
+ npm install styled-components // Use Tailwind CSS
495
+
496
+ // ❌ API call in component (bypass service layer)
497
+ function UserList() {
498
+ const { data } = useQuery({
499
+ queryKey: ["users"],
500
+ queryFn: () => axios.get("/api/users"), // WRONG: Use service
501
+ });
502
+ }
503
+
504
+ // ❌ Business logic in component
505
+ function UserList() {
506
+ const users = data?.filter(u => u.active).sort((a, b) => a.name > b.name);
507
+ // Move to service or utility function
508
+ }
509
+
510
+ // ❌ Hardcoded strings - use i18n
511
+ <Button>Save</Button> // WRONG
512
+ <Button>{t("common.save")}</Button> // CORRECT
513
+
514
+ // ❌ Multiple sources of truth
515
+ const [users, setUsers] = useState([]); // Local state
516
+ const { data } = useQuery({ ... }); // Server state
517
+ // Pick one: TanStack Query for server data
518
+
519
+ // ❌ Prop drilling
520
+ <Parent data={data}>
521
+ <Child data={data}>
522
+ <GrandChild data={data} /> // Use Context or pass minimal props
523
+ </Child>
524
+ </Parent>
525
+
526
+ // ❌ Giant components (>200 lines)
527
+ // Split into smaller components or extract hooks
528
+ ```
@@ -0,0 +1,108 @@
1
+ # Checklists
2
+
3
+ > **Related:** [README](./README.md)
4
+
5
+ ## After Writing Code
6
+
7
+ > **IMPORTANT**: Always run these commands after writing/modifying code:
8
+
9
+ ```bash
10
+ # 1. Type check
11
+ npm run typecheck
12
+
13
+ # 2. Lint check
14
+ npm run lint
15
+
16
+ # Or combined
17
+ npm run typecheck && npm run lint
18
+ ```
19
+
20
+ ---
21
+
22
+ ## Adding New Resource
23
+
24
+ When adding a new resource (e.g., `posts`), follow these steps:
25
+
26
+ ### 1. Service Layer (Always in `services/`)
27
+
28
+ ```bash
29
+ # Create: services/posts.ts
30
+ ```
31
+
32
+ - [ ] Import types: `import type { Post, PostCreate, PostUpdate } from "@omnify/schemas"`
33
+ - [ ] Define only `PostListParams` (Create/Update come from Omnify)
34
+ - [ ] Create `postService` object with CRUD methods
35
+ - [ ] Add JSDoc comments for each method
36
+
37
+ ### 2. Query Keys
38
+
39
+ ```bash
40
+ # Update: lib/queryKeys.ts
41
+ ```
42
+
43
+ - [ ] Add `posts` object to `queryKeys`
44
+
45
+ ```typescript
46
+ posts: {
47
+ all: ["posts"] as const,
48
+ lists: () => [...queryKeys.posts.all, "list"] as const,
49
+ list: (params?: PostListParams) => [...queryKeys.posts.lists(), params] as const,
50
+ details: () => [...queryKeys.posts.all, "detail"] as const,
51
+ detail: (id: number) => [...queryKeys.posts.details(), id] as const,
52
+ },
53
+ ```
54
+
55
+ ### 3. Feature Components (in `features/posts/`)
56
+
57
+ ```bash
58
+ # Create: features/posts/
59
+ ```
60
+
61
+ - [ ] `PostTable.tsx` - Table component
62
+ - [ ] `PostForm.tsx` - Form component
63
+ - [ ] `usePostFilters.ts` - Feature-specific hooks (if needed)
64
+
65
+ ### 4. Pages
66
+
67
+ ```bash
68
+ # Create pages in app/(dashboard)/posts/
69
+ ```
70
+
71
+ - [ ] `page.tsx` - List page (imports from `features/posts/`)
72
+ - [ ] `new/page.tsx` - Create form
73
+ - [ ] `[id]/page.tsx` - Detail view
74
+ - [ ] `[id]/edit/page.tsx` - Edit form
75
+
76
+ ### 5. Shared Components (only if reused)
77
+
78
+ - [ ] If component used in 2+ features → move to `components/common/`
79
+
80
+ ### 6. Translations
81
+
82
+ - [ ] Add labels to `src/i18n/messages/*.json` if needed
83
+
84
+ ### 7. Final Check
85
+
86
+ - [ ] Run `npm run typecheck && npm run lint`
87
+ - [ ] Test create, read, update, delete operations
88
+
89
+ ---
90
+
91
+ ## Adding New Language
92
+
93
+ - [ ] Create message file: `src/i18n/messages/{locale}.json`
94
+ - [ ] Add locale to `src/i18n/config.ts`
95
+ - [ ] Import Ant Design locale in `src/components/AntdThemeProvider.tsx`
96
+ - [ ] Test with `LocaleSwitcher` component
97
+
98
+ ---
99
+
100
+ ## Before Commit
101
+
102
+ - [ ] `npm run typecheck` passes
103
+ - [ ] `npm run lint` passes
104
+ - [ ] No console warnings about deprecated props
105
+ - [ ] No hardcoded strings (use i18n)
106
+ - [ ] Forms handle loading state (`isPending`)
107
+ - [ ] Forms handle validation errors (`getFormErrors`)
108
+ - [ ] Mutations invalidate related queries