Vendors / Open source & self-hostable
nutrixpos / pos
The most modern stack in this batch — Go plus React with an explicitly REST-API-first architecture — and verifiably alive with release v0.13.0 published 2026-05-09 and commits through 2026-07-17, but its own README warns it is in active development with no stable release and no guaranteed backward compatibility.
scored live legacy rubric
- Claims in scope
- 278
- Scored
- 45
- Assessed
- 41
- Unknown
- 237
- Not applicable
- 36
- Cells challenged
- 0
unknown, never as no.Identity
- Owner
- nutrixpos (independent open-source project, GPL-2.0; docs at nutrixpos.com)
- Who it is for
- Small restaurants, cafes and shops wanting a modern self-hosted Go/React POS with a REST-API-first architecture rather than a Java desktop app
- Site
- https://github.com/nutrixpos/pos
Pricing
transparency: unknown · unit: free (GPL-2.0, self-hosted; MongoDB required) · processor lock-in: no
- Software
- Free and open source under GPL-2.0, self-hosted via Docker Compose or a Windows executable with MongoDB. No published commercial tiers, hosting plans, or per-terminal fees.
Capabilities
Every claim is binary and checkable. Grades: A primary documentation · B product documentation · C pricing or feature page · D marketing claim · E third-party reporting · F inference with no source. A yes on a differentiator claim requires A or B.
Order capture & FOH workflow
order-capture-floor-plan-editor
Not scored by this record.
order-capture-seat-level
Not scored by this record.
order-capture-coursing-hold-fire
Not scored by this record.
order-capture-split-merge
The complete OpenAPI path list contains no split, merge or partial-tender resource. POST /orders/{id}/pay declares no request body, and its handler calls PayUnpaidOrder(order_id), which marks the whole order paid. The Order model carries a single IsPaid bool and one PaymentSource string, with no parent/child order reference, seat number or table field. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/specs.api.yaml · retrieved 2026-08-03
order-capture-bar-tab-preauth differentiator
Not scored by this record.
order-capture-transfer-audit
Not scored by this record.
order-capture-native-handheld
Not scored by this record.
order-capture-offline-order-entry
Self-hosted, but it is a client/server web app against MongoDB; no offline-capable terminal client or offline matrix is documented.
order-capture-qr-same-check differentiator
Not scored by this record.
order-capture-kiosk-first-party differentiator
Not scored by this record.
order-capture-drive-thru
Not scored by this record.
order-capture-drive-thru-timers
Not scored by this record.
order-capture-voice-ai differentiator
Not scored by this record.
order-capture-throttling differentiator
Not scored by this record.
order-capture-scheduled-orders
Order carries SubmittedAt, StartedAt, IsAutoStart and IsAutoFinish and no scheduled-for, promise-time or fire-time field; a repo-wide search for "scheduled" returns nothing. OrderSettings holds only queue prefix/next counters and a default cost-calculation method, so there is no per-channel lead time to compute a fire time from. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-03
order-capture-catering
Not scored by this record.
order-capture-order-ready-signal differentiator
Not scored by this record.
order-capture-void-comp-controls
Not scored by this record.
Menu, modifiers & pricing engine
menu-pricing-nested-modifiers
The Product struct is {Materials, SubProducts, Entries, Price, ImageURL, Unit, Quantity, Ready, EnableInventoryConsumption, EnableFixedCost, FixedCost} — there is no modifier-group entity. SubProducts are sub-recipes with a quantity, consumed by GetRecipeTree for BOM costing, not guest-selectable option groups. Repo-wide search finds no min/max selection count, no required/forced flag and no occurrence of "modifier", "option group", "addon" or "topping". https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-03
menu-pricing-modifier-price-by-parent-size
No modifier entity exists to price, and no size or variant entity exists to price it against: Product carries exactly one Price float64 and one Unit string. There is no price matrix, override table or parent-item-scoped price anywhere in the model package or the OpenAPI Product schema. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-03
menu-pricing-fractional-placement differentiator
Not scored by this record.
menu-pricing-half-and-half-rule differentiator
Not scored by this record.
menu-pricing-topping-quantity-tiers
OrderItem carries a bare Quantity float64 with no tier, level or multiplier field, and no modifier entity exists to tier. Repo-wide search finds no "light", "extra", "double" or price-multiplier construct in either the Go models or the Vue ordering page. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-03
menu-pricing-size-style-matrix differentiator
Not scored by this record.
menu-pricing-included-allowance differentiator
Not scored by this record.
menu-pricing-combos
Not scored by this record.
menu-pricing-upsell-prompts differentiator
Not scored by this record.
menu-pricing-86-propagation
Not scored by this record.
menu-pricing-countdown-auto-86 differentiator
Not scored by this record.
menu-pricing-dayparting
Not scored by this record.
menu-pricing-channel-price-books
Not scored by this record.
menu-pricing-dual-pricing differentiator
Not scored by this record.
menu-pricing-allergen-nutrition
Not scored by this record.
menu-pricing-recipe-linkage differentiator
Not scored by this record.
menu-pricing-3p-menu-push
Not scored by this record.
menu-pricing-dynamic-pricing
Not scored by this record.
Payments & money movement
payments-processor-choice differentiator
Not scored by this record.
payments-published-rates differentiator
Not scored by this record.
payments-dual-pricing differentiator
Not scored by this record.
payments-surcharge-guardrails differentiator
Not scored by this record.
payments-emv-nfc
Open-source software project with no first-party payment terminal line; nothing to certify for EMV or NFC. https://github.com/nutrixpos/pos · retrieved 2026-08-01
payments-softpos-tap-to-pay differentiator
Not scored by this record.
payments-pay-at-table
Not scored by this record.
payments-qr-guest-pay differentiator
Not scored by this record.
payments-tip-adjust
Not scored by this record.
payments-tip-pooling differentiator
Not scored by this record.
payments-offline-store-and-forward differentiator
Not scored by this record.
payments-offline-decline-liability differentiator
Not scored by this record.
payments-gift-cards
Tender handling is the PaymentSource struct — a list of {name} labels configured in Settings and stamped onto Order.PaymentSource as a free string. There is no card, balance, ledger or redemption entity in the model package and no gift-card resource in the complete OpenAPI path list, so nothing tracks a balance. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/settings.go · retrieved 2026-08-03
payments-house-accounts
Not scored by this record.
payments-split-tender
Not scored by this record.
payments-refund-void-controls
Refund and waste are role-gated — POST /orders/{order_id}/items/{item_id}/refund and .../waste are wrapped in AllowAnyOfRoles("admin","cashier") — a reason query parameter is mandatory (400 without it), and each writes a LogOrderItemRefund / LogWasteOrderItem row. Shortfall: a cashier refunds unilaterally, since no manager-approval or override endpoint exists in the route table; Order.Discount is an unauthorised free field set at submit time; and the audit row is not attributable by default, because every handler initialises user_id := "0" and overwrites it only when config.Zitadel.Enabled, which is off in the shipped config. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/handlers/order.go · retrieved 2026-08-03
payments-chargeback-tooling differentiator
Not scored by this record.
payments-card-on-file differentiator
Not scored by this record.
payments-payout-timing differentiator
Not scored by this record.
payments-p2pe-pci4
Not scored by this record.
Kitchen & production
kitchen-station-routing
There is no station entity anywhere in the product: a repo-wide, case-insensitive search for "station" across the Go backend, the OpenAPI spec and the Vue frontend returns zero hits. Kitchen.vue is the whole KDS — it GETs /api/orders?filter[state]=!finished&filter[state]=!stashed, i.e. every open order with no item, category, order-type or station filter, and displayOrders() merely deals them round-robin into screen-width columns. Settings enumerates exactly two printers, ClientReceiptPrinter and KitchenReceiptPrinter, each a PrinterSettings{Host} with one host, so there is no second kitchen target to route to either. The vendor's own docs landing page describes Kitchen as "On demand simple interface for displaying and finishing orders, to be used inside the kitchen". https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/src/pages/Kitchen.vue · retrieved 2026-08-04
kitchen-expo-consolidation
There is no prep-station entity. Settings holds exactly one KitchenReceiptPrinter{Host}, and the Kitchen page renders whole orders as QueueOrder cards in wrap columns with a single order-level finish action (POST /orders/{id}/finish). With no stations to route to, there is nothing for an expo view to consolidate and no per-station bump state to wait on. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/settings.go · retrieved 2026-08-03
kitchen-course-firing differentiator
Not scored by this record.
kitchen-prep-time-pacing differentiator
Not scored by this record.
kitchen-order-throttling differentiator
Not scored by this record.
kitchen-channel-pause-propagation differentiator
Not scored by this record.
kitchen-order-ready-callback differentiator
Not scored by this record.
kitchen-bump-bar-hardware
The KDS is a Vue browser route driven entirely by PrimeVue buttons and dialogs (click/touch). There is no keyboard, HID, serial or bump-bar handling anywhere in the frontend, no key-mapping configuration in Settings, and the vendor publishes no supported-hardware list — nutrixpos.com carries only Installation, Architecture and docker-compose pages. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/src/pages/Kitchen.vue · retrieved 2026-08-03
kitchen-all-day-counts
Not scored by this record.
kitchen-sla-alerts
Not scored by this record.
kitchen-printer-fallback differentiator
Not scored by this record.
kitchen-offline-operation differentiator
Not scored by this record.
kitchen-item-build-screens differentiator
Not scored by this record.
kitchen-pizza-fractional-display differentiator
Not scored by this record.
kitchen-recall-refire
Not scored by this record.
kitchen-order-modification-alerts differentiator
Not scored by this record.
kitchen-guest-ready-notification differentiator
Not scored by this record.
kitchen-waste-logging
Not scored by this record.
kitchen-speed-of-service-reporting
Not scored by this record.
kitchen-prep-forecasting
Not scored by this record.
Delivery, dispatch & third-party channels
delivery-driver-roster
Delivery carries no driver at all: OrderDeliveryInfo is {ReceiverName, Address, PhoneNumber}, stamped onto the order for receipt printing, and Order has no driver, assignment-state or run field. A repo-wide case-insensitive search for "driver" matches only the mongo-driver library import, the only staff roles compiled into the route table are superuser, admin, cashier and chef, and no clock-in/out or time-entry construct exists anywhere in the codebase for a driver to use, so drivers are not an entity of any kind, let alone a first-class one with run history. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-04
delivery-dispatch-board
Delivery is an IsDelivery bool plus OrderDeliveryInfo{ReceiverName, Address, PhoneNumber} printed onto the receipt. There is no driver entity, no assignment field, no elapsed-time or run/batch construct, and the frontend router’s complete page list (Home, Kitchen, Admin > inventory/sales/products/categories/orders/settings/customers/users, Hubsync, Login, Setup, Profile, Languages) contains no dispatch screen. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-03
delivery-route-map differentiator
Not scored by this record.
delivery-driver-tracking differentiator
Not scored by this record.
delivery-zones-polygon differentiator
Not scored by this record.
delivery-zone-pricing
No zone entity exists in the model package or the OpenAPI schema list. Delivery addresses are a free-text Address string with no validation or geocoding, and neither Order nor Settings carries a delivery fee, order minimum or quoted promise-time field, so nothing can be applied per zone. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-03
delivery-address-validation
Not scored by this record.
delivery-driver-comp differentiator
Not scored by this record.
delivery-cash-reconcile
Not scored by this record.
delivery-daas-dispatch
Not scored by this record.
delivery-daas-fallback differentiator
Not scored by this record.
delivery-3p-direct-integration differentiator
Not scored by this record.
delivery-3p-injection
Not scored by this record.
delivery-menu-push
Not scored by this record.
delivery-86-sync
Not scored by this record.
delivery-store-pause
Not scored by this record.
delivery-3p-reconciliation differentiator
Not scored by this record.
delivery-injection-error-visibility differentiator
Not scored by this record.
delivery-tracking-page
Not scored by this record.
delivery-promise-time differentiator
Not scored by this record.
delivery-offline-behavior
Not scored by this record.
Digital ordering & guest-facing channels
digital-first-party-web
No guest-facing ordering site ships: every route in the frontend router is staff-facing and role-guarded (/, /kitchen, /admin/*, /login, /setup, /admin-setup, /profile, /no-access), and order creation is POST /api/orders wrapped in AllowAnyOfRoles("admin","cashier"), so an unauthenticated web guest has no path that writes an order. The nutrixpos GitHub organisation holds only pos, posui (archived), docs and devops — no ordering-site product — and nutrixpos.com's feature list is Cashier, Kitchen, Inventory and Reports with no online-ordering mention. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/src/router/index.ts · retrieved 2026-08-04
digital-menu-single-source
There is no first-party digital ordering channel for a menu to propagate to. Every route in the router is staff-facing and role-guarded (/, /kitchen, /admin/*, /login, /setup, /admin-setup, /profile, /no-access), and the nutrixpos GitHub organisation contains only four repositories — pos, posui (archived 2025-08-08), docs and devops — with no guest ordering client among them. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/src/router/index.ts · retrieved 2026-08-03
digital-native-app differentiator
Not scored by this record.
digital-account-saved-payment
The Customer struct is {Id, Name, Phone, Address} — no credentials, no email, no address book, no tokenised payment instrument and no order-history link. There is no guest authentication path (the auth module issues staff JWTs with superuser/admin/cashier/chef roles) and no guest-facing channel in which to reorder. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-03
digital-upsell-engine differentiator
Not scored by this record.
digital-scheduled-pacing
Not scored by this record.
digital-fulfillment-modes
Not scored by this record.
digital-qr-table
Not scored by this record.
digital-kiosk differentiator
Not scored by this record.
digital-group-ordering
Not scored by this record.
digital-catering-portal differentiator
Not scored by this record.
digital-voice-ai-phone differentiator
Not scored by this record.
digital-drivethru-ai
Not scored by this record.
digital-sms-ordering
Not scored by this record.
digital-google-order differentiator
Not scored by this record.
digital-apple-business-connect
Not scored by this record.
digital-loyalty-attach
Not scored by this record.
digital-subscriptions
Not scored by this record.
digital-promo-parity
Not scored by this record.
digital-guest-data-ownership differentiator
Not scored by this record.
digital-checkout-pci-sca
Not scored by this record.
digital-surcharge-transparency differentiator
Not scored by this record.
Guest data, loyalty & marketing
guest-loyalty-unified-profile
Customer is {Id, Name, Phone, Address} and is embedded into Order by value; there is no identity-match, dedup or merge logic in customers.go, no email field to match on, and no loyalty entity. There is also nothing to unify: the product ships no first-party web/app ordering and no kiosk channel, so all transactions originate from the in-store terminal. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-03
guest-loyalty-thirdparty-identity-attach differentiator
Not scored by this record.
guest-loyalty-accrual-models
None of the three accrual models exists, natively or otherwise: a repo-wide search returns zero occurrences of "loyalty", "reward", "points" or "punch"; Customer is {Id, Name, Phone, Address} with no balance, visit counter or tier field; and the complete OpenAPI path list (categories, materials, orders, products, salesperday, settings, languages, customers) has no loyalty resource. Settings holds printers, order-queue counters and payment-source labels — there is nothing in which an accrual rule could be configured. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/specs.api.yaml · retrieved 2026-08-04
guest-loyalty-tiers differentiator
Not scored by this record.
guest-loyalty-offline-behavior differentiator
Not scored by this record.
guest-loyalty-offer-stacking-rules differentiator
Not scored by this record.
guest-loyalty-targeted-offers differentiator
Not scored by this record.
guest-loyalty-rfm-segmentation differentiator
Not scored by this record.
guest-loyalty-lifecycle-automation
The complete OpenAPI path list is categories, materials, orders, products, salesperday, settings, languages and customers — there is no campaign, segment, message, offer or automation resource. Repo-wide search returns zero occurrences of "loyalty" or "reward", and the only outbound messaging in the codebase is the in-app WebSocket topic feed. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/specs.api.yaml · retrieved 2026-08-03
guest-loyalty-native-email-sms differentiator
Not scored by this record.
guest-loyalty-consent-management
Not scored by this record.
guest-loyalty-10dlc-registration
Not scored by this record.
guest-loyalty-campaign-attribution differentiator
Not scored by this record.
guest-loyalty-data-export-portability differentiator
Not scored by this record.
guest-loyalty-review-capture-routing differentiator
Not scored by this record.
guest-loyalty-referral-program
Not scored by this record.
guest-loyalty-wallet-pass differentiator
Not scored by this record.
guest-loyalty-privacy-rights-tooling
Not scored by this record.
guest-loyalty-redemption-fraud-controls
Not scored by this record.
guest-loyalty-ai-offer-recommendation differentiator
Not scored by this record.
guest-loyalty-stored-value-gift
Not scored by this record.
Labor & workforce
labor-clock-in-at-pos
No time clock exists to clock into: the auth module's User model is {ID, Username, Email, PasswordHash, Roles, CreatedAt, UpdatedAt} — no PIN or badge field — and sign-on is a username/password JWT login (LoginRequest{Username, Password}). A repo-wide search for clock, punch, shift, timesheet or time-entry code returns nothing beyond two "pi pi-clock" icon classes, and the complete OpenAPI path list has no time-entry or shift resource, so worked hours cannot be recorded at the terminal at all. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/auth/models/user.go · retrieved 2026-08-04
labor-photo-punch-verification differentiator
Not scored by this record.
labor-offline-time-punch differentiator
Not scored by this record.
labor-granular-rbac
Permissions are compiled into the route table, not granted by the operator: every route is wrapped in auth_svc.AllowAnyOfRoles(handler, ...) against four hardcoded tiers — "superuser", "admin", "cashier", "chef" (refund is ("admin","cashier"); user management is ("superuser")). Roles is a free string list on User, but a new role name matches no route and therefore grants nothing. There is no per-action grant, no permission entity, and no location dimension. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/core.go · retrieved 2026-08-03
labor-manager-override-audit
No manager-override or approval mechanism exists: the complete route table has no approve, override or authorise endpoint, and refunds, wastes, cancels and discounts are executed directly by the acting cashier role. The Log struct does carry a UserId, but every handler initialises user_id := "0" and replaces it only inside if config.Zitadel.Enabled, so under the shipped internal-JWT auth every refund, waste and disposal row is attributed to user_id "0". https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/handlers/order.go · retrieved 2026-08-03
labor-native-scheduling differentiator
Not scored by this record.
labor-demand-labor-forecast differentiator
Not scored by this record.
labor-realtime-labor-percent differentiator
Not scored by this record.
labor-overtime-prevention differentiator
Not scored by this record.
labor-break-compliance-by-state differentiator
Not scored by this record.
labor-minor-labor-rules
Not scored by this record.
labor-tip-pooling-rules
Not scored by this record.
labor-tip-distribution-audit-trail
Not scored by this record.
labor-qualified-tips-w2-reporting differentiator
Not scored by this record.
labor-native-payroll differentiator
Not scored by this record.
labor-payroll-export-formats
Not scored by this record.
labor-shift-swap-workflow differentiator
Not scored by this record.
labor-server-performance-metrics differentiator
Not scored by this record.
Inventory, purchasing & cost control
inventory-recipe-bom-costing
README states it manages inventory, sales and products for a restaurant, but multi-level sub-recipe costing is not documented.
inventory-unit-conversion-yields
Material carries a single Unit string, and MaterialEntry records PurchaseQuantity and PurchasePrice in that same unit; average cost is computed as sum(PurchasePrice/PurchaseQuantity)/n. There is no purchase/recipe/count unit triple, no conversion-factor field, and no yield or waste-percentage field on Material, MaterialEntry or Product. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-03
inventory-theoretical-vs-actual differentiator
Not scored by this record.
inventory-realtime-depletion differentiator
Not scored by this record.
inventory-86-auto-sync differentiator
Not scored by this record.
inventory-count-modes
The complete material path list is /materials, /materials/{id}, /materials/{id}/entries, /materials/{material_id}/entries/{entry_id}, .../cost and /materials/{id}/logs — there is no count, stocktake or adjustment resource. On-hand is derived by summing entry quantities less consumption; corrections are made by adding an entry or a disposal. Nothing records a count event, so there is no per-count variance history to keep separate. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/specs.api.yaml · retrieved 2026-08-03
inventory-mobile-count-offline
Not scored by this record.
inventory-vendor-catalogs-edi differentiator
Not scored by this record.
inventory-invoice-ocr differentiator
Not scored by this record.
inventory-price-change-alerts differentiator
Not scored by this record.
inventory-par-auto-suggest differentiator
Not scored by this record.
inventory-waste-logging
Not scored by this record.
inventory-shelf-life-expiry
Not scored by this record.
inventory-bar-partial-bottle
Not scored by this record.
inventory-cogs-gl-export
Not scored by this record.
inventory-native-not-partner differentiator
Not scored by this record.
inventory-menu-margin-linkage differentiator
Not scored by this record.
Reporting, BI & data access
reporting-realtime-dashboard
A browser dashboard exists and is current: Sales.vue renders a sales/cost/refunds/returns/profit line chart, a product-mix pie chart and a paginated sales log with CSV export, fed by GET /api/logs/salesperday, which queries the MongoDB "sales" collection at request time; FinishOrder calls SalesService.AddOrderToSalesDay, which upserts today's document on order completion, so a finished sale is readable immediately. Three shortfalls: there is no mobile app — frontend/package.json declares no Capacitor, Cordova, React Native or PWA plugin and the org's only repos are pos, posui (archived), docs and devops; the dashboard never auto-refreshes, since loadSales() runs once at mount and Sales.vue opens no WebSocket, so it updates only on manual reload or repaging; and the sales collection is keyed on date formatted "2006-01-02", so the charts have whole-day granularity with no intraday view. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/src/pages/Sales.vue · retrieved 2026-08-04
reporting-eod-closeout
GET /logs/salesperday returns a SalesPerDay row per day — date, orders, refunds, costs, total_sales, refunds_value — and GET /logs/salesperday/exportcsv emits Id, Display Id, Date, Cost, Sale Price, Payment Source, Refunds Value, Profit. Shortfall: it is a sales-and-margin day list, not a close-out packet. There is no tax field anywhere in the codebase (repo-wide search for tax/VAT returns nothing), no tips or discount totals in the day aggregate, no tender-type subtotals, and no expected-cash-deposit or drawer reconciliation — the only drawer feature is an auto_open_cash_drawer toggle. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/handlers/sales.go · retrieved 2026-08-03
reporting-pmix-modifier-level
The Sales page builds a product mix pie chart by walking loaded orders and summing order.items[k].quantity keyed on product.name. Shortfall: it is client-side aggregation over the currently loaded page of days only, carries quantity but no gross or net sales column, has no modifier level (no modifier entity exists in the product model), and offers no daypart or revenue-centre filter — the only server-side grouping is by calendar day. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/src/pages/Sales.vue · retrieved 2026-08-03
reporting-comps-voids-audit
Not scored by this record.
reporting-cash-over-short
Not scored by this record.
reporting-labor-productivity
Not scored by this record.
reporting-server-scorecards differentiator
Not scored by this record.
reporting-channel-profitability differentiator
Not scored by this record.
reporting-scheduled-delivery
Not scored by this record.
reporting-public-api differentiator
Not scored by this record.
reporting-webhooks differentiator
Not scored by this record.
reporting-api-not-upcharged differentiator
Not scored by this record.
reporting-tier-paywall differentiator
Not scored by this record.
reporting-history-retention differentiator
Not scored by this record.
reporting-anomaly-alerts differentiator
Not scored by this record.
reporting-nl-query
Not scored by this record.
reporting-guest-cohorts differentiator
Not scored by this record.
reporting-sales-forecast differentiator
Not scored by this record.
reporting-tip-tax-compliance
Not scored by this record.
Multi-location, franchise & enterprise governance
multi-location-org-hierarchy
Checked the full Go model package, the complete OpenAPI path list and the frontend router: there is no location, branch, site, tenant or group entity, Settings is a single global document, and no report or permission is scoped to a location. The only above-store construct is the hubsync module, which pushes this instance’s materials and sales to a hub host using one bearer token and no hierarchy object. Whether the receiving hub models an enterprise > region > location hierarchy could not be determined: hub.nutrixpos.com returns an unrendered Vite/Vue SPA shell with no readable text, the nutrixpos GitHub organisation contains no hub repository (only pos, posui, docs, devops), and nutrixpos.com publishes only Installation, Architecture and docker-compose pages, none of which mention multiple locations.
multi-location-central-menu-publish
Hubsync is outbound only: SyncInventory issues PUT {host}/v1/api/inventories and UploadSalesToServer issues POST {host}/v1/api/logs on a timer. The module registers exactly two HTTP routes of its own, both /api/settings, so an instance exposes no inbound path on which a corporate menu could be received, and the core API has no bulk product-import or publish endpoint. There is consequently no publish/version history. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/hubsync/services/syncer.go · retrieved 2026-08-03
multi-location-price-zones
Product carries one Price float64 with no channel, daypart, location-group or price-tier dimension, and no separate price-list entity exists in the model package or the OpenAPI schema list. Order records IsDelivery/IsTakeAway/IsDineIn but no revenue centre, and nothing in the pricing path reads those flags — the receipt totals from item.SalePrice alone. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go · retrieved 2026-08-03
multi-location-consolidated-reporting
Not scored by this record.
multi-location-cross-location-giftcard
Not scored by this record.
multi-location-cross-location-loyalty
Not scored by this record.
multi-location-multi-brand differentiator
Not scored by this record.
multi-location-multi-tax-jurisdiction
Not scored by this record.
multi-location-central-labor-policy
Not scored by this record.
Hardware & physical footprint
hardware-commodity-devices differentiator
Not scored by this record.
hardware-os-platforms
Install guide documents a Windows executable and Docker Compose deployment with MongoDB; no minimum OS versions or client device specs. https://nutrixpos.com/userguide/installation.html · retrieved 2026-08-01
hardware-handheld-purpose-built
Not scored by this record.
hardware-handheld-battery-swap differentiator
Not scored by this record.
hardware-handheld-lte
Not scored by this record.
hardware-offline-mode
The product is on-premise self-hosted (a Go binary or docker-compose against a local MongoDB), so a WAN outage does not by itself stop the terminal, the kitchen printer or cash sales — the whole stack is on the LAN. Shortfall: there is no client-side resilience and no published degradation matrix. The frontend declares no PWA, service-worker, Workbox or IndexedDB dependency and has no offline code path (localStorage is used only for the auth token and colour mode), so a server or LAN interruption stops order entry outright, and nutrixpos.com documents nothing about offline behaviour on any of its three pages. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/package.json · retrieved 2026-08-03
hardware-kds
A first-party, touch-operated KDS screen exists: Kitchen.vue is a Vue browser route that subscribes to the WebSocket feed (reacting to order_submitted and order_finished), loads every open order via /api/orders?filter[state]=!finished&filter[state]=!stashed into QueueOrder cards, and finishes an order with an on-screen confirm button that POSTs /orders/{id}/finish. Shortfall: display-and-finish is the entire feature — no station routing (no station entity anywhere in the repo), no course or fire timing (no course, fire or hold construct; Order carries only IsAutoStart/IsAutoFinish), no bump-bar support (PrimeVue click/touch only, no keyboard or HID handling), and no dedicated hardware — it runs on whatever browser device the operator supplies. The vendor's own docs describe it as an "on demand simple interface for displaying and finishing orders". https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/src/pages/Kitchen.vue · retrieved 2026-08-04
hardware-kiosk differentiator
Not scored by this record.
hardware-drive-thru
Not scored by this record.
hardware-printer-compatibility
Not scored by this record.
hardware-peripherals
Not scored by this record.
hardware-p2pe-terminal
Not scored by this record.
hardware-tap-to-phone differentiator
Not scored by this record.
hardware-pricing-transparency differentiator
Not scored by this record.
hardware-ownership-vs-lease differentiator
Not scored by this record.
hardware-usable-after-churn differentiator
Not scored by this record.
hardware-rma-sla differentiator
Not scored by this record.
hardware-byod
Not scored by this record.
hardware-remote-device-management differentiator
Not scored by this record.
hardware-selfpour-scales
Not scored by this record.
hardware-callerid-integration
Not scored by this record.
Integrations, API & extensibility
extensibility-public-api-docs
Publicly readable docs site and pkg.go.dev Go reference with an advertised REST API architecture; a complete endpoint reference was not verifiable. https://github.com/nutrixpos/pos · retrieved 2026-08-01
extensibility-api-access-cost differentiator
Not scored by this record.
extensibility-free-sandbox differentiator
Not scored by this record.
extensibility-oauth-partner-apps
The OpenAPI securitySchemes block declares oidcAuth as type oauth2 with an authorizationCode flow and scopes admin, cashier and chef, implemented by the optional Zitadel integration (ZitadelAuth introspects the bearer token via CheckAuthorization). Shortfall: those "scopes" are the same coarse staff role tiers, not per-resource operator-granted permissions; there is no partner-app registry, consent screen or per-integration revocation surface anywhere in the product; and the integration is off by default (config.Zitadel.Enabled), the shipped path being a self-issued internal JWT carrying role claims rather than OAuth at all. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/specs.api.yaml · retrieved 2026-08-03
extensibility-webhooks-push
Real-time push exists but is not webhooks. A Melody WebSocket endpoint at /ws lets a client subscribe to topics, and the server pushes on exactly three: order_submitted, order_finished and expire_soon (low stock). Shortfall: there is no HTTP callback registration, no subscriber endpoint, no delivery retry, no signing secret and no replay; the feed is designed for and consumed by the bundled Vue client, and it omits modified, paid, voided and refunded order events entirely. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/services/notification_singleton.go · retrieved 2026-08-03
extensibility-webhook-reliability differentiator
Not scored by this record.
extensibility-order-injection-api
Not scored by this record.
extensibility-menu-write-api differentiator
Not scored by this record.
extensibility-doordash-preferred differentiator
Not scored by this record.
extensibility-first-party-delivery-integrations differentiator
Not scored by this record.
extensibility-middleware-compatibility
Not scored by this record.
extensibility-accounting-connectors
Not scored by this record.
extensibility-payroll-export
Not scored by this record.
extensibility-app-marketplace
Not scored by this record.
extensibility-headless-embedded
Not scored by this record.
extensibility-data-portability-exit differentiator
Not scored by this record.
Reliability, offline & operations
reliability-offline-order-entry
Because the server is on-premise, order entry, kitchen ticket printing and check printing all continue through an internet outage — they never leave the LAN. Shortfall: nothing continues on-terminal if the terminal loses the server. The frontend declares no service worker, PWA plugin or IndexedDB dependency and implements no local queue; even the "stashed"/draft order feature is server-side (a state field POSTed to /api/orders), and every action in Home.vue is a synchronous axios call that surfaces an error toast on failure. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/package.json · retrieved 2026-08-03
reliability-offline-card-auth differentiator
Not scored by this record.
reliability-offline-decline-liability differentiator
Not scored by this record.
reliability-lan-degraded-multi-terminal differentiator
Not scored by this record.
reliability-local-transaction-engine differentiator
Not scored by this record.
reliability-offline-kds-printing
Both paths are server-side and LAN-local, so they survive an internet outage: ReceiptService.Print dials the configured printer host directly on TCP 9100 and writes ESC/POS, and the KDS receives orders over the local WebSocket feed. Shortfall: neither survives loss of the server or the LAN, since the KDS is a browser page with no cached order store and the print job is initiated by the backend, and the vendor documents no offline behaviour for either. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/services/receipt.go · retrieved 2026-08-03
reliability-printer-fallback
ReceiptService.Print opens net.Dial("tcp", host+":9100") and, on failure, returns the dial error straight to the caller — there is no retry, no alternate target and no notification emitted. Settings holds exactly one ClientReceiptPrinter{Host} and one KitchenReceiptPrinter{Host}, so no backup printer or KDS station is configurable to fail over to. https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/services/receipt.go · retrieved 2026-08-03
reliability-sync-conflict-handling
Not scored by this record.
reliability-offline-feature-matrix
Not scored by this record.
reliability-public-status-page
Not scored by this record.
reliability-247-live-support
Not scored by this record.
reliability-onsite-install differentiator
Not scored by this record.
reliability-menu-build-service differentiator
Not scored by this record.
reliability-hardware-replacement-sla
Not scored by this record.
reliability-pci-dss-4-attestation
Not scored by this record.
reliability-mfa-role-based-access
Not scored by this record.
reliability-self-serve-training
Not scored by this record.
reliability-failover-terminal-role differentiator
Not scored by this record.
reliability-cellular-backup
Not scored by this record.
Commercial, compliance & data ownership
commercial-month-to-month-contract differentiator
Not scored by this record.
commercial-no-early-termination-fee differentiator
Not scored by this record.
commercial-autorenew-terms-published
GPL-2.0 software with no subscription offering, so no auto-renewal term or cancellation window exists.
commercial-processing-not-bundled differentiator
Not scored by this record.
commercial-interchange-plus-published differentiator
Not scored by this record.
commercial-rate-increase-clause differentiator
Not scored by this record.
commercial-pricing-published
Unambiguously free: GPL-2.0 licensed, self-hosted, with no commercial tier or hosted plan published. https://github.com/nutrixpos/pos · retrieved 2026-08-01
commercial-module-unbundling differentiator
Not scored by this record.
commercial-hardware-purchase-outright
No first-party hardware sold, so no mandatory lease; operators supply their own devices and printers. https://github.com/nutrixpos/pos · retrieved 2026-08-01
commercial-hardware-not-locked differentiator
Not scored by this record.
commercial-data-export-self-serve
Not scored by this record.
commercial-export-customer-and-loyalty differentiator
Not scored by this record.
commercial-post-termination-export-window differentiator
Not scored by this record.
commercial-data-ownership-clause differentiator
Not scored by this record.
commercial-pci-p2pe-tokenization
Not scored by this record.
commercial-pci-dss-4-controls
Not scored by this record.
commercial-privacy-dsar-tooling
Not scored by this record.
commercial-wcag-kiosk-accessibility differentiator
Not scored by this record.
commercial-dual-pricing-compliant differentiator
Not scored by this record.
Adversarial verification
An independent pass was instructed to refute this record, defaulting to downgrade when uncertain. It challenged 36 values — 0 upheld, 0 downgraded, 0 upgraded. This is published in full because a reader who can see which values were contested, on what evidence, and which way they moved has something no affiliate-funded comparison offers.
Capability claims
| Claim | As first scored | Verdict | What the verifier found |
|---|---|---|---|
| order-capture-split-merge | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | The complete OpenAPI path list contains no split, merge or partial-tender resource. POST /orders/{id}/pay declares no request body, and its handler calls PayUnpaidOrder(order_id), which marks the whole order paid. The Order model carries a single IsPaid bool and one PaymentSource string, with no parent/child order reference, seat number or table field. source |
| order-capture-scheduled-orders | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | Order carries SubmittedAt, StartedAt, IsAutoStart and IsAutoFinish and no scheduled-for, promise-time or fire-time field; a repo-wide search for "scheduled" returns nothing. OrderSettings holds only queue prefix/next counters and a default cost-calculation method, so there is no per-channel lead time to compute a fire time from. source |
| menu-pricing-nested-modifiers | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | The Product struct is {Materials, SubProducts, Entries, Price, ImageURL, Unit, Quantity, Ready, EnableInventoryConsumption, EnableFixedCost, FixedCost} — there is no modifier-group entity. SubProducts are sub-recipes with a quantity, consumed by GetRecipeTree for BOM costing, not guest-selectable option groups. Repo-wide search finds no min/max selection count, no required/forced flag and no occurrence of "modifier", "option group", "addon" or "topping". source |
| menu-pricing-modifier-price-by-parent-size | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | No modifier entity exists to price, and no size or variant entity exists to price it against: Product carries exactly one Price float64 and one Unit string. There is no price matrix, override table or parent-item-scoped price anywhere in the model package or the OpenAPI Product schema. source |
| menu-pricing-topping-quantity-tiers | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | OrderItem carries a bare Quantity float64 with no tier, level or multiplier field, and no modifier entity exists to tier. Repo-wide search finds no "light", "extra", "double" or price-multiplier construct in either the Go models or the Vue ordering page. source |
| payments-gift-cards | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | Tender handling is the PaymentSource struct — a list of {name} labels configured in Settings and stamped onto Order.PaymentSource as a free string. There is no card, balance, ledger or redemption entity in the model package and no gift-card resource in the complete OpenAPI path list, so nothing tracks a balance. source |
| payments-refund-void-controls | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-partial | Refund and waste are role-gated — POST /orders/{order_id}/items/{item_id}/refund and .../waste are wrapped in AllowAnyOfRoles("admin","cashier") — a reason query parameter is mandatory (400 without it), and each writes a LogOrderItemRefund / LogWasteOrderItem row. Shortfall: a cashier refunds unilaterally, since no manager-approval or override endpoint exists in the route table; Order.Discount is an unauthorised free field set at submit time; and the audit row is not attributable by default, because every handler initialises user_id := "0" and overwrites it only when config.Zitadel.Enabled, which is off in the shipped config. source |
| kitchen-expo-consolidation | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | There is no prep-station entity. Settings holds exactly one KitchenReceiptPrinter{Host}, and the Kitchen page renders whole orders as QueueOrder cards in wrap columns with a single order-level finish action (POST /orders/{id}/finish). With no stations to route to, there is nothing for an expo view to consolidate and no per-station bump state to wait on. source |
| kitchen-bump-bar-hardware | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | The KDS is a Vue browser route driven entirely by PrimeVue buttons and dialogs (click/touch). There is no keyboard, HID, serial or bump-bar handling anywhere in the frontend, no key-mapping configuration in Settings, and the vendor publishes no supported-hardware list — nutrixpos.com carries only Installation, Architecture and docker-compose pages. source |
| delivery-dispatch-board | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | Delivery is an IsDelivery bool plus OrderDeliveryInfo{ReceiverName, Address, PhoneNumber} printed onto the receipt. There is no driver entity, no assignment field, no elapsed-time or run/batch construct, and the frontend router’s complete page list (Home, Kitchen, Admin > inventory/sales/products/categories/orders/settings/customers/users, Hubsync, Login, Setup, Profile, Languages) contains no dispatch screen. source |
| delivery-zone-pricing | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | No zone entity exists in the model package or the OpenAPI schema list. Delivery addresses are a free-text Address string with no validation or geocoding, and neither Order nor Settings carries a delivery fee, order minimum or quoted promise-time field, so nothing can be applied per zone. source |
| digital-menu-single-source | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | There is no first-party digital ordering channel for a menu to propagate to. Every route in the router is staff-facing and role-guarded (/, /kitchen, /admin/*, /login, /setup, /admin-setup, /profile, /no-access), and the nutrixpos GitHub organisation contains only four repositories — pos, posui (archived 2025-08-08), docs and devops — with no guest ordering client among them. source |
| digital-account-saved-payment | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | The Customer struct is {Id, Name, Phone, Address} — no credentials, no email, no address book, no tokenised payment instrument and no order-history link. There is no guest authentication path (the auth module issues staff JWTs with superuser/admin/cashier/chef roles) and no guest-facing channel in which to reorder. source |
| guest-loyalty-unified-profile | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | Customer is {Id, Name, Phone, Address} and is embedded into Order by value; there is no identity-match, dedup or merge logic in customers.go, no email field to match on, and no loyalty entity. There is also nothing to unify: the product ships no first-party web/app ordering and no kiosk channel, so all transactions originate from the in-store terminal. source |
| guest-loyalty-lifecycle-automation | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | The complete OpenAPI path list is categories, materials, orders, products, salesperday, settings, languages and customers — there is no campaign, segment, message, offer or automation resource. Repo-wide search returns zero occurrences of "loyalty" or "reward", and the only outbound messaging in the codebase is the in-app WebSocket topic feed. source |
| labor-granular-rbac | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | Permissions are compiled into the route table, not granted by the operator: every route is wrapped in auth_svc.AllowAnyOfRoles(handler, ...) against four hardcoded tiers — "superuser", "admin", "cashier", "chef" (refund is ("admin","cashier"); user management is ("superuser")). Roles is a free string list on User, but a new role name matches no route and therefore grants nothing. There is no per-action grant, no permission entity, and no location dimension. source |
| labor-manager-override-audit | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | No manager-override or approval mechanism exists: the complete route table has no approve, override or authorise endpoint, and refunds, wastes, cancels and discounts are executed directly by the acting cashier role. The Log struct does carry a UserId, but every handler initialises user_id := "0" and replaces it only inside if config.Zitadel.Enabled, so under the shipped internal-JWT auth every refund, waste and disposal row is attributed to user_id "0". source |
| inventory-unit-conversion-yields | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | Material carries a single Unit string, and MaterialEntry records PurchaseQuantity and PurchasePrice in that same unit; average cost is computed as sum(PurchasePrice/PurchaseQuantity)/n. There is no purchase/recipe/count unit triple, no conversion-factor field, and no yield or waste-percentage field on Material, MaterialEntry or Product. source |
| inventory-count-modes | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | The complete material path list is /materials, /materials/{id}, /materials/{id}/entries, /materials/{material_id}/entries/{entry_id}, .../cost and /materials/{id}/logs — there is no count, stocktake or adjustment resource. On-hand is derived by summing entry quantities less consumption; corrections are made by adding an entry or a disposal. Nothing records a count event, so there is no per-count variance history to keep separate. source |
| reporting-eod-closeout | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-partial | GET /logs/salesperday returns a SalesPerDay row per day — date, orders, refunds, costs, total_sales, refunds_value — and GET /logs/salesperday/exportcsv emits Id, Display Id, Date, Cost, Sale Price, Payment Source, Refunds Value, Profit. Shortfall: it is a sales-and-margin day list, not a close-out packet. There is no tax field anywhere in the codebase (repo-wide search for tax/VAT returns nothing), no tips or discount totals in the day aggregate, no tender-type subtotals, and no expected-cash-deposit or drawer reconciliation — the only drawer feature is an auto_open_cash_drawer toggle. source |
| reporting-pmix-modifier-level | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-partial | The Sales page builds a product mix pie chart by walking loaded orders and summing order.items[k].quantity keyed on product.name. Shortfall: it is client-side aggregation over the currently loaded page of days only, carries quantity but no gross or net sales column, has no modifier level (no modifier entity exists in the product model), and offers no daypart or revenue-centre filter — the only server-side grouping is by calendar day. source |
| multi-location-central-menu-publish | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | Hubsync is outbound only: SyncInventory issues PUT {host}/v1/api/inventories and UploadSalesToServer issues POST {host}/v1/api/logs on a timer. The module registers exactly two HTTP routes of its own, both /api/settings, so an instance exposes no inbound path on which a corporate menu could be received, and the core API has no bulk product-import or publish endpoint. There is consequently no publish/version history. source |
| multi-location-price-zones | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | Product carries one Price float64 with no channel, daypart, location-group or price-tier dimension, and no separate price-list entity exists in the model package or the OpenAPI schema list. Order records IsDelivery/IsTakeAway/IsDineIn but no revenue centre, and nothing in the pricing path reads those flags — the receipt totals from item.SalePrice alone. source |
| hardware-offline-mode | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-partial | The product is on-premise self-hosted (a Go binary or docker-compose against a local MongoDB), so a WAN outage does not by itself stop the terminal, the kitchen printer or cash sales — the whole stack is on the LAN. Shortfall: there is no client-side resilience and no published degradation matrix. The frontend declares no PWA, service-worker, Workbox or IndexedDB dependency and has no offline code path (localStorage is used only for the auth token and colour mode), so a server or LAN interruption stops order entry outright, and nutrixpos.com documents nothing about offline behaviour on any of its three pages. source |
| extensibility-oauth-partner-apps | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-partial | The OpenAPI securitySchemes block declares oidcAuth as type oauth2 with an authorizationCode flow and scopes admin, cashier and chef, implemented by the optional Zitadel integration (ZitadelAuth introspects the bearer token via CheckAuthorization). Shortfall: those "scopes" are the same coarse staff role tiers, not per-resource operator-granted permissions; there is no partner-app registry, consent screen or per-integration revocation surface anywhere in the product; and the integration is off by default (config.Zitadel.Enabled), the shipped path being a self-issued internal JWT carrying role claims rather than OAuth at all. source |
| extensibility-webhooks-push | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-partial | Real-time push exists but is not webhooks. A Melody WebSocket endpoint at /ws lets a client subscribe to topics, and the server pushes on exactly three: order_submitted, order_finished and expire_soon (low stock). Shortfall: there is no HTTP callback registration, no subscriber endpoint, no delivery retry, no signing secret and no replay; the feed is designed for and consumed by the bundled Vue client, and it omits modified, paid, voided and refunded order events entirely. source |
| reliability-offline-order-entry | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-partial | Because the server is on-premise, order entry, kitchen ticket printing and check printing all continue through an internet outage — they never leave the LAN. Shortfall: nothing continues on-terminal if the terminal loses the server. The frontend declares no service worker, PWA plugin or IndexedDB dependency and implements no local queue; even the "stashed"/draft order feature is server-side (a state field POSTed to /api/orders), and every action in Home.vue is a synchronous axios call that surfaces an error toast on failure. source |
| reliability-offline-kds-printing | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-partial | Both paths are server-side and LAN-local, so they survive an internet outage: ReceiptService.Print dials the configured printer host directly on TCP 9100 and writes ESC/POS, and the KDS receives orders over the local WebSocket feed. Shortfall: neither survives loss of the server or the LAN, since the KDS is a browser page with no cached order store and the print job is initiated by the backend, and the vendor documents no offline behaviour for either. source |
| reliability-printer-fallback | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | ReceiptService.Print opens net.Dial("tcp", host+":9100") and, on failure, returns the dial error straight to the caller — there is no retry, no alternate target and no notification emitted. Settings holds exactly one ClientReceiptPrinter{Host} and one KitchenReceiptPrinter{Host}, so no backup printer or KDS station is configurable to fail over to. source |
| kitchen-station-routing | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | No station concept exists in the product. A case-insensitive repo-wide search for "station" across the Go modules, the OpenAPI spec and the Vue frontend returns zero hits. Kitchen.vue is the entire KDS and requests every open order unfiltered (/api/orders?filter[state]=!finished&filter[state]=!stashed), then deals them round-robin into screen-width columns; there is no per-item, per-category or per-order-type destination. Settings enumerates the printers exhaustively as ClientReceiptPrinter and KitchenReceiptPrinter, each PrinterSettings{Host} with a single host, so no second kitchen target exists to route to. source |
| reporting-realtime-dashboard | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-partial | The browser half is real and current: Sales.vue draws a sales/cost/refunds/profit line chart, a product-mix pie chart and a paginated sales log with CSV export from GET /api/logs/salesperday, which queries the "sales" collection live, and FinishOrder upserts the day's document via AddOrderToSalesDay the moment an order completes. Shortfalls: no mobile app of any kind (no Capacitor, Cordova, React Native or PWA plugin in frontend/package.json; org repos are only pos, posui archived, docs, devops); the page never auto-refreshes, as loadSales() fires once at mount with no WebSocket subscription; and the sales collection is keyed on a "2006-01-02" date string, giving whole-day granularity only. source |
| delivery-driver-roster | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | Delivery carries no driver at all: OrderDeliveryInfo is {ReceiverName, Address, PhoneNumber}, stamped onto the order for receipt printing, and Order has no driver, assignment-state or run field. A repo-wide case-insensitive search for "driver" matches only the mongo-driver library import, the only staff roles compiled into the route table are superuser, admin, cashier and chef, and no clock-in/out or time-entry construct exists anywhere in the codebase for a driver to use. source |
| digital-first-party-web | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | No guest-facing ordering site ships: every route in the frontend router is staff-facing and role-guarded (/, /kitchen, /admin/*, /login, /setup, /admin-setup, /profile, /no-access), and order creation is POST /api/orders wrapped in AllowAnyOfRoles("admin","cashier"), so an unauthenticated web guest has no path that writes an order. The nutrixpos GitHub organisation holds only pos, posui (archived), docs and devops — no ordering-site product — and nutrixpos.com's feature list is Cashier, Kitchen, Inventory and Reports with no online-ordering mention. source |
| guest-loyalty-accrual-models | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | None of the three accrual models exists, natively or otherwise: a repo-wide search returns zero occurrences of "loyalty", "reward", "points" or "punch"; Customer is {Id, Name, Phone, Address} with no balance, visit counter or tier field; and the complete OpenAPI path list has no loyalty resource. Settings holds printers, order-queue counters and payment-source labels — there is nothing in which an accrual rule could be configured. source |
| labor-clock-in-at-pos | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-no | No time clock exists to clock into: the auth module's User model is {ID, Username, Email, PasswordHash, Roles, CreatedAt, UpdatedAt} — no PIN or badge field — and sign-on is a username/password JWT login (LoginRequest{Username, Password}). A repo-wide search for clock, punch, shift, timesheet or time-entry code returns nothing beyond two "pi pi-clock" icon classes, and the complete OpenAPI path list has no time-entry or shift resource. source |
| hardware-kds | unknown (grade F) — placeholder rationale "No public documentation located during the 2026-08-01 research pass", i.e. the cell had never been examined | resolve-to-partial | A first-party, touch-operated KDS screen exists: Kitchen.vue subscribes to the WebSocket feed (reacting to order_submitted and order_finished), loads every open order into QueueOrder cards, and finishes an order with an on-screen confirm button that POSTs /orders/{id}/finish. Shortfall: display-and-finish is the entire feature — no station routing, no course or fire timing, no bump-bar support and no dedicated hardware; the vendor's own docs describe it as an "on demand simple interface for displaying and finishing orders". source |
Sources
Every URL this record cites. 22 in total.
- https://github.com/nutrixpos/pos
- https://nutrixpos.com/userguide/installation.html
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/specs.api.yaml
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/models.go
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/models/settings.go
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/handlers/order.go
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/src/pages/Kitchen.vue
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/src/router/index.ts
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/core.go
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/handlers/sales.go
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/src/pages/Sales.vue
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/hubsync/services/syncer.go
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/frontend/package.json
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/services/notification_singleton.go
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/services/receipt.go
- https://nutrixpos.com/architecture.html
- https://nutrixpos.com/getting_started.html
- https://api.github.com/orgs/nutrixpos/repos
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/services/sales.go
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/core/services/order.go
- https://github.com/nutrixpos/docs/blob/main/index.md
- https://github.com/nutrixpos/pos/blob/69f435a0ba512c9fd5816f086928d185fde5e2c8/modules/auth/models/user.go