18 · Customers CRM & storefront
Who customers are in the tenant DB, staff CRM, customer self-service login, and the public online store that reuses the POS cart/finalize spine.
How customers sit in the platform
flowchart TB
CRM[(Customers · tenant main)]
POS[POS cart · customerId]
LOY[LoyaltyAccount]
GC[Gift card optional customerId]
TIX[Service tickets · portal]
SF[Storefront order]
AP[Appointments]
INV[Invoices]
CRM --> POS
CRM --> LOY
CRM --> GC
CRM --> TIX
CRM --> AP
POS --> INV
SF --> POS
SF -.->|optional login| CRM
Same person can be staff-CRM customer, loyalty member, ticket requester, and storefront shopper — linkage quality depends on email/phone match and whether POS attaches them at sale time.
Staff CRM
| Surface | Path |
|---|---|
| Customer list | /customers |
| Create / edit | /customers/new · /customers/:id |
| POS search/attach | Modern/Mobile customer search → cart attach |
API — /api/customers
Session + tenantResolver. Direct SQL multi-tenant.
| Method | Path | Purpose |
|---|---|---|
| GET | /search | Quick POS search (name/email/phone) |
| GET | / | List |
| GET | /:id | Detail |
| POST | / | Create |
| PUT/PATCH | /:id | Update |
| DELETE | /:id | Delete |
| GET | /:id/stats | Per-customer stats |
Record shape (core)
orgId, name, email, phone, notes, metadata/address — table Customers on tenant main DB.
Also: /api/simple simple-customers (search/list) — lighter path used in some tools.
Customer-facing accounts
| Surface | Path | Role |
|---|---|---|
| Register | /:tenantSlug/customer/register | Create account |
| Login | /:tenantSlug/customer/login | Customer session |
| Dashboard | /:tenantSlug/customer/dashboard | CustomerProtected shell |
API — mounted at /customer
| Path | Purpose |
|---|---|
POST /customer/register | Public registration (password) |
POST /customer/login | Public login → session.customer |
…/customer/tickets | Logged-in customer ticket list/create/comments |
/customer.
They should join on email/tenant; do not assume every CRM row has a portal password.
Customer analytics
/api/customer-analytics (session + tenant)
GET /:customerId— detail analyticsGET /insights/overview· segments · products
Feeds marketing-style insights; separate from sales reports main DB path (see analytics gaps in audit).
Storefront (online store)
| Surface | Path |
|---|---|
| Public shop | /:tenantSlug/store · /embed/store · staff preview /store |
| Admin settings | /admin/storefront |
Config (tenant)
Table-ish storefront_settings via /api/storefront:
- enabled, storeName/description, colors, logo, custom CSS/JS
- productsPerPage, currency, taxIncluded, shippingEnabled
allowGuestCheckout,requireAccountshopCatalogId— full catalog when no menu assignment- Menu items from catalog assignments targeting storefront
Public APIs
| Method | Path | Auth |
|---|---|---|
| GET | /api/storefront/:tenantSlug/config | Public |
| GET | /api/storefront/:tenantSlug/menu-items | Public |
| DELETE | …/carts/:cartId/items/:lineId | Storefront cart helper |
| GET/PUT | /api/storefront/config | Session admin |
Storefront checkout path
flowchart TD
CFG[Load public config + menu-items]
CART[pos.createCart / posApi cart ops]
ADD[addItems · tip · tender card/crypto]
FIN[posApi.finalize]
INV[Core Invoicing]
CFG --> CART --> ADD --> FIN --> INV
/api/pos/* is mounted with requireSessionAuth.
Storefront UI calls those endpoints. True anonymous public checkout only works if something
establishes a session (staff preview, kiosk device flow, or a future guest/session design).
allowGuestCheckout is stored and returned in config; it is not
a server-side gate inside pos.routes createCart/finalize (audit S9-4b).
Gaps & product notes
| Item | Notes |
|---|---|
| Guest checkout enforcement | Config flag vs POS session requirement — reconcile for real public e-com |
| CRM ↔ portal account | Unify identity so loyalty works after storefront login |
| Storefront gift/loyalty tenders | UI path is mainly card/crypto; gift/loyalty stronger on Modern POS |
| Shipping | Flag exists; not a full fulfillment engine in this pass |
| Master-admin “customers” placeholder | Tenant CRM is under /customers, not master-admin customers tile |
File anchors
| Concern | Path |
|---|---|
| Customers API | backend/routes/customers.routes.js |
| Public customer | public-customer.routes.js · mount /customer |
| Simple customers | simple-customers.routes.js |
| Analytics | customerAnalytics.routes.js · service |
| Staff CRM UI | pages/customers/Customers.jsx · CustomerEditor.jsx |
| Customer portal UI | CustomerLogin/Register · CustomerDashboard.jsx |
| Storefront API | storefront.routes.js |
| Storefront UI | pages/store/Storefront.jsx |
| Admin settings | StorefrontSettings.jsx |
| OAO | 19-storefront.html |