Systems

The code for most of this is private; it belongs to the businesses that run on it. The design isn't. Each diagram below is a real system in production; click any node to see what it does and why it's there.

Multi-tenant SaaS

How one request can't reach another shop's data

Every request in the retail ERP/POS SaaS passes four checkpoints before it touches a row. Click a node to see what it does and why it exists.

Case study: Retail ERP / POS SaaS
where: { organizationId }Access tokenorganizationId insideTenantGuardmembership re-resolvedPermissionsGuardcatalogue, not rolesServicepasses organizationId explicitlyPrisma tenant extensionrefuses unfiltered queriesPostgreSQL 16one schema, many shops

Access token

Tenant identity lives in the token, nowhere else

The organization a caller belongs to is carried in the signed access token. Controllers never read organizationId from a request body, a header or a query string. Those are all under the client's control. If you can't forge the token, you can't claim another shop.

// Controllers derive tenant from AuthContext, never from the request.
export interface AuthContext {
  userId: string;
  organizationId: string;
  membershipId: string;
  role: Role;
  branchId: string;
  allowedBranchIds: string[];
  canAccessAllBranches: boolean;
  terminalId: string | null;      // set when a paired till fixes the branch
  permissions: Set<Permission>;
}

Wholesale garments ERP

How the books always balance

The ERP's numbers are exact by construction: integer money, lot-level costing, and a ledger you can only append to. Click through the model.

Case study: Wholesale Garments ERP
receiptFIFOpostsMoneyinteger baisa, never floatShipmentBDT → OMR at a fixed rateStockLotlanded cost per lotSaleconsumes lots FIFOLedgerdouble-entry, append-onlyReportsderived, never stored

Money

A third decimal you can't lose

Omani Rial has three decimal places: 1 rial is 1000 baisa. The Money value object holds a bigint count of baisa, so addition and multiplication by quantity are exact. Rates (VAT, discounts) go through Decimal.js and round half-up back to baisa explicitly. It persists to NUMERIC(18,3). No float ever touches a monetary figure.

export class Money {
  private readonly baisa: bigint;

  static fromOmr(value: string | number | Decimal): Money {
    const dec = new Decimal(value).mul(1000)
      .toDecimalPlaces(0, Decimal.ROUND_HALF_UP);
    return new Money(BigInt(dec.toFixed(0)));
  }

  multiplyByQty(qty: number): Money {
    if (!Number.isInteger(qty)) throw new Error(`Quantity must be an integer`);
    return new Money(this.baisa * BigInt(qty));
  }
}

Building something with the same shape?

If your product has tenants, money, or both, the decisions above are the ones that matter. I'm happy to talk through yours before anything is built.