# AGENTS.md — Nexus POS (pos-restaurant)

Guidance for AI coding agents working in this repo. Prefer matching existing patterns over inventing new stacks.

## Project

Restaurant **POS + back-office** app branded **Nexus POS**.

| Item | Value |
|------|--------|
| Stack | Laravel **12**, PHP **^8.2**, Eloquent, session auth |
| UI | Blade + Bootstrap 5.3 + Bootstrap Icons (CDN) |
| Assets | `public/assets/css|js` (not Vite-driven in layouts) |
| DB | Laragon **MySQL** (`restaurant`). `.env.example` may show sqlite — use local `.env` |
| Routes | `routes/web.php` only (no API) |
| Brand helpers | `app/helpers.php` — `money()`, `can_permission()`, currency helpers |

## Layout map

| Path | Role |
|------|------|
| `app/Http/Controllers/` | Feature controllers (inline validation; few Form Requests) |
| `app/Models/` | Domain models |
| `app/Services/` | `NetPnlStatementService`, `SmsLenzService` |
| `app/Support/` | `AppCurrency` |
| `resources/views/` | Feature views + `layouts/{app,pos,kitchen,auth}` + `partials/` + `components/` |
| `public/assets/css/` | `design-system` → `base` → `layout` → `components` → `pages/*` |
| `public/assets/js/` | `core/`, `components/` (toast, sidebar, data-table, date-range-filter), `pages/*` |
| `database/migrations/` | Schema source of truth |
| `restaurant.sql` | Optional MySQL dump for import — **not** for schema edits |

## Modules

- **POS** (`/pos`) — cart, charge/hold, kitchen place-order, advances, cash/bank posting
- **Kitchen** (`/kitchen`) — order feed + status; kitchen-only users restricted by middleware
- **Products** — catalog, categories, price groups, **add-ons**, **cost recipes** (`product_cost_items`)
- **Inventory** — `stock_items`, warehouses, transfers, inventory categories, units
- **Purchases / suppliers** — purchase + return against stock items (weighted average cost)
- **Sales / customers / tables** — sales list; dining tables (locked Delivery `D-00`)
- **Account** — cash books, bank books, expenses, settlement, payroll (staff, salaries, EPF/ETF)
- **Reports** — overview, sales, products, **P&L** (summary / gross / net), cash-flow, expenses, campaigns
- **Marketing** — SMS templates + campaigns (`SmsLenzService`)
- **Settings** — company, currency, service charge, kitchen mode, payroll rates, users/roles/permissions

## Conventions (follow these)

1. **Money** — always display via `money($amount)`. Never hardcode currency symbols.
2. **Date ranges** — use `Controller::resolveDateRange()` / `redirectDateParams()`. Inputs: `filter_month` (`Y-m`) or `filter_date_from` / `filter_date_to` (aliases `date_from` / `date_to`). Default = today.
3. **Permissions** — slug strings (`products.manage`). Blade: `can_permission('…')`. Mutations: `authorizePermission('…')` (redirect + flash). Seed new slugs in **migrations**, not ad-hoc.
4. **Page assets** — pair Blade with `@push('styles'|'scripts')` → `public/assets/css|js/pages/<feature>.*`. Reuse `data-table`, toast, date-range-filter components.
5. **Controllers** — match existing style: validate in controller, DB transactions when multi-write, status fields (`Active`/`Inactive`), redirect + flash. Add a Service only for heavy domain (P&L, SMS).
6. **Layouts** — shell `layouts.app`; POS uses `layouts.pos`; kitchen uses `layouts.kitchen`.
7. **No React/Inertia** — stay on Blade + vanilla JS unless the user explicitly asks otherwise.
8. **Commits** — only when the user asks. Prefer migrations over editing `restaurant.sql`.

## Critical domain rules

### Dual inventory (do not mix)

| Layer | Table / fields | Used by |
|-------|----------------|---------|
| Sellable POS stock | `products.stock` (+ `products.cost`) | POS sales decrement **this only** |
| Ingredient / warehouse | `stock_items` (`qty`, `average_cost`, warehouse) | Purchases, returns, transfers, P&L COGS |

**Product cost recipes** (`product_cost_items`) link product → stock items and recompute `products.cost` on save. They do **not** auto-consume `stock_items` on sale.

### POS advances

- Column: `sales.advance_amount`
- Affects `settled_amount` and cash-book posts (“POS Advance” + balance as “POS Sale”)
- Table / wedding flows may allow advance > bill (negative balance due)

### Delivery vs dine-in

- Locked dining table code `D-00` / name `Delivery`
- Net P&L rolls Delivery table sales into **Delivery Sales** (separate from food/beverage category buckets)

### Service charge

- Settings: `service_charge_enabled`, `service_charge_percent`
- When enabled, POS stores rate/amount in `sales.tax_rate` / `sales.tax_amount` (service charge, not VAT)

### Net P&L COGS (`NetPnlStatementService`)

```
Opening (day before dateFrom)
+ Purchases (Received)
− Purchase returns
+ Freight (`purchases.freight_amount` + freight-like expenses)
− Closing (as of dateTo)
= Food Cost (COGS)
```

