@famgia/omnify-typescript 0.0.66 → 0.0.68

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 (43) hide show
  1. package/ai-guides/react-form-guide.md +259 -0
  2. package/ai-guides/typescript-guide.md +53 -0
  3. package/dist/{chunk-4L77AHAC.js → chunk-6I4O23X6.js} +521 -66
  4. package/dist/chunk-6I4O23X6.js.map +1 -0
  5. package/dist/index.cjs +761 -65
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +138 -2
  8. package/dist/index.d.ts +138 -2
  9. package/dist/index.js +227 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/plugin.cjs +624 -75
  12. package/dist/plugin.cjs.map +1 -1
  13. package/dist/plugin.d.cts +6 -0
  14. package/dist/plugin.d.ts +6 -0
  15. package/dist/plugin.js +96 -11
  16. package/dist/plugin.js.map +1 -1
  17. package/package.json +4 -3
  18. package/scripts/postinstall.js +29 -40
  19. package/stubs/JapaneseAddressField.tsx.stub +289 -0
  20. package/stubs/JapaneseBankField.tsx.stub +212 -0
  21. package/stubs/JapaneseNameField.tsx.stub +194 -0
  22. package/stubs/ai-guides/checklists/react.md.stub +108 -0
  23. package/stubs/ai-guides/cursor/react-design.mdc.stub +289 -0
  24. package/stubs/ai-guides/cursor/react-form.mdc.stub +277 -0
  25. package/stubs/ai-guides/cursor/react-services.mdc.stub +304 -0
  26. package/stubs/ai-guides/cursor/react.mdc.stub +305 -0
  27. package/stubs/ai-guides/react/README.md.stub +221 -0
  28. package/stubs/ai-guides/react/antd-guide.md.stub +294 -0
  29. package/stubs/ai-guides/react/checklist.md.stub +108 -0
  30. package/stubs/ai-guides/react/datetime-guide.md.stub +137 -0
  31. package/stubs/ai-guides/react/design-philosophy.md.stub +363 -0
  32. package/stubs/ai-guides/react/i18n-guide.md.stub +211 -0
  33. package/stubs/ai-guides/react/laravel-integration.md.stub +181 -0
  34. package/stubs/ai-guides/react/service-pattern.md.stub +180 -0
  35. package/stubs/ai-guides/react/tanstack-query.md.stub +339 -0
  36. package/stubs/ai-guides/react/types-guide.md.stub +524 -0
  37. package/stubs/components-index.ts.stub +13 -0
  38. package/stubs/form-validation.ts.stub +106 -0
  39. package/stubs/rules/index.ts.stub +48 -0
  40. package/stubs/rules/kana.ts.stub +291 -0
  41. package/stubs/use-form-mutation.ts.stub +117 -0
  42. package/stubs/zod-i18n.ts.stub +32 -0
  43. package/dist/chunk-4L77AHAC.js.map +0 -1
