# The Shared Domain

**NUMBER:** ADR-SHR-001
**STATUS:** CANONICAL AUTHORITY — CRITICAL PRIORITY
**SCOPE:** Any code written inside `App\Domains\Shared`. Any violation is a direct architectural breach rejected in Code Review.
**RULE:** This is the ONLY definitive source for what is allowed in the Shared Domain. Any other document mentioning this topic is a REFERENCE, not a definition.
**VIOLATION:** Placing unauthorized code in the Shared Domain constitutes a critical architectural breach.

> **Directory layout:** `00_CONSTITUTION_INDEX.md` → Project Structure (Shared section)
> **Financial precision requirements driving the Money object:** `SPECIFICATIONS/01_BUSINESS_CONTEXT/03_BUSINESS_RULES.md` → BR-006
> **Custom Validation Rules location:** `08_FORM_REQUESTS.md` → Custom Validation Rules

---

## 1. Philosophy

**Primitive Extension & Foundational Entities Library.**

The Shared Domain is **NOT** a business domain for specific features (like contracts or payments). Its function is providing "building blocks" that are common across all Domains. This includes:
1. Extended primitives that wrap PHP native types (e.g., Money).
2. Foundational Entities (Models) that are used by multiple domains and do not belong exclusively to one.
3. Generic structural traits and filters.

**The Modified Iron Rule:** If the code implements *business logic workflows* or *features* for a specific domain (like calculating contract penalties), it is in the wrong place. However, if it is a *Foundational Entity* (like `Client`) used universally, it belongs here.

---

## 2. Absolute Prohibitions

These are prohibited under ANY circumstance. No exceptions.

```text
❌ PROHIBITED: FormRequests or Validation rules (except Custom Rules — see Section 3.4).
❌ PROHIBITED: Services or Actions.
❌ PROHIBITED: Query Classes or Repositories.
❌ PROHIBITED: Enums.
   (Reason: An Enum represents business states. A "Shared Enum" indicates a design flaw or missing domain merge).
❌ PROHIBITED: DTOs (Data Transfer Objects).
   (Reason: A "Shared DTO" is a literal contradiction. DTOs carry business context).
❌ PROHIBITED: Using any database Facade (DB, Cache) inside Shared non-Model classes.
```

---

## 3. Strictly Allowed List

No code is permitted in `Shared` unless it explicitly belongs to one of these categories.

### 3.1 Foundational Models (CANONICAL EXCEPTION)

Models that represent core entities used across multiple domains. They are placed here because no single domain "owns" them exclusively.

**Example:** `Client` — Used by Customer, Agent, Investor, Contract, and Payment domains.

**Rules for Foundational Models:**
- They MAY contain their necessary Eloquent relationships, scopes, and casts.
- They MAY contain methods that inherently belong to their state.
- They MUST NOT contain methods that execute workflows belonging to a specific feature domain (e.g., a method on `Client` that calculates contract penalties — that belongs in the Contract domain).

### 3.2 Value Objects (Primitive Extension)
# The Shared Domain

**NUMBER:** ADR-SHR-001
**STATUS:** CANONICAL AUTHORITY — CRITICAL PRIORITY
**SCOPE:** Any code written inside `App\Domains\Shared`. Any violation is a direct architectural breach rejected in Code Review.
**RULE:** This is the ONLY definitive source for what is allowed in the Shared Domain. Any other document mentioning this topic is a REFERENCE, not a definition.
**VIOLATION:** Placing unauthorized code in the Shared Domain constitutes a critical architectural breach.

> **Financial precision requirements driving the Money object:** `SPECIFICATIONS/01_BUSINESS_CONTEXT/03_BUSINESS_RULES.md` → BR-006
> **Custom Validation Rules location:** `08_FORM_REQUESTS.md` → Custom Validation Rules

---

## 1. Philosophy

**Primitive Extension & Foundational Entities Library.**

The Shared Domain is **NOT** a business domain for specific features (like contracts or payments). Its function is providing "building blocks" that are common across all Domains. This includes:
1. Extended primitives that wrap PHP native types (e.g., Money).
2. Foundational Entities (Models) that are used by multiple domains and do not belong exclusively to one.
3. Generic structural traits and filters.

**The Modified Iron Rule:** If the code implements *business logic workflows* or *features* for a specific domain (like calculating contract penalties), it is in the wrong place. However, if it is a *Foundational Entity* (like `Client`) used universally, it belongs here.

