# Glossary — TinyPOS (`tnx-pos`)

| Term | Definition |
|------|------------|
| `admin_menu` | Navigation tree rows seeded into the database; each row has a `uri`, `icon`, `order`, and optional `parent_id` for nesting. |
| `admin_operation_log` | Audit log of admin HTTP actions (path, method, IP, input); disabled by configuration. |
| `admin_permissions` | RBAC permission records scoped optionally to an HTTP method and path glob. |
| `admin_roles` | Named roles identified by a `slug`; granted to users and assigned permissions and menu entries via pivot tables. |
| `admin_users` | Administrator accounts — the only kind of system user. Customers are CRM records, not accounts. |
| Available stock | `quantity_available = quantity - used`, computed at read time; out-of-stock test is strict `=== 0`. |
| Base unit | The product's primary unit of measure, stored as a free string in `products.unit` (by name, not FK). |
| Brand | Product label/manufacturer reference data stored in `brands`; `brand_id` is a required FK on every product. |
| Category | Product classification organised in a two-level hierarchy (top-level group → child); only child categories (`parent_id` not null) are assignable to products. |
| Conversion quantity | `conversion_qty` — the divisor applied to the base price when a non-base unit is sold: `unitPrice = basePrice / conversion_qty`. |
| Conversion unit | An alternative sale unit for a product, stored in `product_units` by FK to `units`, with its `conversion_qty`. |
| `customer_debts` | Append-only accounts-receivable ledger; each row is one of `pos_debt`, `manual_debt`, `repayment`, or `debt_void`. |
| `customer_gift` | Pivot table recording gift redemptions per customer; carries `points` and `note` as pivot columns. |
| `customer_order_summary` | One-row-per-customer denormalised stats table (order count, spend, points, per-category breakdown) rebuilt by a nightly scheduler; not live. |
| `customers` | CRM records for named customers. Carry a `type` (pricing tier), a `points` loyalty balance, and a `debt_total` accounts-receivable balance. |
| Customer statistics | Nightly precomputed per-customer rollup stored in `customer_order_summary`; same-day sales are not reflected until the next run. |
| Customer type | Pricing tier: `khach_le` (retail/walk-in default when null), `si_1` (wholesale tier 1), `si_2` (wholesale tier 2). |
| Debt (Nợ / Công nợ) | Customer accounts-receivable: an append-only `customer_debts` ledger plus a running `debt_total` balance on the customer row. |
| Debt void | `customer_debts.type = debt_void` — a reversal entry written when a debt-bearing order is deleted; amount is clamped by the current balance. |
| `discounts` | Legacy table and `orders.discount_id` FK retained intentionally for future use; no current code path applies a discount by id. |
| Done order | `orders.status = done` — a finalised sale; points are awarded and any POS debt is posted to the customer ledger at this moment. |
| Draft order | `orders.status = draft` — a held/parked cart recallable in the POS draft picker; no points or debt are posted yet. |
| `earned_point` | `orders.earned_point` — the sum of `round(reward_point,1) * qty` across all lines on an order. |
| Gift | A loyalty reward (`gifts`) redeemable with points; has a `points` cost, per-customer `limit` (0 = unlimited), stock `quantity`, and a running `used` count. |
| `is_editable` | Appended boolean on `orders`: true while `draft`, or while `done` and within 24 hours of `updated_at`. |
| Line / order line | One row in the `order_product` pivot: a product+unit combination with `qty`, `price` (captured at sale time), `unit_id`, and `conversion_qty`. |
| Manual debt | `customer_debts.type = manual_debt` — debt added by staff outside a sale via `CustomerController::storeDebt`. |
| Milk / Medicine special cases | Category ids `1` (Sữa/milk) and `8` (Thuốc/medicine) — singled out in the statistics rollup; all other categories collapse into "other". |
| `order_product` | Pivot table linking orders to products; captures `qty`, `price`, `discount`, `unit_id`, and `conversion_qty` at sale time. |
| `orders` | A single sale record; lifecycle is `draft` → `done`; no soft-delete — deletions are permanent. |
| `orders.count` | The number of distinct **lines** on the order, not the sum of quantities. |
| POS / sales terminal | The cashier screen (`/pos`, `PosController`) where a cart is built and an order is submitted; the root `/` 301-redirects here. |
| POS debt | `customer_debts.type = pos_debt` — debt created automatically when a `done` order is submitted with `debt_amount > 0`; posted exactly once per order. |
| Points awarded | `orders.points_awarded_at` — an idempotency guard timestamp set when an order's points are first credited to prevent double-awarding. |
| `product_units` | Conversion-unit rows linking a product to alternative sale units via `unit_id` FK and storing the `conversion_qty` divisor. |
| `products` | Product catalogue; carries pricing (`price`, `sale_price`, `wholesale_prices`), stock (`qty`), loyalty (`reward_point`), expiry, and soft-delete support. |
| Repayment | `customer_debts.type = repayment` — a customer paying down their balance; cannot exceed `debt_total`. |
| Retail price | `sale_price` (falling back to `price`) — the price charged to `khach_le` customers and the default when no wholesale price is set. |
| Reward point | Loyalty points: `products.reward_point` (per-unit earn rate), `orders.earned_point` (order accrual), `customers.points` (running balance). |
| `settings` | Key/value configuration store; used at minimum for `near_expiry_days` (default 30). |
| Unit | Unit-of-measure reference data stored in `units`; id `1` is edit-locked as the protected default. |
| `units` | Reference table of units of measure; each row has `id`, `name`, and a declared-but-unused `category_id`. |
| Wholesale price | `products.wholesale_prices` — a JSON map of customer type → price override for `si_1` and `si_2` tiers. |
