base-api-scramble-mcp 1.0.0
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 +140 -0
- package/docs/AI-GUIDE-COMPLETE.md +372 -0
- package/docs/EXCEL-EXPORT-SERVICE.md +349 -0
- package/docs/EXPORT-DATA-PROVIDERS.md +340 -0
- package/docs/EXPORT-TEMPLATES.md +459 -0
- package/docs/LARAVEL-API-TEST.md +355 -0
- package/docs/MAKE-EXPORT-EXCEL-COMMAND.md +215 -0
- package/docs/README.md +678 -0
- package/docs/STRUCTURE.md +540 -0
- package/docs/starting_point.md +423 -0
- package/index.js +968 -0
- package/package.json +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# ๐ Base API Scramble โ MCP Server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server yang expose seluruh dokumentasi **base-api-scramble** sebagai knowledge base untuk AI (Claude, Cursor, Copilot, dll).
|
|
4
|
+
|
|
5
|
+
Dengan MCP ini, AI langsung paham:
|
|
6
|
+
- Arsitektur & flow request project
|
|
7
|
+
- Konvensi wajib (UUID, Queryable, ApiResponse)
|
|
8
|
+
- Cara pakai artisan `gc` & `gc:from-migration`
|
|
9
|
+
- Pattern Model / Query Class / Controller / FormRequest
|
|
10
|
+
- FileService, Export Excel, Auth endpoints, dsb.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## ๐ฆ Struktur
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
base-api-mcp/
|
|
18
|
+
โโโ index.js โ MCP Server utama
|
|
19
|
+
โโโ package.json
|
|
20
|
+
โโโ docs/ โ Copy dari base-api-scramble/docs/
|
|
21
|
+
โ โโโ starting_point.md
|
|
22
|
+
โ โโโ AI-GUIDE-COMPLETE.md
|
|
23
|
+
โ โโโ STRUCTURE.md
|
|
24
|
+
โ โโโ README.md
|
|
25
|
+
โ โโโ EXCEL-EXPORT-SERVICE.md
|
|
26
|
+
โ โโโ EXPORT-DATA-PROVIDERS.md
|
|
27
|
+
โ โโโ EXPORT-TEMPLATES.md
|
|
28
|
+
โ โโโ LARAVEL-API-TEST.md
|
|
29
|
+
โ โโโ MAKE-EXPORT-EXCEL-COMMAND.md
|
|
30
|
+
โโโ README.md
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## ๐ Tools yang Tersedia
|
|
36
|
+
|
|
37
|
+
| Tool | Deskripsi |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `get_starting_point` | Kickoff guide: quick start, stack, konvensi โ **mulai dari sini** |
|
|
40
|
+
| `get_architecture` | Arsitektur lengkap, flow, pattern code |
|
|
41
|
+
| `get_structure` | Struktur direktori project |
|
|
42
|
+
| `get_conventions` | Aturan wajib: Model, Migration, Query, Controller, Route |
|
|
43
|
+
| `get_commands` | Referensi artisan gc commands + field type mapping |
|
|
44
|
+
| `get_api_response_format` | Format JSON response + semua method ApiResponse |
|
|
45
|
+
| `get_query_params` | Semua query parameter (search, filter, sort, include, dll) |
|
|
46
|
+
| `get_file_service` | Cara upload/delete file dengan FileService |
|
|
47
|
+
| `get_export_guide` | Excel export system (PhpSpreadsheet + Data Provider) |
|
|
48
|
+
| `get_auth_endpoints` | Endpoint auth, RBAC, file management bawaan |
|
|
49
|
+
| `list_docs` | Daftar semua file doc yang tersedia |
|
|
50
|
+
| `get_doc` | Baca isi lengkap 1 file doc |
|
|
51
|
+
| `search_docs` | Full-text search di semua docs |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## โ๏ธ Setup
|
|
56
|
+
|
|
57
|
+
### 1. Install dependencies (sudah dilakukan)
|
|
58
|
+
```bash
|
|
59
|
+
cd /Users/sunarta25/gotra/CLI/base-api-mcp
|
|
60
|
+
npm install
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2. Tambahkan ke Claude Desktop
|
|
64
|
+
|
|
65
|
+
Edit file: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"mcpServers": {
|
|
70
|
+
"base-api-scramble": {
|
|
71
|
+
"command": "node",
|
|
72
|
+
"args": ["/Users/sunarta25/gotra/CLI/base-api-mcp/index.js"]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
> Jika sudah ada `mcpServers` lain, cukup tambahkan key `"base-api-scramble"` di dalam object yang sudah ada.
|
|
79
|
+
|
|
80
|
+
### 3. Restart Claude Desktop
|
|
81
|
+
|
|
82
|
+
Tutup & buka kembali Claude Desktop. MCP server akan aktif otomatis.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## โ๏ธ Setup Cursor
|
|
87
|
+
|
|
88
|
+
Edit `.cursor/mcp.json` di root project atau `~/.cursor/mcp.json` untuk global:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"mcpServers": {
|
|
93
|
+
"base-api-scramble": {
|
|
94
|
+
"command": "node",
|
|
95
|
+
"args": ["/Users/sunarta25/gotra/CLI/base-api-mcp/index.js"]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## ๐ Update Docs
|
|
104
|
+
|
|
105
|
+
Jika docs di `base-api-scramble` diupdate, sync ulang dengan:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
cp -r /Users/sunarta25/gotra/base-api-scramble/docs/* \
|
|
109
|
+
/Users/sunarta25/gotra/CLI/base-api-mcp/docs/
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## ๐งช Test Manual
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
cd /Users/sunarta25/gotra/CLI/base-api-mcp
|
|
118
|
+
npm start
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Server berjalan via **stdio** โ digunakan oleh Claude/Cursor secara otomatis.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## ๐ก Cara Pakai di Claude
|
|
126
|
+
|
|
127
|
+
Setelah setup, Claude bisa langsung pakai tools ini. Contoh prompt:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
Gunakan get_starting_point untuk memahami project, lalu buatkan module Product
|
|
131
|
+
dengan fields: name, price, stock, image (file), category (relasi).
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
Cari informasi tentang FileService menggunakan search_docs
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
Tampilkan semua endpoint auth yang tersedia menggunakan get_auth_endpoints
|
|
140
|
+
```
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
# AI GUIDE โ Laravel Base API (Query Pattern + Scramble)
|
|
2
|
+
|
|
3
|
+
**Stack:** Laravel 10.x ยท PHP 8.1+ ยท UUID primary keys
|
|
4
|
+
**Path:** `~/gotra/base-api-scramble`
|
|
5
|
+
|
|
6
|
+
**Core Dependencies:**
|
|
7
|
+
| Package | Version | Purpose |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Laravel Sanctum | ^3.3 | Auth (Bearer token) |
|
|
10
|
+
| Spatie Permission | ^6.13 | RBAC |
|
|
11
|
+
| Spatie QueryBuilder | ^6.3 | Filtering/sorting/includes |
|
|
12
|
+
| Spatie Activity Log | ^4.9 | Audit trail |
|
|
13
|
+
| Dedoc Scramble + Pro | ^0.12.35 + ^0.7.18 | Auto OpenAPI docs |
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## ARCHITECTURE
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
FormRequest โ Controller โ Query Class โ Model (Queryable trait) โ ApiResponse
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**5 core components:**
|
|
24
|
+
1. **Query Class** (`App\Queries\*`) โ extends Spatie QueryBuilder, defines `allowedFilters` & `allowedIncludes`
|
|
25
|
+
2. **Queryable Trait** (`App\Traits\Queryable`) โ auto-generates filters/sorts/fields from DB columns, provides `scopeSearch`
|
|
26
|
+
3. **Controller** (`App\Http\Controllers\Api\V1\*`) โ uses `baseQuery()` + ApiResponse methods
|
|
27
|
+
4. **ApiResponse Trait** (`App\Helpers\ApiResponse`) โ standardized JSON output
|
|
28
|
+
5. **FileService** (`App\Services\FileService`) โ upload/compress/delete files
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## TWO WORKFLOWS
|
|
33
|
+
|
|
34
|
+
### A. Migration-First (complex / AI-generated schema)
|
|
35
|
+
```
|
|
36
|
+
AI generates migration โ User saves file โ php artisan gc:from-migration {table} โ php artisan migrate
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### B. Fields-First (simple / quick)
|
|
40
|
+
```
|
|
41
|
+
php artisan gc {Model} --fields=field:type,... โ php artisan migrate
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Decision logic:**
|
|
45
|
+
- User menyebut "migration" OR schema kompleks โ Workflow A
|
|
46
|
+
- Fields < 5 dan jelas โ Workflow B
|
|
47
|
+
- Tidak jelas / > 5 fields โ `gc:wizard {Model}`
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## COMMANDS REFERENCE
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Fields-first
|
|
55
|
+
php artisan gc Product --fields=name:string,price:decimal,stock:integer,image:file
|
|
56
|
+
php artisan gc Product --fields=name,price:decimal --belongsTo=Category,Brand
|
|
57
|
+
|
|
58
|
+
# Migration-first
|
|
59
|
+
php artisan gc:from-migration products # table name (plural)
|
|
60
|
+
|
|
61
|
+
# Interactive
|
|
62
|
+
php artisan gc:wizard Product
|
|
63
|
+
|
|
64
|
+
# Extras
|
|
65
|
+
php artisan gc Product --fields=name,price --preview # preview only
|
|
66
|
+
php artisan gc Product --fields=name,price --migration # migration only
|
|
67
|
+
php artisan gc:help
|
|
68
|
+
php artisan migrate
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## FIELD TYPE MAPPING
|
|
74
|
+
|
|
75
|
+
Auto-detect dari nama field (ID/EN):
|
|
76
|
+
|
|
77
|
+
| Field | Type | Field | Type |
|
|
78
|
+
|---|---|---|---|
|
|
79
|
+
| nama, name, title, judul | `string` | gambar, image, photo, foto, file, dokumen | `file` |
|
|
80
|
+
| deskripsi, description, content | `text` | is_*, aktif, published | `boolean` |
|
|
81
|
+
| harga, price, cost, biaya | `decimal` | *_at, tanggal, date | `datetime` |
|
|
82
|
+
| stok, stock, quantity, jumlah | `integer` | slug | `string` |
|
|
83
|
+
|
|
84
|
+
**Indonesian โ English:** namaโname, hargaโprice, stokโstock, gambarโimage, fotoโphoto, deskripsiโdescription, judulโtitle, kontenโcontent, tanggalโdate, aktifโis_active
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## GENERATED FILES (6 files)
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
app/
|
|
92
|
+
โโโ Models/Product.php # HasUuids, Queryable, $fillable, $appends, $searchable
|
|
93
|
+
โโโ Queries/ProductQuery.php # extends QueryBuilder, allowedFilters, allowedIncludes
|
|
94
|
+
โโโ Http/Controllers/Api/V1/ProductController.php # CRUD + FileService
|
|
95
|
+
โโโ Http/Requests/Api/V1/ProductStoreRequest.php
|
|
96
|
+
โโโ Http/Requests/Api/V1/ProductUpdateRequest.php
|
|
97
|
+
database/migrations/xxxx_create_products_table.php
|
|
98
|
+
# routes/api_v1.php โ Route::apiResource('products', ProductController::class) auto-added
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## PATTERN REFERENCE
|
|
104
|
+
|
|
105
|
+
### Model
|
|
106
|
+
```php
|
|
107
|
+
class Product extends Model
|
|
108
|
+
{
|
|
109
|
+
use HasFactory, HasUuids, Queryable;
|
|
110
|
+
|
|
111
|
+
protected $fillable = ['name', 'price', 'stock', 'image', 'category_id'];
|
|
112
|
+
protected $appends = ['image_url']; // for file fields
|
|
113
|
+
protected array $searchable = ['name']; // columns for ?search=
|
|
114
|
+
protected array $relationIncludes = ['category']; // for ?include=
|
|
115
|
+
|
|
116
|
+
public function category() { return $this->belongsTo(Category::class); }
|
|
117
|
+
|
|
118
|
+
public function getImageUrlAttribute()
|
|
119
|
+
{
|
|
120
|
+
return $this->image ? asset('uploads/products/' . $this->image) : null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Query Class
|
|
126
|
+
```php
|
|
127
|
+
class ProductQuery extends QueryBuilder
|
|
128
|
+
{
|
|
129
|
+
public function __construct()
|
|
130
|
+
{
|
|
131
|
+
parent::__construct(Product::query());
|
|
132
|
+
$this
|
|
133
|
+
->allowedIncludes([AllowedInclude::relationship('category')])
|
|
134
|
+
->allowedFilters([
|
|
135
|
+
AllowedFilter::exact('id'),
|
|
136
|
+
AllowedFilter::partial('name'),
|
|
137
|
+
AllowedFilter::exact('category_id'),
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Controller
|
|
144
|
+
```php
|
|
145
|
+
class ProductController extends Controller
|
|
146
|
+
{
|
|
147
|
+
private FileService $fileService;
|
|
148
|
+
public function __construct() { $this->fileService = new FileService(); }
|
|
149
|
+
|
|
150
|
+
// index โ uses baseQuery() which reads request() internally
|
|
151
|
+
public function index(IndexRequest $request)
|
|
152
|
+
{
|
|
153
|
+
return $this->responseData(
|
|
154
|
+
$this->baseQuery(new ProductQuery()),
|
|
155
|
+
'Product retrieved successfully'
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// show
|
|
160
|
+
public function show(Product $product)
|
|
161
|
+
{
|
|
162
|
+
return $this->responseSuccess($product, 'Product retrieved successfully');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// store
|
|
166
|
+
public function store(ProductStoreRequest $request)
|
|
167
|
+
{
|
|
168
|
+
$data = $request->validated();
|
|
169
|
+
if ($request->hasFile('image')) {
|
|
170
|
+
$file = $this->fileService->saveFileComplete(
|
|
171
|
+
file: $request->file('image'),
|
|
172
|
+
folder: 'products',
|
|
173
|
+
fileName: 'product_' . time(),
|
|
174
|
+
is_compressed: true,
|
|
175
|
+
);
|
|
176
|
+
$data['image'] = $file['name'];
|
|
177
|
+
}
|
|
178
|
+
return $this->responseCreated(Product::create($data), 'Product created successfully');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// update
|
|
182
|
+
public function update(ProductUpdateRequest $request, Product $product)
|
|
183
|
+
{
|
|
184
|
+
$data = $request->validated();
|
|
185
|
+
if ($request->input('image') == null && $product->image) {
|
|
186
|
+
$this->fileService->deleteFile(folder: 'products', fileName: $product->image);
|
|
187
|
+
$data['image'] = '';
|
|
188
|
+
}
|
|
189
|
+
if ($request->hasFile('image')) {
|
|
190
|
+
if ($product->image) $this->fileService->deleteFile(folder: 'products', fileName: $product->image);
|
|
191
|
+
$file = $this->fileService->saveFileComplete(
|
|
192
|
+
file: $request->file('image'), folder: 'products',
|
|
193
|
+
fileName: 'product_' . time(), is_compressed: true,
|
|
194
|
+
);
|
|
195
|
+
$data['image'] = $file['name'];
|
|
196
|
+
}
|
|
197
|
+
$product->update($data);
|
|
198
|
+
return $this->responseSuccess($product, 'Product updated successfully');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// destroy
|
|
202
|
+
public function destroy(Product $product)
|
|
203
|
+
{
|
|
204
|
+
if ($product->image) $this->fileService->deleteFile(folder: 'products', fileName: $product->image);
|
|
205
|
+
$product->delete();
|
|
206
|
+
return $this->responseDeleted('Product deleted successfully');
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### FormRequest (with Scramble PHPDoc)
|
|
212
|
+
```php
|
|
213
|
+
public function rules(): array
|
|
214
|
+
{
|
|
215
|
+
return [
|
|
216
|
+
/** @example iPhone 14 Pro */
|
|
217
|
+
'name' => 'required|string|max:255',
|
|
218
|
+
/** @example 15000000 */
|
|
219
|
+
'price' => 'required|numeric|min:0',
|
|
220
|
+
/** @example 50 */
|
|
221
|
+
'stock' => 'required|integer|min:0',
|
|
222
|
+
/** Product image JPG/PNG max 20MB. @example (binary) */
|
|
223
|
+
'image' => 'nullable|file|mimes:jpg,jpeg,png|max:20480',
|
|
224
|
+
/** @example 550e8400-e29b-41d4-a716-446655440000 */
|
|
225
|
+
'category_id' => 'required|exists:categories,id',
|
|
226
|
+
];
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## API QUERY PARAMETERS
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
# Via baseQuery() โ Controller level
|
|
236
|
+
?search=keyword # searches $searchable columns (LIKE %keyword%)
|
|
237
|
+
?sort_by=price # column to sort
|
|
238
|
+
?sort_order=asc|desc # default: desc
|
|
239
|
+
?paginate=20 # items per page (triggers pagination)
|
|
240
|
+
?first=1 # return first record only
|
|
241
|
+
|
|
242
|
+
# Via Spatie QueryBuilder โ Query Class level
|
|
243
|
+
?filter[name]=iPhone # exact/partial filter (as defined in Query class)
|
|
244
|
+
?filter[category_id]=uuid
|
|
245
|
+
?include=category # relations in $relationIncludes
|
|
246
|
+
?include=category,brand
|
|
247
|
+
?sort=-price # Spatie sort: prefix - for desc
|
|
248
|
+
?fields[products]=id,name,price
|
|
249
|
+
|
|
250
|
+
# Combined example
|
|
251
|
+
GET /api/v1/products?search=phone&filter[category_id]=uuid&sort_by=price&sort_order=asc&paginate=15&include=category
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## API RESPONSE METHODS & FORMAT
|
|
257
|
+
|
|
258
|
+
```php
|
|
259
|
+
$this->responseSuccess($data, $message, $statusCode = 200)
|
|
260
|
+
$this->responseData($data, $message) // auto-detects paginator โ adds pagination key
|
|
261
|
+
$this->responseCreated($data, $message) // 201
|
|
262
|
+
$this->responseDeleted($message) // 200, data: null
|
|
263
|
+
$this->responseError($message, $code = 400)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Standard:** `{ success, message, code, data }`
|
|
267
|
+
**Paginated:** adds `pagination: { current_page, from, to, total, per_page, last_page, next_page, prev_page, path }`
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## MIGRATION TEMPLATE (Workflow A)
|
|
272
|
+
|
|
273
|
+
```php
|
|
274
|
+
// Save as: database/migrations/2024_xx_xx_create_products_table.php
|
|
275
|
+
return new class extends Migration {
|
|
276
|
+
public function up(): void {
|
|
277
|
+
Schema::create('products', function (Blueprint $table) {
|
|
278
|
+
$table->uuid('id')->primary();
|
|
279
|
+
$table->string('name');
|
|
280
|
+
$table->decimal('price', 10, 2);
|
|
281
|
+
$table->integer('stock');
|
|
282
|
+
$table->string('image')->nullable();
|
|
283
|
+
$table->foreignUuid('category_id')->constrained()->cascadeOnDelete();
|
|
284
|
+
$table->timestamps();
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
public function down(): void { Schema::dropIfExists('products'); }
|
|
288
|
+
};
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Then:** `php artisan gc:from-migration products && php artisan migrate`
|
|
292
|
+
|
|
293
|
+
**gc:from-migration auto-detects:**
|
|
294
|
+
- All column types โ `$fillable`, validation rules
|
|
295
|
+
- `foreignUuid` / `foreignId` โ `belongsTo` + `$relationIncludes`
|
|
296
|
+
- File-like field names โ FileService integration + `$appends` accessor
|
|
297
|
+
- `->nullable()` โ `nullable` validation rule
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## FILE SERVICE
|
|
302
|
+
|
|
303
|
+
```php
|
|
304
|
+
// Upload with compression
|
|
305
|
+
$file = $this->fileService->saveFileComplete(
|
|
306
|
+
file: $request->file('image'),
|
|
307
|
+
folder: 'products', // stored in storage/app/{folder}/ (or S3: filemanager/{folder}/)
|
|
308
|
+
fileName: 'product_' . time(),
|
|
309
|
+
is_compressed: true, // Imagick compression (jpg/jpeg/png/webp only)
|
|
310
|
+
);
|
|
311
|
+
$data['image'] = $file['name']; // returns ['name' => 'slugged-name-xxxx.ext', ...]
|
|
312
|
+
|
|
313
|
+
// Delete
|
|
314
|
+
$this->fileService->deleteFile(folder: 'products', fileName: $product->image);
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## AI RULES
|
|
320
|
+
|
|
321
|
+
**ALWAYS:**
|
|
322
|
+
- Translate Indonesian field names to English
|
|
323
|
+
- Use `uuid('id')->primary()` โ no auto-increment
|
|
324
|
+
- Include `php artisan migrate` after gc command
|
|
325
|
+
- Use `gc:from-migration {table}` (plural table name) for existing migrations
|
|
326
|
+
- Add `@example` PHPDoc in FormRequests for Scramble docs
|
|
327
|
+
- `baseQuery(new XxxQuery())` โ ONE argument only
|
|
328
|
+
|
|
329
|
+
**NEVER:**
|
|
330
|
+
- Generate CRUD code manually โ always use gc commands
|
|
331
|
+
- Use `id()->primary()` (use `uuid`)
|
|
332
|
+
- Skip explaining `?search`, `?filter[]`, `?include=` capabilities
|
|
333
|
+
- Suggest `gc:wizard` when fields are clear and < 5
|
|
334
|
+
|
|
335
|
+
**Model name rules:** Singular PascalCase (`Product`, `CategoryItem`), table = plural snake_case (auto)
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## QUICK EXAMPLES
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
# Simple
|
|
343
|
+
php artisan gc Product --fields=name,price:decimal,stock:integer && php artisan migrate
|
|
344
|
+
|
|
345
|
+
# With file
|
|
346
|
+
php artisan gc Product --fields=name,price:decimal,image:file && php artisan migrate
|
|
347
|
+
|
|
348
|
+
# With relations
|
|
349
|
+
php artisan gc Product --fields=name,price:decimal,image:file --belongsTo=Category,Brand && php artisan migrate
|
|
350
|
+
|
|
351
|
+
# From existing migration
|
|
352
|
+
php artisan gc:from-migration products && php artisan migrate
|
|
353
|
+
|
|
354
|
+
# Complex / unclear
|
|
355
|
+
php artisan gc:wizard Product
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## SCRAMBLE DOCS
|
|
361
|
+
|
|
362
|
+
Auto-generated from PHPDoc + FormRequest rules + route definitions.
|
|
363
|
+
Access: `http://your-app.test/docs/api`
|
|
364
|
+
|
|
365
|
+
Controller PHPDoc pattern:
|
|
366
|
+
```php
|
|
367
|
+
/**
|
|
368
|
+
* Get list of products
|
|
369
|
+
* @response array{success: true, code: 200, message: "...", data: Product[], pagination?: array{...}}
|
|
370
|
+
*/
|
|
371
|
+
public function index(IndexRequest $request) { ... }
|
|
372
|
+
```
|