@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,66 @@
1
+ ---
2
+ description: "⛔ DO NOT EDIT - Auto-generated base models by Omnify. These files are overwritten on every generation."
3
+ globs: ["{{LARAVEL_BASE}}/Models/OmnifyBase/**/*.php"]
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # ⛔ DO NOT EDIT - Auto-Generated Base Models
8
+
9
+ This file is **auto-generated by Omnify** and will be **overwritten** on next `npx omnify generate`.
10
+
11
+ ## ❌ ABSOLUTELY FORBIDDEN
12
+
13
+ - Adding methods
14
+ - Modifying relations
15
+ - Changing `$fillable`, `$hidden`, `$casts`
16
+ - Adding traits
17
+ - Any modifications whatsoever
18
+
19
+ ## ✅ CORRECT APPROACH
20
+
21
+ ### To modify schema structure:
22
+
23
+ 1. Edit the schema YAML in `schemas/`
24
+ 2. Run `npx omnify generate`
25
+
26
+ ### To add custom logic:
27
+
28
+ Add to the **User Model** (e.g., `{{LARAVEL_BASE}}/Models/Post.php`), NOT here.
29
+
30
+ ```php
31
+ // ✅ CORRECT: Add custom logic in User Model
32
+ class Post extends PostBaseModel
33
+ {
34
+ public function scopePublished($query) { ... }
35
+ public function getReadTimeAttribute(): int { ... }
36
+ }
37
+ ```
38
+
39
+ ## What BaseModel Provides
40
+
41
+ ### All models include `HasLocalizedDisplayName` trait:
42
+
43
+ ```php
44
+ // Available on all models - DO NOT recreate!
45
+ Model::displayName('ja') // "投稿"
46
+ Model::displayName('en') // "Post"
47
+ Model::propertyDisplayName('title', 'ja') // "タイトル"
48
+ Model::allDisplayNames() // ['ja' => '投稿', 'en' => 'Post']
49
+ Model::allPropertyDisplayNamesForLocale('ja')
50
+ ```
51
+
52
+ ### Each EntityBaseModel provides:
53
+
54
+ | Feature | Description | Source |
55
+ |---------|-------------|--------|
56
+ | `$fillable` | Mass assignable fields | Schema properties |
57
+ | `$hidden` | Hidden from JSON | `hidden: true` in schema |
58
+ | `$casts` | Type casting | Property types |
59
+ | `$table` | Table name | Schema name (snake_case) |
60
+ | Relations | `belongsTo()`, `hasMany()`, etc. | Schema associations |
61
+ | Soft deletes | `use SoftDeletes` | `options.softDelete: true` |
62
+
63
+ ## See Also
64
+
65
+ - `model-editable.mdc` - Rules for editing User Models
66
+ - `omnify-schema.mdc` - Schema YAML reference
@@ -0,0 +1,74 @@
1
+ ---
2
+ description: "⛔ DO NOT EDIT - Auto-generated base form requests by Omnify. These files are overwritten on every generation."
3
+ globs: ["{{LARAVEL_BASE}}/Http/Requests/OmnifyBase/**/*.php"]
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # ⛔ DO NOT EDIT - Auto-Generated Base Requests
8
+
9
+ This file is **auto-generated by Omnify** and will be **overwritten** on next `npx omnify generate`.
10
+
11
+ ## ❌ ABSOLUTELY FORBIDDEN
12
+
13
+ - Adding validation rules
14
+ - Modifying messages
15
+ - Changing `authorize()` method
16
+ - Any modifications whatsoever
17
+
18
+ ## ✅ CORRECT APPROACH
19
+
20
+ ### To modify validation:
21
+
22
+ 1. Edit the schema YAML in `schemas/` - add validation constraints to properties
23
+ 2. Run `npx omnify generate`
24
+
25
+ ### To add custom validation:
26
+
27
+ Add to the **User Request** (e.g., `{{LARAVEL_BASE}}/Http/Requests/PostStoreRequest.php`), NOT here.
28
+
29
+ ```php
30
+ // ✅ CORRECT: Add custom validation in User Request
31
+ class PostStoreRequest extends PostStoreRequestBase
32
+ {
33
+ public function rules(): array
34
+ {
35
+ return array_merge(parent::rules(), [
36
+ // Custom rules only
37
+ 'slug' => ['unique:posts,slug'],
38
+ ]);
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## What BaseRequest Provides
44
+
45
+ | Feature | Description | Source |
46
+ |---------|-------------|--------|
47
+ | `rules()` | Validation rules | Schema property types & constraints |
48
+ | `messages()` | Localized error messages | Schema `displayName` |
49
+ | `attributes()` | Field labels | Schema `displayName` |
50
+
51
+ ## Schema Validation Options
52
+
53
+ ```yaml
54
+ properties:
55
+ email:
56
+ type: Email # → 'email' rule
57
+ required: true # → 'required' rule
58
+ unique: true # → handled in User Request
59
+
60
+ age:
61
+ type: Int
62
+ min: 0 # → 'min:0' rule
63
+ max: 150 # → 'max:150' rule
64
+
65
+ title:
66
+ type: String
67
+ length: 255 # → 'max:255' rule
68
+ minLength: 3 # → 'min:3' rule
69
+ ```
70
+
71
+ ## See Also
72
+
73
+ - `request-editable.mdc` - Rules for editing User Requests
74
+ - `omnify-schema.mdc` - Schema YAML reference
@@ -0,0 +1,78 @@
1
+ ---
2
+ description: "⛔ DO NOT EDIT - Auto-generated base API resources by Omnify. These files are overwritten on every generation."
3
+ globs: ["{{LARAVEL_BASE}}/Http/Resources/OmnifyBase/**/*.php"]
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # ⛔ DO NOT EDIT - Auto-Generated Base Resources
8
+
9
+ This file is **auto-generated by Omnify** and will be **overwritten** on next `npx omnify generate`.
10
+
11
+ ## ❌ ABSOLUTELY FORBIDDEN
12
+
13
+ - Adding fields
14
+ - Modifying field mapping
15
+ - Changing relation includes
16
+ - Any modifications whatsoever
17
+
18
+ ## ✅ CORRECT APPROACH
19
+
20
+ ### To modify API output:
21
+
22
+ 1. Edit the schema YAML in `schemas/` - add/modify properties
23
+ 2. Run `npx omnify generate`
24
+
25
+ ### To add custom fields:
26
+
27
+ Add to the **User Resource** (e.g., `{{LARAVEL_BASE}}/Http/Resources/PostResource.php`), NOT here.
28
+
29
+ ```php
30
+ // ✅ CORRECT: Add custom fields in User Resource
31
+ class PostResource extends PostResourceBase
32
+ {
33
+ public function toArray($request): array
34
+ {
35
+ return array_merge(parent::toArray($request), [
36
+ 'read_time' => $this->getReadTime(),
37
+ 'is_published' => $this->status === 'published',
38
+ ]);
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## What BaseResource Provides
44
+
45
+ | Feature | Description | Source |
46
+ |---------|-------------|--------|
47
+ | All scalar fields | `id`, `title`, `content`, etc. | Schema properties |
48
+ | Timestamps | `created_at`, `updated_at` | Auto-included |
49
+ | Relations | `$this->whenLoaded('author')` | Schema associations |
50
+ | Localized labels | Field display names | Schema `displayName` |
51
+
52
+ ## Schema to Resource Mapping
53
+
54
+ ```yaml
55
+ # Schema YAML
56
+ properties:
57
+ title:
58
+ type: String
59
+ author:
60
+ type: Association
61
+ relation: ManyToOne
62
+ target: User
63
+ ```
64
+
65
+ ```php
66
+ // Generated BaseResource
67
+ return [
68
+ 'id' => $this->id,
69
+ 'title' => $this->title,
70
+ 'author' => UserResource::make($this->whenLoaded('author')),
71
+ 'created_at' => $this->created_at?->toISOString(),
72
+ ];
73
+ ```
74
+
75
+ ## See Also
76
+
77
+ - `resource-editable.mdc` - Rules for editing User Resources
78
+ - `omnify-schema.mdc` - Schema YAML reference
@@ -0,0 +1,421 @@
1
+ ---
2
+ description: "Laravel controller patterns: thin controllers with query builder, OpenAPI documentation (NO /api prefix!), validation with $request->validated(), and proper Resource usage. Apply when creating or editing controllers."
3
+ globs: ["{{LARAVEL_BASE}}/Http/Controllers/**/*.php"]
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Controller Rules
8
+
9
+ ## ⚠️ CRITICAL: Check Route Prefix BEFORE Writing OpenAPI
10
+
11
+ **MUST check route file prefix first!** Don't assume - VERIFY.
12
+
13
+ ### Before Writing OpenAPI Path:
14
+
15
+ 1. **Check route file** → Which file has your route? (`api.php`, `web.php`, custom?)
16
+ 2. **Check prefix** → Look in `RouteServiceProvider` or `bootstrap/app.php`
17
+ 3. **Write path WITHOUT prefix** → OpenAPI path = Route definition path
18
+
19
+ ```php
20
+ // Route trong api.php (prefix: /api)
21
+ Route::get('/users', [UserController::class, 'index']);
22
+
23
+ // ❌ SAI - Duplicate prefix → /api/api/users !!
24
+ #[OA\Get(path: '/api/users')]
25
+
26
+ // ✅ ĐÚNG - Path không có prefix
27
+ #[OA\Get(path: '/users')] // → /api/users
28
+ ```
29
+
30
+ | Route File | Prefix | Route Definition | OpenAPI Path |
31
+ |------------|--------|------------------|--------------|
32
+ | `api.php` | `/api` | `/users` | `/users` |
33
+ | `web.php` | (none) | `/dashboard` | `/dashboard` |
34
+
35
+ **Full guide:** `.claude/omnify/guides/laravel/openapi.md`
36
+
37
+ ---
38
+
39
+ ## Golden Rule: Thin Controller
40
+
41
+ ```php
42
+ // ✅ PERFECT
43
+ public function store(UserStoreRequest $request): UserResource
44
+ {
45
+ return new UserResource(User::create($request->validated()));
46
+ }
47
+
48
+ // ❌ BAD: Fat controller with logic
49
+ public function store(Request $request)
50
+ {
51
+ $validated = $request->validate([...]); // Use FormRequest!
52
+ // 50 lines of business logic... // Use Service!
53
+ }
54
+ ```
55
+
56
+ ## Index Method - Query Builder Template
57
+
58
+ ```php
59
+ use Spatie\QueryBuilder\AllowedFilter;
60
+ use Spatie\QueryBuilder\QueryBuilder;
61
+
62
+ public function index(): AnonymousResourceCollection
63
+ {
64
+ $users = QueryBuilder::for(User::class)
65
+ ->allowedFilters([
66
+ AllowedFilter::callback('search', function ($query, $value) {
67
+ $query->where(function ($q) use ($value) {
68
+ $q->where('name', 'like', "%{$value}%")
69
+ ->orWhere('email', 'like', "%{$value}%");
70
+ });
71
+ }),
72
+ ])
73
+ ->allowedSorts(['id', 'name', 'email', 'created_at'])
74
+ ->defaultSort('-id')
75
+ ->paginate(request()->input('per_page', 10));
76
+
77
+ return UserResource::collection($users);
78
+ }
79
+ ```
80
+
81
+ ## OpenAPI - Schema MUST Match Code
82
+
83
+ Frontend needs exact response/request structure. Always verify against actual code.
84
+
85
+ ### Golden Rule: Verify Before Writing OpenAPI
86
+
87
+ 1. **Response** → Check `*Resource.php` schema
88
+ 2. **Request** → Check `*Request.php` schema
89
+ 3. **Parameters** → Check `allowedFilters()` / `allowedSorts()`
90
+
91
+ ### Schema Location
92
+
93
+ | Type | Define At | Ref In Controller |
94
+ | ------------------------ | ------------------------ | --------------------------------------- |
95
+ | Response | `*Resource.php` | `#/components/schemas/User` |
96
+ | Request body | `*Request.php` | `#/components/schemas/UserStoreRequest` |
97
+ | Pagination | `Schemas.php` | `#/components/schemas/PaginationMeta` |
98
+ | Common params | `Schemas.php` | `#/components/parameters/QueryPage` |
99
+ | Resource-specific params | **Inline in Controller** | N/A |
100
+
101
+ ### Common refs from `Schemas.php`
102
+
103
+ ```php
104
+ // Parameters
105
+ new OA\Parameter(ref: '#/components/parameters/QueryPage'),
106
+ new OA\Parameter(ref: '#/components/parameters/QueryPerPage'),
107
+ new OA\Parameter(ref: '#/components/parameters/PathId'),
108
+
109
+ // Responses
110
+ new OA\Response(ref: '#/components/responses/ValidationError', response: 422),
111
+ new OA\Response(ref: '#/components/responses/NotFound', response: 404),
112
+ new OA\Response(ref: '#/components/responses/NoContent', response: 204),
113
+
114
+ // Pagination
115
+ new OA\Property(property: 'links', ref: '#/components/schemas/PaginationLinks'),
116
+ new OA\Property(property: 'meta', ref: '#/components/schemas/PaginationMeta'),
117
+ ```
118
+
119
+ ### Filter & Sort - MUST Document Specifically
120
+
121
+ `filter` and `sort` differ per resource → Write inline with specific details.
122
+
123
+ #### Filter Types (Spatie Query Builder)
124
+
125
+ | Type | Code | OpenAPI Description | Example |
126
+ | ----------------- | ------------------------------------------ | -------------------------- | ----------------------- |
127
+ | Callback (search) | `AllowedFilter::callback('search', fn...)` | List all searchable fields | `filter[search]=田中` |
128
+ | Exact | `AllowedFilter::exact('status')` | Exact match | `filter[status]=active` |
129
+ | Partial | `AllowedFilter::partial('name')` | LIKE %value% | `filter[name]=田中` |
130
+ | Scope | `AllowedFilter::scope('active')` | Model scope | `filter[active]=1` |
131
+
132
+ #### Filter Documentation Template
133
+
134
+ ```php
135
+ // CODE: allowedFilters() configuration
136
+ ->allowedFilters([
137
+ AllowedFilter::callback('search', function ($query, $value) {
138
+ $query->where(function ($q) use ($value) {
139
+ $q->where('name_lastname', 'like', "%{$value}%")
140
+ ->orWhere('name_firstname', 'like', "%{$value}%")
141
+ ->orWhere('name_kana_lastname', 'like', "%{$value}%")
142
+ ->orWhere('name_kana_firstname', 'like', "%{$value}%")
143
+ ->orWhere('email', 'like', "%{$value}%");
144
+ });
145
+ }),
146
+ AllowedFilter::exact('status'),
147
+ ])
148
+
149
+ // OPENAPI: Document EACH filter with specific description
150
+ new OA\Parameter(
151
+ name: 'filter[search]',
152
+ in: 'query',
153
+ description: 'Partial match on: name_lastname, name_firstname, name_kana_lastname, name_kana_firstname, email',
154
+ schema: new OA\Schema(type: 'string'),
155
+ example: '田中'
156
+ ),
157
+ new OA\Parameter(
158
+ name: 'filter[status]',
159
+ in: 'query',
160
+ description: 'Exact match on status',
161
+ schema: new OA\Schema(type: 'string', enum: ['active', 'inactive']),
162
+ example: 'active'
163
+ ),
164
+ ```
165
+
166
+ #### Sort Documentation Template
167
+
168
+ ```php
169
+ // CODE: allowedSorts() + defaultSort()
170
+ ->allowedSorts(['id', 'name_lastname', 'name_firstname', 'email', 'created_at', 'updated_at'])
171
+ ->defaultSort('-id')
172
+
173
+ // OPENAPI: enum MUST include both asc and desc for each field
174
+ new OA\Parameter(
175
+ name: 'sort',
176
+ in: 'query',
177
+ description: 'Sort field. Prefix `-` for descending. Default: `-id`',
178
+ schema: new OA\Schema(
179
+ type: 'string',
180
+ enum: [
181
+ 'id', '-id',
182
+ 'name_lastname', '-name_lastname',
183
+ 'name_firstname', '-name_firstname',
184
+ 'email', '-email',
185
+ 'created_at', '-created_at',
186
+ 'updated_at', '-updated_at'
187
+ ]
188
+ ),
189
+ example: '-created_at'
190
+ ),
191
+ ```
192
+
193
+ #### Checklist: Filter & Sort Documentation
194
+
195
+ | Item | Check |
196
+ | ----------------------------- | ----------------------------------------------- |
197
+ | Each `AllowedFilter` | Has corresponding `filter[name]` parameter? |
198
+ | Callback filter | Description lists ALL searchable fields? |
199
+ | Exact filter with enum values | `schema.enum` matches valid values? |
200
+ | `allowedSorts()` | `sort.enum` includes both `field` and `-field`? |
201
+ | `defaultSort()` | Mentioned in `sort.description`? |
202
+
203
+ ### OpenAPI Checklist per Action
204
+
205
+ #### `index()` - List
206
+
207
+ **Verify before writing:**
208
+ 1. `allowedFilters()` → Each filter has `filter[name]` param with specific description
209
+ 2. `allowedSorts()` → `sort.enum` includes all fields + `-field` versions
210
+ 3. `defaultSort()` → Mentioned in sort description
211
+ 4. Response → ref to Resource + PaginationLinks + PaginationMeta
212
+
213
+ ```php
214
+ #[OA\Get(
215
+ parameters: [
216
+ // Each allowedFilter → specific param
217
+ new OA\Parameter(
218
+ name: 'filter[search]',
219
+ in: 'query',
220
+ description: 'Partial match on: name_lastname, name_firstname, email', // ← List actual fields!
221
+ schema: new OA\Schema(type: 'string'),
222
+ example: '田中'
223
+ ),
224
+ // Pagination
225
+ new OA\Parameter(ref: '#/components/parameters/QueryPage'),
226
+ new OA\Parameter(ref: '#/components/parameters/QueryPerPage'),
227
+ // Sort with full enum
228
+ new OA\Parameter(
229
+ name: 'sort',
230
+ in: 'query',
231
+ description: 'Sort field. Prefix `-` for descending. Default: `-id`', // ← Include default!
232
+ schema: new OA\Schema(
233
+ type: 'string',
234
+ enum: ['id', '-id', 'name', '-name', 'created_at', '-created_at'] // ← Match allowedSorts!
235
+ ),
236
+ example: '-created_at'
237
+ ),
238
+ ],
239
+ responses: [
240
+ new OA\Response(response: 200, content: new OA\JsonContent(
241
+ properties: [
242
+ new OA\Property(property: 'data', type: 'array', items: new OA\Items(ref: '#/components/schemas/User')),
243
+ new OA\Property(property: 'links', ref: '#/components/schemas/PaginationLinks'),
244
+ new OA\Property(property: 'meta', ref: '#/components/schemas/PaginationMeta'),
245
+ ]
246
+ )),
247
+ ]
248
+ )]
249
+ ```
250
+
251
+ #### `store()` - Create
252
+
253
+ ```php
254
+ // 1. Request: ref to *StoreRequest schema
255
+ // 2. Response: ref to Resource schema
256
+ // 3. Errors: 422 ValidationError
257
+
258
+ #[OA\Post(
259
+ requestBody: new OA\RequestBody(
260
+ required: true,
261
+ content: new OA\JsonContent(ref: '#/components/schemas/UserStoreRequest') // ← Check UserStoreRequest.php
262
+ ),
263
+ responses: [
264
+ new OA\Response(response: 201, content: new OA\JsonContent(
265
+ properties: [new OA\Property(property: 'data', ref: '#/components/schemas/User')]
266
+ )),
267
+ new OA\Response(ref: '#/components/responses/ValidationError', response: 422),
268
+ ]
269
+ )]
270
+ ```
271
+
272
+ #### `show()` - Get Single
273
+
274
+ ```php
275
+ // 1. Parameter: PathId
276
+ // 2. Response: ref to Resource schema
277
+ // 3. Errors: 404 NotFound
278
+
279
+ #[OA\Get(
280
+ parameters: [new OA\Parameter(ref: '#/components/parameters/PathId')],
281
+ responses: [
282
+ new OA\Response(response: 200, content: new OA\JsonContent(
283
+ properties: [new OA\Property(property: 'data', ref: '#/components/schemas/User')]
284
+ )),
285
+ new OA\Response(ref: '#/components/responses/NotFound', response: 404),
286
+ ]
287
+ )]
288
+ ```
289
+
290
+ #### `update()` - Update
291
+
292
+ ```php
293
+ // 1. Parameter: PathId
294
+ // 2. Request: ref to *UpdateRequest schema (NOT StoreRequest!)
295
+ // 3. Response: ref to Resource schema
296
+ // 4. Errors: 404, 422
297
+
298
+ #[OA\Put(
299
+ parameters: [new OA\Parameter(ref: '#/components/parameters/PathId')],
300
+ requestBody: new OA\RequestBody(
301
+ content: new OA\JsonContent(ref: '#/components/schemas/UserUpdateRequest') // ← Check UserUpdateRequest.php
302
+ ),
303
+ responses: [
304
+ new OA\Response(response: 200, content: ...),
305
+ new OA\Response(ref: '#/components/responses/NotFound', response: 404),
306
+ new OA\Response(ref: '#/components/responses/ValidationError', response: 422),
307
+ ]
308
+ )]
309
+ ```
310
+
311
+ #### `destroy()` - Delete
312
+
313
+ ```php
314
+ // 1. Parameter: PathId
315
+ // 2. Response: 204 NoContent
316
+ // 3. Errors: 404 NotFound
317
+
318
+ #[OA\Delete(
319
+ parameters: [new OA\Parameter(ref: '#/components/parameters/PathId')],
320
+ responses: [
321
+ new OA\Response(ref: '#/components/responses/NoContent', response: 204),
322
+ new OA\Response(ref: '#/components/responses/NotFound', response: 404),
323
+ ]
324
+ )]
325
+ ```
326
+
327
+ ## Response Status Codes
328
+
329
+ | Action | Code | Return Type |
330
+ | ------- | ---- | ----------------------------- |
331
+ | index | 200 | Collection |
332
+ | store | 201 | Resource + status |
333
+ | show | 200 | Resource |
334
+ | update | 200 | Resource |
335
+ | destroy | 204 | `response()->json(null, 204)` |
336
+
337
+ ## Imports - MUST use short names
338
+
339
+ ```php
340
+ // ✅ CORRECT
341
+ use Illuminate\Http\JsonResponse;
342
+ use Spatie\QueryBuilder\QueryBuilder;
343
+
344
+ public function store(): JsonResponse
345
+
346
+ // ❌ WRONG - Never FQCN inline
347
+ public function store(): \Illuminate\Http\JsonResponse
348
+ ```
349
+
350
+ ## Keep It Simple
351
+
352
+ ```php
353
+ // ✅ DO
354
+ ->allowedFilters([
355
+ AllowedFilter::callback('search', fn($q, $v) => ...),
356
+ ])
357
+ ->allowedSorts(['id', 'name', 'created_at'])
358
+
359
+ // ❌ DON'T over-engineer
360
+ ->allowedFilters([
361
+ AllowedFilter::exact('author.company.country'), // Too nested!
362
+ ])
363
+ ```
364
+
365
+ ## Don't Mix Concepts
366
+
367
+ | Concept | Use For | DON'T Use For |
368
+ | ---------------- | ---------------- | -------------------- |
369
+ | `*StoreRequest` | POST create | GET list, PUT update |
370
+ | `*UpdateRequest` | PUT/PATCH update | POST create |
371
+ | `*Resource` | Response output | Request input |
372
+ | `index()` | List (no body) | Create/Update |
373
+ | `store()` | Create new | Update existing |
374
+ | `update()` | Update existing | Create new |
375
+
376
+ ```php
377
+ // ❌ WRONG: Using StoreRequest for update
378
+ public function update(UserStoreRequest $request) // WRONG!
379
+
380
+ // ✅ CORRECT: Each action has its own Request
381
+ public function store(UserStoreRequest $request) // Create
382
+ public function update(UserUpdateRequest $request) // Update
383
+ ```
384
+
385
+ ## After Coding Checklist
386
+
387
+ ### Code
388
+ 1. ✅ Run tests: `./artisan test --filter=ControllerTest`
389
+
390
+ ### OpenAPI (only if annotations changed)
391
+
392
+ | Check | Code | OpenAPI | Match |
393
+ | --------------- | ------------------ | ----------------------- | ------------------------------------- |
394
+ | Response | `*Resource.php` | `ref: User` | Schema exists? Properties match? |
395
+ | Request | `*Request.php` | `ref: UserStoreRequest` | Schema exists? Required fields match? |
396
+ | Filters | `allowedFilters()` | `filter[name]` params | Each filter documented? |
397
+ | Callback filter | Fields in callback | `description` | All fields listed? |
398
+ | Exact filter | Valid values | `schema.enum` | Enum matches valid values? |
399
+ | Sort | `allowedSorts()` | `sort.enum` | Includes `field` AND `-field`? |
400
+ | Default sort | `defaultSort()` | `sort.description` | Default mentioned? |
401
+
402
+ ```bash
403
+ # Generate and verify
404
+ ./artisan l5-swagger:generate
405
+
406
+ # Check json output
407
+ cat backend/storage/api-docs/api-docs.json | jq '.components.schemas.User'
408
+ cat backend/storage/api-docs/api-docs.json | jq '.components.schemas.UserStoreRequest'
409
+ ```
410
+
411
+ ### Common Mistakes
412
+
413
+ | Mistake | Fix |
414
+ | ------------------------------- | ------------------------------------------------------------------------- |
415
+ | `ref: User` missing | Add `#[OA\Schema]` to `UserResource.php` |
416
+ | `ref: UserStoreRequest` missing | Add `#[OA\Schema]` to `UserStoreRequest.php` |
417
+ | sort enum incomplete | Include BOTH `field` AND `-field` for each `allowedSorts()` |
418
+ | sort missing default | Add "Default: `-id`" to sort description |
419
+ | filter description vague | List ALL fields: "Partial match on: name_lastname, name_firstname, email" |
420
+ | filter[status] no enum | Add `enum: ['active', 'inactive']` for exact filters |
421
+ | Using StoreRequest for update | Use UpdateRequest for PUT/PATCH |