@famgia/omnify-laravel 0.0.88 → 0.0.89

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 (46) hide show
  1. package/dist/{chunk-YVVAJA3T.js → chunk-V7LWJ6OM.js} +178 -12
  2. package/dist/chunk-V7LWJ6OM.js.map +1 -0
  3. package/dist/index.cjs +180 -11
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +48 -1
  6. package/dist/index.d.ts +48 -1
  7. package/dist/index.js +5 -1
  8. package/dist/plugin.cjs +176 -11
  9. package/dist/plugin.cjs.map +1 -1
  10. package/dist/plugin.js +1 -1
  11. package/package.json +5 -5
  12. package/scripts/postinstall.js +29 -36
  13. package/stubs/ai-guides/claude-agents/architect.md.stub +150 -0
  14. package/stubs/ai-guides/claude-agents/developer.md.stub +190 -0
  15. package/stubs/ai-guides/claude-agents/reviewer.md.stub +134 -0
  16. package/stubs/ai-guides/claude-agents/tester.md.stub +196 -0
  17. package/stubs/ai-guides/claude-checklists/backend.md.stub +112 -0
  18. package/stubs/ai-guides/claude-omnify/antdesign-guide.md.stub +401 -0
  19. package/stubs/ai-guides/claude-omnify/config-guide.md.stub +253 -0
  20. package/stubs/ai-guides/claude-omnify/japan-guide.md.stub +186 -0
  21. package/stubs/ai-guides/claude-omnify/laravel-guide.md.stub +61 -0
  22. package/stubs/ai-guides/claude-omnify/schema-guide.md.stub +115 -0
  23. package/stubs/ai-guides/claude-omnify/typescript-guide.md.stub +310 -0
  24. package/stubs/ai-guides/claude-rules/naming.md.stub +364 -0
  25. package/stubs/ai-guides/claude-rules/performance.md.stub +251 -0
  26. package/stubs/ai-guides/claude-rules/security.md.stub +159 -0
  27. package/stubs/ai-guides/claude-workflows/bug-fix.md.stub +201 -0
  28. package/stubs/ai-guides/claude-workflows/code-review.md.stub +164 -0
  29. package/stubs/ai-guides/claude-workflows/new-feature.md.stub +327 -0
  30. package/stubs/ai-guides/cursor/laravel-controller.mdc.stub +391 -0
  31. package/stubs/ai-guides/cursor/laravel-request.mdc.stub +112 -0
  32. package/stubs/ai-guides/cursor/laravel-resource.mdc.stub +73 -0
  33. package/stubs/ai-guides/cursor/laravel-review.mdc.stub +69 -0
  34. package/stubs/ai-guides/cursor/laravel-testing.mdc.stub +138 -0
  35. package/stubs/ai-guides/cursor/laravel.mdc.stub +82 -0
  36. package/stubs/ai-guides/laravel/README.md.stub +59 -0
  37. package/stubs/ai-guides/laravel/architecture.md.stub +424 -0
  38. package/stubs/ai-guides/laravel/controller.md.stub +484 -0
  39. package/stubs/ai-guides/laravel/datetime.md.stub +334 -0
  40. package/stubs/ai-guides/laravel/openapi.md.stub +369 -0
  41. package/stubs/ai-guides/laravel/request.md.stub +450 -0
  42. package/stubs/ai-guides/laravel/resource.md.stub +516 -0
  43. package/stubs/ai-guides/laravel/service.md.stub +503 -0
  44. package/stubs/ai-guides/laravel/testing.md.stub +1504 -0
  45. package/ai-guides/laravel-guide.md +0 -461
  46. package/dist/chunk-YVVAJA3T.js.map +0 -1
