Skip to content
Infotech

How the system fits together

Infotech POS is one API, one web app and one database. Everything else (print agents, payment gateways, the license server) talks to the API. This page explains the parts and how they connect, so the other developer pages make sense.

The parts

PartFolder in the repoTechnologyWhat it does
APIspring-adminJava 21, Spring Boot 3.5, JDBC, Flyway, OpenAPIAll business rules, authentication, WebSocket live updates, mail queue, billing jobs
Database—PostgreSQL 16All data, including translations and platform settings. Flyway creates and upgrades the schema on start
Web appinfotech-admin-webReact 18, TypeScript, Vite, TailwindThe super-admin console, the merchant back office, the POS till and the kitchen display, in one app
Print agentprint-agentNode.js 22Optional. Runs in a restaurant and prints kitchen tickets on network printers
Release toolingreleaseBash, Docker, CaddyBuilds the install packages buyers download
VPS deploymentdeployBash, Docker Compose, nginx, certbotThe author's own server setup and auto-deploy

The API is a modular monolith: one Spring Boot application with feature packages, not separate services. The main packages are:

security/       login, tokens, recovery, mail queue, encryption
users/ shops/ subscriptions/ addons/ marketplace/
merchant/       shop sign-up, portal, settings
merchant/pos/   till: pricing, sales, payments, receipts
merchant/inventory/  stock ledger, on hand, valuation
merchant/hrm/   staff, roles, stores, warehouses
i18n/ reports/ operations/ media/ audit/ shared/
src/main/resources/db/migration/   versioned PostgreSQL schema

Controllers validate typed requests, services own transactions and rules, and a shared database helper binds parameters.

Who uses what

The API has four roles:

RoleUses
SUPER_ADMINThe platform console (/api/v1/admin/**): shops, plans, add-ons, payments, translations, license
SUPER_ADMIN_VIEWERThe same console, read-only
SHOP_OWNERThe merchant portal and till (/api/v1/shop/**), with every shop permission
SHOP_STAFFThe merchant portal and till, limited by their shop role

Super administrators cannot use the shop API, and shop users cannot use the admin API. The web app reads the signed-in user's context and builds its menu from it.

Authentication uses bearer tokens kept in the browser's memory (never in local storage). Tokens last 30 minutes by default and are refreshed; role and account state are checked in the database on every request.

Tenants and add-ons

A shop is a tenant (one company). Its stores are its branches, each with warehouses. Product areas are sold as add-ons switched on per shop: POS (on by default), Inventory, Purchasing, Accounting, ZATCA Phase 2 and the Kitchen display feature, among others. The API refuses a shop request with 403 ADDON_NOT_ENABLED when the shop lacks the add-on, and the web app hides those pages. Add-on rules live in spring-admin/docs/ADDONS.md.

Live updates

Open screens (drafts, tables, kitchen display, print stations, approvals) are told about changes through one WebSocket at /api/v1/live:

change in a transaction ──▶ PostgreSQL NOTIFY ──▶ COMMIT
   every API instance (LISTEN) ──▶ connected browsers allowed to see it ──▶ screen reloads via the API

There is no Redis or message broker: PostgreSQL fans events out, so several API instances work without extra parts. A browser authenticates with its first message; print agents sign in with an agent key. Any reverse proxy in front of the API must pass the WebSocket upgrade (see Deploy the API and web app to a VPS).

Translations and branding

All UI text is stored in PostgreSQL and edited at runtime by super administrators. English, Bangla and Arabic (right-to-left) are seeded from spring-admin/src/main/resources/i18n/*.json; restarts add missing keys but never overwrite edits. The product name, URL and support email come from the platform settings, so the app can be rebranded without code changes.

Offline till

The production build of the web app includes a service worker that caches the app. The till keeps its catalog, context, open cart and offline sales in the browser's IndexedDB, and sends queued sales in order when the connection returns. The server still prices and records every sale.

Outside services

  • License server: activation and daily check-in (default https://license.infotech.center). A license problem locks the platform console and sign-up, never the shops' selling.
  • Payment gateways: Stripe, PayPal and Razorpay call webhooks under /api/v1/billing/webhooks/….
  • SMTP: sign-up codes, password resets and billing emails go through an encrypted mail outbox.
  • ZATCA: Phase 2 onboarding and invoice reporting for Saudi shops.

Two ways to deploy

Buyer release (Install)Author's VPS (Deploy to a VPS)
Containerspostgres, api, web (Caddy)postgres, api
Web app served byCaddy in the web containerHost nginx, static files in /var/www/…
AddressesOne origin: Caddy proxies /api/* and WebSockets to the APITwo origins: pos.example.com and api.example.com
HTTPSCaddy, automaticcertbot with the nginx plugin
Needs CORS_ORIGINS / VITE_API_URLNoYes
Updates./update.sh with a new packagegit push to main (GitHub Actions)

Last updated 17 Oct 2026