# COMPONENT — erp-web-core (+ accounting-ledger module)

> **Code location:** `app/` (root `app/Http/Controllers/`, `app/Models`, `app/Http/Requests`,
> `app/Events`, `app/Listeners`).
> **Nav:** Master → [../CLAUDE.md](../../../CLAUDE.md) · Rules → [MASTER_RULES.md](../phase-3-shared/MASTER_RULES.md) ·
> Integration → [MASTER_INTEGRATION.md](../phase-3-shared/MASTER_INTEGRATION.md)

> Component scope: the server-rendered Laravel web ERP and its domain — Inventory, Purchasing,
> Manufacturing, WMS, Quality Control, and the cross-cutting Accounting/Ledger module.

## 1. Identity & purpose
The heart of the system. Blade + Alpine controllers under `app/Http/Controllers/` render the ERP UI
and own the core business workflows. Domain models live in `app/Models`, validation in
`app/Http/Requests`, side effects in `app/Events` + `app/Listeners`.

**Owned domains**
- **Inventory:** `Item`, `ItemVariation`, `ItemCategory`, `ItemSupplier`, `Uom`.
- **Purchasing:** `PurchaseRequest`→`PurchaseOrder`→`Grn`→`Qc`→`GatePass` (the core procurement chain).
- **Manufacturing:** `Bom`, `ManufacturingBOM(+Ingredient/Step/History)`, `WorkOrder`,
  `WorkOrderMaterial`, `ManufacturingRun`, `ProductionBatch`, `WoMaterialIssue`, `WoReceipt`.
- **WMS:** `Warehouse`, `WarehouseBin`, `Location`, `StockTransfer`, `StockLedger`, `StockMovement`,
  `StockBalance`, `WarehouseCurrentStock`, `WarehouseStockLedger`, `WarehousePiece`, `StockPiece`.
- **Quality:** `Qc`, `QcItem`, `QualityCheck`, `InspectionRequest`, `InspectionResult`.
- **Accounting:** see the module section below.

## 2. Development environment
See [MASTER_COMMANDS.md](../phase-3-shared/MASTER_COMMANDS.md). TL;DR: `composer run dev` + `npm run dev`.
Views in `resources/views`, assets built by Vite.

## 3. Architecture & structure
```
app/
├── Http/Controllers/        # resource controllers (root = web ERP + accounting)
│   ├── Api/                 # → see COMPONENT_SHOP_POS_API.md (shop + REST)
│   │   └── Desktop/         # → see COMPONENT_DESKTOP_SYNC_API.md (sync)
│   └── Auth/                # Breeze auth
├── Http/Requests/           # FormRequest validation (Store*/Update*)
├── Http/Middleware/         # CheckRole, CheckActiveUser, RequestLogging
├── Models/                  # Eloquent domain models
├── Events/ + Listeners/     # GRNPosted/IGPProcessed → ledger
├── Helpers/ (RoleHelper) + helpers.php
├── Console/Commands/        # Test* integration commands
└── Providers/               # AppServiceProvider, LoggingServiceProvider
routes/{web,api,auth,console}.php · resources/views · database/{migrations,seeders,factories}
```
**Pattern:** thin controller → FormRequest validates → model/`DB::transaction()` writes → event
dispatched for side effects → activitylog records it → Blade or redirect response.

## 4. Code standards
- PSR-12 via Pint. StudlyCase models, `Store*Request`/`Update*Request`, snake_case columns,
  kebab-case route names (`purchase-requests.search`).
- ⚠️ **Legacy duplicates exist here** — `ContactController copy.php`, `ContactController copy 2.php`,
  `QcController copy.php`, `ItemCategoryController copy.php`, `ManualTransactionController copy.php`,
  `DeliveryReceiptController_backup.php`, `Models/DeliveryReceipt_backup.php`,
  `Models/PurchaseRequest copy.php`, `FactoryPOSController copy.php`, `extra/GatepassController1.php`.
  These are **not routed**. Confirm the live class in `routes/web.php` (`php artisan route:list`)
  before editing. **Never add new ones.**

## 5. Framework & library patterns
- **DataTables:** every index grid uses Yajra **server-side** (`DataTables::of($query)…->make(true)`).
  Eager-load relations to avoid N+1.
- **Validation:** always a FormRequest from `app/Http/Requests/<Domain>/`; never mass-assign raw input.
- **PDFs:** `barryvdh/laravel-dompdf` renders a Blade view to PDF (GRNs, gate passes, reports).
- **RBAC:** gate routes with `check.role:` / `check.active.user`; check abilities via Spatie
  (`$user->hasAnyRole([...])`, `RoleHelper`). See `app/Http/Middleware/CheckRole.php`.
- **Audit:** `spatie/laravel-activitylog` on mutations — keep it.

## 6. Testing
Pest feature tests in `tests/`; Dusk for browser flows; the `Test*` artisan commands validate
QC, roles/permissions, and accounting integration end-to-end. Run `php artisan test` before a PR.

## 7. Data & state
- Migrations in `database/migrations` — **one concern each, reversible**; status changes get their
  own `update_*_status_enum` migration (follow the existing precedent).
- **Stock integrity:** movements → `StockLedger` → maintained balances
  (`StockBalance`/`WarehouseCurrentStock`) must stay consistent; wrap in `DB::transaction()`.
  Never edit a balance row directly — post a movement.

## 8. Security
Session auth (Breeze) + `check.active.user` + `check.role`. CSRF on all web routes. Validate
everything via FormRequests. Secrets in `.env`.

## 9. Common workflow — add a module (canonical path)
```
1. php artisan make:migration create_widgets_table   # reversible up()/down()
2. app/Models/Widget.php                              # fillable, relations, casts
3. app/Http/Requests/Widget/{Store,Update}WidgetRequest.php
4. app/Http/Controllers/WidgetController.php          # resource controller, thin actions
5. routes/web.php: Route::resource('widgets', WidgetController::class)
        ->middleware(['check.active.user','check.role:admin']);
6. resources/views/widgets/*.blade.php               # + Yajra DataTables index endpoint
7. seed the permission/role; gate the routes
8. ensure activitylog fires on create/update/delete
9. tests/Feature/WidgetTest.php  (Pest)
```

---

## <a id="accounting-ledger-module"></a>accounting-ledger module

Cross-cutting financial engine. No dedicated folder — controllers live in root `app/Http/Controllers/`.

- **Controllers:** `ChartOfAccountController`, `AccountController`, `AccountTransactionController`,
  `ManualTransactionController`, `CostCenterController`, `AccountingReportController`,
  `CostOfProductionController`.
- **Models:** `ChartOfAccount` (hierarchical), `Account`, `AccountTransaction`, `CostCenter`
  (+ `CostCenterHistory(Detail)`), `WeightedAveragePriceHistory`, `InvoiceType`.
- **Integration:** driven by `GRNPosted`/`IGPProcessed` events → `ProcessGRNPosted`/`ProcessIGP`
  listeners post **balanced double-entry** transactions. See
  [MASTER_INTEGRATION.md §1](../phase-3-shared/MASTER_INTEGRATION.md#1-event-driven-ledger-integration-erp-web-core--accounting-ledger).
- **Rules:** keep double-entry balanced; use weighted-average costing for valuation; correct errors
  with a reversing transaction, never a direct edit; validate with `TestChartOfAccountsIntegration`
  and `TestDualLedgerIntegration` after any change.
