@famgia/omnify-laravel 0.0.88 → 0.0.90
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/dist/{chunk-YVVAJA3T.js → chunk-2QSKZS63.js} +188 -12
- package/dist/chunk-2QSKZS63.js.map +1 -0
- package/dist/index.cjs +190 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -1
- package/dist/index.d.ts +48 -1
- package/dist/index.js +5 -1
- package/dist/plugin.cjs +186 -11
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.js +1 -1
- package/package.json +5 -5
- package/scripts/postinstall.js +29 -36
- package/stubs/ai-guides/README.md.stub +95 -0
- package/stubs/ai-guides/claude-agents/architect.md.stub +150 -0
- package/stubs/ai-guides/claude-agents/developer.md.stub +190 -0
- package/stubs/ai-guides/claude-agents/reviewer.md.stub +134 -0
- package/stubs/ai-guides/claude-agents/tester.md.stub +196 -0
- package/stubs/ai-guides/claude-checklists/backend.md.stub +112 -0
- package/stubs/ai-guides/claude-omnify/antdesign-guide.md.stub +401 -0
- package/stubs/ai-guides/claude-omnify/config-guide.md.stub +253 -0
- package/stubs/ai-guides/claude-omnify/japan-guide.md.stub +186 -0
- package/stubs/ai-guides/claude-omnify/laravel-guide.md.stub +61 -0
- package/stubs/ai-guides/claude-omnify/react-form-guide.md.stub +259 -0
- package/stubs/ai-guides/claude-omnify/schema-guide.md.stub +115 -0
- package/stubs/ai-guides/claude-omnify/typescript-guide.md.stub +310 -0
- package/stubs/ai-guides/claude-rules/naming.md.stub +364 -0
- package/stubs/ai-guides/claude-rules/performance.md.stub +251 -0
- package/stubs/ai-guides/claude-rules/security.md.stub +159 -0
- package/stubs/ai-guides/claude-workflows/bug-fix.md.stub +201 -0
- package/stubs/ai-guides/claude-workflows/code-review.md.stub +164 -0
- package/stubs/ai-guides/claude-workflows/new-feature.md.stub +327 -0
- package/stubs/ai-guides/cursor/laravel-controller.mdc.stub +391 -0
- package/stubs/ai-guides/cursor/laravel-request.mdc.stub +112 -0
- package/stubs/ai-guides/cursor/laravel-resource.mdc.stub +73 -0
- package/stubs/ai-guides/cursor/laravel-review.mdc.stub +69 -0
- package/stubs/ai-guides/cursor/laravel-testing.mdc.stub +138 -0
- package/stubs/ai-guides/cursor/laravel.mdc.stub +82 -0
- package/stubs/ai-guides/cursor/omnify.mdc.stub +58 -0
- package/stubs/ai-guides/laravel/README.md.stub +59 -0
- package/stubs/ai-guides/laravel/architecture.md.stub +424 -0
- package/stubs/ai-guides/laravel/controller.md.stub +484 -0
- package/stubs/ai-guides/laravel/datetime.md.stub +334 -0
- package/stubs/ai-guides/laravel/openapi.md.stub +369 -0
- package/stubs/ai-guides/laravel/request.md.stub +450 -0
- package/stubs/ai-guides/laravel/resource.md.stub +516 -0
- package/stubs/ai-guides/laravel/service.md.stub +503 -0
- package/stubs/ai-guides/laravel/testing.md.stub +1504 -0
- package/ai-guides/laravel-guide.md +0 -461
- package/dist/chunk-YVVAJA3T.js.map +0 -1
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
# Design Philosophy
|
|
2
|
+
|
|
3
|
+
> This document explains the architectural decisions and design principles for this Laravel backend.
|
|
4
|
+
|
|
5
|
+
## Architecture: Thin Controller + Service (When Needed)
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
flowchart TD
|
|
9
|
+
subgraph HTTP["HTTP Layer"]
|
|
10
|
+
Route[Route] --> Middleware --> FormRequest
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
FormRequest --> Controller
|
|
14
|
+
|
|
15
|
+
subgraph Controller["Controller Layer (Thin)"]
|
|
16
|
+
C[Orchestrate request → response]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Controller --> Model
|
|
20
|
+
Controller --> Service
|
|
21
|
+
|
|
22
|
+
subgraph Data["Data Layer"]
|
|
23
|
+
Model["Model (Simple CRUD)"]
|
|
24
|
+
Service["Service (Complex ops)"]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Model --> Resource
|
|
28
|
+
Service --> Resource
|
|
29
|
+
|
|
30
|
+
subgraph Output["Response Layer"]
|
|
31
|
+
Resource[Resource - JSON format]
|
|
32
|
+
end
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
| Layer | Responsibility | Rules |
|
|
36
|
+
| ---------- | ------------------------------ | ----------------------------------- |
|
|
37
|
+
| HTTP | Routing, auth, validation | No business logic |
|
|
38
|
+
| Controller | Orchestrate request → response | Delegate to Model or Service |
|
|
39
|
+
| Model | Simple CRUD | `User::create()`, `$user->update()` |
|
|
40
|
+
| Service | Complex operations | `OrderService`, `PaymentService` |
|
|
41
|
+
| Resource | Format JSON response | Dates to ISO 8601 |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Core Principle: Don't Over-Engineer
|
|
46
|
+
|
|
47
|
+
### ❌ BAD: Over-Engineering Simple CRUD
|
|
48
|
+
|
|
49
|
+
```php
|
|
50
|
+
// DON'T create all these for simple CRUD:
|
|
51
|
+
app/
|
|
52
|
+
├── Repositories/
|
|
53
|
+
│ ├── UserRepositoryInterface.php
|
|
54
|
+
│ └── UserRepository.php
|
|
55
|
+
├── Services/
|
|
56
|
+
│ └── UserService.php
|
|
57
|
+
├── DTOs/
|
|
58
|
+
│ └── UserDTO.php
|
|
59
|
+
└── Contracts/
|
|
60
|
+
└── UserServiceInterface.php
|
|
61
|
+
|
|
62
|
+
// Controller calls Service calls Repository calls Model
|
|
63
|
+
// 4 layers for a simple User::create()!
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### ✅ GOOD: Simple CRUD = Controller + Model
|
|
67
|
+
|
|
68
|
+
```php
|
|
69
|
+
// Simple CRUD - Controller is enough
|
|
70
|
+
class UserController extends Controller
|
|
71
|
+
{
|
|
72
|
+
public function store(UserStoreRequest $request): UserResource
|
|
73
|
+
{
|
|
74
|
+
$user = User::create($request->validated());
|
|
75
|
+
return new UserResource($user);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// That's it! No extra layers needed.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## When to Add Each Layer
|
|
85
|
+
|
|
86
|
+
### Layer Decision Matrix
|
|
87
|
+
|
|
88
|
+
| Scenario | Controller | Service | Action | Job |
|
|
89
|
+
| ------------------------- | ---------- | ------- | ------ | --- |
|
|
90
|
+
| Simple CRUD | ✅ | ❌ | ❌ | ❌ |
|
|
91
|
+
| CRUD + send email | ✅ | ❌ | ❌ | ✅ |
|
|
92
|
+
| Multi-step business logic | ✅ | ✅ | ❌ | ❌ |
|
|
93
|
+
| Reusable single operation | ✅ | ❌ | ✅ | ❌ |
|
|
94
|
+
| Long-running task | ✅ | ❌ | ❌ | ✅ |
|
|
95
|
+
|
|
96
|
+
### Detailed Examples
|
|
97
|
+
|
|
98
|
+
#### 1. Simple CRUD → Controller Only
|
|
99
|
+
|
|
100
|
+
```php
|
|
101
|
+
// ✅ Direct model operations
|
|
102
|
+
public function store(UserStoreRequest $request): UserResource
|
|
103
|
+
{
|
|
104
|
+
$user = User::create($request->validated());
|
|
105
|
+
return new UserResource($user);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public function update(UserUpdateRequest $request, User $user): UserResource
|
|
109
|
+
{
|
|
110
|
+
$user->update($request->validated());
|
|
111
|
+
return new UserResource($user);
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### 2. CRUD + Side Effects → Controller + Job/Event
|
|
116
|
+
|
|
117
|
+
```php
|
|
118
|
+
// ✅ Use Job for async operations
|
|
119
|
+
public function store(UserStoreRequest $request): UserResource
|
|
120
|
+
{
|
|
121
|
+
$user = User::create($request->validated());
|
|
122
|
+
|
|
123
|
+
SendWelcomeEmail::dispatch($user); // Async job
|
|
124
|
+
event(new UserRegistered($user)); // Or event
|
|
125
|
+
|
|
126
|
+
return new UserResource($user);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### 3. Complex Business Logic → Service
|
|
131
|
+
|
|
132
|
+
```php
|
|
133
|
+
// ✅ Use Service for multi-step operations
|
|
134
|
+
class OrderController extends Controller
|
|
135
|
+
{
|
|
136
|
+
public function __construct(
|
|
137
|
+
private OrderService $orderService
|
|
138
|
+
) {}
|
|
139
|
+
|
|
140
|
+
public function store(OrderRequest $request): OrderResource
|
|
141
|
+
{
|
|
142
|
+
$order = $this->orderService->checkout(
|
|
143
|
+
cart: Cart::find($request->cart_id),
|
|
144
|
+
user: $request->user(),
|
|
145
|
+
paymentMethod: $request->payment_method
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
return new OrderResource($order);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Service handles complex logic
|
|
153
|
+
class OrderService
|
|
154
|
+
{
|
|
155
|
+
public function checkout(Cart $cart, User $user, string $paymentMethod): Order
|
|
156
|
+
{
|
|
157
|
+
// 1. Validate cart items in stock
|
|
158
|
+
$this->validateInventory($cart);
|
|
159
|
+
|
|
160
|
+
// 2. Calculate totals
|
|
161
|
+
$totals = $this->calculateTotals($cart);
|
|
162
|
+
|
|
163
|
+
// 3. Process payment
|
|
164
|
+
$payment = $this->paymentService->charge($user, $totals, $paymentMethod);
|
|
165
|
+
|
|
166
|
+
// 4. Create order
|
|
167
|
+
$order = Order::create([...]);
|
|
168
|
+
|
|
169
|
+
// 5. Update inventory
|
|
170
|
+
$this->updateInventory($cart);
|
|
171
|
+
|
|
172
|
+
// 6. Send notifications
|
|
173
|
+
event(new OrderPlaced($order));
|
|
174
|
+
|
|
175
|
+
return $order;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### 4. Single Reusable Operation → Action
|
|
181
|
+
|
|
182
|
+
```php
|
|
183
|
+
// ✅ Use Action for reusable single-purpose operations
|
|
184
|
+
class CreateInvoiceAction
|
|
185
|
+
{
|
|
186
|
+
public function execute(Order $order): Invoice
|
|
187
|
+
{
|
|
188
|
+
$invoice = Invoice::create([
|
|
189
|
+
'order_id' => $order->id,
|
|
190
|
+
'number' => $this->generateNumber(),
|
|
191
|
+
'total' => $order->total,
|
|
192
|
+
]);
|
|
193
|
+
|
|
194
|
+
GenerateInvoicePdf::dispatch($invoice);
|
|
195
|
+
|
|
196
|
+
return $invoice;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Used in multiple places
|
|
201
|
+
class OrderController
|
|
202
|
+
{
|
|
203
|
+
public function store(OrderRequest $request, CreateInvoiceAction $createInvoice)
|
|
204
|
+
{
|
|
205
|
+
$order = Order::create($request->validated());
|
|
206
|
+
$createInvoice->execute($order);
|
|
207
|
+
return new OrderResource($order);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
class RecurringBillingJob
|
|
212
|
+
{
|
|
213
|
+
public function handle(CreateInvoiceAction $createInvoice)
|
|
214
|
+
{
|
|
215
|
+
foreach ($this->getSubscriptions() as $subscription) {
|
|
216
|
+
$order = $subscription->createRenewalOrder();
|
|
217
|
+
$createInvoice->execute($order);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Why NOT Repository Pattern?
|
|
226
|
+
|
|
227
|
+
### Problem: Eloquent IS Already a Repository
|
|
228
|
+
|
|
229
|
+
```php
|
|
230
|
+
// Eloquent provides repository-like methods
|
|
231
|
+
User::find($id);
|
|
232
|
+
User::where('email', $email)->first();
|
|
233
|
+
User::create($data);
|
|
234
|
+
$user->update($data);
|
|
235
|
+
$user->delete();
|
|
236
|
+
|
|
237
|
+
// Adding Repository layer = duplicate abstraction
|
|
238
|
+
interface UserRepositoryInterface {
|
|
239
|
+
public function find(int $id): ?User;
|
|
240
|
+
public function findByEmail(string $email): ?User;
|
|
241
|
+
public function create(array $data): User;
|
|
242
|
+
// ... same methods as Eloquent!
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### When Repository MIGHT Make Sense
|
|
247
|
+
|
|
248
|
+
```php
|
|
249
|
+
// Only if you genuinely need to swap data sources
|
|
250
|
+
// (rare in real projects)
|
|
251
|
+
|
|
252
|
+
interface ProductCatalogInterface {
|
|
253
|
+
public function search(string $query): Collection;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
class EloquentProductCatalog implements ProductCatalogInterface { ... }
|
|
257
|
+
class ElasticsearchProductCatalog implements ProductCatalogInterface { ... }
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Reality**: 99% of Laravel projects never swap databases. Don't add abstraction for hypothetical future needs.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Design Principles
|
|
265
|
+
|
|
266
|
+
### 1. YAGNI (You Aren't Gonna Need It)
|
|
267
|
+
|
|
268
|
+
```php
|
|
269
|
+
// ❌ DON'T: Create interfaces "just in case"
|
|
270
|
+
interface UserServiceInterface { ... }
|
|
271
|
+
class UserService implements UserServiceInterface { ... }
|
|
272
|
+
|
|
273
|
+
// ✅ DO: Add abstraction only when needed
|
|
274
|
+
class UserService { ... } // Concrete class is fine
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### 2. Single Responsibility
|
|
278
|
+
|
|
279
|
+
```php
|
|
280
|
+
// ❌ DON'T: Fat controller
|
|
281
|
+
class UserController
|
|
282
|
+
{
|
|
283
|
+
public function store(Request $request)
|
|
284
|
+
{
|
|
285
|
+
$validated = $request->validate([...]); // Validation in controller
|
|
286
|
+
$user = User::create($validated);
|
|
287
|
+
Mail::send(...); // Email logic in controller
|
|
288
|
+
$this->calculatePoints($user); // Business logic in controller
|
|
289
|
+
return response()->json($user); // Manual JSON formatting
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ✅ DO: Each layer has one job
|
|
294
|
+
class UserController
|
|
295
|
+
{
|
|
296
|
+
public function store(UserStoreRequest $request): UserResource // Type-hinted
|
|
297
|
+
{
|
|
298
|
+
$user = User::create($request->validated()); // FormRequest validates
|
|
299
|
+
event(new UserRegistered($user)); // Event handles side effects
|
|
300
|
+
return new UserResource($user); // Resource formats output
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 3. Explicit Over Implicit
|
|
306
|
+
|
|
307
|
+
```php
|
|
308
|
+
// ❌ DON'T: Magic methods, hidden behavior
|
|
309
|
+
class User extends Model
|
|
310
|
+
{
|
|
311
|
+
public function __call($method, $args) { ... } // Magic
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// ✅ DO: Clear, readable code
|
|
315
|
+
class User extends Model
|
|
316
|
+
{
|
|
317
|
+
public function orders(): HasMany { ... } // Explicit relationship
|
|
318
|
+
public function scopeActive($query) { ... } // Clear scope
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### 4. Fail Fast
|
|
323
|
+
|
|
324
|
+
```php
|
|
325
|
+
// ✅ Validate early with FormRequest
|
|
326
|
+
class OrderStoreRequest extends FormRequest
|
|
327
|
+
{
|
|
328
|
+
public function rules(): array
|
|
329
|
+
{
|
|
330
|
+
return [
|
|
331
|
+
'cart_id' => ['required', 'exists:carts,id'],
|
|
332
|
+
'payment_method' => ['required', 'in:card,bank'],
|
|
333
|
+
];
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ✅ Throw exceptions for invalid states
|
|
338
|
+
class OrderService
|
|
339
|
+
{
|
|
340
|
+
public function checkout(Cart $cart): Order
|
|
341
|
+
{
|
|
342
|
+
if ($cart->items->isEmpty()) {
|
|
343
|
+
throw new EmptyCartException();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (!$this->hasInventory($cart)) {
|
|
347
|
+
throw new InsufficientInventoryException();
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ... proceed with valid cart
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Anti-Patterns to Avoid
|
|
358
|
+
|
|
359
|
+
### 1. ❌ Repository for Everything
|
|
360
|
+
|
|
361
|
+
```php
|
|
362
|
+
// DON'T
|
|
363
|
+
class UserRepository {
|
|
364
|
+
public function all() { return User::all(); }
|
|
365
|
+
public function find($id) { return User::find($id); }
|
|
366
|
+
// Pointless wrapper around Eloquent
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### 2. ❌ Service for Simple CRUD
|
|
371
|
+
|
|
372
|
+
```php
|
|
373
|
+
// DON'T
|
|
374
|
+
class UserService {
|
|
375
|
+
public function create(array $data) {
|
|
376
|
+
return User::create($data); // Just wrapping model method
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### 3. ❌ DTOs for Request Data
|
|
382
|
+
|
|
383
|
+
```php
|
|
384
|
+
// DON'T
|
|
385
|
+
class UserDTO {
|
|
386
|
+
public function __construct(
|
|
387
|
+
public string $name,
|
|
388
|
+
public string $email,
|
|
389
|
+
) {}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// FormRequest already does this!
|
|
393
|
+
$request->validated(); // Returns validated array
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### 4. ❌ Interfaces Without Implementations
|
|
397
|
+
|
|
398
|
+
```php
|
|
399
|
+
// DON'T create interface for single implementation
|
|
400
|
+
interface UserServiceInterface { ... }
|
|
401
|
+
class UserService implements UserServiceInterface { ... }
|
|
402
|
+
|
|
403
|
+
// DO use interface only when you have multiple implementations
|
|
404
|
+
interface PaymentGatewayInterface { ... }
|
|
405
|
+
class StripePaymentGateway implements PaymentGatewayInterface { ... }
|
|
406
|
+
class PayPalPaymentGateway implements PaymentGatewayInterface { ... }
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Summary
|
|
412
|
+
|
|
413
|
+
| Principle | Guideline |
|
|
414
|
+
| ------------------- | --------------------------------- |
|
|
415
|
+
| **Simple CRUD** | Controller + Model + Resource |
|
|
416
|
+
| **Side effects** | Events, Jobs, Observers |
|
|
417
|
+
| **Complex logic** | Service (only when truly complex) |
|
|
418
|
+
| **Reusable action** | Action class |
|
|
419
|
+
| **Validation** | FormRequest (always) |
|
|
420
|
+
| **Response format** | Resource (always) |
|
|
421
|
+
| **Repository** | ❌ Don't use (Eloquent is enough) |
|
|
422
|
+
| **Interfaces** | Only for multiple implementations |
|
|
423
|
+
|
|
424
|
+
**Golden Rule**: Start simple. Add layers only when complexity demands it.
|