# 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
