# Feature Specification: Base Architecture - Foundation Layers (SP-03)

**Feature Branch**: `feat/SP-03-base-architecture`

**Created**: 2026-06-04

**Status**: Draft

**Input**: User description: "Base Architecture - Models Repositories Resources ExceptionHandler Queues"

## User Scenarios & Testing *(mandatory)*

### User Story 1 - Eloquent Models with Semantic Relationships (Priority: P1)

As a Backend Developer, I need all database tables to have corresponding Eloquent models with correctly defined relationships.

**Why this priority**: Models are the foundation of data access. Without proper relationships, queries will be ambiguous and error-prone.

**Independent Test**: Can be tested by instantiating each model and calling relationships to verify return types and relationship integrity.

**Acceptance Scenarios**:

1. **Given** the `User` model exists, **When** I call `$user->contractsAsCustomer()`, **Then** it returns a HasMany relationship to contracts where the user is the customer.
2. **Given** the `User` model exists, **When** I call `$user->contractsAsAgent()`, **Then** it returns a HasMany relationship to contracts where the user is the agent.
3. **Given** the `User` model exists, **When** I call `$user->sharesLogs()`, **Then** it returns a HasMany relationship to agent_shares_logs.
4. **Given** the `Contract` model exists, **When** I call `$contract->customer()`, **Then** it returns the User who is the customer via `customer_id`.
5. **Given** the `Contract` model exists, **When** I call `$contract->installments()`, **Then** they are ordered by `installment_number`.
6. **Given** the `Contract` model exists, **When** I call `$contract->auditLogs()`, **Then** they are ordered by `created_at` descending.
7. **Given** a `User` record exists, **When** any code attempts to call `$user->delete()`, **Then** a `RuntimeException` is thrown preventing deletion.

---

### User Story 2 - Repository Pattern Infrastructure (Priority: P1)

As a Backend Developer, I need a base repository infrastructure so all future data access goes through repositories.

**Why this priority**: The Constitution mandates that the Repository is the sole database gateway. This prevents SQL from leaking into Controllers.

**Independent Test**: Can be tested by instantiating the base repository and verifying it implements the interface contract.

**Acceptance Scenarios**:

1. **Given** the `BaseRepositoryInterface` exists, **When** I inspect it, **Then** it defines standard CRUD methods: `all()`, `find(id)`, `create(data)`, `update(id, data)`, `delete(id)`, and `cursorPaginate()` per Constitution pagination rules.
2. **Given** the `BaseEloquentRepository` exists, **When** I inspect it, **Then** it implements `BaseRepositoryInterface` fully including `cursorPaginate()`.
3. **Given** the `BaseEloquentRepository` uses Laravel's Eloquent, **When** a subclass is created, **Then** it can be bound to the interface in a Service Provider.

---

### User Story 3 - Unified API Response Infrastructure (Priority: P1)

As an API Developer, I need all API resources to extend a `BaseResource` class to ensure consistent response format.

**Why this priority**: The Constitution mandates Unified Response Format. Enforcing this structurally prevents developers from bypassing it.

**Independent Test**: Can be tested by creating a dummy resource extending `BaseResource` and verifying it returns the correct JSON structure.

**Acceptance Scenarios**:

1. **Given** `BaseResource` extends Laravel's JsonResource, **When** I create a resource that extends it, **Then** all responses contain `success`, `message`, and `data` fields.
2. **Given** `BaseResource` is configured, **When** any API response is generated, **Then** it follows the Unified Response Format from the Constitution.

---

### User Story 4 - Exception Handler Integration (Priority: P1)

As an API Developer, I need Laravel exceptions to map to appropriate API responses automatically.

**Why this priority**: Users should never see raw Laravel errors. All exceptions must return structured JSON responses.

**Why this uses ExceptionClassToMethod.php**: The Constitution mandates using `config/ExceptionClassToMethod.php` for mapping exception classes to handler methods in `CostumErrorResponse.php`. This is the absolute rule for exception handling.

**Independent Test**: Can be tested by triggering exceptions and verifying correct HTTP status codes and JSON structure.

**Acceptance Scenarios**:

1. **Given** a `ModelNotFoundException` is thrown, **When** the handler catches it, **Then** it returns HTTP 404 with `modelNotFoundResponse()`.
2. **Given** a validation exception is thrown, **When** the handler catches it, **Then** it returns HTTP 422 with `unprocessableResponse()`.
3. **Given** an `AuthorizationException` is thrown, **When** the handler catches it, **Then** it returns HTTP 403 with `forbiddenResponse()`.
4. **Given** a `RuntimeException` is thrown for User deletion, **When** the handler catches it, **Then** it returns HTTP 403 with immutability violation message.

---

### User Story 5 - Queue Infrastructure (Priority: P1)

As a Backend Developer, I need the queue system configured to use the database driver so async jobs can be dispatched later.

**Why this priority**: SP-04 requires async exports. Queue must be ready before that spec begins.

**Independent Test**: Can be tested by dispatching a test job to the queue and verifying it appears in the jobs table.

**Acceptance Scenarios**:

