Files
lunarfront-app/planning/28_Frontend_Strategy.md

14 KiB

LunarFront Platform

Frontend Strategy — Multiple UI Surfaces

Version 1.0 | Draft

1. Overview

LunarFront serves different users in different contexts — a store owner at their desk, a cashier at the counter, a staff member receiving stock in the back room, and a salesperson at a trade show. One UI cannot serve all of these well.

The platform uses a single backend API with multiple purpose-built frontends. Each frontend is a separate package in the monorepo, shares the same @lunarfront/shared schemas and types, and calls the same REST API. The backend doesn't know or care which frontend is making the request.

2. Frontend Packages

2.1 Admin UI — packages/admin

Status: Active development (current)

Attribute Detail
Form factor Desktop / laptop, large tablet
Stack React, Vite, TanStack Router, TanStack Query, shadcn/ui
Users Store owner, manager, back-office staff
Access Web browser

Purpose: Full management interface. Everything that isn't a real-time transaction happens here — accounts, members, inventory configuration, RBAC, roles, reports, settings, lesson scheduling, repair management, vault.

Design priorities:

  • Dense information display (data tables, detail pages)
  • Keyboard-friendly (tab navigation, search)
  • Multi-column layouts, sidebars, dialogs
  • Not optimized for touch or small screens — that's intentional

2.2 POS UI — packages/pos

Status: Planned

