# Backend Architecture

> How the Laravel application is structured.

_Verified against the codebase on 2026-07-23._

---

## Layering

A classic layered architecture with a repository pattern:

```
HTTP (Controllers, Middleware, Requests, Resources)
        ↓
Services (app/Services/* — ~35 domain services; business logic lives here)
        ↓
Repositories (app/Repositories/{Contracts,Eloquent})
        ↓
Models (Eloquent) + Observers + Casts
```

Supporting layers: **Jobs** (`app/Jobs/*`, database queue), **Events/Listeners**, **Mail**, **Providers**, **Contracts** (e.g. `Contracts/Knowledge`), **Support** utilities, and **Console/Commands** (many custom + scheduler).

## Key structural patterns (validated)

- **Canonical action services.** All pipeline transitions go through `Startup/InvestorLabelActionService` (`app/Services/Actions/`). The dashboard, REST API, MCP tools, and agents all call the same path — no duplicated business logic.
  - **Verified exception (2026-07-23):** this "one shared path" principle is not universal. The note write path has a **separate** AI controller (`Api/V1/Ai/AiNoteWriteController`) with its own inline validation, distinct from `Admin/NotesController` (though the note-body length invariant is now single-sourced via `EntityNote::BODY_MAX_LENGTH` — DR-009). Verify shared-vs-duplicated **per feature**; see [`../07-operation/change-management.md`](../07-operation/change-management.md).
- **Polymorphism reduces duplication.** `Meeting.meetingable`, `NotificationLog.recipient`, `File`/`EntityNote` morphs, and `AutomationDispatch.source` let one table serve both investor and startup flows.
- **Merge-on-insert deduplication.** No satellite rows: a canonical entity absorbs duplicates via `additional_monday_item_ids` (JSON) + `is_duplicate`. (Superseded an earlier scoring approach — see [`../06-history/deprecated.md`](../06-history/deprecated.md).)
- **Bilingual (Arabic/English) throughout.** `*_ar` / `*_en` name pairs with locale-aware accessors; a Claude-based transliteration pipeline backed by `transliteration_cache`.
- **Timezone handling.** Meetings use a custom business-timezone (Riyadh wall-clock) cast; other timestamps stay UTC.
- **Audit logging.** AI/agent activity is recorded (e.g. `AiActivityLogger` with PII redaction; `ai_activity_logs` is append-only).

## `app/` map (high level)
```text
app/
  Http/{Controllers,Middleware,Requests,Resources}
  Services/{Monday,Microsoft,Notifications,Committees,Demos,Signup,Otp,
            Duplicates,Transliteration,Storage,Ai,Agents,Actions,Oauth,...}
  Repositories/{Contracts,Eloquent}
  Models/          # ~89 models
  Jobs/{Ai,Automations,Bookings,Notifications,Sync,Transliteration,Webinars}
  Events/ Listeners/ Observers/ Mail/ Providers/ Contracts/ Casts/ Support/
  Console/Commands/ # grouped custom commands + scheduler
```

See [`../05-development/database-rules.md`](../05-development/database-rules.md) for persistence conventions and [`data-flow.md`](data-flow.md) for runtime flows.
