# Pavitram Agroz – Centralized Multi-Store Manufacturing & POS ERP System
## Master Technical & Production Documentation (Phases 1–4)

---

## 1. System Architecture & High-Level Overview

**Pavitram Agroz** is a centralized, multi-store, unit-traceable manufacturing, inventory, and retail Point-of-Sale (POS) management platform built with modern PHP 8.2+ and Laravel 11 on top of a relational MySQL database (with SQLite support for ultra-fast CI/CD pipeline execution).

The system models a strict end-to-end lifecycle for every single physical product unit (e.g., individual 500ml/1L organic mustard oil, cold-pressed groundnut oil, organic sesame oil, and organic fertilizers):

```mermaid
flowchart LR
    A["Raw Production & Batching"] --> B["Individual Unit & QR Generation"]
    B --> C["Pre-Intake QA Verification"]
    C --> D["Central Logistics Warehouse"]
    D --> E["Inter-Store / Inter-Warehouse Transfer"]
    E --> F["Store Receipt & Quarantine/Inventory"]
    F --> G["Cashier POS Rapid Scan & Checkout"]
    G --> H["Sold / Customer Handover"]
    H -.->|Customer Return| I["Physical Inspection & Restock / Quarantine"]
    H -.->|Consumer Scan| J["Read-Only Authenticity Portal"]
```

### Core Architecture Highlights
- **Single Centralized Database**: Centralized org hierarchy eliminating synchronization drift across regional physical stores.
- **Strict Cryptographic Unit Traceability**: Every physical bottle or package gets a distinct database entity (`ProductUnit`), an immutable internal ID (`PAU-XXXXXXXXXX`), a sequential product-scoped serial number (`PA-P001-000001`), and a cryptographically secure 128-bit random token (`bin2hex(random_bytes(16))`).
- **Multi-Tenant / Multi-Store Isolation (Anti-IDOR)**: Store Admins and Cashiers are strictly restricted to their designated store scope via Laravel Policies, middleware, Eloquent Scopes, and controller validation. Super Admins retain global enterprise visibility.
- **Pessimistic Concurrency Locking**: Checkout and receiving flows employ `lockForUpdate()` database locks and atomic DB transactions to guarantee that a physical unit can **never** be double-sold, double-received, or simultaneously transferred.
- **Double-Entry Audit & Stock Ledger**: Every inventory change writes an immutable row into `stock_movements` and `audit_logs`, providing forensic traceability.

---

## 2. Database Schema Summary (All 4 Phases)

The schema comprises 18 normalized tables:

