# Laravel Project Constitution v2

# ══════════════════════════════════════════════════════════

# هذا الملف هو القانون الأساسي غير القابل للتجاوز للمشروع.

# الأجنت يلتزم بكل ما فيه في كل فيتشر بدون استثناء.

# ══════════════════════════════════════════════════════════

---

## ARCHITECTURE MODE — FIRST THING TO DO ON EVERY TASK

### Step -1 (Before anything else — including reading the rest of this constitution):

1. Check if `docs/architecture-mode.md` exists in the project root.

**If the file EXISTS:**
- Read the single line inside it.
- It will say either `MODE_A` or `MODE_B`.
- Lock that mode for the entire task. Do not ask again. Do not change it.

**If the file DOES NOT EXIST (first use of the project):**
- Stop everything.
- Ask the developer exactly this question — no rewording:

  > **Before we start, I need one architectural decision that will apply to the entire project and cannot be changed later.**
  >
  > **Option A — Full (Repository Pattern):**
  > `Controller → FormRequest → DTO → Service → Repository → Model`
  > Best for large teams, complex domains, high testability requirements.
  >
  > **Option B — Lean (Service + Controller only):**
  > `Controller → FormRequest → Service → Model`
  > Best for small teams, faster delivery, simpler domains. No DTOs, no Repository layer.
  >
  > **Type A or B:**

- Wait for the developer's answer.
- Create the file `docs/architecture-mode.md` with exactly one line:
  - If A → write `MODE_A`
  - If B → write `MODE_B`
- Confirm to the developer: *"Architecture mode locked as [A/B]. This applies to all future features."*
- Then proceed with the task using the chosen mode.

---

### MODE_A — Full Architecture (Repository Pattern)

**Flow:**
```
API:   FormRequest → DTO → Service → Repository → Model
       Controller  → Resource → ResponseTrait::jsonResponse()

Admin: FormRequest → DTO → Service → AdminBasicController
```

- All rules in this constitution apply as written.
- DTOs: required when endpoint has input (see DTO RULE section).
- FormRequests: required when endpoint has input (see FORM REQUEST RULE section).
- Repository layer: MANDATORY — no exceptions.
- `RepositoryServiceProvider`: MANDATORY.

---

### MODE_B — Lean Architecture (Service + Controller only)

**Flow:**
```
API:   FormRequest → DTO → Service → Model
       Controller  → Resource → ResponseTrait::jsonResponse()

Admin: FormRequest → DTO → Service → AdminBasicController
```

**What changes in MODE_B — ONLY the Repository layer is removed:**

| Rule | MODE_A | MODE_B |
|---|---|---|
| Repository layer | MANDATORY | ❌ SKIP entirely — Service calls Model directly |
| `RepositoryServiceProvider` | MANDATORY | ❌ NOT created |
| DTOs | Required when input exists | ✅ Same rule applies |
| FormRequests | Required when input exists | ✅ Same rule applies |
| `ResponseTrait::jsonResponse()` | MANDATORY | ✅ Same rule applies |
| Resources | MANDATORY | ✅ Same rule applies |
| SoftDeletes | MANDATORY | ✅ Same rule applies |
| Factories & Seeders | MANDATORY | ✅ Same rule applies |
| Enums + EnumRetriever | MANDATORY | ✅ Same rule applies |
| AdminBasicController | MANDATORY | ✅ Same rule applies |
| OpenAPI docs | MANDATORY | ✅ Same rule applies |

**Service in MODE_B — receives DTO, calls Model directly:**

```php
// ✅ ALLOWED in MODE_B Service
class ProductService
{
    public function create(CreateProductDTO $dto): Product
    {
        return Product::create([
            'name'  => $dto->name,
            'price' => $dto->price,
        ]);
    }

    public function findById(int $id, array $with = []): ?Product
    {
        return Product::with($with)->find($id);
    }

    public function paginate(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        return Product::query()
            ->when(isset($filters['search']), fn($q) => $q->search($filters['search']))
            ->paginate($perPage);
    }
}
```

**Controller in MODE_B — identical pattern to MODE_A:**

```php
// ✅ MODE_B Controller — same as MODE_A
public function store(StoreProductRequest $request): JsonResponse
{
    $dto     = CreateProductDTO::fromRequest($request);
    $product = $this->productService->create($dto);
    return $this->jsonResponse(
        msg:  __('apis.product_created'),
        code: 201,
        data: new ProductResource($product)
    );
}
```

**FORBIDDEN even in MODE_B:**
```php
// ✗ Controller must NOT call Model directly — still goes through Service
Product::create($request->validated());  // ✗ in Controller

// ✗ response()->json() is still forbidden
return response()->json([...]);  // ✗
```

---

### MODE LOCK RULE (NON-NEGOTIABLE)

Once `docs/architecture-mode.md` exists:
- NEVER ask the developer again.
- NEVER switch modes mid-project.
- NEVER mix patterns (e.g. Repository for some features, not others).
- If the file is accidentally deleted → ask again and recreate it.

---

## ROLE

You are a Senior Laravel Architect & Implementer.

## GOAL

Implement a feature in a Laravel 12 project that has BOTH:

- API (mobile/web)
- Admin Dashboard (Blade)

---

## HARD CONSTRAINTS (DO NOT VIOLATE — EVER)

- Do NOT modify the existing permissions system (manual) or SideBarTrait logic.
- Do NOT learn patterns from existing Requests or Controllers in the codebase —
  they may contain incorrect patterns. Treat them as if they do not exist.
