# Cashio API

## Stack
- Laravel 12, PHP 8.2+.
- Local: XAMPP MariaDB on Windows. Production: MySQL 8 on Linux.
- Filament 5 (CRM panel `crm` at `/`), Pest, Pint, Larastan.
- Shell is Git Bash on Windows: use forward slashes. No Docker, no Sail.

Commands:
- `php artisan serve` (http://localhost:8000)
- `php artisan test`
- `vendor/bin/pint`
- `vendor/bin/phpstan analyse`

## Architecture
- Keep controllers thin: take the request, call an Action or Service, return a Resource.
- Validation goes only in Form Requests.
- Business logic goes in `app/Actions` or `app/Services`, one class per job.
- JSON responses use Eloquent API Resources.
- Enums live in `app/Enums`.
- No repository pattern.
- No events or listeners unless the prompt asks for them. The exceptions so far: `EnquiryCreated` (dispatched from `CreateEnquiry`) → `SendNewEnquiryEmails` and `SendNewEnquirySms`; and `RecordAuthEvents`, which turns Laravel's `Login`, `Failed` and `Logout` events into security log entries (sign-ins can't be seen any other way).
- Security-relevant actions are recorded with `App\Services\SecurityLog` and a `SecurityEvent`, never `activity('…')` directly. Never put passwords, tokens or seller personal data in their properties.

## Wording
- UI text, emails, notifications, SMS and reports use the glossary in `docs/terminology.md` (enquiry, seller, response target, overdue). Never "SLA", "breach" or "lead" in anything a user reads.
- Labels are sentence case.

## Data (UK sellers' personal data)
- Never log request bodies, names, phone numbers, emails or addresses.
- Never put personal data in URLs or query strings.
- Seeders and factories use fake data only.
- Queue, cache and session drivers are `database`. No Redis.
- Migrations must run on both MariaDB (local) and MySQL 8 (CI and production). Don't use MySQL-only JSON functions or CHECK constraints.

## Security
- Every `/api` route needs the `api.secret` middleware and throttling.
- Every Filament resource needs a Policy.
- Authorise with permissions from app/Enums/Permission only; never check role names. Policies, Filament resources and actions call `$user->can(Permission::X->value)`. Only `app/Support/Rbac` may look at roles (the owner guard); CI fails on `hasRole(` elsewhere.
- New permissions are added to app/Enums/Permission and given to roles in `App\Support\Rbac\RoleMatrix`, nowhere else. Staff and role changes go through `RbacGuard`.
- Moving a record into a closed pipeline state requires a reason.

## Testing
- Write Pest tests only for business rules, authorisation and API contracts.
- Don't test framework behaviour or trivial accessors.

## Definition of done (every slice)
- `php artisan test` is green.
- `vendor/bin/pint` is clean.
- Larastan level 5 is clean.
- `php artisan route:list` has been reviewed.
- Migrations are reversible (`down()` works).
- The commit message follows Conventional Commits.

## Working style
- Enter plan mode and propose before writing code.
- Keep diffs small. Explain trade-offs when asked.
- Never run `git push`.
- Never edit `.env`.
- Never run `php artisan migrate:fresh` or any other destructive artisan command (`db:wipe`, `migrate:reset`, `migrate:refresh`, `migrate:rollback`). The user runs those.