| Table | Phase | Purpose & Key Columns |
| :--- | :---: | :--- |
| `users` | 1 | Enterprise user accounts (`name`, `email`, `password`, `status`, `phone`, `last_login_at`). |
| `roles` | 1 | System roles (`name`, `slug`, `description`). Standard slugs: `super-admin`, `store-admin`, `cashier`. |
| `permissions` | 1 | Granular permission catalog across catalog, stores, batches, transfers, billing, reports. |
| `role_user` | 1 | Many-to-many pivot for user role bindings. |
| `permission_role` | 1 | Many-to-many pivot for role permission matrices. |
| `stores` | 1 | Multi-store retail outlets (`code`, `name`, `gstin`, `city`, `state`, `pincode`, `contact_number`, `status`). |
| `store_user` | 1 | User store assignment pivot with `is_primary` and `assigned_at` flags. |
| `product_categories`| 1 | Category classifications (`name`, `slug`, `code`, `status`). |
| `products` | 1 | Product master (`category_id`, `name`, `sku`, `product_code`, `selling_price`, `tax_rate`, `status`). |
| `audit_logs` | 1 | Immutable system audit log (`user_id`, `action`, `entity_type`, `entity_id`, `ip_address`, `meta`). |
| `product_batches` | 2 | Manufacturing batches (`batch_number`, `product_id`, `planned_quantity`, `actual_quantity`, `status`, dates). |
| `product_units` | 2, 4 | Individual physical units (`unit_id`, `serial_number`, `qr_token`, `verification_status`, `status`, `current_location_type`, `warehouse_id`, `store_id`, `invoice_id`, `sold_at`, `sold_by`, `sale_price`). |
| `production_events` | 2 | Manufacturing telemetry events (`batch_id`, `event_type`, `user_id`, `description`, `payload`). |
| `unit_status_histories` | 2 | Granular state transition timeline for individual units (`unit_id`, `from_status`, `to_status`, `changed_by`, `reason`). |
| `label_print_logs` | 2 | Printing and controlled re-print tracking (`batch_id`, `user_id`, `units_printed`, `reprint_reason`). |
| `warehouses` | 3 | Central and regional storage hubs (`name`, `code`, `address`, `contact_number`, `email`, `city`, `state`, `pincode`, `status`). |
| `stock_transfers` | 3 | Dispatch/Transit records (`transfer_number`, `source_type`, `source_id`, `dest_type`, `dest_id`, `status`, carrier info). |
| `stock_transfer_items` | 3 | Item-level transfer disposition (`transfer_id`, `unit_id`, `product_id`, `batch_id`, `receive_status`, `discrepancy_reason`). |
| `stock_movements` | 3, 4 | Permanent ledger tracking all inventory movements (`unit_id`, `movement_type`, locations, statuses, user, reference). |
| `stock_reconciliations` | 3 | Physical audit reconciliation headers (`location_type`, `location_id`, `audit_date`, `status`). |
| `stock_reconciliation_items` | 3 | Physical audit unit discrepancies (`reconciliation_id`, `unit_id`, `physical_status`, `resolution_action`). |
| `invoices` | 4 | Final sales invoices (`invoice_number`, `store_id`, `cashier_id`, `customer_name`, `customer_phone`, `subtotal`, `discount_amount`, `taxable_amount`, `cgst_amount`, `sgst_amount`, `igst_amount`, `final_total`, `payment_status`, `status`, `cancellation_reason`). |
| `invoice_items` | 4 | Line items with physical unit links (`invoice_id`, `product_id`, `unit_id`, `batch_id`, `serial_number`, `unit_price`, `discount_amount`, `tax_rate`, `tax_amount`, `line_total`). |
| `payments` | 4 | POS checkout payment records (`invoice_id`, `store_id`, `payment_method`, `amount`, `transaction_reference`, `notes`). |
| `sales_returns` | 4 | Return headers (`return_number`, `invoice_id`, `store_id`, `initiated_by`, `approved_by`, `status`, `refund_amount`, `refund_method`). |
| `sales_return_items` | 4 | Return line items & QA resolution (`sales_return_id`, `invoice_item_id`, `unit_id`, `condition`, `inspection_notes`, `inspection_resolution`). |

---

## 3. Module Catalog

### Phase 1: Core Foundation & Multi-Store Management
- **Enterprise Authentication**: Rate-limited login (5 attempts / 60 seconds), secure password hashing (Argon2id / Bcrypt), session invalidation on logout, session regeneration upon authentication, secure remember tokens, and uninformative password recovery messages.
- **Role-Based Access Control (RBAC)**: Hierarchical roles (`Super Admin`, `Store Admin`, `Cashier`) with policy-driven access controls.
- **Store & User Master**: Store creation, status toggle (Active/Inactive), store-to-staff assignments, primary store markers.
- **Product & Category Master**: Multi-tier categorization, SKU validation, unique product codes, GST tax rates, and active/inactive status toggles.

### Phase 2: Manufacturing, Unit Serialization & QR Generation
- **Manufacturing Batches**: Batch lifecycle management (`Draft`, `In Production`, `Completed`, `Under Verification`, `Closed`). Closed batches cannot be modified.
- **Hardware Counting Interface Layer**: Abstract contract `CountingMachineInterface` with multi-protocol drivers:
  - `UsbSerialConnector` (USB COM port / RS232)
  - `Rs232Connector` (Baud rate, parity, stop bits)
  - `LanApiConnector` (Ethernet TCP/IP socket / REST API)
  - `PlcGatewayConnector` (Industrial Modbus TCP / Siemens S7)
  - `ManualEntryConnector` (Fallback operator manual quantity entry)
