# CONTEXT — read this FIRST (every session), then proceed

> **Purpose:** the one file an agent reads to get oriented — **so it does NOT re-scan the whole repo**
> each session (that burns time + tokens). It holds: the **map** (where things live), the **state**
> (what's been built + decisions), and the **patterns to mirror** (exact reference files to copy).
>
> **Rule for the agent:** read this file + the task's plan/sprint file, then **act**. Open a specific
> source file **only** when a pattern below points you to it. Do **not** explore the codebase broadly
> unless something you need is genuinely missing here — if so, add it here after you find it.
>
> **Keep it fresh:** at each sprint's Definition of Done, append one line to **§B** (what was built +
> any new reference pattern). This file is the project's memory.

---

## §A — Map (where everything lives)

| Layer | Path |
|---|---|
| Models | `app/Models/` (translatable → `+ {Model}Translation`) |
| Enums | `app/Enums/` (use `App\Traits\Enums\GeneralEnumTrait`; `const PATH` for labels) |
| Admin controllers | `app/Http/Controllers/Admin/` (extend `AdminBaseController`) |
| API controllers | `app/Http/Controllers/Api/V1/` — a **flow** = subfolder of focused controllers (`Auth/`) |
| Admin services | `app/Services/Admin/` · Domain/API services | `app/Services/<Area>/` |
| Admin requests | `app/Http/Requests/Admin/{Entity}/` · API requests | `app/Http/Requests/Api/{Module}/` (extend `BaseApiRequest`) |
| API resources | `app/Http/Resources/Api/V1/` (auth: `app/Http/Resources/Auth/`) |
| Response traits | `app/Traits/Response/` (`respondWithSuccess/Fail/Paginated`) |
| Upload traits | `app/Traits/Upload/` (Spatie media; model `FILES` const) |
| Admin views | `resources/views/admin/{module}/` (Blade = presentation only) |
| Routes | admin `routes/admin.php` · API `routes/api/v1/*.php` (auto-mounted — never edit `bootstrap/app.php`) |
| Lang | `lang/{ar,en}/` (`admin/*`, `api/*`, `validation.php`) — default `ar` |
| Schema (data) | `database/schema/*.json` (+ `features.json`) → `/schema-designer` |
| Migrations | `database/migrations/{domain}/` (additive only) |
| Config | `config/sidebar_routes.php`, `config/auth.php` |
| Build playbooks | `docs/build/*` · Templates | `docs/project-init/*` · Plans | `docs/project/{api,cruds,sprints}/` |
| Kanban | `/kanban` (board `docs/project/board.json`; `php artisan board:sync` / `board:set`) |

Architecture (enforced): **thin controller → Form Request → Service → Resource/response trait**. Blade
presentation-only. Details: `CLAUDE.md` + `.claude/context/{project,domain,team}.md`.

---

## §B — State (what's built + decisions) — APPEND per sprint at DoD

**Base baseline (ships with the template):** admin auth (session `auth:admin` + RBAC), user management,
API auth (OTP + password, Sanctum), complaints, contact messages, notifications (FCM + DB), settings,
geography (country/region/city/district, translatable), pages/faqs/sliders/seo/socials/intro (translatable),
media (Spatie), OTP (`OtpService` + `OtpType`), landing site, schema-designer, kanban.

