@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,449 @@
1
+ # OpenAPI Documentation Guide
2
+
3
+ > **Related:** [README](./README.md) | [Controller Guide](./controller-guide.md) | [Checklist](./checklist.md)
4
+
5
+ ## ⚠️ CRITICAL: Check Route Prefix BEFORE Writing OpenAPI Path
6
+
7
+ ### Step 1: Check Which Route File the Controller Uses
8
+
9
+ ```bash
10
+ # Find where your route is registered
11
+ grep -r "UserController" routes/
12
+ ```
13
+
14
+ ### Step 2: Check the Route Prefix in That File
15
+
16
+ ```php
17
+ // bootstrap/app.php hoặc app/Providers/RouteServiceProvider.php
18
+ // Tìm xem route file có prefix gì
19
+
20
+ // Ví dụ Laravel 11+: bootstrap/app.php
21
+ ->withRouting(
22
+ api: __DIR__.'/../routes/api.php', // ← /api prefix tự động!
23
+ web: __DIR__.'/../routes/web.php',
24
+ apiPrefix: 'api', // ← Đây là prefix!
25
+ )
26
+
27
+ // Ví dụ Laravel 10: app/Providers/RouteServiceProvider.php
28
+ Route::middleware('api')
29
+ ->prefix('api') // ← Đây là prefix!
30
+ ->group(base_path('routes/api.php'));
31
+ ```
32
+
33
+ ### Step 3: Write OpenAPI Path = Actual Route Path (KHÔNG có prefix)
34
+
35
+ | Route File | Route Definition | Prefix | OpenAPI Path | Final URL |
36
+ |------------|------------------|--------|--------------|-----------|
37
+ | `api.php` | `Route::get('/users', ...)` | `/api` | `path: '/users'` | `/api/users` |
38
+ | `api.php` | `Route::get('/users/{id}', ...)` | `/api` | `path: '/users/{id}'` | `/api/users/1` |
39
+ | `web.php` | `Route::get('/dashboard', ...)` | (none) | `path: '/dashboard'` | `/dashboard` |
40
+ | `admin.php` | `Route::get('/stats', ...)` | `/admin/api` | `path: '/stats'` | `/admin/api/stats` |
41
+
42
+ ### ❌ CRITICAL BUG - Duplicate Prefix
43
+
44
+ ```php
45
+ // Route trong api.php (đã có prefix /api)
46
+ Route::get('/users', [UserController::class, 'index']);
47
+
48
+ // ❌ SAI - Viết thêm /api vào path
49
+ #[OA\Get(path: '/api/users')] // → /api/api/users !!
50
+
51
+ // ✅ ĐÚNG - Chỉ viết path sau prefix
52
+ #[OA\Get(path: '/users')] // → /api/users ✓
53
+ ```
54
+
55
+ ### Quick Reference: Common Prefixes
56
+
57
+ | Route File | Default Prefix | OpenAPI Server URL |
58
+ |------------|----------------|-------------------|
59
+ | `api.php` | `/api` | `#[OA\Server(url: '/api')]` |
60
+ | `web.php` | (none) | `#[OA\Server(url: '/')]` |
61
+ | Custom | Check RouteServiceProvider | Match the prefix |
62
+
63
+ ### Checklist Before Writing OpenAPI
64
+
65
+ - [ ] Check route file (`api.php` / `web.php` / custom)
66
+ - [ ] Check prefix in `RouteServiceProvider` or `bootstrap/app.php`
67
+ - [ ] OpenAPI path = Route path (WITHOUT prefix)
68
+ - [ ] `#[OA\Server(url: ...)]` matches the prefix
69
+
70
+ ---
71
+
72
+ ## ⚠️ CRITICAL: L5-Swagger Configuration
73
+
74
+ **MUST set `use_absolute_path` to `false`** in `config/l5-swagger.php`:
75
+
76
+ ```php
77
+ // config/l5-swagger.php
78
+ 'use_absolute_path' => env('L5_SWAGGER_USE_ABSOLUTE_PATH', false),
79
+ ```
80
+
81
+ Without this, Swagger UI will fail to load the API documentation correctly.
82
+
83
+ ---
84
+
85
+ ## Overview
86
+
87
+ This project uses [L5-Swagger](https://github.com/DarkaOnLine/L5-Swagger) with PHP 8 Attributes.
88
+
89
+ **Key files:**
90
+ - `app/OpenApi/Schemas.php` - Reusable components (parameters, responses)
91
+ - `{{LARAVEL_BASE}}/Http/Controllers/*Controller.php` - Endpoint documentation
92
+
93
+ ## Commands
94
+
95
+ ```bash
96
+ ./artisan l5-swagger:generate # Generate OpenAPI JSON
97
+ # View at: https://api.{folder}.app/api/documentation
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Architecture
103
+
104
+ ```
105
+ app/OpenApi/
106
+ └── Schemas.php ← Define reusable components HERE
107
+
108
+ {{LARAVEL_BASE}}/Http/Controllers/
109
+ └── UserController.php ← Use $ref to reference components
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Step 1: Define Reusable Components
115
+
116
+ **File:** `app/OpenApi/Schemas.php`
117
+
118
+ ```php
119
+ <?php
120
+
121
+ namespace App\OpenApi;
122
+
123
+ use OpenApi\Attributes as OA;
124
+
125
+ #[OA\Info(
126
+ version: '1.0.0',
127
+ title: 'My API',
128
+ description: 'API documentation'
129
+ )]
130
+ #[OA\Server(url: '/api', description: 'API Server')]
131
+
132
+ // ============================================================================
133
+ // COMMON PARAMETERS
134
+ // ============================================================================
135
+
136
+ #[OA\Parameter(
137
+ parameter: 'QuerySearch',
138
+ name: 'search',
139
+ in: 'query',
140
+ description: 'Search term',
141
+ schema: new OA\Schema(type: 'string')
142
+ )]
143
+ #[OA\Parameter(
144
+ parameter: 'QueryPage',
145
+ name: 'page',
146
+ in: 'query',
147
+ description: 'Page number',
148
+ schema: new OA\Schema(type: 'integer', default: 1, minimum: 1)
149
+ )]
150
+ #[OA\Parameter(
151
+ parameter: 'QueryPerPage',
152
+ name: 'per_page',
153
+ in: 'query',
154
+ description: 'Items per page',
155
+ schema: new OA\Schema(type: 'integer', default: 10, minimum: 1, maximum: 100)
156
+ )]
157
+ #[OA\Parameter(
158
+ parameter: 'QuerySortBy',
159
+ name: 'sort_by',
160
+ in: 'query',
161
+ description: 'Sort field',
162
+ schema: new OA\Schema(type: 'string', default: 'id')
163
+ )]
164
+ #[OA\Parameter(
165
+ parameter: 'QuerySortOrder',
166
+ name: 'sort_order',
167
+ in: 'query',
168
+ description: 'Sort direction',
169
+ schema: new OA\Schema(type: 'string', enum: ['asc', 'desc'], default: 'desc')
170
+ )]
171
+ #[OA\Parameter(
172
+ parameter: 'PathId',
173
+ name: 'id',
174
+ in: 'path',
175
+ required: true,
176
+ description: 'Resource ID',
177
+ schema: new OA\Schema(type: 'integer', minimum: 1)
178
+ )]
179
+
180
+ // ============================================================================
181
+ // COMMON RESPONSES
182
+ // ============================================================================
183
+
184
+ #[OA\Response(response: 'Success', description: 'Successful operation')]
185
+ #[OA\Response(response: 'Created', description: 'Resource created successfully')]
186
+ #[OA\Response(response: 'NoContent', description: 'Successfully deleted')]
187
+ #[OA\Response(response: 'NotFound', description: 'Resource not found')]
188
+ #[OA\Response(response: 'Unauthorized', description: 'Unauthenticated')]
189
+ #[OA\Response(response: 'Forbidden', description: 'Forbidden')]
190
+ #[OA\Response(
191
+ response: 'ValidationError',
192
+ description: 'Validation failed',
193
+ content: new OA\JsonContent(
194
+ properties: [
195
+ new OA\Property(property: 'message', type: 'string', example: 'The given data was invalid.'),
196
+ new OA\Property(property: 'errors', type: 'object', example: ['email' => ['The email has already been taken.']]),
197
+ ]
198
+ )
199
+ )]
200
+ class Schemas
201
+ {
202
+ // This class exists only to hold OpenAPI attributes
203
+ }
204
+ ```
205
+
206
+ ---
207
+
208
+ ## Step 2: Use $ref in Controllers
209
+
210
+ ### Index (GET list)
211
+
212
+ ```php
213
+ #[OA\Get(
214
+ path: '/users', // ⚠️ NO /api prefix! api.php already has it
215
+ summary: 'List users',
216
+ description: 'Paginated list with search and sorting',
217
+ tags: ['Users'],
218
+ parameters: [
219
+ new OA\Parameter(ref: '#/components/parameters/QuerySearch'),
220
+ new OA\Parameter(ref: '#/components/parameters/QueryPage'),
221
+ new OA\Parameter(ref: '#/components/parameters/QueryPerPage'),
222
+ new OA\Parameter(ref: '#/components/parameters/QuerySortBy'),
223
+ new OA\Parameter(ref: '#/components/parameters/QuerySortOrder'),
224
+ ],
225
+ responses: [
226
+ new OA\Response(ref: '#/components/responses/Success', response: 200),
227
+ ]
228
+ )]
229
+ public function index(Request $request): AnonymousResourceCollection
230
+ ```
231
+
232
+ ### Store (POST)
233
+
234
+ ```php
235
+ #[OA\Post(
236
+ path: '/users', // ⚠️ NO /api prefix!
237
+ summary: 'Create user',
238
+ description: 'Create a new user account',
239
+ tags: ['Users'],
240
+ requestBody: new OA\RequestBody(
241
+ required: true,
242
+ content: new OA\JsonContent(
243
+ required: ['name_lastname', 'name_firstname', 'email', 'password'],
244
+ properties: [
245
+ new OA\Property(property: 'name_lastname', type: 'string', maxLength: 50, example: '田中'),
246
+ new OA\Property(property: 'name_firstname', type: 'string', maxLength: 50, example: '太郎'),
247
+ new OA\Property(property: 'email', type: 'string', format: 'email', example: 'tanaka@example.com'),
248
+ new OA\Property(property: 'password', type: 'string', format: 'password', minLength: 8),
249
+ ]
250
+ )
251
+ ),
252
+ responses: [
253
+ new OA\Response(ref: '#/components/responses/Created', response: 201),
254
+ new OA\Response(ref: '#/components/responses/ValidationError', response: 422),
255
+ ]
256
+ )]
257
+ public function store(UserStoreRequest $request): UserResource
258
+ ```
259
+
260
+ ### Show (GET single)
261
+
262
+ ```php
263
+ #[OA\Get(
264
+ path: '/users/{id}', // ⚠️ NO /api prefix!
265
+ summary: 'Get user',
266
+ description: 'Get user by ID',
267
+ tags: ['Users'],
268
+ parameters: [
269
+ new OA\Parameter(ref: '#/components/parameters/PathId'),
270
+ ],
271
+ responses: [
272
+ new OA\Response(ref: '#/components/responses/Success', response: 200),
273
+ new OA\Response(ref: '#/components/responses/NotFound', response: 404),
274
+ ]
275
+ )]
276
+ public function show(User $user): UserResource
277
+ ```
278
+
279
+ ### Update (PUT)
280
+
281
+ ```php
282
+ #[OA\Put(
283
+ path: '/users/{id}', // ⚠️ NO /api prefix!
284
+ summary: 'Update user',
285
+ description: 'Update user (partial update supported)',
286
+ tags: ['Users'],
287
+ parameters: [
288
+ new OA\Parameter(ref: '#/components/parameters/PathId'),
289
+ ],
290
+ requestBody: new OA\RequestBody(
291
+ content: new OA\JsonContent(
292
+ properties: [
293
+ new OA\Property(property: 'name_lastname', type: 'string', maxLength: 50),
294
+ new OA\Property(property: 'name_firstname', type: 'string', maxLength: 50),
295
+ new OA\Property(property: 'email', type: 'string', format: 'email'),
296
+ new OA\Property(property: 'password', type: 'string', format: 'password', minLength: 8),
297
+ ]
298
+ )
299
+ ),
300
+ responses: [
301
+ new OA\Response(ref: '#/components/responses/Success', response: 200),
302
+ new OA\Response(ref: '#/components/responses/NotFound', response: 404),
303
+ new OA\Response(ref: '#/components/responses/ValidationError', response: 422),
304
+ ]
305
+ )]
306
+ public function update(UserUpdateRequest $request, User $user): UserResource
307
+ ```
308
+
309
+ ### Destroy (DELETE)
310
+
311
+ ```php
312
+ #[OA\Delete(
313
+ path: '/users/{id}', // ⚠️ NO /api prefix!
314
+ summary: 'Delete user',
315
+ description: 'Permanently delete user',
316
+ tags: ['Users'],
317
+ parameters: [
318
+ new OA\Parameter(ref: '#/components/parameters/PathId'),
319
+ ],
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
+ public function destroy(User $user): JsonResponse
326
+ ```
327
+
328
+ ---
329
+
330
+ ## Available Components
331
+
332
+ ### Parameters (use with `ref: '#/components/parameters/...'`)
333
+
334
+ | Name | Description |
335
+ | ---------------- | -------------------------------------- |
336
+ | `QuerySearch` | Search term |
337
+ | `QueryPage` | Page number (default: 1) |
338
+ | `QueryPerPage` | Items per page (default: 10, max: 100) |
339
+ | `QuerySortBy` | Sort field (default: id) |
340
+ | `QuerySortOrder` | Sort direction (asc/desc) |
341
+ | `PathId` | Resource ID in path |
342
+
343
+ ### Responses (use with `ref: '#/components/responses/...'`)
344
+
345
+ | Name | HTTP Code | Description |
346
+ | ----------------- | --------- | -------------------- |
347
+ | `Success` | 200 | Successful operation |
348
+ | `Created` | 201 | Resource created |
349
+ | `NoContent` | 204 | Successfully deleted |
350
+ | `NotFound` | 404 | Resource not found |
351
+ | `ValidationError` | 422 | Validation failed |
352
+ | `Unauthorized` | 401 | Unauthenticated |
353
+ | `Forbidden` | 403 | Forbidden |
354
+
355
+ ---
356
+
357
+ ## ⚠️ Important: Verify Fields Before Writing
358
+
359
+ **DO NOT make up fields!** Check these files first:
360
+
361
+ | What to Document | Check This File |
362
+ | ------------------- | ------------------------------------------------------------------- |
363
+ | Request body fields | `{{LARAVEL_BASE}}/Http/Requests/OmnifyBase/*RequestBase.php` → `schemaRules()` |
364
+ | Response fields | `{{LARAVEL_BASE}}/Http/Resources/OmnifyBase/*ResourceBase.php` → `schemaArray()` |
365
+
366
+ ---
367
+
368
+ ## Adding New Components
369
+
370
+ ### New Parameter
371
+
372
+ ```php
373
+ // In app/OpenApi/Schemas.php
374
+ #[OA\Parameter(
375
+ parameter: 'QueryStatus', // Unique name
376
+ name: 'status', // Query param name
377
+ in: 'query',
378
+ description: 'Filter by status',
379
+ schema: new OA\Schema(type: 'string', enum: ['active', 'inactive'])
380
+ )]
381
+ ```
382
+
383
+ ### New Response
384
+
385
+ ```php
386
+ // In app/OpenApi/Schemas.php
387
+ #[OA\Response(
388
+ response: 'PaymentRequired',
389
+ description: 'Payment required'
390
+ )]
391
+ ```
392
+
393
+ ---
394
+
395
+ ## Checklist
396
+
397
+ ### Before Writing
398
+
399
+ - [ ] Check `OmnifyBase/*RequestBase.php` for request fields
400
+ - [ ] Check `OmnifyBase/*ResourceBase.php` for response fields
401
+ - [ ] DON'T make up fields that don't exist!
402
+
403
+ ### Writing OpenAPI
404
+
405
+ - [ ] Add `#[OA\Tag]` to controller class
406
+ - [ ] Use `$ref` for common parameters (QuerySearch, QueryPage, etc.)
407
+ - [ ] Use `$ref` for common responses (Success, NotFound, etc.)
408
+ - [ ] Only write `requestBody` properties manually (match FormRequest)
409
+ - [ ] Use Japanese examples for JapaneseName fields
410
+
411
+ ### After Writing
412
+
413
+ - [ ] Run `./artisan l5-swagger:generate`
414
+ - [ ] Verify at `/api/documentation`
415
+
416
+ ---
417
+
418
+ ## Anti-Patterns
419
+
420
+ ```php
421
+ // ❌ BAD: Repeating common parameters
422
+ parameters: [
423
+ new OA\Parameter(name: 'page', in: 'query', schema: new OA\Schema(type: 'integer')),
424
+ new OA\Parameter(name: 'per_page', in: 'query', schema: new OA\Schema(type: 'integer')),
425
+ ]
426
+
427
+ // ✅ GOOD: Use $ref
428
+ parameters: [
429
+ new OA\Parameter(ref: '#/components/parameters/QueryPage'),
430
+ new OA\Parameter(ref: '#/components/parameters/QueryPerPage'),
431
+ ]
432
+
433
+ // ❌ BAD: Repeating response definitions
434
+ responses: [
435
+ new OA\Response(response: 404, description: 'Resource not found'),
436
+ ]
437
+
438
+ // ✅ GOOD: Use $ref
439
+ responses: [
440
+ new OA\Response(ref: '#/components/responses/NotFound', response: 404),
441
+ ]
442
+
443
+ // ❌ BAD: Making up fields
444
+ new OA\Property(property: 'username', ...) // Does this exist?
445
+
446
+ // ✅ GOOD: Check OmnifyBase first, then write
447
+ // Checked: OmnifyBase/UserStoreRequestBase.php has name_lastname, name_firstname...
448
+ new OA\Property(property: 'name_lastname', type: 'string', example: '田中'),
449
+ ```