- **Unit Generator Service**: Bulk generation in memory-safe 500-unit batches. Generates formatted continuous serials (e.g. `PA-P001-000001` to `PA-P001-001000`) and cryptographically random 32-character hex QR tokens.
- **Thermal & Sheet Label Printing**: SVG QR code generation via `chillerlan/php-qrcode`. Formatted for 50x25mm, 50x30mm thermal rolls and A4 24-up label sheets. Controlled reprint requires mandatory min 5-character reason and increments reprint count.
- **Pre-Warehouse QA Verification Terminal**: Rapid keyboard-wedge scanner interface for verifying physical units before entering warehouse storage.
- **Public Read-Only Verification Portal**: Public scan URL (`/scan/{token}`). Authenticates genuine Pavitram Agroz units while sanitizing private warehouse, store, purchase price, and staff identity data.

### Phase 3: Central Warehouse, Inventory & Transfers
- **Warehouse Management**: Central logistics hub creation, location-specific inventory breakdown, stock movement auditing.
- **Warehouse Inbound Intake**: Physical unit scan validation ensuring only `verified` units enter warehouse storage.
- **Inter-Store / Warehouse Stock Transfers**: Complete multi-state transfer workflow (`Draft` -> `Dispatched` -> `In Transit` -> `Received` / `Partially Received`). Automatic detection of missing or damaged units with discrepancy reporting.
- **Anti-IDOR Store Isolation**: Store Admins can only view and receive transfers destined for their store. Unassigned store data returns HTTP 403 Forbidden.
- **Physical Stock Reconciliation**: Discrepancy resolution workflow (`reconcile`, `quarantine_damaged`, `write_off_missing`).

### Phase 4: Point of Sale, Billing, Returns & Analytics
- **Cashier POS Station**:
  - High-speed scanner input: supports USB 2D hardware barcode scanners (keyboard-wedge input with auto-Enter detection), camera scanning via HTML5-QRCode, and quick product search.
  - Cart calculation engine: dynamic subtotals, configurable line discounts with validation, and automatic GST breakup (CGST + SGST for intra-state, IGST for inter-state).
  - Multi-tender checkout: Cash, UPI, Card, Net Banking.
  - Concurrency defense: `lockForUpdate()` row locks ensure the same physical unit cannot be checked out simultaneously by two terminals.
- **Invoice Management**:
  - Sequential format: `PA-INV-{STORE_CODE}-{YYYYMMDD}-{XXXXX}`.
  - Dual print templates: 80mm/58mm ESC/POS thermal receipt view and formal A4 Tax Invoice with GST tax breakdown.
  - Controlled invoice cancellation: requires a mandatory explanation, reverts unit lifecycle back to `In Store`, and logs reversing stock movement ledger entries.
- **Returns & Refunds Workflow**:
  - Lookup by Invoice Number or Unit Serial Number.
  - Physical quality inspection per unit: `Restock` (re-enters `In Store`), `Damaged / Quarantine` (moves to `Damaged` / `Quarantine`), `Dispose`, or `Rejected`.
  - Cashier initiates return request; Store Admin or Super Admin approves refund settlement.
- **Enterprise Reporting & Analytics**:
  - Daily, weekly, monthly, custom sales velocity.
  - Cross-store sales comparisons (Super Admin only).
  - Product-level and batch-level turnover.
  - Cashier performance and revenue per tender method.
  - Return rate analytics and damaged stock logs.
  - 90-day expiry risk alerting.
  - Streaming CSV export for all reports.

---

## 4. API & Web Routes Registry

