# Enums

**NUMBER:** ADR-ENUM-001
**STATUS:** CANONICAL AUTHORITY
**SCOPE:** Every class defined using the `enum` keyword in this project.
**RULE:** This is the ONLY definitive source for Enum architecture, permitted behaviors, and Display class patterns. Any other document mentioning this topic is a REFERENCE, not a definition.
**VIOLATION:** Implementing Enum patterns based on any other source constitutes an architectural breach.

> **Business state transitions governed by Enums:** `SPECIFICATIONS/03_ARCHITECTURE/02_STATE_MACHINES.md`
> **Database schema conventions for status columns:** `04_DATABASE_COMMUNICATION.md` → Schema Conventions

---

## 1. Philosophy

**Knowledge Keeper Without Side Effects.**

The Enum is the only entity permitted to **know** its own rules, but it is **prohibited** from **executing** any effect on the system. We use PHP 8.1 enum methods to prevent scattered `if` checks in Services, while maintaining complete isolation from the database and presentation layers.

---

## 2. Absolute Prohibitions

```text
❌ PROHIBITED: Dependency Injection inside the Enum.
❌ PROHIBITED: Any database read or write operations.
❌ PROHIBITED: Any presentation data (HTML colors, icons, translated user-facing text).
❌ PROHIBITED: Creating "Manager" classes for Enums (e.g., EnumManager, StatusManager).
❌ PROHIBITED: Non-Backed Enums if the value will be stored in the database.
❌ PROHIBITED: Duplicating system-wide state machine maps inside the Enum if they are defined in Specifications.
```

---

## 3. Permitted Behavior (Pure Methods)

**Golden Rule:** The function must need ONLY the Enum value itself (or simple passed inputs) to return a value or Boolean. These are Pure Functions representing **inherent traits of the value**, not workflow orchestration.

### 3.1 Good Examples (Inherent Traits)

Methods that describe *what this value IS* or *how it behaves fundamentally*.

```php
enum PaymentType: string
{
    case CompanyPayout = 'company_payout';
    case InitialPayment = 'initial_payment';
    case InstallmentPayment = 'installment_payment';

    // PERMITTED: Describes a fundamental characteristic of the payment type
    public function affectsCustomerBalance(): bool
    {
        return match($this) {
            self::InitialPayment, 
            self::InstallmentPayment => true,
            self::CompanyPayout => false,
        };
    }

    // PERMITTED: Describes a structural requirement of the type
    public function requiresInstallmentLink(): bool
    {
        return $this === self::InstallmentPayment;
    }
}
```

```php
enum ShareTransactionType: string
{
    case Add = 'add';
    case Withdraw = 'withdraw';

    // PERMITTED: Describes mathematical direction
    public function isCredit(): bool
    {
        return $this === self::Add;
    }

    public function isDebit(): bool
    {
        return $this === self::Withdraw;
    }
}
```

### 3.2 Bad Examples (Workflow Orchestration / State Machines)

Methods that describe *what happens IN THE SYSTEM* when this value occurs.

```php
// PROHIBITED: This is a state machine map, not an inherent trait.
// It belongs in SPECIFICATIONS, or calculated via DB state, not hardcoded here.
public function allowedTransitions(): array
{
    return match($this) {
        self::Draft => [self::Active],
        // ...
    };
}

// PROHIBITED: Requires DB context
public function calculatePenalty(): float { ... }
```

---

## 4. Transition Guarding Pattern

Since Enums do not hold state machine maps, transition validation is handled by Domain Validators or Services checking inherent traits of the current state.

If an Enum value has an inherent trait that prevents modification (e.g., a Closed status), it may expose it:
```php
// Inside Service
enum ContractStatus: string {   
public function isModifiable(): bool 
    {
        return $this === self::Draft;    
    }
}
```

---

## 5. Presentation via Dedicated Display Classes

The Domain Enum is prohibited from knowing anything about the UI. A separate `[EnumName]Display` class handles all presentation logic.

### 5.1 Rules

1. Created in `Enums/Display/` subfolder within the Domain (NOT in Shared).
2. Contains ONLY functions returning text or display data.
3. Called EXCLUSIVELY from inside API Resources or Blade Views.

### 5.2 Canonical Pattern

```php
namespace App\Domains\Contract\Display;

use App\Domains\Contract\Enums\ContractStatus;

class ContractStatusDisplay
{
    public static function label(ContractStatus $status): string
    {
        return match($status) {
            ContractStatus::Draft     => __('statuses/contract.draft'),
            ContractStatus::Active    => __('statuses/contract.active'),
            ContractStatus::Completed => __('statuses/contract.completed'),
        };
    }
}
```

### 5.3 Usage in Resource

```php
class ContractResource extends JsonResource
{
    public function toArray($request): array
    {
        $statusEnum = ContractStatus::from($this->status);
        
        return [
            'status'       => $this->status,
            'status_label' => ContractStatusDisplay::label($statusEnum),
        ];
    }
}
```

---

## 6. Approved Enum Catalog (CANONICAL)

Every `VARCHAR` status or type column in the system MUST have a corresponding backed enum.

| Database Column | Enum Name | Values |
|:---|:---|:---|
| `contracts.status` | `ContractStatus` | `draft`, `active`, `completed` |
| `installments.status` | `InstallmentStatus` | `pending`, `paid`, `overdue` |
| `payments.type` | `PaymentType` | `company_payout`, `initial_payment`, `installment_payment` |
| `client_shares_logs.transaction_type` | `ShareTransactionType` | `add`, `withdraw` |
| `client_shares_logs.status` | `ShareLogStatus` | `active`, `modified`, `deleted` |
| `payment_audit_logs.action_type` | `AuditActionType` | `create`, `update`, `delete` |

### Structural Constraints

1. Enum values MUST match database stored values exactly (lowercase strings).
2. Database columns MUST remain `VARCHAR`.
3. **Adding a new status** requires: (1) Add to the Enum class, (2) Update any `match` statements.

---

## 7. Edge Cases

### 7.1 Enum Needs External Data (e.g., determining "Overdue")

**Correct Approach: Service decides the status using external data**
```php
$installment->update([
    'status' => $installment->due_date < now()
        ? InstallmentStatus::Overdue->value
        : InstallmentStatus::Pending->value
]);
```

### 7.2 Unknown Value in Database

**Rule:** Always use `tryFrom` in Read Paths (Resources, Query Classes) to handle unexpected data gracefully.

```php
$statusEnum = ContractStatus::tryFrom($this->status);
if ($statusEnum === null) {
    // Handle legacy/invalid value gracefully
}
```

---

## 8. Decision Cheat Sheet

1. Does the function need a Service or Query Builder call?
   └─ YES → Remove it. Put it in the Service.

2. Does the function return a color or translated text?
   └─ YES → Remove it. Put it in [EnumName]Display.

3. Does the function describe a system workflow (like allowed transitions)?
   └─ YES → Remove it. Check Specifications or Domain Validator.

4. Does the function describe an inherent trait of the value (e.g., isCredit)?
   └─ YES → Correct place.

5. Do I need a StatusManager class?
   └─ YES → Do NOT create it. Put the function inside the Enum.

6. Am I using a Non-Backed Enum for a database column?
   └─ YES → Error. Change it to `enum Name: string`.