@famgia/omnify-laravel 0.0.89 → 0.0.90
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/dist/{chunk-V7LWJ6OM.js → chunk-2QSKZS63.js} +11 -1
- package/dist/{chunk-V7LWJ6OM.js.map → chunk-2QSKZS63.js.map} +1 -1
- package/dist/index.cjs +10 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin.cjs +10 -0
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.js +1 -1
- package/package.json +4 -4
- package/stubs/ai-guides/README.md.stub +95 -0
- package/stubs/ai-guides/claude-omnify/react-form-guide.md.stub +259 -0
- package/stubs/ai-guides/cursor/omnify.mdc.stub +58 -0
package/dist/plugin.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@famgia/omnify-laravel",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.90",
|
|
4
4
|
"description": "Laravel migration and TypeScript type generator for omnify-schema",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@famgia/omnify-types": "0.0.
|
|
29
|
-
"@famgia/omnify-
|
|
30
|
-
"@famgia/omnify-
|
|
28
|
+
"@famgia/omnify-types": "0.0.79",
|
|
29
|
+
"@famgia/omnify-core": "0.0.81",
|
|
30
|
+
"@famgia/omnify-atlas": "0.0.75"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"build": "tsup",
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# .claude/omnify Documentation
|
|
2
|
+
|
|
3
|
+
> AI-focused documentation for Omnify projects. Navigate by PURPOSE.
|
|
4
|
+
|
|
5
|
+
## Quick Navigation
|
|
6
|
+
|
|
7
|
+
| Purpose | Folder | When to Read |
|
|
8
|
+
| ------------------------ | ---------------------------- | --------------------------------- |
|
|
9
|
+
| **AI Personas** | [agents/](./agents/) | Select agent for task |
|
|
10
|
+
| **HOW to do tasks** | [workflows/](./workflows/) | New feature, bug fix, code review |
|
|
11
|
+
| **WHAT rules to follow** | [rules/](./rules/) | Security, performance, naming |
|
|
12
|
+
| **HOW to implement** | [guides/](./guides/) | Controller, Resource, Testing |
|
|
13
|
+
| **Quick verify** | [checklists/](./checklists/) | Before commit, PR review |
|
|
14
|
+
|
|
15
|
+
## Agents
|
|
16
|
+
|
|
17
|
+
| Agent | Role | When to Use |
|
|
18
|
+
| ----------------------------------- | -------------- | ------------------------- |
|
|
19
|
+
| [@developer](./agents/developer.md) | Implementation | Writing code, features |
|
|
20
|
+
| [@reviewer](./agents/reviewer.md) | Code Review | PR review, security audit |
|
|
21
|
+
| [@architect](./agents/architect.md) | System Design | Schema, API design |
|
|
22
|
+
| [@tester](./agents/tester.md) | Testing | Writing tests |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Structure
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
.claude/omnify/
|
|
30
|
+
├── agents/ # AI Personas (WHO)
|
|
31
|
+
│ ├── developer.md # Implementation agent
|
|
32
|
+
│ ├── reviewer.md # Code review agent
|
|
33
|
+
│ ├── architect.md # System design agent
|
|
34
|
+
│ └── tester.md # Testing agent
|
|
35
|
+
│
|
|
36
|
+
├── workflows/ # Step-by-step processes (HOW)
|
|
37
|
+
│ ├── new-feature.md # Create new feature
|
|
38
|
+
│ ├── bug-fix.md # Fix a bug
|
|
39
|
+
│ └── code-review.md # Review PR
|
|
40
|
+
│
|
|
41
|
+
├── rules/ # Must-follow rules (WHAT)
|
|
42
|
+
│ ├── security.md # Security rules
|
|
43
|
+
│ ├── performance.md # Performance & quality rules
|
|
44
|
+
│ └── naming.md # Naming conventions
|
|
45
|
+
│
|
|
46
|
+
├── guides/ # Implementation guides (REFERENCE)
|
|
47
|
+
│ ├── omnify/ # Omnify tool documentation
|
|
48
|
+
│ ├── laravel/ # Laravel implementation
|
|
49
|
+
│ └── react/ # React implementation
|
|
50
|
+
│
|
|
51
|
+
└── checklists/ # Quick verification (QA)
|
|
52
|
+
├── backend.md
|
|
53
|
+
└── react.md
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## By Task Type
|
|
59
|
+
|
|
60
|
+
### New Feature
|
|
61
|
+
|
|
62
|
+
1. Read [workflows/new-feature.md](./workflows/new-feature.md)
|
|
63
|
+
2. Follow step-by-step: Schema → API → Tests → OpenAPI → Frontend
|
|
64
|
+
|
|
65
|
+
### Bug Fix
|
|
66
|
+
|
|
67
|
+
1. Read [workflows/bug-fix.md](./workflows/bug-fix.md)
|
|
68
|
+
2. Reproduce → Locate → Test → Fix → Verify
|
|
69
|
+
|
|
70
|
+
### Code Review
|
|
71
|
+
|
|
72
|
+
1. Read [workflows/code-review.md](./workflows/code-review.md)
|
|
73
|
+
2. Security → Performance → Quality → Tests → Approve
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Debugging Quick Reference
|
|
78
|
+
|
|
79
|
+
| Issue | Check |
|
|
80
|
+
| ---------------------- | ------------------------------ |
|
|
81
|
+
| API returns wrong data | `guides/laravel/resource.md` |
|
|
82
|
+
| Validation fails | `guides/laravel/request.md` |
|
|
83
|
+
| 404 error | Route + Model binding |
|
|
84
|
+
| N+1 queries | `rules/performance.md` |
|
|
85
|
+
| Security concern | `rules/security.md` |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Key Principles
|
|
90
|
+
|
|
91
|
+
1. **Schema-First**: Start with `schemas/` folder
|
|
92
|
+
2. **Thin Controllers**: Validate → Delegate → Respond
|
|
93
|
+
3. **UTC Everywhere**: Store UTC, send ISO 8601
|
|
94
|
+
4. **Test Everything**: 正常系 + 異常系
|
|
95
|
+
5. **Don't Over-Engineer**: Simple CRUD = Controller + Model
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# Omnify React Form Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to build forms using Omnify generated schemas with **Ant Design** and **TanStack Query**.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Form } from 'antd';
|
|
9
|
+
import { useFormMutation } from '@/omnify/hooks';
|
|
10
|
+
import { type CustomerCreate } from '@/omnify/schemas';
|
|
11
|
+
import { CustomerForm } from '@/features/customers';
|
|
12
|
+
import { api } from '@/lib/api';
|
|
13
|
+
|
|
14
|
+
function CreateCustomerPage() {
|
|
15
|
+
const [form] = Form.useForm<CustomerCreate>();
|
|
16
|
+
|
|
17
|
+
const mutation = useFormMutation<CustomerCreate>({
|
|
18
|
+
form,
|
|
19
|
+
mutationFn: (data) => api.post('/customers', data),
|
|
20
|
+
invalidateKeys: [['customers']],
|
|
21
|
+
successMessage: 'Customer created successfully',
|
|
22
|
+
onSuccess: () => form.resetFields(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<CustomerForm
|
|
27
|
+
form={form}
|
|
28
|
+
onSubmit={mutation.mutate}
|
|
29
|
+
loading={mutation.isPending}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## useFormMutation Hook
|
|
36
|
+
|
|
37
|
+
Location: `resources/ts/omnify/hooks/use-form-mutation.ts`
|
|
38
|
+
|
|
39
|
+
### Usage with Types
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { useFormMutation } from '@/omnify/hooks';
|
|
43
|
+
import { type CustomerCreate } from '@/omnify/schemas';
|
|
44
|
+
|
|
45
|
+
// With type parameter for type safety
|
|
46
|
+
const mutation = useFormMutation<CustomerCreate>({
|
|
47
|
+
form,
|
|
48
|
+
mutationFn: (data) => api.post('/customers', data),
|
|
49
|
+
invalidateKeys: [['customers']],
|
|
50
|
+
successMessage: 'Saved successfully',
|
|
51
|
+
onSuccess: () => form.resetFields(),
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Options
|
|
56
|
+
|
|
57
|
+
| Option | Type | Description |
|
|
58
|
+
|--------|------|-------------|
|
|
59
|
+
| `form` | `FormInstance<T>` | Ant Design form instance (required) |
|
|
60
|
+
| `mutationFn` | `(data: T) => Promise` | API call function (required) |
|
|
61
|
+
| `invalidateKeys` | `string[][]` | Query keys to invalidate on success |
|
|
62
|
+
| `successMessage` | `string` | Toast message on success |
|
|
63
|
+
| `onSuccess` | `(data) => void` | Callback after success |
|
|
64
|
+
| `onError` | `(error) => void` | Callback after error |
|
|
65
|
+
|
|
66
|
+
### Laravel Error Handling
|
|
67
|
+
|
|
68
|
+
The hook automatically handles Laravel validation errors (422):
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"message": "The given data was invalid.",
|
|
73
|
+
"errors": {
|
|
74
|
+
"email": ["The email has already been taken."]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Japanese Form Components
|
|
80
|
+
|
|
81
|
+
Omnify provides specialized components for Japanese data input.
|
|
82
|
+
|
|
83
|
+
### OmnifyForm.JapaneseName
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { OmnifyForm } from '@/omnify/components';
|
|
87
|
+
|
|
88
|
+
<OmnifyForm.JapaneseName
|
|
89
|
+
schemas={customerSchemas}
|
|
90
|
+
i18n={customerI18n}
|
|
91
|
+
prefix="name" // name_lastname, name_firstname, etc.
|
|
92
|
+
required // Show required asterisk
|
|
93
|
+
showKana={true} // Show kana fields (default)
|
|
94
|
+
/>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Fields:** `{prefix}_lastname`, `{prefix}_firstname`, `{prefix}_kana_lastname`, `{prefix}_kana_firstname`
|
|
98
|
+
|
|
99
|
+
### OmnifyForm.JapaneseAddress
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { OmnifyForm } from '@/omnify/components';
|
|
103
|
+
|
|
104
|
+
<OmnifyForm.JapaneseAddress
|
|
105
|
+
form={form}
|
|
106
|
+
schemas={customerSchemas}
|
|
107
|
+
i18n={customerI18n}
|
|
108
|
+
prefix="address"
|
|
109
|
+
enablePostalLookup={true} // Postal code → address lookup
|
|
110
|
+
/>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Fields:** `{prefix}_postal_code`, `{prefix}_prefecture`, `{prefix}_address1`, `{prefix}_address2`, `{prefix}_address3`
|
|
114
|
+
|
|
115
|
+
**Options:**
|
|
116
|
+
- `enablePostalLookup` - Enable postal code search
|
|
117
|
+
- `autoSearch` - Auto-search when 7 digits entered
|
|
118
|
+
- `usePrefectureId` - Use numeric ID instead of string enum
|
|
119
|
+
|
|
120
|
+
### OmnifyForm.JapaneseBank
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
import { OmnifyForm } from '@/omnify/components';
|
|
124
|
+
|
|
125
|
+
<OmnifyForm.JapaneseBank
|
|
126
|
+
schemas={customerSchemas}
|
|
127
|
+
i18n={customerI18n}
|
|
128
|
+
prefix="bank"
|
|
129
|
+
/>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Fields:** `{prefix}_bank_code`, `{prefix}_branch_code`, `{prefix}_account_type`, `{prefix}_account_number`, `{prefix}_account_holder`
|
|
133
|
+
|
|
134
|
+
Account type options auto-loaded from `BankAccountType` enum with i18n.
|
|
135
|
+
|
|
136
|
+
## Complete Form Example
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import { Form, Input, Button, Card, Space, Divider } from 'antd';
|
|
140
|
+
import type { FormInstance } from 'antd';
|
|
141
|
+
import { zodRule, setZodLocale } from '@/omnify/lib';
|
|
142
|
+
import { OmnifyForm } from '@/omnify/components';
|
|
143
|
+
import {
|
|
144
|
+
type Customer, type CustomerCreate,
|
|
145
|
+
customerSchemas, customerI18n,
|
|
146
|
+
getCustomerFieldLabel, getCustomerFieldPlaceholder,
|
|
147
|
+
} from '@/omnify/schemas';
|
|
148
|
+
|
|
149
|
+
const LOCALE = 'ja';
|
|
150
|
+
|
|
151
|
+
interface CustomerFormProps {
|
|
152
|
+
form: FormInstance<CustomerCreate>;
|
|
153
|
+
initialValues?: Partial<Customer>;
|
|
154
|
+
onSubmit: (values: CustomerCreate) => void;
|
|
155
|
+
loading?: boolean;
|
|
156
|
+
isEdit?: boolean;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function CustomerForm({ form, initialValues, onSubmit, loading, isEdit }: CustomerFormProps) {
|
|
160
|
+
setZodLocale(LOCALE);
|
|
161
|
+
|
|
162
|
+
const label = (key: string) => getCustomerFieldLabel(key, LOCALE);
|
|
163
|
+
const placeholder = (key: string) => getCustomerFieldPlaceholder(key, LOCALE);
|
|
164
|
+
const rule = (key: keyof typeof customerSchemas) => zodRule(customerSchemas[key], label(key));
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<Card>
|
|
168
|
+
<Form form={form} layout="horizontal" labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}
|
|
169
|
+
initialValues={initialValues} onFinish={onSubmit} style={{ maxWidth: 800 }}>
|
|
170
|
+
|
|
171
|
+
<Divider orientation="left">Name</Divider>
|
|
172
|
+
<OmnifyForm.JapaneseName schemas={customerSchemas} i18n={customerI18n} prefix="name" required />
|
|
173
|
+
|
|
174
|
+
<Divider orientation="left">Contact</Divider>
|
|
175
|
+
<Form.Item name="phone" label={label('phone')} rules={[rule('phone')]}>
|
|
176
|
+
<Input placeholder={placeholder('phone')} />
|
|
177
|
+
</Form.Item>
|
|
178
|
+
<Form.Item name="email" label={label('email')} rules={[rule('email')]}>
|
|
179
|
+
<Input type="email" placeholder={placeholder('email')} />
|
|
180
|
+
</Form.Item>
|
|
181
|
+
|
|
182
|
+
<Divider orientation="left">Address</Divider>
|
|
183
|
+
<OmnifyForm.JapaneseAddress form={form} schemas={customerSchemas} i18n={customerI18n}
|
|
184
|
+
prefix="address" enablePostalLookup={true} />
|
|
185
|
+
|
|
186
|
+
<Divider orientation="left">Bank Account</Divider>
|
|
187
|
+
<OmnifyForm.JapaneseBank schemas={customerSchemas} i18n={customerI18n} prefix="bank" />
|
|
188
|
+
|
|
189
|
+
<Form.Item wrapperCol={{ offset: 6, span: 18 }}>
|
|
190
|
+
<Space>
|
|
191
|
+
<Button type="primary" htmlType="submit" loading={loading}>
|
|
192
|
+
{isEdit ? 'Update' : 'Create'}
|
|
193
|
+
</Button>
|
|
194
|
+
</Space>
|
|
195
|
+
</Form.Item>
|
|
196
|
+
</Form>
|
|
197
|
+
</Card>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Zod Validation with i18n
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
import { zodRule, setZodLocale } from '@/omnify/lib';
|
|
206
|
+
|
|
207
|
+
// Set locale once at component level
|
|
208
|
+
setZodLocale('ja');
|
|
209
|
+
|
|
210
|
+
// Use zodRule for field validation
|
|
211
|
+
<Form.Item name="email" label={label('email')} rules={[zodRule(customerSchemas.email, label('email'))]}>
|
|
212
|
+
<Input />
|
|
213
|
+
</Form.Item>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Kana Validation Rules
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
import { kanaString, KATAKANA_PATTERN } from '@/omnify/lib/rules';
|
|
220
|
+
|
|
221
|
+
// Full-width katakana (default)
|
|
222
|
+
const kanaSchema = kanaString();
|
|
223
|
+
|
|
224
|
+
// Custom options
|
|
225
|
+
const kanaSchema = kanaString({
|
|
226
|
+
fullWidthKatakana: true,
|
|
227
|
+
hiragana: true,
|
|
228
|
+
allowNumbers: true,
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## File Structure
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
resources/ts/omnify/
|
|
236
|
+
├── components/
|
|
237
|
+
│ ├── JapaneseNameField.tsx
|
|
238
|
+
│ ├── JapaneseAddressField.tsx
|
|
239
|
+
│ └── JapaneseBankField.tsx
|
|
240
|
+
├── enum/
|
|
241
|
+
│ └── plugin/
|
|
242
|
+
│ ├── Prefecture.ts
|
|
243
|
+
│ └── BankAccountType.ts
|
|
244
|
+
├── hooks/
|
|
245
|
+
│ └── use-form-mutation.ts
|
|
246
|
+
├── lib/
|
|
247
|
+
│ ├── form-validation.ts
|
|
248
|
+
│ ├── zod-i18n.ts
|
|
249
|
+
│ └── rules/kana.ts
|
|
250
|
+
└── schemas/
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Tips
|
|
254
|
+
|
|
255
|
+
1. **Use type generics** - `useFormMutation<CustomerCreate>` for type safety
|
|
256
|
+
2. **Use `setZodLocale`** - Call once for localized validation messages
|
|
257
|
+
3. **Use OmnifyForm.* components** - Built-in i18n, validation, postal lookup
|
|
258
|
+
4. **Set `invalidateKeys`** - Auto-refresh lists after mutations
|
|
259
|
+
5. **Don't pass `form` to Name/Bank components** - Only Address needs it for postal lookup
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Omnify schema-driven code generation rules"
|
|
3
|
+
globs: ["schemas/**/*.yaml", "omnify.config.ts"]
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Omnify Schema Rules
|
|
8
|
+
|
|
9
|
+
This project uses Omnify for schema-driven code generation.
|
|
10
|
+
|
|
11
|
+
## Documentation
|
|
12
|
+
|
|
13
|
+
Read these files in `.claude/omnify/guides/omnify/`:
|
|
14
|
+
|
|
15
|
+
| File | Content |
|
|
16
|
+
| --------------------- | -------------------------------- |
|
|
17
|
+
| `schema-guide.md` | Base schema format |
|
|
18
|
+
| `config-guide.md` | Configuration (omnify.config.ts) |
|
|
19
|
+
| `laravel-guide.md` | Laravel generator |
|
|
20
|
+
| `typescript-guide.md` | TypeScript generator |
|
|
21
|
+
| `japan-guide.md` | Japanese field types |
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx omnify generate # Generate code from schemas
|
|
27
|
+
npx omnify validate # Validate all schemas
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Important
|
|
31
|
+
|
|
32
|
+
- **DO NOT** manually edit files in `database/migrations/omnify/`
|
|
33
|
+
- **DO NOT** manually edit files in `resources/ts/omnify/schemas/base/`
|
|
34
|
+
- **DO NOT** manually edit files in `app/Models/OmnifyBase/`
|
|
35
|
+
- Schema changes → Run `npx omnify generate`
|
|
36
|
+
|
|
37
|
+
## Schema Quick Reference
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
name: User
|
|
41
|
+
displayName:
|
|
42
|
+
ja: ユーザー
|
|
43
|
+
en: User
|
|
44
|
+
|
|
45
|
+
properties:
|
|
46
|
+
email:
|
|
47
|
+
type: Email
|
|
48
|
+
unique: true
|
|
49
|
+
name:
|
|
50
|
+
type: String
|
|
51
|
+
role:
|
|
52
|
+
type: EnumRef
|
|
53
|
+
target: UserRole
|
|
54
|
+
|
|
55
|
+
options:
|
|
56
|
+
timestamps: true
|
|
57
|
+
softDelete: true
|
|
58
|
+
```
|