### Authentication & Public Routes
| Method | URI | Action | Middleware |
| :--- | :--- | :--- | :--- |
| GET | `/login` | `AuthController@showLogin` | `guest` |
| POST | `/login` | `AuthController@login` | `guest`, `throttle:5,1` |
| POST | `/logout` | `AuthController@logout` | `auth` |
| GET | `/forgot-password` | `AuthController@showForgotPassword` | `guest` |
| POST | `/forgot-password` | `AuthController@sendResetLink` | `guest`, `throttle:3,1` |
| GET | `/scan/{token}` | `PublicScanController@verify` | `throttle:60,1` |

### Dashboard & Core Navigation
| Method | URI | Action | Middleware / Policy |
| :--- | :--- | :--- | :--- |
| GET | `/` | Redirect to `/dashboard` | `auth` |
| GET | `/dashboard` | `DashboardController@index` | `auth` |
| GET | `/stores` | `StoreController@index` | `auth`, `role:super-admin` |
| POST | `/stores` | `StoreController@store` | `auth`, `role:super-admin` |
| GET | `/products` | `ProductController@index` | `auth` |
| POST | `/products` | `ProductController@store` | `auth`, `role:super-admin` |

### Manufacturing & Batches (Phase 2)
| Method | URI | Action | Middleware / Policy |
| :--- | :--- | :--- | :--- |
| GET | `/manufacturing/batches` | `BatchController@index` | `auth`, `role:super-admin` |
| POST | `/manufacturing/batches` | `BatchController@store` | `auth`, `role:super-admin` |
| POST | `/manufacturing/batches/{batch}/record-quantity` | `BatchController@recordQuantity`| `auth`, `role:super-admin` |
| POST | `/manufacturing/batches/{batch}/generate-units` | `BatchController@generateUnits` | `auth`, `role:super-admin` |
| GET | `/manufacturing/batches/{batch}/labels` | `LabelPrintingController@preview` | `auth`, `role:super-admin` |
| POST | `/manufacturing/batches/{batch}/labels/print` | `LabelPrintingController@printJob` | `auth`, `role:super-admin` |
| POST | `/manufacturing/units/{unit}/reprint` | `LabelPrintingController@reprintUnit`| `auth`, `role:super-admin` |
| GET | `/manufacturing/qa-verification` | `VerificationController@index` | `auth`, `role:super-admin` |
| POST | `/manufacturing/qa-verification/verify` | `VerificationController@verifyUnit` | `auth`, `role:super-admin` |

### Warehouse & Stock Transfers (Phase 3)
| Method | URI | Action | Middleware / Policy |
| :--- | :--- | :--- | :--- |
| GET | `/warehouses` | `WarehouseController@index` | `auth`, `role:super-admin` |
| POST | `/warehouses` | `WarehouseController@store` | `auth`, `role:super-admin` |
| GET | `/warehouses/{warehouse}` | `WarehouseController@show` | `auth`, `role:super-admin` |
| GET | `/warehouse-receiving` | `WarehouseReceivingController@index`| `auth`, `role:super-admin` |
| POST | `/warehouse-receiving/scan` | `WarehouseReceivingController@receiveUnit` | `auth`, `role:super-admin` |
| GET | `/inventory/transfers` | `StockTransferController@index` | `auth` |
| POST | `/inventory/transfers` | `StockTransferController@store` | `auth`, `role:super-admin` |
| POST | `/inventory/transfers/{transfer}/dispatch` | `StockTransferController@dispatch` | `auth`, `role:super-admin` |
| POST | `/inventory/transfers/{transfer}/receive` | `StockTransferController@receive` | `auth` (Scoped to destination) |
| GET | `/inventory/store-stock` | `StoreInventoryController@index` | `auth` (Scoped to assigned store) |
| GET | `/inventory/reconciliation` | `StockReconciliationController@index`| `auth`, `role:super-admin,store-admin` |