---

## 2. Absolute Prohibitions

```text
❌ PROHIBITED: FormRequests or Validation rules (except Custom Rules — see Section 3.4).
❌ PROHIBITED: Services or Actions.
❌ PROhibited: Query Classes or Repositories.
❌ PROHIDDEN: Enums.
   (Reason: An Enum represents business states. A "Shared Enum" indicates a design flaw or missing domain merge).
❌ PROHIBITED: DTOs (Data Transfer Objects).
   (Reason: A "Shared DTO" is a literal contradiction. DTOs carry business context).
❌ PROHIDDEN: Using any database Facade (DB, Cache) inside Shared non-Model classes.
```

---

## 3. Strictly Allowed List

No code is permitted in `Shared` unless it explicitly belongs to one of these categories.

### 3.1 Foundational Models (CANONICAL EXCEPTION)

Models that represent core entities used across multiple domains. They are placed here because no single domain "owns" them exclusively.

**Example:** `Client` — Used by Customer, Agent, Investor, Contract, and Payment domains.

**Rules for Foundational Models:**
- They MAY contain their necessary Eloquent relationships, scopes, and casts.
- They MAY contain methods that inherently belong to their state.
- They MUST NOT contain methods that execute workflows belonging to a specific feature domain (e.g., a method on `Client` that calculates contract penalties — that belongs in the Contract domain).

### 3.2 Value Objects (Primitive Extension)

In a financial system, using raw `string` for money is a disaster (Primitive Obsession). The Shared Domain is the place to define extended primitives.

**Canonical Example: The `Money` Value Object**

```php
namespace App\Domains\Shared\ValueObjects;

use InvalidArgumentException;

/**
 * Value Object representing monetary values with arbitrary precision.
 *
 * Architectural Rule (BR-006-1):
 * - NEVER use floating point numbers in financial calculations.
 * - Money accepts ONLY strings or integers.
 * - Internal representation is always a precise string.
 * - Amounts are normalized to the configured scale.
 */
readonly class Money
{
    public string $amount;

    private function __construct(
        string|int $amount,
        private int $scale = 8
    ) {
        $stringAmount = (string) $amount;

        $trueAmount = $this->normalizeAmount($stringAmount);

        $this->amount = $trueAmount;
    }

    public static function of(string|int $amount, int $scale = 8): self
    {
        return new self($amount, $scale);
    }

    public function equals(Money $other): bool
    {
        return bccomp($this->amount, $other->amount, $this->scale) === 0;
    }

    public function isGreaterThan(Money $other): bool
    {
        return bccomp($this->amount, $other->amount, $this->scale) === 1;
    }

    public function isZero(): bool
    {
        return bccomp($this->amount, '0', $this->scale) === 0;
    }

    public function multiply(Money $other): Money
    {
        return new self(
            bcmul($this->amount, $other->amount, $this->scale),
            $this->scale
        );
    }

    /**
     * Formats the amount for presentation purposes only.
     * WARNING: Never use this method for financial calculations.
     * It converts the value to float ONLY for display.
     */
    public function formatted(int $decimals = 2): string
    {
        return number_format((float) $this->amount, $decimals);
    }

    /**
     * Returns the raw string representation.
     * Safe for database writes.
     */
    public function raw(): string
    {
        return $this->amount;
    }

    public function __toString(): string
    {
        return $this->amount;
    }

    private function normalizeAmount(string $amount): string
    {
        if (!preg_match('/^\d+(?:\.\d+)?$/', $amount)) {
            throw new InvalidArgumentException("Invalid monetary value: {$amount}");
        }

        return bcadd($amount, '0', $this->scale);
    }
}
```

**Creation Warning:** Do NOT create `Money` until you actually need it. Create it ONLY when you find yourself writing raw `bccomp` for the third time in a different Domain (YAGNI applies to Shared too).

### 3.3 Structural Traits

Traits that modify framework behavior **WITHOUT** containing business logic. Protection methods in these traits MUST use the `final` keyword to prevent overriding.

| Permitted | Prohibited Here |
|:---|:---|
| `HasReferenceNumber` (Interacts with Eloquent Boot) | Any Trait containing business logic |
| `PreventsDeletion` (Disables `delete()`/`destroy()` using `final`) | `HasFinancialCalculations` |

**Trait Boot Mechanism (CANONICAL):**
Always use the Laravel official `boot{TraitName}` naming convention for trait boot methods.

