# POS P1 — Premium Interface Foundation

**Status:** Complete · committed locally (not pushed)
**Date:** 2026-11-13
**Scope:** Frontend only — a presentation redesign over the **existing** order &
payment engine. No backend code changed; no payment processing, reversals or
new write paths were added.

## 1. Objective

Redesign the staff POS to the selected Cacart layout direction — a polished,
desktop-first three-column workspace (category rail · product grid · cart) with
a top-level mode switcher — while **reusing all existing POS functionality and
business logic** and preparing the workspace for later unified payment
integration. This phase is the UI foundation, **not** a payment rebuild.

## 2. Current POS audit (before)

The POS lives at `/pos` and is served by
[`CreateOrderPage`](../../../frontend/src/pages/orders/CreateOrderPage.tsx)
(the legacy `/orders/new` link redirects into it). It is already a complete,
server-authoritative order-entry screen; P1 re-skins its presentation only.

**Pre-P1 structure** (commit `02780f6` and earlier):

- A top **Section A** card: customer (Existing/New + search), order source,
  fulfillment (pickup/delivery), timing (ASAP/scheduled), delivery address +
  saved addresses, notes.
- A 2-column grid below: **Section B** a product **list** (rows) with a text
  search and horizontal **category chips**; **Section C** a sticky order
  summary + the reused `OrderMoneyPanel`.
- Products add through a lazy draft; variants/modifiers via a configure dialog;
  pricing/tax/shipping always resolved server-side.

**Engine facts confirmed during the audit** (drove the honest matrix below):

- Order lines require a catalogue `product_id` + `product_variant_id`
  (`ordersApi.addLine`) — there is **no ad-hoc/custom line** endpoint.
- Totals expose `discount_total_minor` / `line_discount_minor` as **read-only**
  projections; there is **no manual discount-entry endpoint** in `ordersApi`.
- Payments: `recordOffline` (cash / e-transfer / bank / other), verify/reject,
  and secure payment links. Card = sandbox online link. Partial amounts are
  allowed (multiple receipts), but there is **no dedicated split-payment UI**
  and **no debit/credit terminal** integration.
- No serialized-inventory (IMEI/serial) concept exists in the product/order API.

## 3. Screenshot → feature mapping (supported / partial / missing)

| Screenshot element | Status | Notes / where it lives in P1 |
|---|---|---|
| Categories rail | **Supported (redesigned)** | Was horizontal chips → now a vertical icon+label rail with a clear selected state |
| Product grid | **Supported (redesigned)** | Was a row list → now responsive product **tiles** (image, price, availability, variant count) |
| Search | **Supported** | Name/SKU search (debounced client filter over the loaded catalogue) |
| Barcode / SKU input | **Supported (new)** | Scanner-friendly: Enter adds the item on an exact SKU match or a single filtered result |
| Customer selection | **Supported** | Existing/New + search, avatar, saved contact persons — in the cart column |
| Walk-in | **Supported** | Default when no customer is chosen |
| Cart items + qty | **Supported** | Live lines, qty steppers, per-line modifier chips, remove |
| Subtotal / tax / total | **Supported** | Server-authoritative totals in the sticky checkout foot |
| Variant selection | **Supported** | Existing configure dialog (variant + modifier rules) |
| Cash | **Supported** | `OrderMoneyPanel` → record offline (cash) |
| Checkout | **Supported** | Save as draft · Save & send payment link · Record payment |
| Credit / Debit | **Partial** | Card = sandbox online **payment link**; no in-person card/debit terminal yet |
| Split Payment | **Partial** | Multiple partial receipts are possible on one order; no dedicated split UI |
| Top Sale / Specials / Combo | **Missing** | No "top sellers/specials" data source; combos exist only as combo-type products |
| Instant / Custom Sale | **Missing** | Engine has no ad-hoc line; every line needs a catalogue product + variant |
| Discount | **Missing (control)** | Totals surface a discount line, but there is no manual discount-entry endpoint |
| Serialized Product Details | **Missing** | No serialized-inventory (serial/IMEI) model exists |

Missing/partial items are **documented, not simulated** — the UI exposes no
control that pretends to perform them.

## 4. What was built (P1)

### Layout (§2)
- **Left — category rail:** vertical, scrollable, icon + label per category
  (plus "All"), strong teal selected state. Icons are a deterministic,
  decorative pick from the shared icon set (no data-model change).
- **Centre — products:** a sticky "Search or scan" bar + a responsive tile grid.
  Each tile shows the thumbnail (or a type icon), name, price and an
  availability badge; multi-variant tiles show an "N options" hint. Out-of-stock
  / unavailable tiles are dimmed and disabled.
- **Right — cart:** customer (Existing/New/search/avatar, walk-in default),
  a collapsible **Order options** panel (location, source, fulfillment, timing,
  delivery + saved addresses, notes — all preserved), live cart lines with qty
  controls, the reused `OrderMoneyPanel`, and a **sticky checkout foot**
  (subtotal/tax/delivery/total + Save & send link / Save as draft). The cart
  column scrolls independently of the product grid on desktop.