### Point of Sale, Invoices, Returns & Reports (Phase 4)
| Method | URI | Action | Middleware / Policy |
| :--- | :--- | :--- | :--- |
| GET | `/pos` | `PosController@index` | `auth`, `permission:pos.access` |
| POST | `/pos/scan-unit` | `PosController@scanUnit` | `auth`, `permission:pos.access` |
| GET | `/pos/search-products` | `PosController@searchProducts` | `auth`, `permission:pos.access` |
| POST | `/pos/checkout` | `PosController@checkout` | `auth`, `permission:pos.access` |
| GET | `/pos/invoices` | `InvoiceController@index` | `auth` |
| GET | `/pos/invoices/{invoice}` | `InvoiceController@show` | `auth`, `can:view,invoice` |
| GET | `/pos/invoices/{invoice}/thermal` | `InvoiceController@thermalReceipt` | `auth`, `can:view,invoice` |
| GET | `/pos/invoices/{invoice}/print` | `InvoiceController@printTaxInvoice` | `auth`, `can:view,invoice` |
| POST | `/pos/invoices/{invoice}/cancel` | `InvoiceController@cancel` | `auth`, `can:cancel,invoice` |
| GET | `/pos/returns` | `SalesReturnController@index` | `auth` |
| GET | `/pos/returns/create` | `SalesReturnController@create` | `auth`, `permission:pos.access` |
| POST | `/pos/returns` | `SalesReturnController@store` | `auth`, `permission:pos.access` |
| GET | `/pos/returns/{salesReturn}` | `SalesReturnController@show` | `auth` |
| POST | `/pos/returns/items/{item}/inspect` | `SalesReturnController@inspectItem` | `auth`, `can:approve,salesReturn` |
| POST | `/pos/returns/{salesReturn}/approve`| `SalesReturnController@approve` | `auth`, `can:approve,salesReturn` |
| GET | `/reports` | `ReportController@index` | `auth`, `permission:reports.view` |
| GET | `/reports/export` | `ReportController@export` | `auth`, `permission:reports.view` |

---

## 5. Role-Based Access Control (RBAC) Matrix

| Feature / Action | Super Admin | Store Admin | Cashier |
| :--- | :---: | :---: | :---: |
| **Manage Stores (Create/Edit)** | Full Access | No Access (403) | No Access (403) |
| **Manage Users & Role Assignment** | System-Wide | Own Store Staff Only | No Access (403) |
| **Product Master & Category CRUD** | Full Access | Read-Only | Read-Only |
| **Create Batches & Production Recording**| Full Access | No Access (403) | No Access (403) |
| **Generate Physical Units & Print Labels**| Full Access | No Access (403) | No Access (403) |
| **Authorize Unit Label Reprints** | Full Access (Reason required) | No Access (403) | No Access (403) |
| **Pre-Warehouse QA Verification** | Full Access | No Access (403) | No Access (403) |
| **Manage Warehouses & Inbound Intake** | Full Access | No Access (403) | No Access (403) |
| **Initiate & Dispatch Stock Transfers**| Full Access | No Access (403) | No Access (403) |
| **Receive Inbound Stock Transfers** | Full Access | Assigned Store Only | No Access (403) |
| **View Store Inventory** | All Stores | Assigned Store Only | Assigned Store Only |
| **Access POS Billing Terminal** | Full Access | Full Access | Assigned Store Only |
| **Scan Units & Complete Sale** | Yes | Yes | Yes |
| **Cancel Invoice & Revert Stock** | Yes | Yes (Mandatory reason) | No Access (403) |
| **Initiate Sales Return Request** | Yes | Yes | Yes |
| **Approve Return & Settle Refund** | Yes | Yes | No Access (403) |
| **View Financial & Sales Reports** | System-Wide & Store Comparison | Assigned Store Only | Strictly Forbidden (403) |
| **Export Reporting CSV Streams** | Full Access | Assigned Store Only | Strictly Forbidden (403) |
| **Public QR Scan Verification** | Public | Public | Public |

---

## 6. POS Hardware & Barcode Scanner Integration Guide