1. **Given** the `.env` is configured with `QUEUE_CONNECTION=database`, **When** I dispatch a job, **Then** it is stored in the `jobs` table.
2. **Given** the `config/queue.php` is configured for database driver, **When** a worker processes the queue, **Then** jobs are executed in order.

---

### Edge Cases

- What happens when a relationship is called on a model that doesn't exist? (Should throw EntityNotFoundException via exception mapping)
- How does the system handle concurrent deletion attempts on the same User? (DB-level RESTRICT prevents it, plus RuntimeException at model level)
- What occurs when a Job dispatch fails mid-transaction? (Queue should handle via failed_jobs table)

---

## Requirements *(mandatory)*

### Functional Requirements

- **FR-001**: System MUST create `User` model in `app/Models/User.php` with semantic relationships: `contractsAsCustomer()`, `contractsAsAgent()`, `sharesLogs()`
- **FR-002**: System MUST create `Admin` model in `app/Domains/Auth/Models/Admin.php` with `HasRoles` trait and `guard_name = 'admin'`
- **FR-003**: System MUST create `Contract` model in `app/Domains/Contract/Models/Contract.php` with relationships: `customer()`, `agent()`, `installments()`, `payments()`, `auditLogs()`
- **FR-004**: System MUST create `Installment` model in `app/Domains/Contract/Models/Installment.php` with `contract()` relationship
- **FR-005**: System MUST create `Payment` model in `app/Domains/Payment/Models/Payment.php` with `contract()` and `auditLogs()` relationships
- **FR-006**: System MUST create `PaymentAuditLog` model in `app/Domains/Payment/Models/PaymentAuditLog.php` with `contract()` and `payment()` relationships
- **FR-007**: System MUST create `AgentSharesLog` model in `app/Domains/Agent/Models/AgentSharesLog.php` with `agent()` relationship
- **FR-008**: System MUST create `NotificationTemplate` model in `app/Domains/Notification/Models/NotificationTemplate.php` as a standalone model (no relationships)
- **FR-009**: System MUST implement "Hard Immutable Entity" rule for `User` model by overriding `delete()`, `destroy()` methods to throw `RuntimeException`
- **FR-010**: System MUST create `BaseRepositoryInterface` in `app/Shared/Repositories/Contracts/BaseRepositoryInterface.php` defining standard CRUD operations plus `cursorPaginate()` per Constitution pagination rules
- **FR-011**: System MUST create `BaseEloquentRepository` in `app/Shared/Repositories/Eloquent/BaseEloquentRepository.php` implementing `BaseRepositoryInterface`
- **FR-012**: System MUST create `BaseResource` in `app/Shared/Http/Resources/BaseResource.php` extending Laravel's JsonResource
- **FR-013**: System MUST configure exception mapping using `config/ExceptionClassToMethod.php` following the existing pattern (do NOT use withExceptions() in bootstrap/app.php)
- **FR-014**: System MUST configure `.env` to use `QUEUE_CONNECTION=database`
- **FR-015**: System MUST ensure the `jobs` table migration exists and has run
- **FR-016**: All monetary fields MUST use `decimal(10,2)` casting in model `$casts` property

### Key Entities

- **User**: Unified human entity - cannot be deleted (hard immutability). Has customer/agent/investor roles inferred from relationships.
- **Admin**: System administrator with Spatie RBAC integration using 'admin' guard.
- **Contract**: Installment agreement - immutable after signing.
- **Installment**: State table for due dates and payment status tracking.
- **Payment**: Financial ledger entry with LIFO modification capability.
- **PaymentAuditLog**: Append-only narrative log for payment changes.
- **AgentSharesLog**: Append-only transaction log for agent share movements.
- **NotificationTemplate**: Standalone template for dynamic notification generation.

---

## Success Criteria *(mandatory)*

### Measurable Outcomes

- **SC-001**: All 8 business models exist and can be instantiated without errors
- **SC-002**: Calling `$user->delete()` throws a `RuntimeException` with message "Users cannot be deleted"
- **SC-003**: `$contract->installments` returns installments ordered by `installment_number` ascending
- **SC-004**: `$contract->auditLogs` relationship returns logs ordered by `created_at` descending (NOT cascading delete)
- **SC-005**: `BaseRepositoryInterface` defines all 5 CRUD methods plus `cursorPaginate()` per Constitution
- **SC-006**: `BaseEloquentRepository` implements `BaseRepositoryInterface` fully
- **SC-007**: A dispatched job appears in the `jobs` table within 1 second
- **SC-008**: Exception handler returns correct HTTP status codes: 404 for ModelNotFound, 422 for validation, 403 for authorization via ExceptionClassToMethod.php mapping
- **SC-009**: API resources extending `BaseResource` produce responses with `success`, `message`, `data` fields

---

## Assumptions

- Laravel framework is already installed (SP-01/SP-02 completed)
- Database migrations have run successfully (from SP-02)
- `ApiResponseHelper.php` and `CostumErrorResponse.php` exist from SP-01 scaffolding
- `config/ExceptionClassToMethod.php` exists and defines exception-to-method mappings
- The Domain folder structure follows the Constitution (app/Domains/{Domain}/)
- PHPUnit is configured for testing
- Jobs table migration exists in Laravel defaults but needs verification
- notification_templates table exists from SP-02 migrations