**Project sprints (fill as you go):**
- `✅ DB layer (catalog + bookings)` — 7 enums (`lang/{ar,en}/enums.php`), 17 models (+2 translation), 15 factories, seeders in `database/seeders/{Catalog,Booking}`, `provider` Sanctum guard · `Provider` = auth model (mirror `Admin`/`User`); new tables have no image columns so media = Spatie collections (`registerMediaCollections`); `CanRetrieve` only on SoftDeletes models.
- `🔄 Sprint 1 — Foundations` — **code built, DB-unverified** (no MySQL creds). Provider auth API (`routes/api/v1/provider.php`; `Api/V1/Provider/Auth/*`; `Services/Provider/ProviderAuthService`+`ProviderForgotPasswordService`; `Resources/Provider/ProviderResource` token-inside; guard `auth:provider` + abilities `activation`/`provider`/`forget-password`; OTP-first register with Spatie `documents` collection; login checks blocked/rejected/suspended/phone-verified). Admin CRUD: `servicecategories` + `occasions` (translatable + media, mirror Country/Slider; base naming = `Str::plural(strtolower(class))` → `servicecategories`). Static-verified: app boots, `route:list` OK, pint/lint clean.
- `🔄 Sprint 2 — Provider operational API` — **code built, DB-unverified**. Under `auth:provider`+`ability:provider` in `routes/api/v1/provider.php`: profile (show/update/documents/change-password/4-step change-phone), `services`(+toggle), `packages`(+items sync, toggle), `works`, `availability`. Controllers `Api/V1/Provider/{Profile,Service,Package,Work,Availability}`; services `Services/Provider/Provider*Service`; resources `Resources/Provider/*`. **Ownership = every query starts from `$provider->relation()` + `findOrFail` (404, no IDOR); `service_id` inputs validated via `Rule::exists(...)->where('provider_id', user)`.** `providers.price_from` recomputed by `Observers/ServiceObserver` (`#[ObservedBy]` on Service).
- `🔄 Sprint 2b — Provider catalog (admin side)` — **code built, DB-unverified**. Admin CRUD `providers` (status transition guards in `ProviderStatus::allowedTransitions/canMoveTo`; `ProviderService::transition()` uses DB txn + `lockForUpdate`; approve sets is_verified; switch active/blocked/featured/verified; documents+gallery+stats on show) + `services`/`packages` oversight (list/show/toggle/delete). Shared `Services/Admin/Base/AppliesExactFilters` (exact id/enum/flag filters vs base LIKE). `Provider` uses `HandleNumbersTrait` (fixPhone for phone_normalized).
- `🔄 Sprint 6 (admin part) — oversight & CMS` — **code built, DB-unverified**. Admin: `bookings` (filter status/payment/provider/date; show timeline+financial+transactions; **cancel** pending/confirmed & **refund** paid→refunded + RFD- txn, both txn+lock guarded), `reviews` (switchVisible + delete → recompute provider rating from visible only), `transactions` (read-only), `reports` (`ReportService`: revenue/commission/VAT over paid, top providers/categories; date filter on created_at), `faqs` CRUD (real schema = `type`(FaqType)+translated question/answer 255), dashboard **marketplace KPIs** (`ReportService::marketplaceOverview()` → `admin/home/parts/marketplace.blade`), settings pricing +`currency`+`booking_auto_confirm`. Sidebar group `operations` (المبيعات والحجوزات). 272 routes, view:cache compiles.
- `🔄 Sprint 3 — User browse` — **code built, DB-unverified**. Public catalog `routes/api/v1/catalog.php` (occasions, service-categories, providers list[filters+sort]+show+services/packages/works/reviews/availability/time-slots — `Api/V1/Catalog/*`, `Services/Catalog/ProviderBrowseService`, `visible()`=approved+active, `is_favorite` via `withExists` only when user token present). Favorites `routes/api/v1/favorites.php` (`FavoriteController`, instanceof User guard). User register/verify (`Api/V1/Auth/{Register,Verify}Controller` + `UserRegistrationService`, OTP-first mirror of provider). Profile additions (update/notifications/language/delete). Home `routes/api/v1/home.php` (`HomeService`: greeting/sliders/occasions/categories/featured). Search `routes/api/v1/search.php` (+recent_searches). Resources under `Resources/Home/` namespaced to avoid catalog clash.
- `🔄 Sprint 4 — Booking & payment` — **code built, DB-unverified**. Addresses + payment-cards (`Api/V1/{Address,PaymentCard}Controller`, own-scoped, set-default atomic, cards store token only no PAN/CVV). Bookings `routes/api/v1/bookings.php` (`Api/V1/Booking/*`): create in `DB::transaction`+`lockForUpdate` → slot-conflict recheck → create (`IHF-YYYY-####`) → `PaymentGateway` (`Services/Payment/Gateway/*`, contract bound in AppServiceProvider, `FakePaymentGateway`) → `Transaction` (`PAY-YYYY-#####`) → paid + confirmed-if-auto; **pricing server-side** (total=subtotal; commission=subtotal*app_commission%; vat=subtotal*vat_ratio% — recorded, not added). **State machine `BookingStatus::canMoveTo()`** (shared). Timeline `Services/Booking/BookingTimelineService` (admin reuses). Cancel (own, pending/confirmed). Review (own+completed+unique) → `Observers/ReviewObserver::recompute` (single source; admin ReviewService delegates). `ResolvesCustomer` trait.
- `🔄 Sprint 5 — Provider bookings (API)` — **code built, DB-unverified**. In `routes/api/v1/provider.php`: received bookings (own-scoped), show+timeline, transitions confirm/start/complete/reject (`Api/V1/Provider/Booking/TransitionController`, txn+lock, `canMoveTo` guard, **confirm requires payment_status=paid**, reject sets refund_pending flag), reviews list, dashboard stats (`ProviderDashboardService`). Dispatches `Events/Booking/{BookingConfirmed,BookingStarted,BookingCompleted,BookingRejected}`.
- `🔄 Sprint 6 — notifications + public support` — **code built, DB-unverified**. Support `routes/api/v1/support.php` (faqs, pages/{slug}, contact-messages guest+auth morph, notifications inbox list/unread-count/read/read-all — `Api/V1/Support/*`). **Notifications system:** `Enums/NotificationType` (8 types, `lang/{ar,en}/notifications.php`), `Services/Notification/BookingNotifier` (localized title/body, DB+FCM via base `UserNotification`, **skips when is_notify=false**), listeners `Listeners/Booking/*` + `SendWelcomeNotification` + `ReviewSubmitted` event (from ReviewObserver), scheduled `bookings:send-reminders` command. **(Fixed broken `use` lines in 4 booking listeners — now bound to `App\Events\Booking\*` per `event:list`.)** 328 routes, views compile, pint clean (2 pre-existing base `View/Components/Table/*` failures unrelated).