- Do NOT use response()->json() anywhere in the API layer.
- Do NOT use Eloquent directly in Services or Controllers. **(MODE_A only — in MODE_B, Services may use Eloquent directly; Controllers still may not)**
- Do NOT trigger lazy loading inside Resources.
- Do NOT skip the Repository layer, even for simple flows. **(MODE_A only — does not apply in MODE_B)**
- Do NOT create a custom admin CRUD flow unless explicitly required in REQUIREMENTS.
- Do NOT invent business rules not present in analysis_fragment.md or feature_name.md.
- Do NOT use city_id or country_id to represent geographic location or address.
- Do NOT create a FormRequest or DTO for any endpoint that receives NO user input — skip both entirely (e.g. GET /home that only returns data needs neither a Request nor a DTO).
- Do NOT create a separate Model or migration for user types (client, customer, driver, vendor…) — ALL user types map to the existing `users` table and `User` model. Add a `type` column or role if needed, never a new table.
- Do NOT create a new Model or migration for splash or intro screens — use the existing `Intro` model and `intros` table. Never introduce names like "onboard", "splash", "walkthrough", "welcome_screen" as new models or tables.
- Do NOT create a new Model or migration for homepage sliders or rotating banners — use the existing `Image` model and `images` table. Never create "Slider", "Banner", "Carousel" models.
- Do NOT register repository bindings in `AppServiceProvider` — a dedicated `RepositoryServiceProvider` MUST own ALL repository-to-interface bindings. **(MODE_A only)**

---

## SOURCE PRIORITY (NON-NEGOTIABLE)

1. Business rules & constraints → analysis_fragment.md
2. UI fields & screen flows → figma_fragment.json
3. On conflict → business rules override UI
4. Every field must carry a SourceTag: BUSINESS_RULE | UI_FIELD | UI_ONLY | SPEC_ONLY

---

## NAMESPACE CONVENTIONS (MANDATORY — FOLLOW EXACTLY)

Every class in this project MUST follow these namespace patterns:

| Layer               | Namespace Pattern                                                         |
| ------------------- | ------------------------------------------------------------------------- | -------------------------- |
| Models              | `App\Models\{ModelName}`                                                  |
| Services            | `App\Services\{ModelName}Service`                                         |
| Repository Contract | `App\Repositories\{DomainGroup}\Contracts\{ModelName}RepositoryInterface` |
| Repository Eloquent | `App\Repositories\{DomainGroup}\Eloquent\{ModelName}Repository`           |
| DTOs                | `App\DTOs\{ModelName}DTO` (e.g. `Create{ModelName}DTO`)                   |
| API Controllers     | `App\Http\Controllers\Api\{ModelName}Controller`                          |
| Admin Controllers   | `App\Http\Controllers\Admin\{ModelName}Controller`                        |
| API Requests        | `App\Http\Requests\Api\{Store                                             | Update}{ModelName}Request` |
| Admin Requests      | `App\Http\Requests\Admin\{Store                                           | Update}{ModelName}Request` |
| API Resources       | `App\Http\Resources\{ModelName}Resource`                                  |
| Enums               | `App\Enums\{ModelName}Enum`                                               |

> {DomainGroup} = logical grouping for repositories (e.g. `AllUsers`, `Orders`, `Providers`)
> Example: `App\Repositories\AllUsers\Contracts\ClientRepositoryInterface`
> `App\Repositories\AllUsers\Eloquent\ClientRepository`

---

## ARCHITECTURE RULES (MANDATORY)

### Flow

```
API:   FormRequest → DTO → Service → Repository → Model
       Controller  → Resource → ResponseTrait::jsonResponse()

Admin: FormRequest → DTO → Service → AdminBasicController contract responses
```

### Controllers — must be thin

- Receive FormRequest
- Build DTO via `SomeDTO::fromRequest($request)`
- Call service method
- Return via `$this->jsonResponse(...)`
- NOTHING else — no queries, no business logic, no Eloquent

### Services — business logic only

- Receive DTO
- Apply business rules from analysis
- Call repository methods only
- Return domain result
- NO Eloquent queries
- NO response formatting
- NO HTTP logic

### Repositories — all data access

- ALL reads, writes, filters, existence checks go here
- Eager load ALL required relations here
- NO business logic
- NO response formatting
- Responsible for relation loading strategy (N+1 prevention)

### Resources — output formatting only

- Read already-loaded model data
- Use `whenLoaded()` for optional relations
- NEVER call relations directly (no lazy loading)
- NEVER trigger any query

---

## DTO RULE (MANDATORY — EXACT STRUCTURE)

### WHEN TO CREATE A DTO

**Ask this question first:** Does this endpoint/action receive input data that needs to be carried into the Service?

| Situation | Create DTO? |
|---|---|
| Endpoint receives body/query params that affect write/business logic | ✅ YES |
| Endpoint is a simple GET that only returns data (no filters, no input) | ❌ NO |
| Action is triggered by a route param only (e.g. `show($id)`, `destroy($id)`) | ❌ NO |
| Endpoint has optional filters (search, pagination) | ✅ YES (with nullable properties) |

**FORBIDDEN:** Creating an empty DTO class (`public function __construct() {}`) just to satisfy the pattern. If there is no data to carry, there is no DTO.

---

Every DTO built from a FormRequest MUST follow this EXACT structure:

```php
<?php

namespace App\DTOs;

use App\Http\Requests\Api\StoreXxxRequest;

readonly class CreateXxxDTO
{
    public function __construct(
        public int    $field1,
        public string $field2,
        public float  $field3,
    ) {}

    public static function fromRequest(StoreXxxRequest $request): self
    {
        return new self(
            field1: $request->validated()['field1'],
            field2: $request->validated()['field2'],
            field3: $request->validated()['field3'],
        );
    }
}
```

Rules:

- Class MUST be `readonly`
- All properties MUST be promoted public constructor parameters
- `fromRequest()` MUST be static, typed `: self`, map every argument from `$request->validated()`
- Constructor argument order MUST match `fromRequest()` mapping order
- Controller MUST call `SomeDTO::fromRequest($request)` — never `new SomeDTO(...)` in controller
- For DTOs not built from a single FormRequest: use constructor only, no `fromRequest()`

---

## FORM REQUEST RULE (MANDATORY)

### WHEN TO CREATE A FORM REQUEST

**Ask this question first:** Does this endpoint accept user-supplied input that requires validation?

| Situation | Create FormRequest? |
|---|---|
| POST / PUT / PATCH with body fields | ✅ YES |
| GET endpoint with filterable query params (search, date range…) | ✅ YES |
| GET endpoint that returns data with no input (e.g. home, slider, profile without edit) | ❌ NO |
| DELETE / action triggered only by a route param | ❌ NO |

**FORBIDDEN:** Creating an empty FormRequest class (`public function rules(): array { return []; }`) just to satisfy the pattern. If there is nothing to validate, there is no FormRequest.

---

Form Request = **VALIDATION ONLY**.

**ALLOWED:**

```php
// Input format validation
'name'     => ['required', 'string', 'max:255'],
'email'    => ['required', 'email'],
'category' => ['required', Rule::exists('categories', 'id')],
'email'    => ['required', Rule::unique('users', 'email')->ignore($id)],

// Input normalization only
protected function prepareForValidation(): void
{
    $this->merge(['phone' => fixPhone($this->phone)]);
}
```

**FORBIDDEN:**

```php
// ✗ DB queries of any kind
User::where('email', $this->email)->first();
Model::find($this->id);

// ✗ Business condition checks
public function withValidator($validator): void
{
    $validator->after(function () {
        if ($user->is_blocked) { ... }   // ✗ goes in Service
    });
}

// ✗ prepareForValidation fetching models
protected function prepareForValidation(): void
{
    $model = Model::find($this->id);  // ✗ forbidden
}
```

All existence checks, blocked checks, status checks, business conditions → **Service via Repository**.

---

## EXISTING MODELS MAP (MANDATORY — CHECK BEFORE CREATING ANYTHING NEW)

Before creating any new Model, Migration, or table, **check this map first**.
If the concept matches an existing model → use it. Do NOT create a parallel one.

| Business Concept | Existing Model | Existing Table | Notes |
|---|---|---|---|
| User / Client / Customer / Driver / Vendor / Any human actor | `App\Models\User` | `users` | Add `type` enum column if role distinction needed |
| Splash screen / Intro screen / Onboarding / Walkthrough | `App\Models\Intro` | `intros` | Never create Onboard, Splash, WelcomeScreen models |
| Homepage slider / Banner / Carousel / Animated images | `App\Models\Image` | `images` | Never create Slider, Banner, Carousel models |

### Decision rule (run before Step 1 of every feature):

```
For each entity in the feature:
  1. Does it match any row in the EXISTING MODELS MAP?
     YES → use the existing Model/table — do NOT create a new migration
     NO  → proceed to create new Model + migration
```

**VIOLATION:** Creating a `clients` table when `users` already exists = hard violation.
**VIOLATION:** Creating an `onboardings` table when `intros` already exists = hard violation.
**VIOLATION:** Creating a `sliders` table when `images` already exists = hard violation.

---

## REPOSITORY BINDING — SERVICE PROVIDER RULE (MANDATORY)

ALL repository interface-to-implementation bindings MUST live in a dedicated `RepositoryServiceProvider`.

**FORBIDDEN:** Registering bindings in `AppServiceProvider`.

```php
// ✗ FORBIDDEN — do not do this
class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(ClientRepositoryInterface::class, ClientRepository::class); // ✗
    }
}
```

**CORRECT — dedicated provider:**

```php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

// Users domain
use App\Repositories\AllUsers\Contracts\UserRepositoryInterface;
use App\Repositories\AllUsers\Eloquent\UserRepository;

// Orders domain
use App\Repositories\Orders\Contracts\OrderRepositoryInterface;
use App\Repositories\Orders\Eloquent\OrderRepository;

class RepositoryServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Users domain
        $this->app->bind(UserRepositoryInterface::class, UserRepository::class);

        // Orders domain
        $this->app->bind(OrderRepositoryInterface::class, OrderRepository::class);
    }
}
```

**Registration in `config/app.php` (or `bootstrap/providers.php` in Laravel 11+):**

```php
App\Providers\RepositoryServiceProvider::class,
```

### First-task check:

On the **very first feature** implemented, before writing any code:
1. Confirm `RepositoryServiceProvider` exists at `app/Providers/RepositoryServiceProvider.php`
2. Confirm it is registered in the application providers
3. If it does not exist → **create it first**, before any repository file

Every new repository binding added in subsequent features MUST be appended to `RepositoryServiceProvider` — never anywhere else.

---

## REPOSITORY RULE (MANDATORY — NO EXCEPTIONS)

Repository Pattern is MANDATORY for ALL features including the simplest ones
(login, OTP, profile, settings — no exceptions).

**Must produce for every feature:**

1. Repository contract (interface)
2. Repository Eloquent implementation
3. Service consuming the **contract** (not the implementation)
4. Controller consuming the service

**FORBIDDEN in Services and Controllers:**

```php
// ✗ All of these must go in Repository
Model::query()
Model::where(...)
Model::find(...)
Model::create(...)
Model::update(...)
Model::delete(...)
Model::with(...)
```

**Repository contract example:**

```php
<?php

namespace App\Repositories\AllUsers\Contracts;

interface ClientRepositoryInterface
{
    public function findById(int $id, array $with = []): ?Client;
    public function create(array $data): Client;
    public function update(int $id, array $data): bool;
    public function delete(int $id): bool;
    public function paginate(array $filters = [], int $perPage = 15): LengthAwarePaginator;
}
```

**Repository implementation example:**

```php
<?php

namespace App\Repositories\AllUsers\Eloquent;

use App\Models\Client;
use App\Repositories\AllUsers\Contracts\ClientRepositoryInterface;

class ClientRepository implements ClientRepositoryInterface
{
    public function findById(int $id, array $with = []): ?Client
    {
        return Client::with($with)->find($id);
    }

    public function create(array $data): Client
    {
        return Client::create($data);
    }
    // ...
}
```

---

## ADMIN BASIC CONTROLLER CONTRACT (MANDATORY)

Admin controllers MUST extend `App\Http\Controllers\Admin\Core\AdminBasicController`
and configure it via `parent::__construct(...)`.

**Signature (use exactly):**

```php
parent::__construct(
    model:                  ModelClass::class,
    storeRequest:           StoreXxxRequest::class,
    updateRequest:          UpdateXxxRequest::class,
    directoryName:          'directory_name',        // blade views folder name
    serviceName:            $xxxService,             // injected via constructor
    indexScopes:            'search',                // scope name or ''
    with:                   ['relation1'],            // eager loads for index
    indexConditions:        [],                      // extra where conditions
    indexCompactVariables:  [],                      // extra vars for index view
    createCompactVariables: [],                      // extra vars for create view
    editCompactVariables:   [],                      // extra vars for edit view
    showCompactVariables:   [],                      // extra vars for show view
    destroyOneConditions:   [],                      // conditions before delete
    destroyRelationsToCheck:[],                      // relations to check before delete
    relationsConditions:    []                       // relation conditions for delete
);
```

**What AdminBasicController provides automatically (do NOT re-implement):**

- `index()` — AJAX returns `{html, modelCount}` | non-AJAX renders index view
- `create()` — renders create view
- `store()` — resolves StoreRequest, calls `$serviceName->create()`, returns `{url}`
- `update($id)` — resolves UpdateRequest, calls `$serviceName->update()`, returns `{url}`
- `edit($id)` — calls `$serviceName->find($id)`, renders edit view
- `show($id)` — calls `$serviceName->find($id, with:[...])`, renders show view
- `destroy($id)` — calls `$serviceName->delete(...)`, returns `{key, msg}`
- `destroyAll(Request $request)` — calls `$serviceName->deleteMultiple(...)`, returns `{key, msg}`

**Child controller example:**

```php
<?php

namespace App\Http\Controllers\Admin;

use App\Services\ProductService;
use App\Http\Requests\Admin\StoreProductRequest;
use App\Http\Requests\Admin\UpdateProductRequest;
use App\Http\Controllers\Admin\Core\AdminBasicController;

class ProductController extends AdminBasicController
{
    public function __construct(ProductService $productService)
    {
        parent::__construct(
            model:           \App\Models\Product::class,
            storeRequest:    StoreProductRequest::class,
            updateRequest:   UpdateProductRequest::class,
            directoryName:   'products',
            serviceName:     $productService,
            indexScopes:     'search',
            with:            ['category'],
        );
    }
}
```

**Override a method ONLY when business logic requires it:**

```php
public function store(): JsonResponse
{
    $request = app(StoreProductRequest::class);
    $dto = CreateProductDTO::fromRequest($request);
    $this->productService->createWithImages($dto);  // custom logic
    return response()->json(['url' => route('admin.products.index')]);
}
```

---

## RESPONSE TRAIT (MANDATORY)

All API responses MUST use `App\Traits\ResponseTrait::jsonResponse()`.

**Signature:**

```php
$this->jsonResponse(
    msg:    string|null  = null,     // null uses apis.data_retrieved_successfully
    code:   int          = 200,
    data:   mixed        = [],
    error:  bool         = false,
    errors: array        = [],       // validation errors array
    key:    string|null  = null      // null auto-resolves: 'success' or 'fail'
): JsonResponse
```

**Usage examples:**

```php
// Success with data
return $this->jsonResponse(
    msg:  __('apis.users.retrieved'),
    data: UserResource::collection($users)
);

// Success with pagination
return $this->jsonResponse(data: [
    'users'      => UserResource::collection($users),
    'pagination' => $this->paginationModel($users),
]);

// Created
return $this->jsonResponse(
    msg:  __('apis.users.created'),
    code: 201,
    data: new UserResource($user)
);

// Business error
return $this->jsonResponse(
    msg:   __('apis.users.blocked'),
    code:  423,
    error: true,
    key:   'blocked'
);
```

**FORBIDDEN:**

```php
// ✗ Never use these
return response()->json([...]);
return response()->json([...], 422);
JsonResponse::create([...]);
```

**Response shape (always):**

```json
{
    "key": "success",
    "msg": "تم جلب البيانات بنجاح",
    "code": 200,
    "response_status": {
        "error": false,
        "validation_errors": null
    },
    "data": {}
}
```

> Note: `data` returns `null` (not `{}`) when the data collection is empty.

---

## PAGINATION RULE (MANDATORY)

All list endpoints MUST use `PaginationTrait::paginationModel()`.

**Trait method:**

```php
$this->paginationModel($collection)
// Returns:
[
    'total_items'   => int,
    'count_items'   => int,
    'per_page'      => int,
    'total_pages'   => int,
    'current_page'  => int,
    'next_page_url' => string,
    'perv_page_url' => string,   // note: project uses 'perv' not 'prev'
]
```

**Response structure for paginated lists:**

```php
return $this->jsonResponse(data: [
    '{plural_model_name}' => XxxResource::collection($items),  // e.g. 'users', 'orders'
    'pagination'          => $this->paginationModel($items),
]);
```

**Controller must use both traits:**

```php
use App\Traits\ResponseTrait;
use App\Traits\PaginationTrait;

class XxxController extends Controller
{
    use ResponseTrait, PaginationTrait;
}
```

---

## ENUM RETRIEVER TRAIT (MANDATORY)

All Enums in this project MUST use the `App\Traits\EnumRetriever` trait.

**Available methods (use as needed):**

```php
// In Enum definition:
enum StatusEnum: string
{
    use EnumRetriever;

    case Active   = 'active';
    case Inactive = 'inactive';
}

// Available methods:
StatusEnum::values()                    // ['active', 'inactive']
StatusEnum::names()                     // ['Active', 'Inactive']
StatusEnum::valuesWithout(['inactive']) // ['active']
StatusEnum::toArray('status_enum')      // [['id'=>'active','name'=>'نشط'], ...]  ← for dropdowns
StatusEnum::getNames('status_enum')     // assoc array with value+name+label
StatusEnum::getFullObj('active', 'status_enum')  // ['value','name','label']
StatusEnum::getTranslatedName('active', 'status_enum') // 'نشط'
```

**In API Resources — expose enum as full object:**

```php
'status' => StatusEnum::getFullObj($this->status, 'status_enum'),
// Returns: ['value' => 'active', 'name' => 'Active', 'label' => 'نشط']
```

**In Admin Blade — get dropdown options:**

```php
// In controller compact variables:
'statuses' => StatusEnum::toArray('status_enum')
// Returns: [['id' => 'active', 'name' => 'نشط'], ...]
```

**The enum key for translations** = the snake_case class name without 'Enum' suffix:

- `StatusEnum` → key = `status_enum`
- `OrderStatusEnum` → key = `order_status_enum`

---

## I18N STRUCTURE (MANDATORY)

Files location: `lang/{locale}/` (e.g. `lang/ar/`)

### lang/ar/apis.php — flat key-value, domain-grouped by comment

```php
<?php
return [
    // General
    'data_retrieved_successfully' => 'تم جلب البيانات بنجاح',
    'loggedOut'                   => 'تم تسجيل الخروج بنجاح',

    // Users
    'users_retrieved'  => 'تم جلب المستخدمين بنجاح',
    'user_created'     => 'تم إنشاء المستخدم بنجاح',
    'user_updated'     => 'تم تحديث المستخدم بنجاح',
    'user_deleted'     => 'تم حذف المستخدم بنجاح',
    'user_blocked'     => 'هذا الحساب محظور',

    // Orders
    'order_created'    => 'تم إنشاء الطلب بنجاح',
    'order_updated'    => 'تم تحديث الطلب بنجاح',
];
```

### lang/ar/admin.php — flat key-value, mixed domain labels and messages

```php
<?php
return [
    // General labels
    'pages'            => 'الصفحات',
    'title'            => 'العنوان',
    'update_successfully' => 'تم التحديث بنجاح',

    // Domain-specific
    'user'             => 'المستخدم',       // used by AdminBasicController::getClassNameTranslated()
    'order'            => 'الطلب',
    'product'          => 'المنتج',

    // Action messages (used by destroy/destroyAll responses)
    'deleted_successfully'       => 'تم الحذف بنجاح',
    'cannot_delete_has_children' => 'لا يمكن الحذف، يوجد عناصر مرتبطة',
];
```

### lang/ar/enums.php — nested by enum key

```php
<?php
return [
    'status_enum' => [
        'Active'   => 'نشط',
        'Inactive' => 'غير نشط',
    ],
    'order_status_enum' => [
        'Pending'   => 'قيد الانتظار',
        'Confirmed' => 'مؤكد',
        'Delivered' => 'تم التوصيل',
        'Cancelled' => 'ملغي',
    ],
];
```

### lang/ar/validation.php — add attributes section

```php
<?php
return [
    // ... existing Laravel validation messages ...

    'attributes' => [
        'name'     => 'الاسم',
        'email'    => 'البريد الإلكتروني',
        'phone'    => 'رقم الهاتف',
        'password' => 'كلمة المرور',
        // add feature-specific attributes here
    ],
];
```

---

## SOFT DELETES RULE (MANDATORY)

ALL models in this project MUST use SoftDeletes.

```php
use Illuminate\Database\Eloquent\SoftDeletes;

class Product extends Model
{
    use SoftDeletes;
    // ...
}
```

Migration MUST include:

```php
$table->softDeletes(); // adds deleted_at column
```

---

## AUTH MIDDLEWARE RULE (MANDATORY)

API routes requiring authentication MUST use `sanctum` guard:

```php
// Protected routes
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
});

// Public routes
Route::post('/login', [AuthController::class, 'login']);
```

OpenAPI security scheme:

```json
"securitySchemes": {
    "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
    }
}
```

Endpoint requiring auth:

```json
"security": [{ "BearerAuth": [] }]
```

---

## GEOGRAPHIC LOCATION RULE (MANDATORY)

When UI or analysis mentions "موقع جغرافي" or "العنوان":

**MUST use exactly these three fields:**
| Field | Type | Description |
|------------|---------|--------------------------|
| `map_desc` | string | Text description/address |
| `lat` | decimal | Latitude |
| `lng` | decimal | Longitude |

**FORBIDDEN:** `city_id`, `country_id`, `address_id`, `location_id`

Apply in: migrations, DTOs, FormRequests, Resources, OpenAPI.

---

## BLADE STRUCTURE (MANDATORY)

```
resources/views/admin/{directoryName}/
    index.blade.php    ← always required
    table.blade.php    ← always required (AJAX table rows)
    create.blade.php   ← if create screen needed
    edit.blade.php     ← if edit screen needed
    show.blade.php     ← if show screen needed
```

**index.blade.php must use:**

```blade
<x-admin.buttons ... />
<x-admin.filter ... />
<div class="table_content_append"></div>
```

**Shared scripts (include, do NOT rewrite):**

```blade
@include('admin.shared.deleteOne')
@include('admin.shared.deleteAll')
@include('admin.shared.filter_js', ['index_route' => route('admin.xxx.index')])
```

**When to create show.blade.php:** only when the feature explicitly requires a detail view.

---

## ADMIN ROUTES STRUCTURE (MANDATORY)

```
routes/
  web.php                              ← includes routes/Admin/*.php
  Admin/
    {module}.php                       ← sidebar parent metadata
    {Module}/
      routes-links.php                 ← actual CRUD routes
```

**Sidebar parent metadata (routes/Admin/{module}.php):**

```php
Route::get('/{module}-management', function () {})->middleware(['auth', 'admin'])->name('{module}-management')->title('{Module} Management')->sidebarData([
    'type'          => 'parent',
    'title'         => 'إدارة {النموذج}',
    'icon'          => 'icon-class',
    'has_sub_route' => true,
    'child'         => ['{module}-management.index'],
]);
```

**Actual routes (routes/Admin/{Module}/routes-links.php):**

```php
[
    'uses'     => '{Module}Controller@index',
    'as'       => '{module}-management.index',
    'title'    => 'قائمة {النماذج}',
    'sub_link' => true,
],
[
    'uses'  => '{Module}Controller@store',
    'as'    => '{module}-management.store',
    'title' => 'إضافة {نموذج}',
],
// ... create, edit, update, destroy, destroyAll
```

---

## OPENAPI GENERATION RULES (MANDATORY — STRICT)

### RULE 1 — REAL EXAMPLE VALUES (ZERO TOLERANCE)

Every field under `"properties"` MUST have `"type"` AND `"example"` with a real value.

**FORBIDDEN:**

```json
"data": { "type": "object", "properties": {} }
"name": { "type": "string", "example": "" }
"id":   { "type": "integer" }
```

**CORRECT:**

```json
"data": {
    "type": "object",
    "properties": {
        "id":         { "type": "integer", "example": 1 },
        "name":       { "type": "string",  "example": "أحمد محمد" },
        "status":     { "type": "string",  "example": "active" },
        "created_at": { "type": "string",  "example": "2024-01-15T10:30:00Z" }
    }
}
```

### RULE 2 — POSTMAN TEST SCRIPT ON EVERY ENDPOINT

Every endpoint MUST include `x-postman-test` with a **non-empty** script:

```json
"x-postman-test": {
    "script": "pm.test('Status is 200', function() { pm.response.to.have.status(200); });"
}
```

**FORBIDDEN:**

```json
"x-postman-test": {}
"x-postman-test": { "script": "" }
```

Adjust status code to match expected success code (200 or 201).

### RULE 3 — REQUIRED RESPONSE CODES

| Endpoint type            | Required codes         |
| ------------------------ | ---------------------- |
| Accepts input            | 200/201 + 422          |
| Requires auth            | + 401                  |
| Has access restrictions  | + 403                  |
| Business-specific errors | + real code (e.g. 423) |

### RULE 4 — RESPONSE TEMPLATES (USE EXACTLY)

**SUCCESS (200):**

```json
"200": {
    "description": "Success",
    "content": {
        "application/json": {
            "schema": {
                "type": "object",
                "properties": {
                    "key":  { "type": "string",  "example": "success" },
                    "msg":  { "type": "string",  "example": "تم التنفيذ بنجاح" },
                    "code": { "type": "integer", "example": 200 },
                    "response_status": {
                        "type": "object",
                        "properties": {
                            "error":            { "type": "boolean", "example": false },
                            "validation_errors": { "type": "object", "nullable": true }
                        }
                    },
                    "data": {
                        "type": "object",
                        "properties": {
                            "← FILL WITH REAL ENDPOINT-SPECIFIC FIELDS →": {},
                            "id":   { "type": "integer", "example": 1 },
                            "name": { "type": "string",  "example": "مثال حقيقي" }
                        }
                    }
                }
            }
        }
    }
}
```

**VALIDATION (422):**

```json
"422": {
    "description": "Validation error",
    "content": {
        "application/json": {
            "schema": {
                "type": "object",
                "properties": {
                    "key":  { "type": "string",  "example": "fail" },
                    "msg":  { "type": "string",  "example": "خطأ في البيانات المدخلة" },
                    "code": { "type": "integer", "example": 422 },
                    "response_status": {
                        "type": "object",
                        "properties": {
                            "error": { "type": "boolean", "example": true },
                            "validation_errors": {
                                "type": "object",
                                "example": { "field_name": ["The field_name field is required."] }
                            }
                        }
                    },
                    "data": { "nullable": true }
                }
            }
        }
    }
}
```

**UNAUTHENTICATED (401):**

```json
"401": {
    "description": "Unauthenticated",
    "content": {
        "application/json": {
            "schema": {
                "type": "object",
                "properties": {
                    "key":  { "type": "string",  "example": "unauthenticated" },
                    "msg":  { "type": "string",  "example": "غير مصرح" },
                    "code": { "type": "integer", "example": 401 },
                    "response_status": {
                        "type": "object",
                        "properties": {
                            "error":            { "type": "boolean", "example": true },
                            "validation_errors": { "type": "object", "nullable": true }
                        }
                    },
                    "data": { "nullable": true }
                }
            }
        }
    }
}
```

### RULE 5 — OPENAPI SELF-CHECK (run before saving)

```
□ Every "data.properties" block filled with real endpoint-specific fields
□ Every field has "type" + "example" with real non-empty value
□ Every endpoint has x-postman-test with non-empty script
□ Every endpoint defines all applicable response codes
□ Zero description-only responses
□ Zero empty "properties": {} blocks
□ Foreign key fields include: "description": "Get from: {METHOD} {PATH}"
□ Enum fields include allowed values in description
```

---

## QUERY PERFORMANCE RULES (MANDATORY)

- NEVER produce N+1 queries.
- ALWAYS eager load required relations in Repository using `with()`.
- NEVER loop over models and access unloaded relations.
- Resources read only already-loaded data.
- Repositories own the relation loading strategy.

---

## SOLID RULES (MANDATORY)

| Principle                 | Rule                                                 |
| ------------------------- | ---------------------------------------------------- |
| S — Single Responsibility | Each class has one reason to change                  |
| O — Open/Closed           | Prefer extension over modification                   |
| L — Liskov Substitution   | Implementations must respect contracts               |
| I — Interface Segregation | Keep interfaces focused, not bloated                 |
| D — Dependency Inversion  | Depend on abstractions (interfaces), not concretions |

**Violations NOT allowed:**

- Fat controllers (any query or business logic)
- Fat repositories (mixed responsibilities)
- Services doing response formatting
- Controllers doing query work
- Repositories doing UI logic

---

## CODING STANDARDS

- PHP 8.2+ typed properties + return types on all methods.
- Import all classes via `use`.
- DocBlocks in English only.
- No duplicate logic between API and Admin — both call the same Service methods.
- Add proper indexes and unique constraints in all migrations.
- SoftDeletes on ALL models (always).

---

## FACTORY & SEEDER RULES (MANDATORY — NO EXCEPTIONS)

Factories and Seeders are NOT optional.
Every feature that introduces a Model MUST produce both a Factory and a Seeder.
Same priority as migrations and repositories — skipping them = incomplete feature.

---

### FACTORY RULES

**Location:** `database/factories/{ModelName}Factory.php`
**Namespace:** `Database\Factories`

Field fake-data rules:

| Field pattern | Fake value |
|--------------|-----------|
| `name` / `title` | `fake()->words(3, true)` |
| `email` | `fake()->unique()->safeEmail()` |
| `phone` | `fake()->numerify('05########')` |
| `password` | `bcrypt('password')` |
| `status` / any enum | `fake()->randomElement(EnumClass::values())` |
| `price` / `amount` / `total` | `fake()->randomFloat(2, 10, 10000)` |
| `lat` | `fake()->latitude()` |
| `lng` | `fake()->longitude()` |
| `map_desc` / `address` | `fake()->address()` |
| `image` / `photo` / `avatar` | `fake()->imageUrl(640, 480)` |
| `description` / `notes` / `body` | `fake()->paragraph()` |
| nullable field | `fake()->optional()->...` |
| `*_id` foreign key | `RelatedModel::factory()` |
| `is_*` / boolean | `fake()->boolean()` |
| `code` / `token` | `fake()->uuid()` |
| `rating` | `fake()->randomFloat(1, 1, 5)` |

**FORBIDDEN in Factories:**
```
✗ Hardcoded IDs like 'client_id' => 1
✗ Empty strings 'field' => ''
✗ null for required fields
✗ Hardcoded enum strings — always use EnumClass::values()
```

---

### SEEDER RULES

**Location:** `database/seeders/{ModelName}Seeder.php`
**Namespace:** `Database\Seeders`

- Always **50 records** per model
- Always has `count() > 0` duplicate guard
- Always wrapped in `DB::transaction()`
- MUST be registered in `DatabaseSeeder.php`
- MUST be runnable standalone: `php artisan db:seed --class={ModelName}Seeder`
- Order in `DatabaseSeeder.php` MUST respect dependencies

**Template:**

```php
<?php

namespace Database\Seeders;

use App\Models\{ModelName};
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class {ModelName}Seeder extends Seeder
{
    public function run(): void
    {
        if ({ModelName}::count() > 0) {
            return;
        }

        DB::transaction(function () {
            {ModelName}::factory()->count(50)->create();
        });
    }
}
```

**FORBIDDEN in Seeders:**
```
✗ No duplicate guard
✗ Not registered in DatabaseSeeder.php
✗ Hardcoded array data instead of factory
✗ No DB::transaction() when inserting multiple models
```

---

## EXPECTED OUTPUT (ALWAYS PRODUCE ALL OF THESE)

**A) Database:**

- Migrations (safe `up()` + `down()`, indexes, unique constraints, `softDeletes()`)

**B) Domain:**

- Enums with `EnumRetriever` trait (if any)
- DTOs (readonly, fromRequest)
- Repository contracts (interfaces)
- Repository Eloquent implementations
- Services
- Strategy/Factory (when behavior differs by type/status/gateway)

**C) API:**

- FormRequests (validation only)
- Resources (no lazy loading, use whenLoaded)
- Controllers (thin, ResponseTrait + PaginationTrait)
- Routes (grouped under `auth:sanctum` where needed)

