@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.
- package/README.md +105 -0
- package/dist/chunk-RCTEXK7C.js +549 -0
- package/dist/chunk-RCTEXK7C.js.map +1 -0
- package/dist/config/rules.yaml +524 -0
- package/dist/index.cjs +587 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +55 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/knowledge/agents/architect.md.stub +150 -0
- package/dist/knowledge/agents/developer.md.stub +190 -0
- package/dist/knowledge/agents/reviewer.md.stub +134 -0
- package/dist/knowledge/agents/tester.md.stub +196 -0
- package/dist/knowledge/checklists/backend.md.stub +112 -0
- package/dist/knowledge/checklists/react.md.stub +108 -0
- package/dist/knowledge/claude-rules/laravel-controllers.md.stub +57 -0
- package/dist/knowledge/claude-rules/laravel-migrations.md.stub +47 -0
- package/dist/knowledge/claude-rules/laravel-tests.md.stub +52 -0
- package/dist/knowledge/claude-rules/naming.md.stub +369 -0
- package/dist/knowledge/claude-rules/performance.md.stub +256 -0
- package/dist/knowledge/claude-rules/php-standards.md.stub +305 -0
- package/dist/knowledge/claude-rules/react-components.md.stub +67 -0
- package/dist/knowledge/claude-rules/schema-yaml.md.stub +83 -0
- package/dist/knowledge/claude-rules/security.md.stub +164 -0
- package/dist/knowledge/cursor-rules/antd-deprecations.mdc.stub +62 -0
- package/dist/knowledge/cursor-rules/basemodel-readonly.mdc.stub +66 -0
- package/dist/knowledge/cursor-rules/baserequest-readonly.mdc.stub +74 -0
- package/dist/knowledge/cursor-rules/baseresource-readonly.mdc.stub +78 -0
- package/dist/knowledge/cursor-rules/laravel-controller.mdc.stub +421 -0
- package/dist/knowledge/cursor-rules/laravel-request.mdc.stub +112 -0
- package/dist/knowledge/cursor-rules/laravel-resource.mdc.stub +73 -0
- package/dist/knowledge/cursor-rules/laravel-review.mdc.stub +69 -0
- package/dist/knowledge/cursor-rules/laravel-testing.mdc.stub +138 -0
- package/dist/knowledge/cursor-rules/laravel.mdc.stub +138 -0
- package/dist/knowledge/cursor-rules/migrations-workflow.mdc.stub +224 -0
- package/dist/knowledge/cursor-rules/model-editable.mdc.stub +120 -0
- package/dist/knowledge/cursor-rules/omnify-migrations.mdc.stub +109 -0
- package/dist/knowledge/cursor-rules/omnify-schema.mdc.stub +358 -0
- package/dist/knowledge/cursor-rules/omnify.mdc.stub +58 -0
- package/dist/knowledge/cursor-rules/react-design.mdc.stub +693 -0
- package/dist/knowledge/cursor-rules/react-form.mdc.stub +292 -0
- package/dist/knowledge/cursor-rules/react-services.mdc.stub +304 -0
- package/dist/knowledge/cursor-rules/react.mdc.stub +336 -0
- package/dist/knowledge/cursor-rules/request-editable.mdc.stub +111 -0
- package/dist/knowledge/cursor-rules/resource-editable.mdc.stub +125 -0
- package/dist/knowledge/cursor-rules/schema-create.mdc.stub +440 -0
- package/dist/knowledge/cursor-rules/validation-rules.mdc.stub +181 -0
- package/dist/knowledge/laravel/README.md.stub +59 -0
- package/dist/knowledge/laravel/architecture.md.stub +424 -0
- package/dist/knowledge/laravel/authentication.md.stub +588 -0
- package/dist/knowledge/laravel/controller.md.stub +484 -0
- package/dist/knowledge/laravel/datetime.md.stub +334 -0
- package/dist/knowledge/laravel/migrations-team.md.stub +376 -0
- package/dist/knowledge/laravel/openapi.md.stub +449 -0
- package/dist/knowledge/laravel/request.md.stub +450 -0
- package/dist/knowledge/laravel/resource.md.stub +516 -0
- package/dist/knowledge/laravel/service.md.stub +503 -0
- package/dist/knowledge/laravel/testing.md.stub +1504 -0
- package/dist/knowledge/omnify/antdesign-guide.md.stub +401 -0
- package/dist/knowledge/omnify/config-guide.md.stub +405 -0
- package/dist/knowledge/omnify/japan-guide.md.stub +186 -0
- package/dist/knowledge/omnify/laravel-guide.md.stub +61 -0
- package/dist/knowledge/omnify/partial-schema-guide.md.stub +353 -0
- package/dist/knowledge/omnify/react-form-guide.md.stub +225 -0
- package/dist/knowledge/omnify/schema-guide.md.stub +144 -0
- package/dist/knowledge/omnify/typescript-guide.md.stub +337 -0
- package/dist/knowledge/react/README.md.stub +221 -0
- package/dist/knowledge/react/antd-guide.md +528 -0
- package/dist/knowledge/react/antd-guide.md.stub +528 -0
- package/dist/knowledge/react/checklist.md.stub +108 -0
- package/dist/knowledge/react/datetime-guide.md.stub +137 -0
- package/dist/knowledge/react/design-philosophy.md.stub +363 -0
- package/dist/knowledge/react/i18n-guide.md.stub +211 -0
- package/dist/knowledge/react/laravel-integration.md.stub +181 -0
- package/dist/knowledge/react/service-pattern.md.stub +180 -0
- package/dist/knowledge/react/tanstack-query.md.stub +339 -0
- package/dist/knowledge/react/types-guide.md +669 -0
- package/dist/knowledge/react/types-guide.md.stub +669 -0
- package/dist/knowledge/workflows/bug-fix.md.stub +201 -0
- package/dist/knowledge/workflows/code-review.md.stub +164 -0
- package/dist/knowledge/workflows/new-feature.md.stub +327 -0
- package/dist/plugin-M95GyBll.d.cts +191 -0
- package/dist/plugin-M95GyBll.d.ts +191 -0
- package/dist/plugin.cjs +573 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +2 -0
- package/dist/plugin.d.ts +2 -0
- package/dist/plugin.js +15 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# Omnify TypeScript Generator Guide
|
|
2
|
+
|
|
3
|
+
This guide covers TypeScript-specific features and generated code patterns for Omnify.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
Install the runtime package for React components, hooks, and utilities:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @famgia/omnify-react
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// omnify.config.ts
|
|
15
|
+
import typescriptPlugin from '@famgia/omnify-typescript/plugin';
|
|
16
|
+
|
|
17
|
+
export default defineConfig({
|
|
18
|
+
plugins: [
|
|
19
|
+
typescriptPlugin({
|
|
20
|
+
modelsPath: 'node_modules/.omnify/schemas',
|
|
21
|
+
}),
|
|
22
|
+
],
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Benefits:**
|
|
27
|
+
- Clean project structure (generated code in node_modules)
|
|
28
|
+
- Runtime code versioned separately (update via npm)
|
|
29
|
+
- No accidental edits to runtime utilities
|
|
30
|
+
- Prisma-like developer experience
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Create new project (recommended)
|
|
36
|
+
npx @famgia/omnify create-laravel-project my-app
|
|
37
|
+
cd my-app
|
|
38
|
+
|
|
39
|
+
# Or initialize in existing project
|
|
40
|
+
npx @famgia/omnify init
|
|
41
|
+
|
|
42
|
+
# Generate TypeScript types
|
|
43
|
+
npx @famgia/omnify generate
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Generated Files
|
|
47
|
+
|
|
48
|
+
When you run `npx @famgia/omnify generate`, the following TypeScript files are generated:
|
|
49
|
+
|
|
50
|
+
- `base/*.ts` - Base model interfaces
|
|
51
|
+
- `enum/*.ts` - Enum types with multi-locale labels
|
|
52
|
+
- `rules/*.ts` - Ant Design compatible validation rules
|
|
53
|
+
|
|
54
|
+
## Type Generation
|
|
55
|
+
|
|
56
|
+
### Object Schema → Interface
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
# yaml-language-server: $schema=./node_modules/.omnify/combined-schema.json
|
|
60
|
+
name: User
|
|
61
|
+
properties:
|
|
62
|
+
id:
|
|
63
|
+
type: BigInt
|
|
64
|
+
required: true
|
|
65
|
+
name:
|
|
66
|
+
type: String
|
|
67
|
+
required: true
|
|
68
|
+
maxLength: 255
|
|
69
|
+
email:
|
|
70
|
+
type: String
|
|
71
|
+
required: true
|
|
72
|
+
unique: true
|
|
73
|
+
profile:
|
|
74
|
+
type: Json
|
|
75
|
+
createdAt:
|
|
76
|
+
type: DateTime
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Generated:
|
|
80
|
+
```typescript
|
|
81
|
+
export interface User {
|
|
82
|
+
id: number;
|
|
83
|
+
name: string;
|
|
84
|
+
email: string;
|
|
85
|
+
profile: Record<string, unknown> | null;
|
|
86
|
+
createdAt: Date | null;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Type Mapping
|
|
91
|
+
|
|
92
|
+
| Schema Type | TypeScript Type |
|
|
93
|
+
| ------------- | -------------------------- |
|
|
94
|
+
| `String` | `string` |
|
|
95
|
+
| `Text` | `string` |
|
|
96
|
+
| `MediumText` | `string` |
|
|
97
|
+
| `LongText` | `string` |
|
|
98
|
+
| `TinyInt` | `number` |
|
|
99
|
+
| `Int` | `number` |
|
|
100
|
+
| `BigInt` | `number` |
|
|
101
|
+
| `Float` | `number` |
|
|
102
|
+
| `Decimal` | `number` |
|
|
103
|
+
| `Boolean` | `boolean` |
|
|
104
|
+
| `Date` | `Date` |
|
|
105
|
+
| `DateTime` | `Date` |
|
|
106
|
+
| `Timestamp` | `Date` |
|
|
107
|
+
| `Json` | `Record<string, unknown>` |
|
|
108
|
+
| `EnumRef` | Generated enum type |
|
|
109
|
+
| `Association` | Related model type / array |
|
|
110
|
+
|
|
111
|
+
## Hidden Schemas
|
|
112
|
+
|
|
113
|
+
Schemas with `options.hidden: true` are skipped for TypeScript generation:
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
name: AppCache
|
|
117
|
+
options:
|
|
118
|
+
hidden: true # No TypeScript interface generated
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Use cases:
|
|
122
|
+
- System tables (cache, sessions, jobs)
|
|
123
|
+
- Tables that don't need frontend types
|
|
124
|
+
|
|
125
|
+
## Enum Generation (Multi-locale)
|
|
126
|
+
|
|
127
|
+
```yaml
|
|
128
|
+
# schemas/PostStatus.yaml
|
|
129
|
+
name: PostStatus
|
|
130
|
+
kind: enum
|
|
131
|
+
displayName:
|
|
132
|
+
ja: 投稿ステータス
|
|
133
|
+
en: Post Status
|
|
134
|
+
values:
|
|
135
|
+
draft:
|
|
136
|
+
ja: 下書き
|
|
137
|
+
en: Draft
|
|
138
|
+
published:
|
|
139
|
+
ja: 公開済み
|
|
140
|
+
en: Published
|
|
141
|
+
archived:
|
|
142
|
+
ja: アーカイブ
|
|
143
|
+
en: Archived
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Generated:
|
|
147
|
+
```typescript
|
|
148
|
+
export const PostStatus = {
|
|
149
|
+
draft: 'draft',
|
|
150
|
+
published: 'published',
|
|
151
|
+
archived: 'archived',
|
|
152
|
+
} as const;
|
|
153
|
+
|
|
154
|
+
export type PostStatus = typeof PostStatus[keyof typeof PostStatus];
|
|
155
|
+
|
|
156
|
+
// Multi-locale labels
|
|
157
|
+
export const PostStatusLabels: Record<PostStatus, Record<string, string>> = {
|
|
158
|
+
draft: { ja: '下書き', en: 'Draft' },
|
|
159
|
+
published: { ja: '公開済み', en: 'Published' },
|
|
160
|
+
archived: { ja: 'アーカイブ', en: 'Archived' },
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Get label for specific locale
|
|
164
|
+
export function getPostStatusLabel(value: PostStatus, locale: string = 'en'): string {
|
|
165
|
+
return PostStatusLabels[value]?.[locale] ?? PostStatusLabels[value]?.['en'] ?? value;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Helper functions
|
|
169
|
+
export const PostStatusValues = Object.values(PostStatus);
|
|
170
|
+
export function isPostStatus(value: unknown): value is PostStatus {
|
|
171
|
+
return PostStatusValues.includes(value as PostStatus);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Validation Rules (Ant Design)
|
|
176
|
+
|
|
177
|
+
Omnify generates Ant Design compatible validation rules in `rules/` directory.
|
|
178
|
+
|
|
179
|
+
**See detailed guide:** `.claude/omnify/antdesign-guide.md`
|
|
180
|
+
|
|
181
|
+
Quick example:
|
|
182
|
+
```tsx
|
|
183
|
+
import { Form, Input } from 'antd';
|
|
184
|
+
import { getUserRules, getUserPropertyDisplayName } from './types/model/rules/User.rules';
|
|
185
|
+
|
|
186
|
+
function UserForm({ locale = 'ja' }) {
|
|
187
|
+
const rules = getUserRules(locale);
|
|
188
|
+
return (
|
|
189
|
+
<Form>
|
|
190
|
+
<Form.Item name="name" label={getUserPropertyDisplayName('name', locale)} rules={rules.name}>
|
|
191
|
+
<Input />
|
|
192
|
+
</Form.Item>
|
|
193
|
+
</Form>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Association Types
|
|
199
|
+
|
|
200
|
+
### ManyToOne
|
|
201
|
+
```yaml
|
|
202
|
+
author:
|
|
203
|
+
type: Association
|
|
204
|
+
relation: ManyToOne
|
|
205
|
+
target: User
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Generated:
|
|
209
|
+
```typescript
|
|
210
|
+
export interface Post {
|
|
211
|
+
authorId: number;
|
|
212
|
+
author?: User; // Optional: loaded relation
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### OneToMany
|
|
217
|
+
```yaml
|
|
218
|
+
posts:
|
|
219
|
+
type: Association
|
|
220
|
+
relation: OneToMany
|
|
221
|
+
target: Post
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Generated:
|
|
225
|
+
```typescript
|
|
226
|
+
export interface User {
|
|
227
|
+
posts?: Post[]; // Optional: loaded relation array
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### ManyToMany
|
|
232
|
+
```yaml
|
|
233
|
+
tags:
|
|
234
|
+
type: Association
|
|
235
|
+
relation: ManyToMany
|
|
236
|
+
target: Tag
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Generated:
|
|
240
|
+
```typescript
|
|
241
|
+
export interface Post {
|
|
242
|
+
tags?: Tag[]; // Optional: loaded relation array
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Nullable Fields
|
|
247
|
+
|
|
248
|
+
Fields without `required: true` are nullable:
|
|
249
|
+
|
|
250
|
+
```yaml
|
|
251
|
+
description:
|
|
252
|
+
type: LongText # No required: true
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Generated:
|
|
256
|
+
```typescript
|
|
257
|
+
description: string | null;
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Using Generated Types
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
import { User, Post, PostStatus, isPostStatus } from './types/omnify-types';
|
|
264
|
+
|
|
265
|
+
// Type-safe object creation
|
|
266
|
+
const user: User = {
|
|
267
|
+
id: 1,
|
|
268
|
+
name: 'John',
|
|
269
|
+
email: 'john@example.com',
|
|
270
|
+
profile: null,
|
|
271
|
+
createdAt: new Date(),
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// Enum usage
|
|
275
|
+
const status: PostStatus = PostStatus.draft;
|
|
276
|
+
|
|
277
|
+
// Type guard
|
|
278
|
+
function handleStatus(value: unknown) {
|
|
279
|
+
if (isPostStatus(value)) {
|
|
280
|
+
console.log('Valid status:', value);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Commands
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
# Create new project
|
|
289
|
+
npx @famgia/omnify create-laravel-project my-app
|
|
290
|
+
|
|
291
|
+
# Generate TypeScript types
|
|
292
|
+
npx @famgia/omnify generate
|
|
293
|
+
|
|
294
|
+
# Force regenerate all files
|
|
295
|
+
npx @famgia/omnify generate --force
|
|
296
|
+
|
|
297
|
+
# Only generate TypeScript types
|
|
298
|
+
npx @famgia/omnify generate --types-only
|
|
299
|
+
|
|
300
|
+
# Validate schemas
|
|
301
|
+
npx @famgia/omnify validate
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Configuration
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
// omnify.config.ts
|
|
308
|
+
import { defineConfig } from '@famgia/omnify';
|
|
309
|
+
import typescript from '@famgia/omnify-typescript/plugin';
|
|
310
|
+
|
|
311
|
+
export default defineConfig({
|
|
312
|
+
schemasDir: './schemas',
|
|
313
|
+
lockFilePath: './.omnify.lock',
|
|
314
|
+
|
|
315
|
+
plugins: [
|
|
316
|
+
typescript({
|
|
317
|
+
// Output path for TypeScript files
|
|
318
|
+
path: './resources/ts/types/models',
|
|
319
|
+
|
|
320
|
+
// Generate Ant Design validation rules
|
|
321
|
+
generateRules: true,
|
|
322
|
+
}),
|
|
323
|
+
],
|
|
324
|
+
|
|
325
|
+
locale: {
|
|
326
|
+
locales: ['ja', 'en'],
|
|
327
|
+
defaultLocale: 'ja',
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Configuration Options
|
|
333
|
+
|
|
334
|
+
| Option | Type | Default | Description |
|
|
335
|
+
| --------------- | --------- | ------------------- | ------------------------------------ |
|
|
336
|
+
| `path` | `string` | `./src/types/model` | TypeScript output directory |
|
|
337
|
+
| `generateRules` | `boolean` | `true` | Generate Ant Design validation rules |
|
|
@@ -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) | `@omnify/schemas` (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)
|