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 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
+ ```