Stock value: prefer `stock_snapshots` for the date; else reconstruct qty from purchases/returns/transfers × `average_cost`, then persist snapshots.

Statement sections: Sales → COGS → Gross → Operating expenses → Other income/expense → Net profit. Map operating lines via expense category codes (ELEC, WATER, GAS, …) and payroll employer EPF/ETF.

### Reports export

Shared header export/print via `reports/partials/header` + `public/assets/js/pages/reports-export.js`. Tables/statements should be exportable (`data-report-table` / `data-report-statement`).

## Auth & permissions

- Session login; inactive/locked users blocked; `LoginHistory` recorded.
- `users.role_id` → roles ↔ permissions. `User::hasPermission($slug)` needs Active role + Active permission.
- Common slugs: `dashboard.view`, `pos.access`, `pos.home`, `products.view|manage`, `inventory.view|manage`, `sales.view`, `purchases.view|manage`, `customers.view|manage`, `suppliers.view|manage`, `tables.view|manage`, `account.view|manage`, `account.cash-books.manage`, `kitchen.view|manage|home`, `reports.view`, `marketing.view|manage`, `settings.view|manage`, `users.view|manage`.
- Post-login home: `pos.home` → POS; kitchen-only → kitchen; else dashboard.
- Middleware `RestrictKitchenUsers` limits kitchen-only accounts to kitchen/profile/logout.

## Local run (Laragon)

```bash
composer install
# .env → MySQL DB restaurant, APP_KEY
php artisan migrate
# optional: php artisan db:seed
# or import restaurant.sql then migrate remaining
php artisan storage:link   # product images
```

Serve via Laragon vhost or `php artisan serve`. Demo seed user (after roles/seeder): `admin@nexuspos.com` / `demo1234`.

PHP **8.2+** required. Prefer Laragon’s PHP 8.2/8.3 binary if system PHP is older.

## Do not casually touch

- `vendor/`, `node_modules/`, `public/build/`, compiled `storage/framework/views/`
- `.env` / secrets
- `restaurant.sql` as a substitute for migrations
- Broad redesign of `design-system.css` / shared JS without a scoped need
- Force-push, `--no-verify`, or amending pushed commits

## Testing

PHPUnit skeleton only (`tests/Feature|Unit/ExampleTest.php`). Example feature test may not match real `/` → login redirect. Do **not** assume green CI. Prefer manual Laragon checks for POS, cash/bank, inventory, and P&L changes.

## Recent schema notes (`2026_07_20*`)

| Migration | Adds |
|-----------|------|
| `…_170000_add_book_entry_performance_indexes` | Cash/bank entry indexes |
| `…_173000_create_product_cost_items_table` | Cost recipe lines |
| `…_180000_add_advance_amount_to_sales_table` | POS advances |
| `…_190000_add_pnl_reporting_support` | `freight_amount`, `stock_snapshots`, P&L expense categories |

## Working checklist for agents

1. Start with `.ai/context.md` + `.ai/todo.md` (see **AI Development Rules** below).
2. Read only files related to the current task; match nearby controllers/views/JS.
3. Keep **products.stock** vs **stock_items** boundaries intact.
4. Preserve date-filter query params on redirects.
5. Gate UI with `can_permission`; gate writes with `authorizePermission`.
6. Add migrations for schema + permission seeds; run `php artisan migrate`.
7. Scope CSS/JS to the page; reuse existing components.
8. After the task: update `.ai/context.md` + `.ai/todo.md` (and `.ai/decisions.md` if needed).
9. Commit only when asked; describe *why* in the message.

---

# AI Development Rules

You are the AI developer for this project.

## Before starting any task

Read only the following files:

- `.ai/context.md`
- `.ai/todo.md`
- `.ai/decisions.md` (only if required)

Do not read previous chat history if the required information exists in these files.

Do not scan the entire repository unless absolutely necessary.

Only inspect files related to the current task.

Use root `AGENTS.md` for stable project map and domain rules. Use `.ai/*` for **current** work state.

---

## During development

- Follow the existing coding style.
- Keep changes minimal.
- Never modify unrelated files.
- Reuse existing components whenever possible.
- Explain important architectural decisions.

---

## After completing every task

Update the following files:

### `.ai/context.md`

Keep it short.

Include:

- Current module
- Current progress
- Files modified
- Important implementation notes
- What should be done next

Overwrite outdated information.

Do not keep old task history.

---

### `.ai/todo.md`

- Mark completed tasks.
- Add newly discovered tasks.
- Remove obsolete tasks.

---

### `.ai/decisions.md`

Only update if an architectural or business decision has changed.

Examples:

- New package installed
- Database structure changed
- Authentication changed
- Business rules changed

Do not update for normal bug fixes.

---

## Token Optimization

Always prefer:

`.ai/context.md`

instead of

- Previous chat history
- Reading unrelated files
- Reading every markdown file

Keep documentation concise.

Avoid duplicate information.

Never generate unnecessary explanations.
