This commit adds a full unauthenticated PWA for in-store retail order taking: - Dedicated `/new-order` route with complete order form, customer/company picker - Public `/api/counter/*` endpoints for search, order creation, and photo uploads - Photo capture and gallery selection with 10-photo per order limit - Offline caching via dedicated service worker and app manifest - Shortcut redirect at `/counter` for quick installation - Comprehensive setup and usage documentation in `docs/counter-pwa.md` - Minor cleanup to root layout metadata and service worker registration - Small layout fix for collection pool row text truncation Orders submitted via the PWA appear immediately in the main CRM's New tab, and the app is designed for trusted office kiosk phones without requiring user login.
4.8 KiB
4.8 KiB
Counter PWA — install + use
A standalone, installable web app on the office counter phones. One tap, no login, and the order lands on the New tab of the order board.
What it does
- Pick an existing customer (search by name, email, or phone) — or tap Add new to create a customer inline (and a new company in the same sheet if needed).
- Add any number of line items (description, qty, optional price).
- Snap photos with the phone camera (up to 10 per order).
- Tap Submit Order — the order appears on
/ordersunder the New tab immediately (via PocketBase realtime).
Install on a counter phone
iPhone (Safari)
- Open
https://<your-coolify-host>/new-orderin Safari. - Tap Share → Add to Home Screen.
- Confirm the name "Counter". The icon appears on the home screen.
- Tap the icon — it opens full-screen, no address bar.
Android (Chrome)
- Open the URL in Chrome.
- Tap the ⋮ menu → Install app (or "Add to Home Screen").
- Confirm. The icon appears in the launcher.
- Tap the icon — it opens full-screen.
The same shortcut URL works: https://<host>/counter redirects to /new-order.
What runs where
| Layer | What |
|---|---|
| Browser (phone) | /new-order — single-screen form, no login |
| Next.js route handlers | /api/counter/* — public, no Bearer token |
src/lib/server/counter-service.ts |
Thin service layer; calls existing createOrder(), createCustomer(), createCompany() |
| PocketBase | orders row + order_items rows with item_status="pending" (lands on New tab) + photos on orders.order_attachements |
The counter routes intentionally do not go through the same Bearer-token
gate as /api/v1/* — the counter phones are kiosk-mode and assumed to be on
office Wi-Fi.
Smoke test after deploy
npm run dev→ openhttp://<host>:3000/new-orderfrom the dev machine.- Pick an existing customer, add one line item, hit Submit.
- Open
/ordersin the main app — confirm the new order sits on the New tab. - Submit again, this time with a photo. Confirm the photo opens from the
order detail page (
/orders/<id>). - From an iPhone on the same Wi-Fi, open the same URL → Add to Home Screen → confirm the standalone icon works.
Troubleshooting
- Order doesn't appear on the board. Check Coolify logs for
/api/counter/orders— PB admin SDK auth (PB_ADMIN_EMAIL/PB_ADMIN_PASSWORD) must be set in.env.local. - Photos rejected with 413. The phone uploaded a file > the cap.
Default
COUNTER_MAX_PHOTO_MB=8. Drop it lower if your network is slow, or compress on the client (not implemented yet). - Customer combobox empty. The
/api/counter/customersendpoint failed on first load — see toast in the top-right and check the browser console. - "Photo upload failed" after submit. The order was saved (it appears on the board) but the photos didn't make it. Open the order in the main CRM and re-attach from there.
- Sheet won't open on iPhone 16+. Some iOS versions need a user-tap to
fire
<input capture>. The form provides two buttons (camera + gallery) so the operator can fall back to gallery.
Files added / changed
src/app/(counter)/layout.tsx new
src/app/(counter)/shell.tsx new
src/app/(counter)/page.tsx new (redirect)
src/app/(counter)/new-order/page.tsx new
src/app/(counter)/new-order/components/ new dir
header.tsx
counter-select.tsx
new-customer-sheet.tsx
items-list.tsx
photo-capture.tsx
success-screen.tsx
src/lib/server/counter-service.ts new
src/app/api/counter/customers/route.ts new
src/app/api/counter/companies/route.ts new
src/app/api/counter/orders/route.ts new
src/app/api/counter/orders/[id]/attachments/route.ts new
public/manifest-counter.json new
public/sw-counter.js new
src/components/service-worker-registration.tsx edited (dual SW)
src/app/layout.tsx edited (cleanup)
next.config.ts edited (/counter redirect)
.env.local edited (COUNTER_MAX_PHOTO_MB)
Out of scope (intentionally)
- No login / PIN — phones are physically controlled by staff.
- No offline-queue — a flaky network at submit time means the order is lost. The PWA caches the page chrome so navigation stays fast, but a pending-submit queue would be a separate feature.
- No per-user audit (rep picker left blank — rep can be set later in the main CRM process page).
- No quote linking — counter orders are standalone.