**Key decisions (project-wide):**
- **Provider = separate model + Sanctum guard `provider`** (multi-auth like `admins`); tokens carry abilities (`activation` pre-verify, `provider` full, `forget-password`). OTP flows via `OtpService`/`OtpType` (register uses `ACTIVATE`).
- **Provider lifecycle:** `pending → approved/rejected/suspended` (ProviderStatus). Only `approved` shows in catalog / receives bookings. Registration requires documents (Spatie `documents` collection) + admin approval.
- **Marketplace money:** per-booking commission + VAT via **settings** (`app_commission`, `vat_ratio`, `currency`, `booking_auto_confirm`) — base keys reused; payment behind a `PaymentGateway` strategy (Sprint 4). Commission-only (no subscriptions).
- **Catalog dims:** `service_categories` (NEW, not base `categories` which is complaints) + `occasions` (both translatable). Provider belongsTo one service_category, belongsToMany occasions.
- **Booking:** `IHF-YYYY-####`; statuses pending→confirmed→in_progress→completed(+cancelled); payment_status unpaid/paid/refunded; `transactions` `PAY-YYYY-#####`.
- **Guest = browse-only;** protected actions 401 → «برجاء تسجيل الدخول اولا». Addresses use geo FKs (city_id/district_id). `users.locale` added for language toggle.
- **Env/verify:** `.env` created (DB `munasabat`) but **MySQL password missing** → `migrate:fresh --seed`/`schema:check`/tests pending. Repo now git (an init reverted `analysis.md` once — re-restored).

---

## §C — Patterns to mirror (build X → copy Y; don't re-derive)

| Building… | Mirror (exact reference) |
|---|---|
| **Admin CRUD** (translatable) | `Admin/CountryController` + `Services/Admin/CountryService` + `Requests/Admin/Country/*` + `resources/views/admin/countries/` + `config/sidebar_routes.php` + lang. Extend `AdminBaseController`. |
| **Admin CRUD** (with media/upload) | mirror `Slider` (model `app/Models/Slider.php` uses media) + its admin controller/views. |
| **API multi-endpoint flow** | `Api/V1/Auth/*` (focused controllers: `LoginCodeController`, `RequestCodeController`, `MeController`, `LogoutController`) + `Services/Auth/AuthService` + `Requests/Api/Auth/*` + `Resources/Auth/UserResource` (token INSIDE the resource). |
| **API single-entity + resource** | `Api/V1/CountryController` + `Resources/Api/V1/CountryResource` + `CountryCollection` (pagination via `PaginationTrait`). |
| **Model — translatable** | `app/Models/Country.php` (+ `CountryTranslation`, `*_translations` table). |
| **Model — auth-style** (login) | `app/Models/User.php` (`BaseAuthModelTrait`, `HasApiTokens`, `SoftDeletes`, hashed password). |
| **Multi-audience auth** (provider/delegate/company) | **default = model + Sanctum guard per audience** (mirror `admins`) → `docs/build/build-auth-audience.md`. |
| **OTP / verification flow** | `app/Services/Otp/OtpService.php` (`sendOtp`/`verifyOtp`/`failActiveOtps`) + `OtpType` (`OLD_*/NEW_*` for credential changes). |
| **Side effects** (job/event/observer/notification) | `docs/build/build-side-effects.md` (base: `app/Jobs/SendNotificationJob.php`, `app/Notifications/UserNotification.php`). |
| **Response envelope** | `app/Traits/Response/*` — never a custom shape. |
| **Enum** | `app/Enums/LoginType.php` (`use GeneralEnumTrait` + `const PATH`). |

> The **build playbooks** (`docs/build/*`) own the full "how"; this table just points you at the **live
> reference file** to copy so you skip the hunt. When in doubt on a convention, read the sibling first.