Attribute Detail
Form factor Counter-mounted tablet (10"+) or touchscreen monitor
Stack React, Vite (same toolchain as admin)
Users Cashier, sales associate
Access Web browser (full-screen / kiosk mode)

Purpose: Point-of-sale for in-store transactions. Staff stares at this 8 hours a day. Every interaction must be fast and require minimal taps.

Design priorities:

  • Always-on, single-screen (no page navigation)
  • Large touch targets (44px+ minimum)
  • Fast product search (keyboard wedge barcode scanner + text search)
  • Cart management (add, remove, adjust quantity, apply discount)
  • Payment flow (cash, card via terminal, split payment)
  • Cash drawer integration
  • Receipt printing (thermal printer via browser print or ESC/POS)
  • Session management (clock in/out, cash drawer open/close, X/Z reports)
  • Offline resilience — queue transactions if network drops, sync when back

PIN unlock:

The POS terminal stays authenticated but locks between use. Staff unlock with a 4-6 digit PIN instead of email/password. The PIN maps to their real user account — every action (sale, void, drawer open) is attributed to the person who unlocked.

  • Each user sets a numeric PIN from their profile or admin assigns one
  • PIN is stored as a bcrypt hash on the user record (separate from password)
  • POS lock screen shows a numeric keypad — tap PIN, unlock, start selling
  • Auto-locks after configurable idle timeout (default: 2 minutes)
  • Manual lock button always visible
  • Shift change: current user walks away, screen locks, next user enters their PIN
  • Wrong PIN: brief delay, max 5 attempts then require full login
  • PIN unlock issues a short-lived JWT (or extends the existing session) scoped to POS permissions
  • Backend: POST /v1/auth/pin-login — accepts { pin }, returns token with same user identity and permissions
  • PIN is optional — users without a PIN set must use full email/password login on the POS

This gives full audit trail (who did what) without the friction of typing credentials hundreds of times a day.

Discounts & price overrides:

  • Line item discount (percentage or flat dollar amount)
  • Whole-cart discount (e.g. 10% off everything)
  • Price override with reason code (item rings up wrong, manual correction)
  • Manager override: cashier attempts a discount or void above their permission level, manager punches their PIN to approve without taking over the session. Logged as "approved by [manager] for [cashier]"
  • Configurable discount limits per role (e.g. sales associate can give up to 10%, manager up to 25%, admin unlimited)

Parked carts / layaway:

  • Park a cart — customer wants to keep shopping or come back later
  • Multiple parked carts, each tagged with customer name or account
  • Retrieve a parked cart to resume the sale
  • Layaway: park with a deposit, schedule remaining payments
  • Auto-expire parked carts after configurable period (default: 7 days)

Gift cards & store credit:

  • Sell a gift card (physical or digital, generates a unique code)
  • Redeem gift card as payment method (scan or type code)
  • Check balance
  • Issue store credit (returns, adjustments) — tied to an account
  • Store credit appears as a payment option when account is linked to the sale

Returns:

  • With receipt: lookup transaction by receipt number or barcode, select items, refund to original payment method
  • Without receipt: store credit only, capped amount (configurable), requires manager override
  • Exchange: return + new sale in one transaction
  • Restocking fee support (percentage or flat, configurable per category)
  • Returned items: prompt for condition (resellable, damaged, defective) — updates inventory accordingly

End of day / cash management:

  • Open session: cashier counts starting cash, enters amount, system records
  • Cash drops: mid-shift safe drops, logged with amount and time
  • Close session: two modes:
    • Counted close: cashier counts the drawer, enters totals by denomination, system calculates over/short
    • Blind close: cashier counts and enters total without seeing expected amount — prevents fudging
  • Z report: end-of-day summary — gross sales, net sales, tax collected, payment method breakdown (cash, card, gift card, store credit), refunds, discounts given, over/short
  • X report: mid-day snapshot (same data as Z but doesn't close the session)
  • All reports printable on receipt printer

Training mode:

  • Toggle per POS session — transactions don't hit real inventory or accounting
  • Visually distinct: large "TRAINING MODE" banner across the screen, different background color
  • Manager enables/disables via their PIN
  • Training transactions are logged separately for review but don't affect reports or stock

Customer-facing display:

  • Second screen (or portion of a split screen) showing the customer what's being rung up
  • Line items, quantities, prices, running total
  • Shows payment status ("Insert card", "Approved", "Change due: $4.25")
  • Some jurisdictions legally require itemized display during transaction
  • Configurable: on/off, which screen, store branding/logo

Quick keys / favorites:

  • Configurable grid of frequently sold items (strings, picks, reeds, cables, lesson payments)
  • Admin configures the grid layout (drag and drop in admin UI)
  • Supports categories/tabs (e.g. "Accessories", "Lessons", "Repairs")
  • Faster than searching — one tap to add to cart
  • Can also map to common actions (open drawer, apply house discount, gift card sale)

Receipts:

  • Thermal printer via ESC/POS (USB or network)
  • Browser print fallback with receipt-formatted CSS
  • Email receipt option (if customer has account with email)
  • Text/SMS receipt (future, via email system)
  • Configurable header/footer (store name, address, return policy, social media)
  • Barcode/QR on receipt for easy return lookup

Key screens:

  1. Lock screen — numeric keypad, current time, store name
  2. Sale screen — product search (left), quick keys (top), cart (right), totals + pay button (bottom)
  3. Payment screen — amount due, payment method selection, card terminal status, change calculation, tip (optional)
  4. Return/exchange screen — lookup original transaction, select items, refund method, condition prompt
  5. Parked carts — list of held transactions, tap to resume
  6. Drawer management — open session, cash drops, close session with denomination counting
  7. Reports — X report, Z report, transaction history for current session

Hardware integration:

  • Barcode scanner: keyboard wedge (types into focused input, no special API)
  • Card reader: local network or USB terminal via Stripe Terminal SDK or Global Payments SDK
  • Cash drawer: triggered via receipt printer (kick pulse) or USB relay
  • Receipt printer: ESC/POS over USB or network, or browser window.print() with receipt-formatted CSS
  • Customer display: secondary screen via window.open() or dedicated display API
  • Scale (future): for items sold by weight

2.3 Floor App — packages/floor

Status: Planned

Attribute Detail
Form factor Phone or small tablet
Stack React Native (Expo) or PWA
Users Sales staff on floor, inventory staff, trade show sales
Access Native app (iOS/Android) or PWA in Safari/Chrome

Purpose: Two modes in one mobile app — inventory management and mobile sales. Both are walk-around-the-store (or walk-around-a-trade-show) workflows with scanning, big inputs, and minimal typing.

Design priorities:

  • Phone-first layout (single column, stacked)
  • Camera barcode scanning (no external scanner needed)
  • Large buttons, minimal text input
  • Works on cellular (trade shows) and store WiFi
  • Offline support for inventory counts (sync when connected)

Inventory Mode

Purpose: Receiving, cycle counts, transfers, shelf checks.

Key screens:

  1. Receive stock — scan items, enter quantities, confirm receipt against purchase order
  2. Cycle count — scan location/shelf, scan items, enter counts, submit discrepancies
  3. Quick lookup — scan barcode, see product details, stock levels across locations, price history
  4. Transfer — scan items to move between locations
  5. Condition check — scan item, update condition (new, used, damaged), add notes/photo

Mobile POS Mode

Purpose: Sales at trade shows, on the shop floor, off-site events.

Key screens:

  1. Quick sale — search/scan products, add to cart, take payment
  2. Payment — Bluetooth card reader integration, or manual card entry
  3. Customer lookup — search by name/phone/account number for account-linked sales
  4. Receipt — email or text receipt (no printer at a trade show)

Build Strategy

Phase 1 — PWA:

  • Build as a web app with mobile-optimized UI
  • "Add to Home Screen" for app-like experience
  • Camera scanning via navigator.mediaDevices + barcode detection library
  • Local network card reader for payments
  • No App Store, no developer cert, works on any device

Phase 2 — Native (if needed):

  • React Native with Expo
  • Reuses @lunarfront/shared schemas and business logic
  • Native Bluetooth for card reader pairing
  • Native camera for faster barcode scanning
  • Requires Apple Developer ($99/year) and Google Play ($25 one-time)
  • Only worth it if PWA limitations become blockers (Bluetooth, offline, performance)

3. Shared Infrastructure

All frontends share:

Layer Package What it provides
Validation @lunarfront/shared Zod schemas — same validation client and server
Types @lunarfront/shared TypeScript interfaces for all domain entities
Business logic @lunarfront/shared Formatters, calculators, state normalization
API Backend REST Same endpoints, same auth, same response format
Auth JWT Same token works across all frontends
Permissions RBAC Same permission checks — POS user doesn't need admin access

This means:

  • A bug fix in a Zod schema fixes validation everywhere
  • A new API endpoint is immediately available to all frontends
  • No data format translation between frontends
  • One test suite covers the API regardless of which frontend calls it

4. Permission Mapping

Different frontends surface different permissions:

Permission Admin POS Floor
accounts.view/edit/admin Yes View only (customer lookup) View only
inventory.view/edit/admin Yes View only (product search) Full access
pos.view/edit/admin Reports only Full access Mobile POS mode
rentals.* Yes Process returns No
lessons.* Yes No No
repairs.* Yes Intake only No
vault.* Yes No No
users.* Yes No No

The backend enforces permissions regardless — the frontend just decides what to show.

5. Offline Strategy

Offline support is critical for POS (network drops) and Floor (dead zones in warehouse).

POS offline:

  • Cache product catalog in IndexedDB (refresh periodically)
  • Queue transactions locally when offline
  • Process card payments when back online (or show "cash only" mode)
  • Sync queue when connection restores
  • Visual indicator: "Offline — transactions will sync when connected"

Floor offline (inventory):

  • Cache current inventory counts
  • Store count entries locally
  • Sync on reconnect
  • Conflict resolution: last-write-wins with audit log of discrepancies

Admin:

  • No offline support needed. Back-office work requires connectivity.

6. Deployment

Frontend Hosting Notes
Admin Same server as backend (Caddy/nginx serves static files) Single origin, no CORS
POS Same server or dedicated POS terminal Kiosk mode browser, auto-launch on boot
Floor PWA from same server, or App Store Phone/tablet accesses over store WiFi or cellular

For on-prem: all frontends are served from the same LunarFront server. One box, one URL, multiple apps at different paths (/admin, /pos, /floor).

7. Implementation Order

  1. Admin UI — current, continue until core management is complete
  2. POS UI — next major effort after admin is stable. This is the revenue-critical surface.
  3. Floor App (Inventory mode) — PWA first. Enables stock receiving and cycle counts.
  4. Floor App (Mobile POS mode) — add-on to floor app. Trade show / floor sales.
  5. Floor App (Native) — only if PWA hits limitations. Bluetooth reader, performance, offline.

Each frontend is independently deployable. Stores can run just Admin + POS if they don't need mobile inventory. Modules control which features are available, not which frontends are installed.