# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

```bash
# Initial setup
composer run setup          # install, .env, key:generate, migrate, npm install, build

# Development (runs all services concurrently)
composer run dev            # artisan serve + queue:listen + pail logs + vite dev

# Build
npm run build               # Vite production build

# Testing
composer run test           # config:clear then php artisan test
php artisan test tests/Feature/UsersControllerTest.php   # single file
php artisan test --filter=testMethodName                 # single method

# Code style
./vendor/bin/pint           # fix PHP code style (Laravel Pint)

# Database
php artisan migrate
php artisan migrate:refresh --seed
```

Tests use an in-memory SQLite database (configured in phpunit.xml). The default app database is also SQLite.

## Architecture

### Multi-Guard Authentication
Two completely separate auth contexts:
- **Admin guard** (`auth:admin`, model `App\Models\Admin`) — back-office dashboard at `/admin/*`
- **Employee guard** (`auth:employee`, model `App\Models\HR\Employee\Employee`) — self-service portal at `/portal/*`

Super Admin role bypasses all permission checks (gate bypass registered in `AppServiceProvider`). Spatie Laravel Permission v6 handles RBAC for the admin guard.

### Module Structure
The system has 7 functional modules, each with its own controller folder, service folder, model subfolder, and view subfolder:

| Module | Controller namespace | Key concepts |
|---|---|---|
| Core | `Admin\Core` | Branch (multi-branch), Settings, NumberSequence |
| Finance | `Admin\Finance` | Accounts, Journals, FiscalYear/Period, Vouchers, Reports |
| HR | `Admin\HR` | Employees, Payroll, Attendance, Leave, Recruitment, Requests |
| Inventory | `Admin\Inventory` | Items, Warehouses, StockMovements, PurchaseOrders |
| Sales | `Admin\Sales` | Customers, Quotations, Orders, Invoices, Payments, Returns |
| Admin Settings | `Admin\settings` | Countries, Cities, Categories, Files |
| Portal | `Portal` | Employee self-service views of HR data |

### Service Layer Pattern
Controllers are thin — all business logic lives in `app/Services/`. Controllers inject services and call them; they do not contain DB queries or business rules. When adding features, follow this pattern and keep controllers to input validation + service call + response.

Finance has a sub-namespace for complex concerns:
- `app/Services/Finance/Posting/` — journal posting and reversal logic
- `app/Services/Finance/Integrations/` — cross-module posting (e.g. invoice → GL, expense → GL)
- `app/Services/Finance/Reports/` — one service per report type (TrialBalance, BalanceSheet, etc.)

### Finance Posting & Reversal Pattern
Finance documents (vouchers, invoices, expenses) follow a strict lifecycle: `draft → posted → reversed`. Posting creates GL entries in `journal_entries`. Reversal creates offsetting entries and sets `posting_status = reversed`. The `ReceiptVoucher` is canonical for AR settlement. Posting is gated by keys in the `Settings` table (checked by `SettingService`).

### Branch Scoping
All operational data has a `branch_id`. Queries must be scoped to the active branch. The `Branch` model and `BranchService` manage this. Do not write queries that aggregate across branches unless the intent is a cross-branch report.

### Fiscal Period Scoping
Finance transactions belong to a `FiscalPeriod`, which belongs to a `FiscalYear`. Period-close logic prevents posting to closed periods. Always resolve the active fiscal period before creating finance transactions.

### HR Request Workflow
Leave, loan, bonus, complaint, resignation, etc. share a common approval workflow via `RequestWorkflow` and `Approval` models. Multi-step approvals with status transitions. Do not bypass the workflow when creating HR requests.

### Document Numbering
All document types (invoices, POs, vouchers, etc.) use `NumberSequenceService` — never generate document numbers manually.

### Localization
Routes are prefixed by locale (e.g. `/en/admin/...`). The `mcamara/laravel-localization` middleware handles detection and redirection. Model fields that need translation use `spatie/laravel-translatable` (stored as JSON). Currently only English (`en`) is active.

### Frontend
Blade templates + Tailwind CSS v4 + Vite. No Vue/React/Livewire — all interactivity is standard HTML forms and DataTables (yajra/laravel-datatables, Ajax/server-side). PDF export via `barryvdh/laravel-dompdf`. Client-side validation via `proengsoft/laravel-jsvalidation`.

### Key Config Locations
- Guards & providers: `config/auth.php`
- Timezone (`Africa/Cairo`): `config/app.php`
- Permission tables/models: `config/permission.php`
- Locales: `config/laravellocalization.php`

### Soft Deletes
All master-data tables (accounts, branches, departments, items, customers, etc.) use soft deletes. Scope queries with `withTrashed()` only when the feature explicitly requires showing deleted records.
