# CLAUDE.md — BAMS Legal (Greenfield Build)

Project memory for Claude Code. Read before every session. The documentation set
under `docs/` is the single source of truth; this file is the operating manual.

## What we are building

A complete **Legal Practice Management System** for a Nigerian law firm, built
from scratch (not on the old BAMS-V2 codebase). One platform covering: matters,
litigation tracking, court scheduling, deadlines, tasks, time & billing, trust
accounting, firm finance, documents, communication, dashboards/reports, a client
portal, and dashboards/reports across every module.

Product qualities, in priority order: **secure → correct → usable → fast → pretty**.

## Documentation map (read order for a new session)

| Doc | Contents |
|---|---|
| `docs/00-INDEX.md` | Table of contents + status tracker |
| `docs/01-PRODUCT-OVERVIEW.md` | Vision, personas, module catalogue, glossary |
| `docs/02-ARCHITECTURE.md` | Stack, layering, folder layout, coding conventions, scalability |
| `docs/03-DATA-MODEL.md` | ERD, shared column conventions, index strategy |
| `docs/04-SECURITY.md` | AuthN/Z model, RBAC matrix, OWASP mapping, data protection |
| `docs/05-UI-UX.md` | Design system rules, navigation, page patterns, UX standards |
| `docs/06-DEVELOPMENT-PLAN.md` | Phases, definition of done, testing & git workflow |
| `docs/modules/M01…M12` | One functional spec per module |

## Stack (as built — see docs/00-INDEX stack-reality note)

> Phase 0 decision: the installed foundation is the **Laravel React Starter
> Kit** (Inertia + React + TypeScript + shadcn/ui, Tailwind v4, Fortify, Pest,
> Laravel 13 / PHP 8.3+). This overrides the "Blade + Alpine, no SPA" line
> below — UI is Inertia React pages built from shadcn primitives
> (`docs/05a-TEMPLATE-MAP.md`). Dev DB is MariaDB 10.4 via XAMPP (MySQL 8 in
> prod). Everything else in this file still applies.

- **PHP 8.2 / Laravel 12**, MySQL 8, Redis (cache + queues), Laravel Horizon
- Blade + the firm's chosen admin template, Alpine.js for interactivity,
  Vite for assets. No SPA framework in v1.
- Packages: `spatie/laravel-permission`, `spatie/laravel-activitylog`,
  `spatie/laravel-backup`, `spatie/laravel-medialibrary` (documents),
  `barryvdh/laravel-dompdf`, `maatwebsite/excel`, `laravel/sanctum` (portal API
  tokens if needed), `laravel/pint`, `larastan/larastan` (level 6+), `pestphp/pest`.

## Architecture rules (non-negotiable)

1. **Layering**: Controller → FormRequest (validation) → Action/Service (business
   logic) → Model. Controllers stay thin (< ~40 lines/method); zero business
   logic or queries with joins in Blade views.
2. **Single-firm now, multi-tenant-ready**: every domain table has `firm_id`;
   a global `FirmScope` applies it automatically. Never query without it.
3. **Authorization**: every route behind a permission; every model with row-level
   rules gets a Policy. No `if($user->role == …)` checks — Spatie
   permissions/roles + Policies only.
4. **Money**: `decimal(18,2)`, stored in NGN; all postings via `LedgerService`
   (double-entry, immutable journal lines). Client/trust money is a liability.
5. **Files**: MediaLibrary, private disk only; downloads streamed through
   authorized controllers; nothing legal in `public/`.
6. **Every write is audited** (activitylog) and wrapped in a DB transaction when
   it touches more than one table.
7. **Jobs & mail are queued**; anything slower than ~200ms (PDF, Excel, email,
   reminders) goes to the queue.
8. **IDs exposed to users are ULIDs** (`HasUlids`) — no enumerable integer IDs
   in URLs.

## Coding conventions

- FormRequests for ALL validation. Enums (`app/Enums`, backed string enums) for
  all statuses/types. Actions in `app/Actions/{Domain}` (single `handle()`),
  services in `app/Services` for cross-cutting engines (Ledger, Numbering,
  Reminder).
- Route names `domain.action` (`matters.store`); RESTful verbs; route model
  binding by ULID.
- Migrations: one concern each, FKs `constrained()` + explicit `onDelete`,
  every FK and every frequently-filtered column indexed.
- Tests: Pest feature tests per module — happy path, permission denial,
  cross-firm isolation, and any money/deadline logic. Money and deadline logic
  additionally get unit tests.
- Run before declaring done: `php artisan test`, `./vendor/bin/pint`,
  `./vendor/bin/phpstan analyse`.

## UI/UX rules (summary — full rules in docs/05-UI-UX.md)

- **Brand palette (locked, dark gold-on-charcoal theme)**: Gold `#F5B800`
  (primary accent) · Gold Light `#FFD54F` (hover) · Gold Muted `#B8891A`
  (secondary/borders) · Charcoal `#1E1E1E` (background) · Charcoal 2 `#2D2D2D`
  (cards) · Off-white `#F9F5EC` (light sections/PDFs) · Text Light `#E8E0CC`
  (body on dark) · Text Muted `#A09070` (secondary text). Defined once as CSS
  custom properties; never hardcode hex in views. Full application rules in
  docs/05-UI-UX.md §8.
- First session: inventory the new template's components into
  `docs/05a-TEMPLATE-MAP.md` (buttons, cards, tables, forms, modals, badges,
  charts) and reuse ONLY those primitives — never hand-roll styles.
- Every list page = header (title + primary action) → KPI strip → filter bar →
  data table. Every entity = a detail page with tabs. Every destructive action =
  confirm modal. Every form = inline validation errors + preserved old input.
- Empty states, loading states, and success/error toasts are mandatory, not
  optional polish.

## Working agreement

1. Build in the phase order of `docs/06-DEVELOPMENT-PLAN.md`; one module per
   session where possible.
2. Per module: migrations → enums → models/policies → actions/services →
   FormRequests → routes → controllers → views → seeders → Pest tests → tick the
   module's acceptance checklist → update `docs/00-INDEX.md` status.
3. If a spec and code reality conflict, stop and flag it in the commit message;
   don't silently improvise.
4. Never weaken a security rule for convenience (e.g., skipping a Policy "for
   now"). Security debt is not accepted.