### Top-level modes (§3)
A `role="tablist"` switcher: **New Sale** (the workspace), **Get Payment** and
**Payment History**. Get Payment and Payment History both operate on the
**in-progress sale** and route to the **existing** `OrderMoneyPanel` /
`order.payments` — with honest empty states ("No sale in progress", "No payments
yet") and a link to Orders when there is nothing to show. The switcher is
structured so Orders / Customer CRM / IPTV / Repairs can later deep-link into a
specific mode. No mode presents a fabricated submit control.

### Product workflows (§4)
Standard products, product variants, combo-type products and service products
all reuse the existing add → (variant/modifier) configure → lazy-draft line
flow. Serialized devices and manual discounts are **not** introduced (documented
as missing). No inventory logic was duplicated.

### Barcode / keyboard / touch (§6)
The search field doubles as a scan field: pressing **Enter** adds the item when
the query identifies exactly one sellable product (exact SKU, else the single
filtered result) — otherwise nothing happens (no silent wrong-item add). Tiles
are large touch targets; the rail, search and qty controls are keyboard-usable.

## 5. Styling

A new `pos-*` CSS layer in
[`orders.css`](../../../frontend/src/pages/orders/orders.css) built on the
existing Cacart design tokens: white/off-white surfaces, teal selected states,
deep-navy price/heading accents, elegant tiles with a subtle hover lift, clear
pricing hierarchy and accessible spacing. The existing `oe-*` cart internals are
reused unchanged.

## 6. Preserved data & engines (§7)

No change to sales orders, customer records, tax calculations, the inventory
ledger, IPTV billing, repair tickets, invoice numbering, the payment ledger or
payment gateway integrations. This is a frontend presentation change only;
pricing, tax and shipping remain server-authoritative (the client never sends a
price). NH POS was not touched and no legacy PHP was executed.

## 7. Verification & test results (§8)

- **New unit tests** — `PosWorkspace.test.tsx` (5, all green): renders the
  3-column workspace (mode tabs, rail, tiles); does not auto-create a draft and
  shows honest payment-mode empty states; adds a single-variant tile to the cart
  through the real order engine; barcode/SKU Enter adds the exact-SKU product;
  opens the variant picker for a multi-variant product instead of adding
  directly.
- **Regression** — `src/pages/orders` + `src/routes` suites: **58/58 pass**
  (run serially). `PosRouting` and `navigation` pass in isolation and serially;
  a concurrent full-suite run shows the project's known load-induced timeout
  flakes (pass serially / in isolation — not a P1 regression).
- **TypeScript** (`tsc --noEmit`): clean. **ESLint**: clean. **Build**
  (`vite build`): succeeds (only the pre-existing chunk-size advisory).
- **Playwright (live app, logged in as VM Admin / TechTitans Main Store):**
  verified the workspace end-to-end — mode switcher (3 tabs), rail (All + 3
  categories), 3 product tiles, add-to-cart via the variant picker
  ("iPhone 15 — 128GB", CA$999 line with live totals and the Payments & balance
  panel), Get Payment routing to the real money panel, Payment History read
  view. **No horizontal overflow at 1920 / 1440 / 1024 / 768 / 390**, and
  **0 console errors**.

## 8. Screenshots

In [`screenshots/pos-p1/`](screenshots/pos-p1/):

| File | Shows |
|------|-------|
| `p1-desktop-1920-idle.png` | Empty workspace — rail, tiles, cart, mode switcher |
| `p1-desktop-1920-cart.png` | Populated cart (iPhone 15 — 128GB), selected tile, totals, payment panel |
| `p1-desktop-1920-payment.png` | **Get Payment** mode → existing Payments & balance panel |
| `p1-desktop-1920-history.png` | **Payment History** mode |
| `p1-1440.png` / `p1-1024.png` | Desktop / small-desktop three columns |
| `p1-768.png` | Tablet — icon-rail / stacked cart screen |
| `p1-390.png` | Mobile — horizontal category strip, 2-col tiles, full-width cart |

*Before/after note:* the P1 commit replaces the view in place, so a live "before"
capture was not taken; the pre-P1 layout is described in §2 and reconstructable
from commit `02780f6`.

## 9. Limitations (documented, not simulated)

- **Credit/debit terminal** and **split-payment UI** are not implemented (card is
  a sandbox online link; multiple partial receipts are possible but there is no
  split workflow).
- **Manual discounts**, **instant/custom sale lines**, **Top Sellers/Specials**
  and **serialized product details** are not available — no engine support
  exists yet; no placeholder controls were added.
- **Get Payment / Payment History** operate on the current in-progress sale; a
  consolidated cross-order payment history/reporting view is a later phase (the
  modes link to Orders in the meantime).
- Small-screen cart is a stacked full-width **screen** below the tiles; an
  overlay cart **drawer** is a P2 refinement.

## 10. P2 / P3 roadmap

- **P2 — Unified payments:** in-person card/debit (terminal) + a real split-
  payment workflow in Get Payment; cross-order Payment History with filters;
  deep links from Orders / CRM / IPTV / Repairs into a specific POS mode.
- **P2 — Merchandising:** Top Sellers / Specials / Quick Sale rails (needs a
  sales-aggregate source); an Instant/Custom sale line (needs an ad-hoc line
  endpoint); a manual discount control (needs a discount endpoint + permission).
- **P3 — Serialized devices:** serialized-inventory model and a
  serial/IMEI selection step at add time (new backend capability, assessed
  separately — not inferred from product type).
- **P3 — POS polish:** optional overlay cart drawer on mobile, held/parked
  sales, and receipt printing hooks.

## 11. Commits (local only)

- Frontend: `3d98c10` — *TechTitans POS P1: premium 3-column interface
  foundation* (branch `techtitans/integration`).
- Backend: documentation + screenshots only (this file).

Committed **locally only** — not pushed or deployed.
