A point-of-sale and inventory-management system for multi-tenant retail (think a chain of stores, each with its own catalogue, staff and sales), written in pure, object-oriented Java with zero third-party dependencies.
It demonstrates clean layered architecture, classic design patterns, a transactional billing engine that never oversells stock, salted password hashing, and pluggable persistence β local CSV files by default, or PostgreSQL in production behind the same interfaces. The codebase compiles against nothing but the JDK (the PostgreSQL JDBC driver is the only runtime add-on), and both storage backends are exercised in CI.
Re-engineered from an earlier prototype into a proper OOP backend with a test suite and continuous integration.
-
π Live demo: possystem-pvup.onrender.com (free tier β first load after idle takes ~30s to wake)
-
π§βπ» Run it in your browser β no install:
In the browser terminal:
./build.sh && java -jar out/pos-system.jar(CLI) Β or Βjava -jar out/pos-system.jar --web(web dashboard). -
π One-click deploy your own live link:
Multi-tenant core
- Every store is an isolated tenant β its own products, staff and sales ledger.
- Data isolation enforced at the service layer (a store can only ever see its own rows).
Authentication & roles
- Salted PBKDF2-HMAC-SHA256 password hashing with constant-time verification β no plaintext, no third-party crypto lib.
- Role-based access control:
ADMINβΈMANAGERβΈCASHIER, with privilege ordering.
Inventory management
- Add / update / delete products, barcode lookup, free-text search (name Β· barcode Β· category).
- Low-stock alerts driven by a per-product reorder threshold.
- Restock / stock-adjustment with validation (stock can never go negative).
Billing engine (the heart of the system)
- Cart with automatic line-merging and exact
BigDecimalmoney math. - Transactional checkout: validates all stock before mutating anything, so a sale is all-or-nothing.
- Automatic rollback if persistence fails mid-write β the catalogue is left exactly as it started.
- Concurrency-safe so two cashiers can't both pass validation and jointly oversell (the classic check-then-act race).
- Pluggable payment methods (Cash / Card / UPI) via the Strategy pattern.
- Printable text receipts.
Reporting & analytics
- Total & daily revenue, best-selling products, payment-method mix.
- One-click CSV export of the sales ledger.
Web dashboard (optional, same zero-dependency Java)
- A live dashboard served by the JDK's built-in
HttpServerβ no Spring, no servlet container, no jars. - JSON API (
/api/summary,/api/products,/api/top,/api/daily,/api/payments,/api/sell) over the exact same service layer the CLI uses. - Ring up a sale from the browser and watch stock + analytics update live.
- Containerised and deployable to a real
https://URL (see Deploy).
Pluggable persistence (CSV β PostgreSQL)
- Repositories sit behind interfaces, so storage swaps with zero changes to business logic.
- CSV backend (default): human-readable tables, RFC-4180 quoting, atomic crash-safe writes (temp file + atomic move) β no setup, nothing to install.
- PostgreSQL backend (production): real JDBC repositories with a connection-per-op model and transactional commit/rollback for sales. Activated automatically when a
DATABASE_URLis present. - The JDBC code uses only
java.sql(JDK), so the project still compiles with zero dependencies β the Postgres driver is the single runtime-only dependency, added in Docker. - Both backends are verified end-to-end in CI.
A strict, one-directional layered architecture β each layer depends only on the layer beneath it:
flowchart TD
A["CLI Layer<br/>PosApplication Β· Console Β· DemoRunner"] --> B
B["Service Layer<br/>AuthService Β· InventoryService Β· BillingService Β· ReportService"] --> C
B --> P["Payment Strategies<br/>Cash Β· Card Β· UPI"]
C["Repository Layer<br/>Store Β· User Β· Product Β· Transaction"] --> D
D["Persistence Layer<br/>Database Β· CsvFile (atomic) Β· Csv codec"]
B --> M["Domain Models<br/>Store Β· User Β· Product Β· Cart Β· Transaction"]
C --> M
| Pattern | Where | Why |
|---|---|---|
| Repository | repository/* |
Decouples business logic from CSV storage behind a generic CRUD contract. |
| Template Method | AbstractCsvRepository |
Base class handles loading, id-generation, locking & atomic persistence; subclasses only map a row β entity. |
| Strategy | service/payment/* |
Each tender type is its own class; adding one doesn't touch the billing engine. |
| Factory | PaymentProcessor |
Resolves a PaymentMethod to its strategy. |
| Facade / Unit of Work | Database |
Single entry point owning the four repositories and their shared state. |
| Service Layer | service/* |
Encapsulates all business rules and validation. |
- Transactional consistency without a database β validate-then-apply plus rollback gives all-or-nothing semantics over plain files.
- Crash-safe persistence β atomic file replacement means the on-disk table is always a complete, consistent snapshot.
- Thread safety β repositories guard state with a
ReentrantReadWriteLock; checkout is synchronized to prevent oversell races. - Custom exception hierarchy rooted at
PosExceptionfor precise, catchable error handling. BigDecimalmoney throughout β no floating-point rounding bugs in totals.
POSSystem/
βββ src/main/java/com/rudra/pos/
β βββ Main.java # entry point (interactive or --demo)
β βββ app/ # CLI: PosApplication, Console, DemoRunner
β βββ model/ # Store, User, Product, Cart, Transaction, enums
β βββ exception/ # PosException hierarchy
β βββ persistence/ # Database facade, CsvFile (atomic I/O)
β βββ repository/ # generic + concrete repositories
β βββ service/ # Auth, Inventory, Billing, Report
β β βββ payment/ # Strategy + Factory for tenders
β βββ util/ # PasswordHasher, Csv, Money, ReceiptPrinter
β βββ seed/ # DemoData seeder
βββ src/test/java/com/rudra/pos/ # zero-dependency test suite (TestMain, Assert)
βββ .github/workflows/ci.yml # compile + test + run demo on every push
βββ build.sh / build.bat # one-command build (JDK only)
βββ pom.xml # optional Maven build
Requirements: a JDK 11 or newer. No Maven, no internet, no dependencies.
# macOS / Linux
./build.sh
# Windows
build.batThis compiles the sources, packages a runnable jar, then compiles and runs the full test suite.
mvn package# Interactive POS (seeds a demo store on first launch)
java -jar out/pos-system.jar
# Scripted, non-interactive walk-through (seed β sell β reports)
java -jar out/pos-system.jar --demo
# Web dashboard β then open http://localhost:8080
java -jar out/pos-system.jar --web| Account | Login | Password |
|---|---|---|
| Store admin | BHOPAL01 |
admin123 |
| Cashier | ravi |
cashier123 |
| Manager | neha |
manager123 |
The project ships a hand-rolled, dependency-free test suite (TestMain) covering
the CSV codec, password hashing, authentication, inventory rules, the
transactional billing engine (including oversell rejection and rollback), a
persistence reload test, and reporting. It exits non-zero on any failure.
Every push runs GitHub Actions CI (.github/workflows/ci.yml): it compiles
the project on JDK 17, runs the test suite, and executes the end-to-end demo β
so the badge at the top reflects a genuinely working build.
# run just the tests locally
./build.sh # tests run as the final stepThe web mode is containerised, so you can put it on a public URL for free. The
repo already includes a Dockerfile and a render.yaml blueprint.
Render (recommended, free):
- Push this repo to GitHub.
- Go to render.com β New βΈ Blueprint β select this repo.
Render reads
render.yaml: it provisions a free PostgreSQL database, builds theDockerfile, wiresDATABASE_URLinto the web service, and deploys. - When it finishes you get a URL like
https://pos-system-xxxx.onrender.com. Open it β the dashboard loads with the seeded demo store, now backed by Postgres. - Paste that URL into the Live demo line near the top of this README.
The app uses PostgreSQL when
DATABASE_URLis set (so data persists across restarts) and falls back to local CSV files otherwise. Free Render instances sleep after inactivity, so the first request after idle can take ~30s to wake.
Run it in a browser instead (no deploy): use the Open in Cloud Shell /
Gitpod buttons at the top, then run java -jar out/pos-system.jar --web.
To embed a recording of the CLI in this README:
# Option A β terminal recording (asciinema)
asciinema rec demo.cast -c "java -jar out/pos-system.jar --demo"
# upload, then paste the player link here
# Option B β animated GIF
# run the --demo command and screen-record it with ScreenToGif (Windows)
# or Kap (macOS), save as docs/demo.gif, then reference it:
# - REST API layer (Spring Boot) over the same service core
- Pluggable storage backend (swap CSV for SQLite/Postgres behind the
Repositoryinterface) - Web/JavaFX front end reusing the service layer
- Receipt export to PDF / thermal printer
- Per-role permission checks enforced in the CLI menus
Released under the MIT License β free to use and modify.