Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Restaurant POS

A full-stack restaurant point-of-sale system:

  • Backend: C# ASP.NET Core 9 Web API, Dapper, SQL Server, JWT auth, Serilog, Swagger
  • Frontend: React + TypeScript + Vite, React Query, React Router

Folder layout

ResturantPOS/
  RestaurantPOS.sln
  database/
    schema.sql                    -- run first on a fresh database, creates everything
    seed.sql                      -- run second, sample categories/menu/tables/payment methods/permissions
    add_*.sql                     -- historical migrations for upgrading a database created before
                                      these were folded into schema.sql/seed.sql (see note below)
  src/
    RestaurantPOS.Domain          -- entities
    RestaurantPOS.Application     -- DTOs, repository interfaces, billing calculator, screen keys
    RestaurantPOS.Infrastructure  -- Dapper repositories, JWT service
    RestaurantPOS.Api             -- controllers, Program.cs, appsettings.json, screen-based authorization
  frontend/
    src/
      api/       -- axios client
      types/     -- shared TS interfaces
      state/     -- auth context, restaurant/currency context
      components/-- shared UI + layout
      pages/     -- Tables, Order Taking, Kitchen Display, Billing, Shift, Reports, Menu Setup,
                    Tables & Sections, Users, Permissions, Audit Log, receipt/KOT print views

Note on database/add_*.sql files: if you're setting up a brand-new database, you only need schema.sql and seed.sql — everything from these incremental scripts has already been folded into them. The add_*.sql scripts are only needed if you have an existing database created before a given feature was added and want to upgrade it in place instead of starting fresh.

Prerequisites

  • .NET 9 SDK
  • SQL Server (Express/Developer/LocalDB all work) reachable at localhost
  • Node.js 18+ and npm

1. Database

sqlcmd -S localhost -i database\schema.sql
sqlcmd -S localhost -i database\seed.sql

The seed script inserts a placeholder password hash for the admin user that will not verify. Generate a real BCrypt hash before logging in — easiest way:

cd src\RestaurantPOS.Api
dotnet run

Then, with the API running, open Swagger (check the console output for the actual port — typically https://localhost:62640/swagger) and hash a password once via a scratch endpoint, or simply update the row directly:

UPDATE Users SET PasswordHash = '<bcrypt hash>' WHERE Username = 'admin';

You can generate a BCrypt hash from PowerShell with a one-off C# script, or add a temporary /api/auth/bootstrap endpoint that calls BCrypt.Net.BCrypt.HashPassword("Admin@123") and prints it, then remove it once you have the hash. Once you can log in as admin (Administrator role), you can create all further staff accounts from the Users screen — no more direct SQL needed after this first bootstrap.

2. Backend API

cd src\RestaurantPOS.Api
dotnet restore
dotnet build
dotnet run
  • Update appsettings.jsonConnectionStrings:RestaurantPOS if your SQL Server instance isn't the default localhost trusted-connection setup.
  • Set a real JWT signing secret via user-secrets — do not put it in appsettings.json, since that file is committed to source control:
    dotnet user-secrets set "Jwt:Key" "<a long random string, 32+ chars>"
    appsettings.json ships with an obvious placeholder (CHANGE_THIS_TO_A_LONG_RANDOM_SECRET...) precisely so a real secret never accidentally gets committed. Anyone else running this (a teammate, a different machine) needs to set their own.
  • Swagger UI is enabled in the Development environment at /swagger.
  • CORS is configured for http://localhost:5173 (the Vite dev server) — update Cors:AllowedOrigins if you serve the frontend elsewhere.

3. Frontend

cd frontend
npm install
npm run dev

Visit http://localhost:5173. The API base URL is hardcoded to https://localhost:62640/api in frontend/src/api/client.ts — update it if your API runs on a different port (check the dotnet run console output, or launchSettings.json).

What's implemented end-to-end

  • JWT login, role claims (Administrator/Manager/Cashier/Waiter/Kitchen Staff)
  • Dynamic, admin-configurable role permissions — Billing, Shift, Reports, Menu Setup, and Tables & Sections access can be granted per role from the Permissions screen, enforced on both the frontend (nav/routes) and the backend (real 403s, not just hidden UI). Administrator always has full access, hardcoded; Users management, Permissions, and Audit Log are always Administrator-only and are not part of the configurable grid, to prevent privilege escalation.
  • User management — create/disable/reset-password for staff accounts from the Users screen.
  • Dining tables with live status (Available/Occupied/Reserved/Cleaning) — a table only becomes Occupied once an order actually has an item in it (not merely from opening it), and frees back up if emptied out again before anything is sent to the kitchen.
  • Admin-managed floors/sections and tables — add a new section or table without touching SQL.
  • Categories + menu items with variants and modifier groups, including required/single-choice option groups (e.g. a required "Spice Level" on curries, absent on breads).
  • Custom order items (ticket-only, never touch the menu).
  • Order taking → send to kitchen → Kitchen Display → status flow.
  • Seat assignment + split-by-seat billing — assign items to a seat number, then bill each seat separately with its own receipt; the table stays occupied until every seat is settled.
  • Billing: server-computed tax, including optional compound tax components (e.g. India's CGST + SGST shown as separate lines instead of one flat rate — purely additive, existing flat-rate categories are unaffected), discount with reason, split payments across multiple methods, and customer search/attach (with quick-create for a new customer).
  • Bill voiding (Administrator/Manager only) — reopens the affected order/items and excludes the bill from all sales reporting, with a full audit trail.
  • Printed receipts and kitchen order tickets, via the browser's print dialog — works with printers registered as a normal Windows printer; this is not raw ESC/POS network printing.
  • Shift open/close with correct cash reconciliation (expected cash = opening float + cash sales actually taken during the shift), a live in-shift sales/payment-method breakdown, and full shift history with per-shift drill-down.
  • Reports: date-range and shift filtering, gross sales, tax collected, payment-method breakdown, top items (scoped to actually-billed orders, not abandoned/unpaid ones).
  • Audit log of sensitive actions — discounts, voids, user/permission changes, shift open/close — Administrator only.
  • Restaurant settings (name, address, GST/registration number, currency symbol) — no currency symbol is hardcoded anywhere in the UI or on receipts.
  • Menu setup screen (categories, items, tax categories and their optional compound components, modifier/option groups).

Not implemented (left as extension points)

  • Real ESC/POS or network printer protocol integration — printing goes through the OS print dialog (works with most registered thermal receipt printers), not a raw printer socket.
  • Real-time push (SignalR) — the frontend polls instead.
  • Inventory, multi-branch, offline mode, reservation integration.
  • Refresh token rotation — a RefreshTokens table exists in the schema but isn't wired up.
  • Split-by-seat apportions a flat (currency-amount) order-level discount across seats by each seat's subtotal share; a percent discount applies the same to every seat regardless of split.

Before running this in production

See PRODUCTION_READINESS.md for details, but in short:

  • No automated tests or CI pipeline — every change so far has been verified by hand.
  • No backup/disaster-recovery process for the database.
  • Uses a self-signed dev HTTPS certificate — needs a real TLS cert (or a reverse proxy) for a real network.
  • Single-restaurant by design — RestaurantId is hardcoded to 1 in a few places.
  • No payment gateway integration — payments are recorded manually, not processed through a card/gateway API.

About

ResturantPOS

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages