# Full Up — Backend Architecture Guide

## Overview

Full Up uses three independent Laravel 13 backends sharing one MySQL 8.4 LTS database
through a private Composer package (`mawad008/platform-core`).

| Backend | Directory | Port | Purpose | Runs Migrations? |
|---|---|---|---|---|
| Super & Admin | `SuperAdmin/` | 8000 | Admin portal, SP management, settings, users/roles | **YES — sole executor** |
| Service Provider | `ServiceProvider/` | 8001 | Provider portal, station management, staff, blacklist | No |
| Organizations | `Organizations/` | 8002 | Company, government, diplomatic, exhibition dashboards | No |

## Shared Package: platform-core

**Namespace:** `Mawad008\PlatformCore`
**Repository:** `github.com/mawad008/platform-core` (private)

### What goes in platform-core

- Eloquent models for tables that multiple backends read/write
- PHP enums (status domains, scope kinds, portal codes)
- Custom casts (money, compound status)
- Shared traits (HasCompositeKey, HasAuditFields)
- Shared query scopes
- **No migrations.** platform-core contains no migration files (decision D-01; enforced by `NoMigrationsTest` and `scripts/check-no-migrations.php`)
- Base seeder classes for reference data
- Shared repository contracts (only when justified by multi-backend use)

### What stays in each backend

- Controllers, Form Requests, API Resources
- Module-specific services
- Module-specific repository interfaces and implementations
- Policies
- Backend-specific seeders
- Tests

## Repository Design Pattern

All backends follow the Controller → Service → Repository → Model pattern.

### Architectural Flow

```
HTTP Request
    ↓
Controller          — Receives request, delegates to service, returns API Resource
    ↓
FormRequest         — Validates input (injected into controller method)
    ↓
Service             — Business logic, orchestrates repositories, enforces rules
    ↓
Repository Interface — Contract defining data access methods
    ↓
Eloquent Repository  — Implements interface using Eloquent ORM
    ↓
Model               — Eloquent model (from platform-core or local)
    ↓
MySQL 8.4 LTS       — Shared database
    ↓
API Resource         — Transforms model into JSON response
```

### Directory Structure (per backend)

```
app/
├── Http/
│   ├── Controllers/       ← Route handlers, thin, delegate to services
│   ├── Requests/          ← Form request validation classes
│   ├── Resources/         ← API resource transformers
│   └── Middleware/         ← Request middleware
├── Services/              ← Business logic layer
├── Repositories/
│   ├── Contracts/         ← Repository interfaces
│   └── Eloquent/          ← Eloquent implementations
├── Policies/              ← Authorization policies
└── Providers/
    └── RepositoryServiceProvider.php  ← DI bindings
```

### Binding Convention

In `RepositoryServiceProvider.php`:

```php
$this->app->bind(
    \App\Repositories\Contracts\UserRepositoryInterface::class,
    \App\Repositories\Eloquent\EloquentUserRepository::class,
);
```

### Naming Convention

| Layer | Pattern | Example |
|---|---|---|
| Interface | `{Entity}RepositoryInterface` | `StationRepositoryInterface` |
| Implementation | `Eloquent{Entity}Repository` | `EloquentStationRepository` |
| Service | `{Entity}Service` | `StationService` |
| Controller | `{Entity}Controller` | `StationController` |
| Form Request | `{Action}{Entity}Request` | `CreateStationRequest` |
| API Resource | `{Entity}Resource` | `StationResource` |
| Policy | `{Entity}Policy` | `StationPolicy` |

## Database

### Engine

MySQL 8.4 LTS — one shared database named `fullup`.

### Migration Ownership

**Super & Admin is the SOLE migration owner and executor (decision D-01).** Migrations live in
`SuperAdmin/database/migrations/` (flat directory, no subdirectories; enforced by `MigrationOwnershipTest`).
`PlatformCoreServiceProvider` does not load migrations. The canonical schema source is the ERD
repository (`Erd&Brd&Architecture`, 16 `*-spec.json` files) together with its Decision Register
(`docs/decision-register/`); migrations are generated from it. Deferred foreign keys (cycles and
self-references) are added by the final migration.

- `SuperAdmin`: runs `php artisan migrate` (production: `--force`)
- `ServiceProvider`: **never** runs migrate
- `Organizations`: **never** runs migrate

### Status System

Centralised, simplified `status` table (decision G-04): one row per status with a globally unique,
domain-prefixed `code` (for example `USER_ACTIVE`, `ORDER_PENDING`), `name_ar`, `name_en` and `color`.
Every lifecycle column is a plain foreign key:

```
status_id → status(id)
```

There are no `*_domain_code` columns and no composite status keys; the allowed codes per table are
validated in the application layer.

## Technology Stack

| Component | Version | Requirement |
|---|---|---|
| PHP | 8.4 | `^8.4` in all composer.json |
| Laravel | 13.x | `^13.17` |
| MySQL | 8.4 LTS | Shared across all backends |
| Composer | 2.8+ | — |
| PHPUnit | 12.x | Testing |
| PHPStan | 2.x | Static analysis (level 6) |
| Laravel Pint | 1.x | Code style (Laravel preset) |

## Code Quality Standards

### PHP

- `declare(strict_types=1)` in every file
- `final` on all classes (unless designed for extension)
- Return type declarations on all methods
- PHPStan level 6 — zero errors allowed
- Laravel Pint with `laravel` preset — zero diff allowed

### Localization

- Arabic (`ar`) is the default application locale; English (`en`) is the fallback locale
- User-facing application text uses translation keys, never hard-coded strings
- Application-owned translation keys are maintained in both `lang/ar` and `lang/en` (enforced by
  `TranslationParityTest`); `validation.php` is intentionally asymmetric — Arabic carries the full
  Laravel catalogue, English relies on Laravel's built-in messages and only overrides attributes
- Internal/developer diagnostics (e.g. exception messages for misconfigured routes) are not
  user-facing text and are not translated

### Testing

- Feature tests for API endpoints (HTTP tests)
- Unit tests for services and repositories
- SQLite `:memory:` for unit tests that do not touch the schema; the migrations use MySQL 8.4 features
  (CHECK constraints, stored generated columns, charset-specific columns), so any test that runs the
  migrations must use a disposable MySQL 8.4 database — never the shared `fullup` database

### CI Pipeline (GitHub Actions)

1. Checkout + Setup PHP 8.4
2. Install platform-core + backend dependencies
3. Laravel Pint (code style)
4. PHPStan (static analysis)
5. PHPUnit (tests against MySQL 8.4 service)

## Local Development Setup

```bash
# 1. Clone all repos
git clone <platform-core-repo> platform-core
git clone <super-admin-repo> SuperAdmin
git clone <service-provider-repo> ServiceProvider
git clone <organizations-repo> Organizations

# 2. Install platform-core
cd platform-core && composer install

# 3. Install Super & Admin (migration executor)
cd ../SuperAdmin
cp .env.example .env
composer install
php artisan key:generate
php artisan migrate          # ← ONLY here

# 4. Install Service Provider (no migrate)
cd ../ServiceProvider
cp .env.example .env
composer install
php artisan key:generate

# 5. Install Organizations (no migrate)
cd ../Organizations
cp .env.example .env
composer install
php artisan key:generate

# 6. Start all backends
cd ../SuperAdmin && php artisan serve --port=8000 &
cd ../ServiceProvider && php artisan serve --port=8001 &
cd ../Organizations && php artisan serve --port=8002 &
```