@@ -0,0 +1,310 @@
1
+ # Omnify TypeScript Generator Guide
2
+
3
+ This guide covers TypeScript-specific features and generated code patterns for Omnify.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Create new project (recommended)
9
+ npx @famgia/omnify create-laravel-project my-app
10
+ cd my-app
11
+
12
+ # Or initialize in existing project
13
+ npx @famgia/omnify init
14
+
15
+ # Generate TypeScript types
16
+ npx @famgia/omnify generate
17
+ ```
18
+
19
+ ## Generated Files
20
+
21
+ When you run `npx @famgia/omnify generate`, the following TypeScript files are generated:
22
+
23
+ - `base/*.ts` - Base model interfaces
24
+ - `enum/*.ts` - Enum types with multi-locale labels
25
+ - `rules/*.ts` - Ant Design compatible validation rules
26
+
27
+ ## Type Generation
28
+
29
+ ### Object Schema → Interface
30
+
31
+ ```yaml
32
+ # yaml-language-server: $schema=./node_modules/.omnify/combined-schema.json
33
+ name: User
34
+ properties:
35
+ id:
36
+ type: BigInt
37
+ required: true
38
+ name:
39
+ type: String
40
+ required: true
41
+ maxLength: 255
42
+ email:
43
+ type: String
44
+ required: true
45
+ unique: true
46
+ profile:
47
+ type: Json
48
+ createdAt:
49
+ type: DateTime
50
+ ```
51
+
52
+ Generated:
53
+ ```typescript
54
+ export interface User {
55
+ id: number;
56
+ name: string;
57
+ email: string;
58
+ profile: Record<string, unknown> | null;
59
+ createdAt: Date | null;
60
+ }
61
+ ```
62
+
63
+ ## Type Mapping
64
+
65
+ | Schema Type | TypeScript Type |
66
+ |-------------|-----------------|
67
+ | `String` | `string` |
68
+ | `Text` | `string` |
69
+ | `MediumText` | `string` |
70
+ | `LongText` | `string` |
71
+ | `TinyInt` | `number` |
72
+ | `Int` | `number` |
73
+ | `BigInt` | `number` |
74
+ | `Float` | `number` |
75
+ | `Decimal` | `number` |
76
+ | `Boolean` | `boolean` |
77
+ | `Date` | `Date` |
78
+ | `DateTime` | `Date` |
79
+ | `Timestamp` | `Date` |
80
+ | `Json` | `Record<string, unknown>` |
81
+ | `EnumRef` | Generated enum type |
82
+ | `Association` | Related model type / array |
83
+
84
+ ## Hidden Schemas
85
+
86
+ Schemas with `options.hidden: true` are skipped for TypeScript generation:
87
+
88
+ ```yaml
89
+ name: AppCache
90
+ options:
91
+ hidden: true # No TypeScript interface generated
92
+ ```
93
+
94
+ Use cases:
95
+ - System tables (cache, sessions, jobs)
96
+ - Tables that don't need frontend types
97
+
98
+ ## Enum Generation (Multi-locale)
99
+
100
+ ```yaml
101
+ # schemas/PostStatus.yaml
102
+ name: PostStatus
103
+ kind: enum
104
+ displayName:
105
+ ja: 投稿ステータス
106
+ en: Post Status
107
+ values:
108
+ draft:
109
+ ja: 下書き
110
+ en: Draft
111
+ published:
112
+ ja: 公開済み
113
+ en: Published
114
+ archived:
115
+ ja: アーカイブ
116
+ en: Archived
117
+ ```
118
+
119
+ Generated:
120
+ ```typescript
121
+ export const PostStatus = {
122
+ draft: 'draft',
123
+ published: 'published',
124
+ archived: 'archived',
125
+ } as const;
126
+
127
+ export type PostStatus = typeof PostStatus[keyof typeof PostStatus];
128
+
129
+ // Multi-locale labels
130
+ export const PostStatusLabels: Record<PostStatus, Record<string, string>> = {
131
+ draft: { ja: '下書き', en: 'Draft' },
132
+ published: { ja: '公開済み', en: 'Published' },
133
+ archived: { ja: 'アーカイブ', en: 'Archived' },
134
+ };
135
+
136
+ // Get label for specific locale
137
+ export function getPostStatusLabel(value: PostStatus, locale: string = 'en'): string {
138
+ return PostStatusLabels[value]?.[locale] ?? PostStatusLabels[value]?.['en'] ?? value;
139
+ }
140
+
141
+ // Helper functions
142
+ export const PostStatusValues = Object.values(PostStatus);
143
+ export function isPostStatus(value: unknown): value is PostStatus {
144
+ return PostStatusValues.includes(value as PostStatus);
145
+ }
146
+ ```
147
+
148
+ ## Validation Rules (Ant Design)
149
+
150
+ Omnify generates Ant Design compatible validation rules in `rules/` directory.
151
+
152
+ **See detailed guide:** `.claude/omnify/antdesign-guide.md`
153
+
154
+ Quick example:
155
+ ```tsx
156
+ import { Form, Input } from 'antd';
157
+ import { getUserRules, getUserPropertyDisplayName } from './types/model/rules/User.rules';
158
+
159
+ function UserForm({ locale = 'ja' }) {
160
+ const rules = getUserRules(locale);
161
+ return (
162
+ <Form>
163
+ <Form.Item name="name" label={getUserPropertyDisplayName('name', locale)} rules={rules.name}>
164
+ <Input />
165
+ </Form.Item>
166
+ </Form>
167
+ );
168
+ }
169
+ ```
170
+
171
+ ## Association Types
172
+
173
+ ### ManyToOne
174
+ ```yaml
175
+ author:
176
+ type: Association
177
+ relation: ManyToOne
178
+ target: User
179
+ ```
180
+
181
+ Generated:
182
+ ```typescript
183
+ export interface Post {
184
+ authorId: number;
185
+ author?: User; // Optional: loaded relation
186
+ }
187
+ ```
188
+
189
+ ### OneToMany
190
+ ```yaml
191
+ posts:
192
+ type: Association
193
+ relation: OneToMany
194
+ target: Post
195
+ ```
196
+
197
+ Generated:
198
+ ```typescript
199
+ export interface User {
200
+ posts?: Post[]; // Optional: loaded relation array
201
+ }
202
+ ```
203
+
204
+ ### ManyToMany
205
+ ```yaml
206
+ tags:
207
+ type: Association
208
+ relation: ManyToMany
209
+ target: Tag
210
+ ```
211
+
212
+ Generated:
213
+ ```typescript
214
+ export interface Post {
215
+ tags?: Tag[]; // Optional: loaded relation array
216
+ }
217
+ ```
218
+
219
+ ## Nullable Fields
220
+
221
+ Fields without `required: true` are nullable:
222
+
223
+ ```yaml
224
+ description:
225
+ type: LongText # No required: true
226
+ ```
227
+
228
+ Generated:
229
+ ```typescript
230
+ description: string | null;
231
+ ```
232
+
233
+ ## Using Generated Types
234
+
235
+ ```typescript
236
+ import { User, Post, PostStatus, isPostStatus } from './types/omnify-types';
237
+
238
+ // Type-safe object creation
239
+ const user: User = {
240
+ id: 1,
241
+ name: 'John',
242
+ email: 'john@example.com',
243
+ profile: null,
244
+ createdAt: new Date(),
245
+ };
246
+
247
+ // Enum usage
248
+ const status: PostStatus = PostStatus.draft;
249
+
250
+ // Type guard
251
+ function handleStatus(value: unknown) {
252
+ if (isPostStatus(value)) {
253
+ console.log('Valid status:', value);
254
+ }
255
+ }
256
+ ```
257
+
258
+ ## Commands
259
+
260
+ ```bash
261
+ # Create new project
262
+ npx @famgia/omnify create-laravel-project my-app
263
+
264
+ # Generate TypeScript types
265
+ npx @famgia/omnify generate
266
+
267
+ # Force regenerate all files
268
+ npx @famgia/omnify generate --force
269
+
270
+ # Only generate TypeScript types
271
+ npx @famgia/omnify generate --types-only
272
+
273
+ # Validate schemas
274
+ npx @famgia/omnify validate
275
+ ```
276
+
277
+ ## Configuration
278
+
279
+ ```typescript
280
+ // omnify.config.ts
281
+ import { defineConfig } from '@famgia/omnify';
282
+ import typescript from '@famgia/omnify-typescript/plugin';
283
+
284
+ export default defineConfig({
285
+ schemasDir: './schemas',
286
+ lockFilePath: './.omnify.lock',
287
+
288
+ plugins: [
289
+ typescript({
290
+ // Output path for TypeScript files
291
+ path: './resources/ts/types/models',
292
+
293
+ // Generate Ant Design validation rules
294
+ generateRules: true,
295
+ }),
296
+ ],
297
+
298
+ locale: {
299
+ locales: ['ja', 'en'],
300
+ defaultLocale: 'ja',
301
+ },
302
+ });
303
+ ```
304
+
305
+ ### Configuration Options
306
+
307
+ | Option | Type | Default | Description |
308
+ |--------|------|---------|-------------|
309
+ | `path` | `string` | `./src/types/model` | TypeScript output directory |
310
+ | `generateRules` | `boolean` | `true` | Generate Ant Design validation rules |
@@ -0,0 +1,364 @@
1
+ # Naming Conventions Guide
2
+
3
+ > **Related:** [README](./README.md) | [Testing Guide](./testing-guide.md)
4
+
5
+ ## Overview
6
+
7
+ Consistent naming is critical for maintainability. This guide defines naming patterns for all backend code.
8
+
9
+ ---
10
+
11
+ ## PHP Imports
12
+
13
+ **Always use `use` statements. Never use FQCN (Fully Qualified Class Name) inline.**
14
+
15
+ ```php
16
+ // ❌ WRONG: Inline FQCN
17
+ public function store(): \Illuminate\Http\JsonResponse
18
+ {
19
+ return new \App\Http\Resources\UserResource($user);
20
+ }
21
+
22
+ // ✅ CORRECT: Import at top, use short names
23
+ use Illuminate\Http\JsonResponse;
24
+ use App\Http\Resources\UserResource;
25
+
26
+ public function store(): JsonResponse
27
+ {
28
+ return new UserResource($user);
29
+ }
30
+ ```
31
+
32
+ | Rule | Description |
33
+ | ------------------ | -------------------------------- |
34
+ | Import all classes | Use `use` at top of file |
35
+ | Short class names | Never `\Full\Path\Class` inline |
36
+ | Group imports | Framework, then App, then Others |
37
+ | No unused imports | Remove unused `use` statements |
38
+
39
+ ---
40
+
41
+ ## File & Class Naming
42
+
43
+ ### Pattern: `{Model}{Type}.php`
44
+
45
+ | Type | Pattern | Example |
46
+ | ---------- | ------------------------ | ------------------------- |
47
+ | Controller | `{Model}Controller` | `UserController.php` |
48
+ | Request | `{Model}{Action}Request` | `UserStoreRequest.php` |
49
+ | Resource | `{Model}Resource` | `UserResource.php` |
50
+ | Model | `{Model}` (singular) | `User.php` |
51
+ | Service | `{Model}Service` | `OrderService.php` |
52
+ | Action | `{Verb}{Noun}Action` | `CreateInvoiceAction.php` |
53
+ | Job | `{Verb}{Noun}Job` | `SendWelcomeEmailJob.php` |
54
+ | Event | `{Model}{PastTense}` | `UserRegistered.php` |
55
+ | Observer | `{Model}Observer` | `UserObserver.php` |
56
+ | Policy | `{Model}Policy` | `UserPolicy.php` |
57
+ | Test | `{Model}ControllerTest` | `UserControllerTest.php` |
58
+
59
+ ### Request Naming
60
+
61
+ | Action | Pattern | Example |
62
+ | ------ | ---------------------- | ----------------------- |
63
+ | Create | `{Model}StoreRequest` | `UserStoreRequest.php` |
64
+ | Update | `{Model}UpdateRequest` | `UserUpdateRequest.php` |
65
+
66
+ > **Note:** Use `Store` (not `Create`) and `Update` (not `Edit`) to match Laravel CRUD conventions.
67
+
68
+ ---
69
+
70
+ ## Method Naming
71
+
72
+ ### Controller Methods (RESTful)
73
+
74
+ | HTTP Method | Controller Method | Route | Description |
75
+ | ----------- | ----------------- | ----------------- | --------------- |
76
+ | GET | `index()` | `/api/users` | List all |
77
+ | POST | `store()` | `/api/users` | Create new |
78
+ | GET | `show()` | `/api/users/{id}` | Get single |
79
+ | PUT/PATCH | `update()` | `/api/users/{id}` | Update existing |
80
+ | DELETE | `destroy()` | `/api/users/{id}` | Delete |
81
+
82
+ ### Service Methods
83
+
84
+ | Pattern | Example |
85
+ | --------------------- | ------------------------- |
86
+ | `{verb}{Noun}` | `processPayment()` |
87
+ | `{verb}{Noun}{State}` | `calculateTotalWithTax()` |
88
+
89
+ ```php
90
+ // ✅ Good
91
+ public function processPayment(Order $order): Payment
92
+ public function calculateDiscount(Cart $cart): float
93
+ public function sendNotification(User $user): void
94
+
95
+ // ❌ Bad
96
+ public function payment(Order $order) // Missing verb
97
+ public function doStuff() // Too vague
98
+ ```
99
+
100
+ ### Model Methods
101
+
102
+ | Type | Pattern | Example |
103
+ | -------- | --------------------- | ----------------------- |
104
+ | Scope | `scope{Name}` | `scopeActive($query)` |
105
+ | Accessor | `{attribute}` (PHP 8) | `fullName(): Attribute` |
106
+ | Mutator | `{attribute}` (PHP 8) | `password(): Attribute` |
107
+ | Relation | `{relation}` (noun) | `posts()`, `author()` |
108
+
109
+ ```php
110
+ // Scope - filter queries
111
+ public function scopeActive(Builder $query): Builder
112
+ {
113
+ return $query->where('status', 'active');
114
+ }
115
+
116
+ // Accessor (PHP 8+)
117
+ protected function fullName(): Attribute
118
+ {
119
+ return Attribute::get(fn () => "{$this->first_name} {$this->last_name}");
120
+ }
121
+
122
+ // Relationship
123
+ public function posts(): HasMany
124
+ {
125
+ return $this->hasMany(Post::class);
126
+ }
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Test Naming (PEST)
132
+
133
+ Use `describe()` to group tests by endpoint, `it()` for individual test cases.
134
+
135
+ ### Naming Rules
136
+
137
+ | Category | Prefix | Pattern | Example |
138
+ | --------------------- | ------- | ---------------------------------------- | ----------------------------------------------------- |
139
+ | **正常系 (Normal)** | `正常:` | `it('正常: {verb} {what}')` | `it('正常: creates user with valid data')` |
140
+ | **異常系 (Abnormal)** | `異常:` | `it('異常: fails to {action} {reason}')` | `it('異常: fails to create user with invalid email')` |
141
+ | **異常系 (404/401)** | `異常:` | `it('異常: returns {status} {reason}')` | `it('異常: returns 404 when user not found')` |
142
+
143
+ ### 正常系 (Normal Cases) - Success Behavior
144
+
145
+ **Pattern:** `it('正常: {verb} {what}')`
146
+
147
+ **Common verbs:** `returns`, `creates`, `updates`, `deletes`, `filters`, `sorts`, `paginates`
148
+
149
+ ```php
150
+ // GET (index)
151
+ it('正常: returns paginated users')
152
+ it('正常: returns users filtered by search')
153
+ it('正常: returns users sorted by created_at')
154
+
155
+ // POST (store)
156
+ it('正常: creates user with valid data')
157
+
158
+ // GET (show)
159
+ it('正常: returns user by id')
160
+
161
+ // PUT (update)
162
+ it('正常: updates user with valid data')
163
+ it('正常: updates user with partial data')
164
+
165
+ // DELETE (destroy)
166
+ it('正常: deletes user')
167
+ ```
168
+
169
+ ### 異常系 (Abnormal Cases) - Failure Behavior
170
+
171
+ **Pattern:** `it('異常: fails to {action} {reason}')` or `it('異常: returns {status} {reason}')`
172
+
173
+ ```php
174
+ // Validation errors (422) - use "fails to"
175
+ it('異常: fails to create user with missing email')
176
+ it('異常: fails to create user with invalid email format')
177
+ it('異常: fails to create user with duplicate email')
178
+ it('異常: fails to create user with short password')
179
+ it('異常: fails to create user with invalid kana format') // Japanese
180
+ it('異常: fails to update user with invalid data')
181
+
182
+ // Not found (404) - use "returns 404"
183
+ it('異常: returns 404 when user not found')
184
+ it('異常: returns 404 when updating nonexistent user')
185
+ it('異常: returns 404 when deleting nonexistent user')
186
+
187
+ // Authentication (401) - use "returns 401"
188
+ it('異常: returns 401 when not authenticated')
189
+
190
+ // Authorization (403) - use "returns 403"
191
+ it('異常: returns 403 when user cannot access resource')
192
+ it('異常: returns 403 when deleting without admin role')
193
+ ```
194
+
195
+ ### Complete Example
196
+
197
+ ```php
198
+ describe('POST /api/users', function () {
199
+ // ================================================================
200
+ // 正常系 (Normal Cases)
201
+ // ================================================================
202
+ it('正常: creates user with valid data', function () { ... });
203
+
204
+ // ================================================================
205
+ // 異常系 (Abnormal Cases)
206
+ // ================================================================
207
+
208
+ // Required fields
209
+ it('異常: fails to create user with missing email', function () { ... });
210
+ it('異常: fails to create user with missing password', function () { ... });
211
+
212
+ // Format validation
213
+ it('異常: fails to create user with invalid email format', function () { ... });
214
+ it('異常: fails to create user with short password', function () { ... });
215
+
216
+ // Unique constraint
217
+ it('異常: fails to create user with duplicate email', function () { ... });
218
+
219
+ // Japanese field validation
220
+ it('異常: fails to create user with invalid kana format', function () { ... });
221
+ });
222
+
223
+ describe('GET /api/users/{id}', function () {
224
+ // 正常系
225
+ it('正常: returns user by id', function () { ... });
226
+
227
+ // 異常系
228
+ it('異常: returns 404 when user not found', function () { ... });
229
+ });
230
+ ```
231
+
232
+ ---
233
+
234
+ ## Database Naming
235
+
236
+ ### Tables
237
+
238
+ | Pattern | Example |
239
+ | ------------------------ | ----------- |
240
+ | Plural, snake_case | `users` |
241
+ | Pivot: singular_singular | `post_tag` |
242
+ | (alphabetical order) | `role_user` |
243
+
244
+ ### Columns
245
+
246
+ | Type | Pattern | Example |
247
+ | ------------- | ------------------ | -------------------- |
248
+ | Primary key | `id` | `id` |
249
+ | Foreign key | `{table}_id` | `user_id` |
250
+ | Boolean | `is_{state}` | `is_active` |
251
+ | Timestamp | `{action}_at` | `verified_at` |
252
+ | Japanese name | `name_{part}` | `name_lastname` |
253
+ | Japanese kana | `name_kana_{part}` | `name_kana_lastname` |
254
+
255
+ ### Japanese Name Fields (JapaneseName type)
256
+
257
+ | Field | Description | Max Length |
258
+ | --------------------- | ---------------- | ---------- |
259
+ | `name_lastname` | Family name (姓) | 50 |
260
+ | `name_firstname` | Given name (名) | 50 |
261
+ | `name_kana_lastname` | Family name kana | 100 |
262
+ | `name_kana_firstname` | Given name kana | 100 |
263
+
264
+ ---
265
+
266
+ ## Route Naming
267
+
268
+ ### API Routes
269
+
270
+ | Pattern | Example |
271
+ | ------------------ | -------------------------- |
272
+ | Plural resource | `/api/users` |
273
+ | Nested resource | `/api/users/{user}/posts` |
274
+ | Action on resource | `/api/orders/{order}/ship` |
275
+
276
+ ```php
277
+ // routes/api.php
278
+ Route::apiResource('users', UserController::class);
279
+ Route::apiResource('posts', PostController::class);
280
+
281
+ // Nested
282
+ Route::apiResource('users.posts', UserPostController::class);
283
+
284
+ // Custom actions
285
+ Route::post('/orders/{order}/ship', [OrderController::class, 'ship']);
286
+ ```
287
+
288
+ ---
289
+
290
+ ## Variable Naming
291
+
292
+ ### PHP Variables
293
+
294
+ | Type | Pattern | Example |
295
+ | -------------- | ------------ | ------------------ |
296
+ | Model instance | `$camelCase` | `$user`, `$post` |
297
+ | Collection | `$plural` | `$users`, `$posts` |
298
+ | Boolean | `$is{State}` | `$isActive` |
299
+ | Query builder | `$query` | `$query` |
300
+
301
+ ```php
302
+ // ✅ Good
303
+ $user = User::find($id);
304
+ $users = User::all();
305
+ $isActive = $user->status === 'active';
306
+
307
+ // ❌ Bad
308
+ $u = User::find($id); // Too short
309
+ $userData = User::find($id); // Redundant "Data"
310
+ $active = true; // Missing "is" prefix for boolean
311
+ ```
312
+
313
+ ---
314
+
315
+ ## OpenAPI/Swagger Naming
316
+
317
+ ### Tag Names
318
+
319
+ | Pattern | Example |
320
+ | ------------------ | ------- |
321
+ | Plural, PascalCase | `Users` |
322
+
323
+ ### Parameter Names
324
+
325
+ | Type | Pattern | Example |
326
+ | ----- | ------------- | ------------- |
327
+ | Query | `Query{Name}` | `QuerySearch` |
328
+ | Path | `Path{Name}` | `PathId` |
329
+
330
+ ### Response Names
331
+
332
+ | Pattern | Example |
333
+ | --------------- | ----------------- |
334
+ | `{Description}` | `Success` |
335
+ | `{HttpStatus}` | `NotFound` |
336
+ | `{Error}Error` | `ValidationError` |
337
+
338
+ ---
339
+
340
+ ## Summary Table
341
+
342
+ | Type | Convention | Example |
343
+ | -------------------- | ---------------------------------------- | ----------------------------------------------------- |
344
+ | **Imports** | | |
345
+ | PHP imports | `use` at top, short name inline | `use JsonResponse;` → `: JsonResponse` |
346
+ | **Files** | | |
347
+ | Controller | `{Model}Controller` | `UserController.php` |
348
+ | Request | `{Model}{Action}Request` | `UserStoreRequest.php` |
349
+ | Resource | `{Model}Resource` | `UserResource.php` |
350
+ | Test | `{Model}ControllerTest` | `UserControllerTest.php` |
351
+ | **Methods** | | |
352
+ | Controller | RESTful verbs | `index`, `store`, `show` |
353
+ | Service | `{verb}{Noun}` | `processPayment()` |
354
+ | Scope | `scope{Name}` | `scopeActive()` |
355
+ | **Test Naming** | | |
356
+ | 正常系 (Normal) | `it('正常: {verb} {what}')` | `it('正常: creates user with valid data')` |
357
+ | 異常系 (Abnormal) | `it('異常: fails to {action} {reason}')` | `it('異常: fails to create user with invalid email')` |
358
+ | 異常系 (404/401/403) | `it('異常: returns {status} {reason}')` | `it('異常: returns 404 when user not found')` |
359
+ | **Database** | | |
360
+ | Table | plural, snake_case | `users`, `order_items` |
361
+ | Column | snake_case | `user_id`, `created_at` |
362
+ | Boolean column | `is_{state}` | `is_verified` |
363
+ | **Routes** | | |
364
+ | API | plural, kebab-case | `/api/users`, `/api/order-items` |