311 lines
4.9 KiB
Markdown
311 lines
4.9 KiB
Markdown
# API-First Architecture – Canonical Rules (SkinBase)
|
||
|
||
> **This document defines how Copilot must generate API-first code.**
|
||
> It applies to **Artworks and all future modules**.
|
||
> If generated code conflicts with this file, **this file wins**.
|
||
|
||
---
|
||
|
||
## 1. What “API-First” Means (MANDATORY)
|
||
|
||
API-first means:
|
||
|
||
* Business logic lives in **Services**
|
||
* Controllers are **thin adapters**
|
||
* Output is defined by **API Resources**
|
||
* Web (Blade), API, Admin all use **the same services**
|
||
* No duplicated logic between web & API
|
||
|
||
Copilot MUST assume:
|
||
|
||
* Web UI exists (Blade / SSR)
|
||
* API exists (JSON)
|
||
* Both consume the **same backend logic**
|
||
|
||
---
|
||
|
||
## 2. Layered Architecture (STRICT)
|
||
|
||
Copilot MUST generate code following this flow:
|
||
|
||
```
|
||
Request
|
||
→ Controller (Web or API)
|
||
→ Service (business rules)
|
||
→ Models / Queries
|
||
→ Resource (output shape)
|
||
```
|
||
|
||
### Forbidden shortcuts
|
||
|
||
❌ Controller → Model directly
|
||
❌ Controller → DB query
|
||
❌ Resource contains logic
|
||
❌ Model contains business logic
|
||
|
||
---
|
||
|
||
## 3. Directory Structure (REFERENCE)
|
||
|
||
Copilot MUST follow this structure:
|
||
|
||
```
|
||
app/
|
||
├── Http/
|
||
│ ├── Controllers/
|
||
│ │ ├── Api/
|
||
│ │ │ └── ArtworkController.php
|
||
│ │ └── Web/
|
||
│ │ └── ArtworkController.php
|
||
│ │
|
||
│ ├── Resources/
|
||
│ │ ├── ArtworkResource.php
|
||
│ │ ├── ArtworkListResource.php
|
||
│ │ └── CategoryResource.php
|
||
│
|
||
├── Services/
|
||
│ ├── ArtworkService.php
|
||
│ ├── ArtworkStatsService.php
|
||
│ └── CategoryService.php
|
||
│
|
||
├── Policies/
|
||
│ └── ArtworkPolicy.php
|
||
│
|
||
├── Models/
|
||
│ └── Artwork.php
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Services Layer (CORE)
|
||
|
||
### 4.1 ArtworkService (MANDATORY)
|
||
|
||
Copilot MUST generate an `ArtworkService` that handles:
|
||
|
||
* Fetch public artwork by slug
|
||
* Fetch artworks by category
|
||
* Apply visibility rules
|
||
* Apply soft delete rules
|
||
* Throw domain-appropriate exceptions
|
||
|
||
Example responsibilities (NOT code):
|
||
|
||
* `getPublicArtworkBySlug(string $slug)`
|
||
* `getCategoryArtworks(Category $category)`
|
||
* `getLatestArtworks(int $limit)`
|
||
|
||
### Rules
|
||
|
||
* Services MUST NOT return JSON
|
||
* Services MUST return models or collections
|
||
* Services MUST enforce visibility rules
|
||
|
||
---
|
||
|
||
## 5. Controllers (ADAPTERS ONLY)
|
||
|
||
### 5.1 API Controllers
|
||
|
||
Location:
|
||
|
||
```
|
||
app/Http/Controllers/Api/
|
||
```
|
||
|
||
Rules:
|
||
|
||
* Return API Resources only
|
||
* Never return models directly
|
||
* No business logic
|
||
* Stateless
|
||
|
||
Example:
|
||
|
||
```php
|
||
return new ArtworkResource(
|
||
$this->service->getPublicArtworkBySlug($slug)
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
### 5.2 Web Controllers
|
||
|
||
Location:
|
||
|
||
```
|
||
app/Http/Controllers/Web/
|
||
```
|
||
|
||
Rules:
|
||
|
||
* Use same services as API
|
||
* Prepare data for Blade
|
||
* No duplication of logic
|
||
* SEO handled here (meta tags, schema)
|
||
|
||
Example:
|
||
|
||
```php
|
||
return view('artworks.show', [
|
||
'artwork' => new ArtworkResource($artwork),
|
||
]);
|
||
```
|
||
|
||
---
|
||
|
||
## 6. API Resources (OUTPUT CONTRACT)
|
||
|
||
### Rules
|
||
|
||
Copilot MUST:
|
||
|
||
* Use Laravel `JsonResource`
|
||
* Define explicit fields
|
||
* Never expose internal fields accidentally
|
||
* Avoid N+1 queries
|
||
* Include relations conditionally
|
||
|
||
### ArtworkResource MUST include:
|
||
|
||
* slug
|
||
* title
|
||
* description
|
||
* dimensions
|
||
* categories
|
||
* URLs (canonical)
|
||
|
||
### ArtworkListResource MUST:
|
||
|
||
* Be lightweight
|
||
* Exclude heavy relations
|
||
* Exclude stats unless requested
|
||
|
||
---
|
||
|
||
## 7. Routes (SEO-Safe)
|
||
|
||
### API routes
|
||
|
||
Location:
|
||
|
||
```
|
||
routes/api.php
|
||
```
|
||
|
||
Rules:
|
||
|
||
* Stateless
|
||
* Slug-based
|
||
* Versionable (`/api/v1/...`)
|
||
|
||
Example:
|
||
|
||
```
|
||
GET /api/v1/artworks/{slug}
|
||
GET /api/v1/categories/{slug}/artworks
|
||
```
|
||
|
||
---
|
||
|
||
### Web routes
|
||
|
||
Location:
|
||
|
||
```
|
||
routes/web.php
|
||
```
|
||
|
||
Rules:
|
||
|
||
* Slug-based
|
||
* No IDs
|
||
* SEO-friendly
|
||
* SSR output
|
||
|
||
---
|
||
|
||
## 8. Stats Handling (High Load Rule)
|
||
|
||
Copilot MUST:
|
||
|
||
* Use `ArtworkStatsService`
|
||
* Increment stats via Jobs
|
||
* Never mutate counters inline
|
||
* Assume Redis may be present
|
||
|
||
Forbidden:
|
||
|
||
❌ `$artwork->increment('views')`
|
||
❌ Updating stats inside controllers
|
||
|
||
---
|
||
|
||
## 9. Caching Rules
|
||
|
||
Copilot SHOULD assume:
|
||
|
||
* Redis is available
|
||
* Cache keys are service-level
|
||
* Resources are cacheable
|
||
|
||
Examples:
|
||
|
||
* `artwork:{slug}`
|
||
* `category:{slug}:artworks`
|
||
|
||
Cache invalidation:
|
||
|
||
* On update
|
||
* On delete
|
||
* On restore
|
||
|
||
---
|
||
|
||
## 10. Error Handling Rules
|
||
|
||
Copilot MUST:
|
||
|
||
* Return 404 for missing public content
|
||
* Return 410 or 301 for soft-deleted content (if requested)
|
||
* Never expose private content via API
|
||
|
||
---
|
||
|
||
## 11. Testing Philosophy
|
||
|
||
Copilot MUST generate tests that:
|
||
|
||
* Hit API endpoints
|
||
* Validate JSON structure
|
||
* Test visibility & approval
|
||
* Do NOT test Blade HTML
|
||
|
||
---
|
||
|
||
## 12. Forbidden Patterns (ABSOLUTE)
|
||
|
||
❌ Controllers with logic
|
||
❌ Models with business rules
|
||
❌ Duplicate logic between API & Web
|
||
❌ Direct DB queries in controllers
|
||
❌ Different rules for API vs Web
|
||
|
||
---
|
||
|
||
## 13. Final Instruction (NON-NEGOTIABLE)
|
||
|
||
> **API is the primary contract.**
|
||
> Web UI, Admin UI, Mobile apps are **clients**.
|
||
|
||
Copilot MUST always ask:
|
||
|
||
> “Can this logic live in a service?”
|
||
|
||
If yes → put it there.
|
||
|
||
---
|
||
|
||
### ✅ End of API-First Architecture Instructions
|