```php
trait PreventsDeletion
{
    final public function delete(): bool
    {
        throw new \RuntimeException('Deletion is blocked by system policy.');
    }

    final public function destroy($ids): int
    {
        throw new \RuntimeException('Mass deletion is blocked by system policy.');
    }
}
```

### 3.4 Pure Filter Components

Filters that know nothing about any specific database table.

| Permitted | Prohibited Here |
|:---|:---|
| `DateRangeFilter` (Takes `from`/`to`, applies `whereBetween`) | `AgentStatusFilter` (Knows about agents) |
| `SearchFilter` (Takes table name and column, applies `whereLike`) | Any filter mentioning a business entity name |

### 3.5 Custom Validation Rules

Reusable structural rules that can be applied in any FormRequest. See `08_FORM_REQUESTS.md` → Section 6.1 for full architecture.

**Location:** `App/Domains/Shared/Validation/Rules/`

---

## 4. The Belonging Litmus Test (For Non-Models)

Before creating or keeping ANY non-Model file in `Shared`, it MUST pass this exact test.

```text
Q1: Does this code know a database table name?
   └─ YES → PROHIBITED. Move to the specific Domain.

Q2: Does this code know a specific business feature term (Contract, Share, Installment)?
   └─ YES → PROHIDDEN. Move to the specific Domain.

Q3: Could this code be used in an e-commerce app instead of this financing system?
   └─ NO (e.g., it calculates installment interest) → PROHIBITED.
   └─ YES (e.g., it adds two decimal numbers precisely) → Proceed to Q4.

Q4: Is this code actually used in MORE THAN ONE Domain right now?
   └─ NO → PROHIDDEN. Put it in the Domain that uses it (YAGNI).
   └─ YES → Its final home is Shared.
```

---

## 5. Promotion & Demotion Rule

### Promotion (Domain → Shared)
If code in a specific Domain starts being used in a SECOND Domain AND passes the Litmus Test:
1. Move it to `Shared/ValueObjects`, `Shared/Traits`, `Shared/Filters`, or `Shared/Validation/Rules`.
2. Replace old calls with Shared versions.

### Demotion (Shared → Domain)
If code in Shared is found to be used in ONLY ONE Domain:
1. Move it to that specific Domain.
2. Do NOT leave it in Shared "because it might be used later" (YAGNI).

---

## 6. Final Directory Structure

```text
App/Domains/Shared/
├── Models/                  ← Foundational entities (e.g., Client.php)
├── ValueObjects/            ← Money, etc.
├── Traits/                  ← HasReferenceNumber, PreventsDeletion, etc.
├── Filters/                 ← DateRangeFilter, SearchFilter, etc.
└── Validation/
    └── Rules/               ← UniqueExceptCurrentPhone, ValidEnumValue, etc.
```

**Prohibited Folders:** `Helpers`, `DTOs`, `Enums`, `Rules` (at root level), `Services`, `Queries`, `Exceptions`, `Scopes` (Scopes belong inside the Model or Domain).
```

---

### 7. Decision Cheat Sheet

When you are about to create a file or move a class into `App\Domains\Shared/`:

1. Is it a Foundational Model used by 3+ domains?
   └─ YES → Allowed in Shared/Models/.

2. Is it a Value Object handling raw PHP types (like Money)?
   └─ YES → Allowed in Shared/ValueObjects/.

3. Is it a Trait modifying Eloquent Boot or blocking destructive actions?
   └─ YES → Allowed in Shared/Traits/. Use `final` on protection methods.

4. Is it a generic Query filter (like Date Range)?
   └─ YES → Allowed in Shared/Filters/.

5. Is it a reusable Custom Validation Rule?
   └─ YES → Allowed in Shared/Validation/Rules/.

6. Is it an Enum?
   └─ YES → ERROR. Enums belong in their respective Domain/Enums/ folder.

7. Is it a DTO?
   └─ YES → ERROR. DTOs belong in their Domain/DTOs/ folder.

8. Is it only used by ONE Domain right now?
   └─ YES → ERROR. Keep it in that Domain.
```

---


### 3.3 Structural Traits

Traits that modify framework behavior **WITHOUT** containing business logic. Protection methods in these traits MUST use the `final` keyword to prevent overriding.