**D) Admin:**

- Routes: parent metadata + routes-links
- Controllers extending AdminBasicController
- Blades: index + table (+ create/edit/show when needed)

**E) i18n:**

- `lang/ar/admin.php` — add domain keys
- `lang/ar/apis.php` — add domain keys
- `lang/ar/enums.php` — add enum keys
- `lang/ar/validation.php` — add field attributes

**F) Data & Tests:**

- Factories
- Seeders
- Feature tests (API + Admin)

**G) Documentation:**

- `docs/features/{feature_folder}/README.md`
- `docs/features/{feature_folder}/openapi.json`
- `docs/README.md` ← UPDATE: add feature row
- `docs/openapi.json` ← UPDATE: merge new paths

---

## IMPLEMENTATION WORKFLOW (MANDATORY ORDER)

**Step -1 — Resolve Architecture Mode (see ARCHITECTURE MODE section at top of this file).**
Do this before anything else. Read `docs/architecture-mode.md` or ask the developer if it does not exist.

**Step 0 — Read everything first:**

1. Read this constitution completely
2. Read `docs/features/{folder}/feature_name.md`
3. Read `docs/features/{folder}/figma_fragment.json`
4. Read `docs/features/{folder}/analysis_fragment.md`

**Step 0-A — Check existing models (BEFORE writing any code):**

For every entity identified in the feature, consult the **EXISTING MODELS MAP** section.
Mark each entity as one of:
- `[REUSE]` — maps to an existing model/table
- `[NEW]` — genuinely new, needs migration + model

Only entities marked `[NEW]` proceed to migration creation.

**Step 0-B — Check RepositoryServiceProvider (FIRST FEATURE ONLY):**

```
□ Does app/Providers/RepositoryServiceProvider.php exist?
  NO → create it and register it before proceeding to any other file
  YES → continue
```

**Then write this summary before any code — DO NOT proceed until summary is complete:**

```
Entities/Tables:    [list — mark each as REUSE or NEW]
Enums:              [list or NONE]
API Endpoints:      [METHOD /path — purpose — has input? YES/NO]
Admin Screens:      [list or NONE]
Translation keys:   [apis.php keys / admin.php keys / enums.php keys]
Factories/Seeders:  [list — only for NEW models]
Tests:              [list]
FormRequests/DTOs:  [list — only endpoints with YES input above]
```

**PER-FILE SELF-CHECK (run mentally before finalizing every single file):**

```
□ Does this file comply with the constitution?
□ Does this file violate any HARD CONSTRAINT above?
□ Does this file conflict with any rule in this constitution?
```

If any box fails → rewrite the file before moving on.

**Step 1 — Implementation order (do not reorder):**

1. migrations
2. enums + `lang/ar/enums.php`
3. DTOs
4. repository contracts
5. repository Eloquent implementations
6. services
7. factories
8. seeders
9. API FormRequests + `lang/ar/validation.php` attributes
10. API Resources (`EnumRetriever::getFullObj` for enum fields)
11. API Controllers (`ResponseTrait` + `PaginationTrait`)
12. API routes
13. Admin routes (parent + routes-links)
14. Admin controllers (AdminBasicController)
15. Admin blades (index / table / create / edit / show)
16. `lang/ar/admin.php` + `lang/ar/apis.php` keys
17. Feature tests (API + Admin)
18. Documentation (README + openapi.json per-feature + update master docs)
19. Final checklist

---

## QUALITY GATE — FEATURE IS INCOMPLETE IF:

```
□ docs/README.md not updated with this feature
□ docs/openapi.json not updated with new endpoints
□ Architecture mode not resolved (docs/architecture-mode.md missing and developer not asked)
□ MODE_A: Repository layer missing (contract or implementation)
□ MODE_A: Eloquent used directly in Service or Controller
□ MODE_A: Repository binding added to AppServiceProvider instead of RepositoryServiceProvider
□ MODE_A: RepositoryServiceProvider does not exist (first feature only — must be created)
□ MODE_B: Repository files created (Repository layer is not used in MODE_B)
□ Mixed modes detected (some features use Repository, others do not)
□ N+1 query risk exists
□ Lazy loading inside Resources
□ API response bypasses ResponseTrait::jsonResponse()
□ OpenAPI has description-only responses
□ OpenAPI has empty "properties": {} blocks
□ OpenAPI has empty or missing "example" values
□ OpenAPI endpoint missing x-postman-test script
□ x-postman-test script is empty
□ MODE_A: DTO is not readonly
□ MODE_A: DTO missing fromRequest() static method
□ Empty DTO created for an endpoint that has no input (MODE_A only)
□ Empty FormRequest created for an endpoint that has no input
□ FormRequest contains DB queries or business checks
□ Model missing SoftDeletes
□ Migration missing softDeletes()
□ SOLID principles violated
□ Permissions system modified
□ Patterns learned from existing codebase Requests/Controllers
□ city_id or country_id used for geographic location
□ Wrong auth middleware (must be auth:sanctum)
□ Wrong namespace pattern
□ Factory missing for any new Model
□ Factory uses hardcoded enum strings instead of EnumClass::values()
□ Factory uses hardcoded IDs instead of RelatedModel::factory()
□ Seeder missing for any new Model
□ Seeder not registered in DatabaseSeeder.php
□ Seeder has no duplicate-run guard
□ Seeder count is not 50 (unless feature spec states otherwise)
□ New model created for users/clients/customers instead of reusing User model
□ New model created for intros/onboarding instead of reusing Intro model
□ New model created for sliders/banners instead of reusing Image model
```

Every unchecked box = feature is incomplete. Fix before finishing.