### 6.1 Handheld USB / Wireless 2D Barcode Scanners
- **Supported Hardware**: Any standard 2D Image Barcode Scanner (Honeywell Xenon 1900, Zebra DS2208, Datalogic QuickScan, Netum 2D, TVS BS-i201G, etc.).
- **Scanner Mode**: Configure scanner to **HID Keyboard Wedge Mode** (standard factory default).
- **Scanner Suffix Configuration**: Ensure the scanner is configured to send a carriage return / enter suffix (`CR` or `CR+LF`) after scanning.
- **Workflow**:
  1. Cashier opens `/pos`.
  2. Cashier aims scanner at the physical product QR code or serial barcode.
  3. The scanner types the 32-character token or serial number into the input box and fires the `Enter` key event.
  4. The POS terminal intercepts the enter keystroke, halts default form submission, transmits an AJAX POST to `/pos/scan-unit`, performs cryptographic re-validation, and appends the verified unit into the active billing cart with audio feedback.

### 6.2 Camera-Based QR Scanning
- The POS terminal integrates HTML5 webcam scanning for tablets, smartphones, and laptops equipped with front/rear cameras.
- Requires HTTPS in production environments for browser camera permissions.

### 6.3 Receipt & Label Printer Integration
- **Thermal POS Receipt Printers (80mm & 58mm)**:
  - Supported: Epson TM-T82, TVS RP-3200, Star Micronics TSP143, Citizen CT-S310, generic ESC/POS thermal printers.
  - Integration: Open `/pos/invoices/{id}/thermal`. Click `Print Receipt` (invokes `window.print()` with `@media print` CSS rules tailored to 72mm printable width on 80mm rolls). Margins are set to zero to avoid clipping.
- **Industrial Barcode Label Printers**:
  - Supported: TSC TE244, Zebra ZD220, Citizen CL-E300, TVS LP-46.
  - Standard Label Sizes: 50mm x 25mm, 50mm x 30mm, 35mm x 25mm rolls.
  - Pre-calibrated label CSS templates are provided under `/manufacturing/batches/{id}/labels`.

---

## 7. Security Architecture & Hardening Summary

1. **CSRF Protection**: All POST/PUT/DELETE forms and AJAX requests pass Laravel's CSRF token check (`X-CSRF-TOKEN`).
2. **SQL Injection Prevention**: 100% of queries use Eloquent ORM or parameterized PDO bindings (`?` or named placeholders). Zero raw string concatenation in queries.
3. **Cross-Site Scripting (XSS) Prevention**: All Blade output is auto-escaped using `{{ $var }}`. HTML outputs (e.g. SVG QR codes) use validated internal generation with explicit sanitization.
4. **Anti-IDOR Multi-Store Isolation**:
   - Every store-scoped operation validates that `Auth::user()->isStoreAdmin()` matches the target `store_id`.
   - Store admins attempting to access `/inventory/store-stock?store_id=999` are overridden to their own assigned store or rejected with HTTP 403.
5. **Brute Force & Rate Limiting**:
   - Login endpoint: throttled to 5 attempts per minute per IP/account.
   - Public QR verification: throttled to 60 requests per minute per IP to prevent dictionary scanning.
   - Password reset: throttled to 3 attempts per minute.
6. **Information Disclosure Prevention**:
   - Password recovery returns a uniform success response whether the email exists in the database or not.
   - Public QR verification endpoint exposes only brand name, product name, net quantity, batch number, serial number, packaging date, and expiry date. It strictly conceals warehouse names, store names, purchase prices, suppliers, cashier identities, and internal database primary keys.
7. **Pessimistic Locking & Idempotency**:
   - `DB::transaction()` paired with `lockForUpdate()` prevents race conditions during unit checkout, unit warehouse receiving, and transfer dispatch.

---

## 8. Production Deployment Guide

### 8.1 Server Requirements
- PHP >= 8.2 (with extensions: `pdo_mysql`, `bcmath`, `ctype`, `fileinfo`, `json`, `mbstring`, `openssl`, `tokenizer`, `xml`, `gd` or `imagick`).
- MySQL >= 8.0 or MariaDB >= 10.6.
- Web Server: Nginx or Apache with `mod_rewrite` enabled.
- Composer >= 2.6.
- Node.js >= 18 LTS & NPM.

