Appearance
Multi-Tenancy & Access Control
MEGSTAT POS is built from the ground up to support multi-store chains, franchises, and multi-tenant software-as-a-service deployments.
Tenancy Isolation Model
Isolation is enforced at the database level using a shared database with discriminator columns (tenantId). Every core entity carries a non-nullable, indexed tenantId:
- Tenants & Branches:
Tenant,Branch,Terminal - Identity & Access:
User,Role,TenantUser - Catalog & Pricing:
Product,Category,PriceList,Promotion - Customers & Suppliers:
Customer,Supplier,CustomerGroup - Operations:
Register,Shift,Sale,Purchase,StockMovement,LedgerEntry
prisma
model Product {
id String @id @default(cuid())
tenantId String
sku String
name String
// ...
tenant Tenant @relation(fields: [tenantId], references: [id])
@@unique([tenantId, sku])
@@index([tenantId])
}Golden Rule of Tenancy
The Golden Rule
tenantId is ALWAYS extracted from the verified session, NEVER trusted from request body or query parameters.
In backend/src/middleware/tenant.ts:
- The authentication middleware verifies the incoming JWT or session cookie and sets
c.set("user", user)andc.set("tenantId", tenantId). - All database queries throughout route handlers and services inject
where: { tenantId }derived from the context. - If an endpoint explicitly accepts
:tenantIdin the URL (for multi-tenant cross-store administrative actions), the handler must userequireTargetTenantPermissionorrequireTenantParamto verify that the calling user has authorized access to that specific tenant.
Role-Based Access Control (RBAC)
MEGSTAT POS implements fine-grained RBAC with role inheritance and override capabilities:
Predefined Roles
- Owner: Full system authority, store billing, tenant settings, and rollover control.
- Store Manager: Shift authorization, cashier overrides, voiding transactions, price adjustments, and stock auditing.
- Cashier / POS Operator: Billing, cash drawer movements, hold/recall sales, customer creation.
- Inventory Clerk: Purchase receiving, warehouse transfers, stock adjustments, and stocktaking counts.
Permissions Matrix
Permissions are represented as scoped strings:
pos:checkout,pos:refund,pos:hold,pos:discountinventory:view,inventory:adjust,inventory:transfer,inventory:auditreports:view,reports:export,reports:financialssettings:tax,settings:users,settings:hardware
Routes enforce permissions declaratively:
ts
app.post("/sales", requirePermission("pos:checkout"), async (c) => {
// Handler logic
});Manager Override Engine
Counter cashiers frequently encounter situations requiring elevated approval (e.g., overriding a maximum line discount, voiding an already-tendered line item, or opening a drawer outside of a sale).
MEGSTAT POS provides a lightweight manager override mechanism:
- Cashier UI triggers
ManagerOverrideModal. - Manager enters their 4-digit PIN or credentials.
- Endpoint
POST /api/auth/manager-overrideverifies manager permissions. - Generates an ephemeral single-use override token logged directly to
AuditLog. - The cashier's action completes under the audited manager approval.