| Permitted | Prohibited Here |
|:---|:---|
| `HasReferenceNumber` (Interacts with Eloquent Boot) | Any Trait containing business logic |
| `PreventsDeletion` (Disables `delete()`/`destroy()` using `final`) | `HasFinancialCalculations` |

**Trait Boot Mechanism (CANONICAL):**
Always use the Laravel official `boot{TraitName}` naming convention for trait boot methods.

```php
trait PreventsDeletion
{
    final public function delete(): bool
    {
        throw new \RuntimeException('Deletion is blocked by system policy.');
    }

    final public function destroy($ids): int
    {
        throw new \RuntimeException('Mass deletion is blocked by system policy.');
    }
}
```

### 3.4 Pure Filter Components

Filters that know nothing about any specific database table.

| Permitted | Prohibited Here |
|:---|:---|
| `DateRangeFilter` (Takes `from`/`to`, applies `whereBetween`) | `AgentStatusFilter` (Knows about agents) |
| `SearchFilter` (Takes table name and column, applies `whereLike`) | Any filter mentioning a business entity name |

### 3.5 Custom Validation Rules

Reusable structural rules that can be applied in any FormRequest. See `08_FORM_REQUESTS.md` → Section 6.1 for full architecture.

**Location:** `App/Domains/Shared/Validation/Rules/`

---

## 4. The Belonging Litmus Test (For Non-Models)

Before creating or keeping ANY non-Model file in `Shared`, it MUST pass this exact test.

```text
Q1: Does this code know a database table name?
   └─ YES → PROHIBITED. Move to the specific Domain.

Q2: Does this code know a specific business feature term (Contract, Share, Installment)?
   └─ YES → PROHIBITED. Move to the specific Domain.

Q3: Could this code be used in an e-commerce app instead of this financing system?
   └─ NO (e.g., it calculates installment interest) → PROHIBITED.
   └─ YES (e.g., it adds two decimal numbers precisely) → Proceed to Q4.

Q4: Is this code actually used in MORE THAN ONE Domain right now?
   └─ NO → PROHIBITED. Put it in the Domain that uses it (YAGNI).
   └─ YES → Its final home is Shared.
```

---

## 5. Promotion & Demotion Rule

### Promotion (Domain → Shared)
If code in a specific Domain starts being used in a SECOND Domain AND passes the Litmus Test:
1. Move it to `Shared/ValueObjects`, `Shared/Traits`, `Shared/Filters`, or `Shared/Validation/Rules`.
2. Replace old calls with Shared versions.

### Demotion (Shared → Domain)
If code in Shared is found to be used in ONLY ONE Domain:
1. Move it to that specific Domain.
2. Do NOT leave it in Shared "because it might be used later" (YAGNI).

---

## 6. Final Directory Structure

```text
App/Domains/Shared/
├── Models/                  ← Foundational entities (e.g., Client.php)
├── ValueObjects/            ← Money, etc.
├── Traits/                  ← HasReferenceNumber, PreventsDeletion, etc.
├── Filters/                 ← DateRangeFilter, SearchFilter, etc.
└── Validation/
    └── Rules/               ← UniqueExceptCurrentPhone, ValidEnumValue, etc.
```

**Prohibited Folders:** `Helpers`, `DTOs`, `Enums`, `Rules` (at root level), `Services`, `Queries`, `Exceptions`, `Scopes` (Scopes belong inside the Model or Domain).

---

## 7. Decision Cheat Sheet

When you are about to create a file or move a class into `App\Domains\Shared/`:

1. Is it a Foundational Model used by 3+ domains?
   └─ YES → Allowed in Shared/Models/.

2. Is it a Value Object handling raw PHP types (like Money)?
   └─ YES → Allowed in Shared/ValueObjects/.

3. Is it a Trait modifying Eloquent Boot or blocking destructive actions?
   └─ YES → Allowed in Shared/Traits/. Use `final` on protection methods.

4. Is it a generic Query filter (like Date Range)?
   └─ YES → Allowed in Shared/Filters/.

5. Is it a reusable Custom Validation Rule?
   └─ YES → Allowed in Shared/Validation/Rules/.

6. Is it an Enum?
   └─ YES → ERROR. Enums belong in their respective Domain/Enums/ folder.

7. Is it a DTO?
   └─ YES → ERROR. DTOs belong in their Domain/DTOs/ folder.

8. Is it only used by ONE Domain right now?
   └─ YES → ERROR. Keep it in that Domain.