### 8.2 Production Deployment Steps
1. **Clone repository into web server root**:
   ```bash
   git clone <repo-url> /var/www/pavitram-agroz
   cd /var/www/pavitram-agroz
   ```

2. **Install composer dependencies (no dev)**:
   ```bash
   composer install --no-dev --optimize-autoloader
   ```

3. **Configure Environment File**:
   ```bash
   cp .env.example .env
   php artisan key:generate
   ```
   Update `.env` with production credentials:
   ```env
   APP_ENV=production
   APP_DEBUG=false
   APP_URL=https://erp.pavitramagroz.com

   DB_CONNECTION=mysql
   DB_HOST=127.0.0.1
   DB_PORT=3306
   DB_DATABASE=pavitram_agroz_prod
   DB_USERNAME=pavitram_dbuser
   DB_PASSWORD=SecurePassword123!

   SESSION_SECURE_COOKIE=true
   SESSION_LIFETIME=120
   ```

4. **Run Migrations & Seeders**:
   ```bash
   php artisan migrate --force
   php artisan db:seed --force
   ```

5. **Optimize Laravel Caches**:
   ```bash
   php artisan config:cache
   php artisan route:cache
   view:cache
   php artisan event:cache
   ```

6. **Set File Permissions**:
   ```bash
   chown -R www-data:www-data /var/www/pavitram-agroz/storage /var/www/pavitram-agroz/bootstrap/cache
   chmod -R 775 /var/www/pavitram-agroz/storage /var/www/pavitram-agroz/bootstrap/cache
   ```

7. **Nginx Configuration Snippet**:
   ```nginx
   server {
       listen 443 ssl http2;
       server_name erp.pavitramagroz.com;
       root /var/www/pavitram-agroz/public;

       index index.php;
       charset utf-8;

       ssl_certificate /etc/letsencrypt/live/erp.pavitramagroz.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/erp.pavitramagroz.com/privkey.pem;

       add_header X-Frame-Options "SAMEORIGIN";
       add_header X-Content-Type-Options "nosniff";
       add_header X-XSS-Protection "1; mode=block";

       location / {
           try_files $uri $uri/ /index.php?$query_string;
       }

       location ~ \.php$ {
           fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
           fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
           include fastcgi_params;
       }

       location ~ /\.(?!well-known).* {
           deny all;
       }
   }
   ```

---

## 9. Backup & Disaster Recovery Instructions

### 9.1 Automated Daily Database Backup
Add cron task for MySQL automated dumping:
```bash
0 2 * * * mysqldump -u pavitram_dbuser -p'SecurePassword123!' --single-transaction --routines --triggers pavitram_agroz_prod | gzip > /var/backups/pavitram_agroz_$(date +\%Y\%m\%d_\%H\%M\%S).sql.gz
```

### 9.2 Database Restoration Procedure
To restore from a backup:
```bash
gunzip < /var/backups/pavitram_agroz_20261105_020000.sql.gz | mysql -u pavitram_dbuser -p'SecurePassword123!' pavitram_agroz_prod
```

---

## 10. Troubleshooting Guide

| Issue / Symptom | Root Cause | Resolution |
| :--- | :--- | :--- |
| **Scanner beeps but POS does not add unit to cart** | Scanner not configured with Enter key suffix. | Scan manufacturer configuration barcode for "Suffix: Enter (CR)". |
| **Unit scan displays: "Unit belongs to another store"** | Unit was transferred or received at a different retail location. | Confirm dispatch status in `/inventory/transfers` or receive the inbound transfer first. |
| **Receipt printer prints gibberish or blank paper** | Thermal roll loaded upside down or baud rate mismatch. | Invert thermal roll paper; verify ESC/POS driver settings. |
| **"Unit is already sold" error on scan** | Unit serial was already checked out on a completed invoice. | Physical unit cannot be re-sold. If returned by customer, complete sales return inspection and approve restock first. |
| **HTTP 403 Forbidden on Reports** | User has Cashier role. Cashiers are strictly blocked from financial data. | Log in with a Store Admin or Super Admin account. |
