@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,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 |
|