@@ -0,0 +1,221 @@
1
+ # Frontend Architecture Guide
2
+
3
+ > **Related docs:**
4
+ > - [Design Philosophy](./design-philosophy.md) ⭐ **Start here** - Architecture, principles
5
+ > - [Types Guide](./types-guide.md) - Where to define types
6
+ > - [Service Pattern](./service-pattern.md) - API services
7
+ > - [TanStack Query](./tanstack-query.md) - Data fetching
8
+ > - [Ant Design](./antd-guide.md) - UI components
9
+ > - [i18n](./i18n-guide.md) - Multi-language
10
+ > - [DateTime](./datetime-guide.md) - Day.js, UTC handling
11
+ > - [Laravel Integration](./laravel-integration.md) - Backend integration
12
+ > - [Checklists](./checklist.md) - Before commit, new resource
13
+
14
+ ## Overview
15
+
16
+ See [Design Philosophy](./design-philosophy.md) for architecture diagram and principles.
17
+
18
+ **Stack**: Next.js 16 + TypeScript + Ant Design 6 + TanStack Query + Axios
19
+
20
+ ---
21
+
22
+ ## Directory Structure
23
+
24
+ ```
25
+ frontend/src/
26
+ ├── app/ # Next.js App Router (Pages)
27
+ │ ├── layout.tsx # Root: Providers wrapper
28
+ │ ├── page.tsx # Public: Home page
29
+ │ │
30
+ │ ├── (auth)/ # Group: Auth pages (no layout)
31
+ │ │ ├── login/page.tsx
32
+ │ │ └── register/page.tsx
33
+ │ │
34
+ │ └── (dashboard)/ # Group: Protected pages
35
+ │ ├── layout.tsx # Shared: Sidebar + Header
36
+ │ ├── page.tsx # /dashboard
37
+ │ └── users/ # Resource: Users
38
+ │ ├── page.tsx # GET /users (List)
39
+ │ ├── new/page.tsx # POST /users (Create)
40
+ │ └── [id]/
41
+ │ ├── page.tsx # GET /users/:id (Show)
42
+ │ └── edit/page.tsx # PUT /users/:id (Edit)
43
+
44
+ ├── features/ # Feature-specific components & hooks
45
+ │ ├── users/ # User feature
46
+ │ │ ├── UserTable.tsx # Only used in users feature
47
+ │ │ ├── UserForm.tsx
48
+ │ │ └── useUserFilters.ts # Feature-specific hook
49
+ │ └── posts/
50
+ │ ├── PostCard.tsx
51
+ │ └── PostEditor.tsx
52
+
53
+ ├── components/ # SHARED components (2+ features)
54
+ │ ├── layouts/ # Layout wrappers
55
+ │ │ ├── DashboardLayout.tsx
56
+ │ │ └── AuthLayout.tsx
57
+ │ └── common/ # Reusable UI
58
+ │ ├── DataTable.tsx # Generic table
59
+ │ └── PageHeader.tsx
60
+
61
+ ├── services/ # API Service Layer (ALWAYS here)
62
+ │ ├── auth.ts # POST /login, /logout, /register
63
+ │ └── users.ts # CRUD /api/users
64
+
65
+ ├── hooks/ # SHARED hooks (2+ features)
66
+ │ ├── useAuth.ts # App-wide auth
67
+ │ └── useDebounce.ts # Utility hook
68
+
69
+ ├── lib/ # Core Infrastructure
70
+ │ ├── api.ts # Axios instance + interceptors
71
+ │ ├── query.tsx # QueryClient provider
72
+ │ ├── queryKeys.ts # Query key factory
73
+ │ └── dayjs.ts # Day.js config + utilities
74
+
75
+ ├── i18n/ # Internationalization
76
+ │ ├── config.ts # Locales config
77
+ │ ├── request.ts # Server-side locale detection
78
+ │ └── messages/ # Translation files
79
+ │ ├── ja.json
80
+ │ ├── en.json
81
+ │ └── vi.json
82
+
83
+ └── types/ # TypeScript Types
84
+ └── model/ # Omnify auto-generated types
85
+ ```
86
+
87
+ ---
88
+
89
+ ## When to Use Which Folder
90
+
91
+ ### Decision Rules
92
+
93
+ | Question | Answer | Location |
94
+ | ------------------------------------ | ----------- | --------------------- |
95
+ | Component used in how many features? | 1 feature | `features/{feature}/` |
96
+ | Component used in how many features? | 2+ features | `components/common/` |
97
+ | Is it a layout wrapper? | Yes | `components/layouts/` |
98
+ | Is it a service (API calls)? | Yes | `services/` (ALWAYS) |
99
+ | Hook used in how many features? | 1 feature | `features/{feature}/` |
100
+ | Hook used in how many features? | 2+ features | `hooks/` |
101
+
102
+ ### Flowchart
103
+
104
+ ```
105
+ ┌─────────────────────────────────────────────────────────┐
106
+ │ NEW COMPONENT │
107
+ └─────────────────────┬───────────────────────────────────┘
108
+
109
+ Used in how many features?
110
+
111
+ ┌─────────────┴─────────────┐
112
+ │ │
113
+ 1 feature 2+ features
114
+ │ │
115
+ ▼ ▼
116
+ features/{feature}/ components/common/
117
+ UserTable.tsx DataTable.tsx
118
+ ```
119
+
120
+ ```
121
+ ┌─────────────────────────────────────────────────────────┐
122
+ │ NEW HOOK │
123
+ └─────────────────────┬───────────────────────────────────┘
124
+
125
+ Used in how many features?
126
+
127
+ ┌─────────────┴─────────────┐
128
+ │ │
129
+ 1 feature 2+ features
130
+ │ │
131
+ ▼ ▼
132
+ features/{feature}/ hooks/
133
+ useUserFilters.ts useDebounce.ts
134
+ ```
135
+
136
+ ```
137
+ ┌─────────────────────────────────────────────────────────┐
138
+ │ NEW SERVICE │
139
+ └─────────────────────┬───────────────────────────────────┘
140
+
141
+ ALWAYS
142
+
143
+
144
+ services/
145
+ users.ts
146
+ ```
147
+
148
+ ### Examples
149
+
150
+ ```typescript
151
+ // ❌ WRONG: Service in features folder
152
+ features/users/services/users.ts
153
+
154
+ // ✅ CORRECT: Service always centralized
155
+ services/users.ts
156
+ ```
157
+
158
+ ```typescript
159
+ // ❌ WRONG: Feature-specific component in components/
160
+ components/users/UserTable.tsx // Only used in users feature
161
+
162
+ // ✅ CORRECT: Feature-specific in features/
163
+ features/users/UserTable.tsx
164
+ ```
165
+
166
+ ```typescript
167
+ // ❌ WRONG: Shared component in features/
168
+ features/users/DataTable.tsx // Used in users AND posts
169
+
170
+ // ✅ CORRECT: Shared in components/
171
+ components/common/DataTable.tsx
172
+ ```
173
+
174
+ ---
175
+
176
+ ## Naming Conventions
177
+
178
+ ### Files
179
+
180
+ | Type | Pattern | Example |
181
+ | --------- | ------------------------ | ------------------------------- |
182
+ | Component | PascalCase | `UserForm.tsx`, `DataTable.tsx` |
183
+ | Hook | camelCase + `use` prefix | `useAuth.ts`, `useUsers.ts` |
184
+ | Service | camelCase | `users.ts`, `auth.ts` |
185
+ | Utility | camelCase | `utils.ts`, `formatters.ts` |
186
+ | Type | camelCase or PascalCase | `types.ts`, `User.ts` |
187
+ | Page | lowercase | `page.tsx`, `layout.tsx` |
188
+
189
+ ### Code
190
+
191
+ | Type | Pattern | Example |
192
+ | -------------- | --------------------- | --------------------------- |
193
+ | Component | PascalCase | `function UserForm()` |
194
+ | Hook | camelCase + `use` | `function useAuth()` |
195
+ | Service object | camelCase + `Service` | `const userService = {}` |
196
+ | Interface | PascalCase | `interface User` |
197
+ | Type | PascalCase | `type UserFormData` |
198
+ | Constant | UPPER_SNAKE_CASE | `const API_TIMEOUT = 30000` |
199
+ | Function | camelCase | `function formatDate()` |
200
+ | Variable | camelCase | `const userData = ...` |
201
+
202
+ ---
203
+
204
+ ## Types
205
+
206
+ See [Types Guide](./types-guide.md) for complete type definition rules.
207
+
208
+ **Quick reference:**
209
+
210
+ | Type | Location |
211
+ | ------------------ | --------------------------------------- |
212
+ | Model (User, Post) | `@/types/model` (Omnify auto-generated) |
213
+ | Input types | Service file (colocated) |
214
+ | Props | Component file |
215
+ | API Response | `lib/api.ts` |
216
+
217
+ **Omnify files:**
218
+ - `base/`, `rules/`, `enum/` → ❌ DO NOT EDIT
219
+ - `User.ts` (root level) → ✅ CAN EDIT (extension)
220
+
221
+ See also: [Omnify TypeScript Guide](../omnify/typescript-guide.md)
@@ -0,0 +1,294 @@
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 "@/types/model";
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
+ ## Deprecated Props (v6+)
216
+
217
+ > ⚠️ **CRITICAL**: Always use the latest prop names. Using deprecated props will show console warnings.
218
+
219
+ | Component | Deprecated | Use Instead |
220
+ | ------------ | -------------------------- | ----------------------- |
221
+ | Space | `direction` | `orientation` |
222
+ | Modal | `visible` | `open` |
223
+ | Drawer | `visible` | `open` |
224
+ | Dropdown | `visible` | `open` |
225
+ | Tooltip | `visible` | `open` |
226
+ | Popover | `visible` | `open` |
227
+ | Popconfirm | `visible` | `open` |
228
+ | Select | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` |
229
+ | TreeSelect | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` |
230
+ | Cascader | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` |
231
+ | AutoComplete | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` |
232
+ | Table | `filterDropdownVisible` | `filterDropdownOpen` |
233
+
234
+ ```typescript
235
+ // ❌ DON'T: Use deprecated props
236
+ <Space direction="vertical">
237
+ <Modal visible={isOpen}>
238
+ <Dropdown visible={show}>
239
+
240
+ // ✅ DO: Use new props
241
+ <Space orientation="vertical">
242
+ <Modal open={isOpen}>
243
+ <Dropdown open={show}>
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Anti-Patterns
249
+
250
+ ```typescript
251
+ // ❌ Creating components that Ant Design already has
252
+ function CustomButton({ children }) { ... } // Use <Button> from antd
253
+ function CustomModal({ visible }) { ... } // Use <Modal> from antd
254
+ function CustomTable({ data }) { ... } // Use <Table> from antd
255
+ function DataGrid({ rows }) { ... } // Use <Table> from antd
256
+
257
+ // ❌ Installing libraries without permission
258
+ npm install lodash // Ask first!
259
+ npm install react-icons // Use @ant-design/icons
260
+ npm install styled-components // Use Tailwind CSS
261
+
262
+ // ❌ API call in component (bypass service layer)
263
+ function UserList() {
264
+ const { data } = useQuery({
265
+ queryKey: ["users"],
266
+ queryFn: () => axios.get("/api/users"), // WRONG: Use service
267
+ });
268
+ }
269
+
270
+ // ❌ Business logic in component
271
+ function UserList() {
272
+ const users = data?.filter(u => u.active).sort((a, b) => a.name > b.name);
273
+ // Move to service or utility function
274
+ }
275
+
276
+ // ❌ Hardcoded strings - use i18n
277
+ <Button>Save</Button> // WRONG
278
+ <Button>{t("common.save")}</Button> // CORRECT
279
+
280
+ // ❌ Multiple sources of truth
281
+ const [users, setUsers] = useState([]); // Local state
282
+ const { data } = useQuery({ ... }); // Server state
283
+ // Pick one: TanStack Query for server data
284
+
285
+ // ❌ Prop drilling
286
+ <Parent data={data}>
287
+ <Child data={data}>
288
+ <GrandChild data={data} /> // Use Context or pass minimal props
289
+ </Child>
290
+ </Parent>
291
+
292
+ // ❌ Giant components (>200 lines)
293
+ // Split into smaller components or extract hooks
294
+ ```
@@ -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 "@/types/model"`
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