Back to Projects
Live

XFinance

Multi-Tenant Finance & Accounting SaaS

Key Technical Highlights

Dual deployment architecture — DEPLOYMENT_MODE=saas enables full multi-tenancy with subdomain routing and super admin; standalone mode bypasses subscription gates for single-client on-premise deployments

All data scoped by groupId on every Prisma model, sourced from request context — never re-queried from the database mid-request, keeping tenant isolation fast and auditable

Real-time sidebar updates via Socket.IO — balance sheets, payroll summaries, and audit logs update instantly across all connected clients

CI/CD runs parallel Docker image builds to GHCR on every push to main; standalone clients self-update via Watchtower watching a :stable tag — zero manual intervention for client upgrades

Per-group branding — each tenant configures their own logo and colour theme, served from their subdomain

The Case Study

The Problem

Nigerian businesses managing multiple entities — subsidiaries, departments, branch offices — had no affordable, locally-built accounting SaaS that understood their operating context. Enterprise tools were too expensive and foreign. Local tools were too simple.

The Solution

XFinance is a multi-tenant Finance and Accounting SaaS with a dual deployment model. Businesses use the hosted SaaS at xfinance.ng with full multi-tenancy, or deploy the standalone Docker image for a single-client on-premise installation. Same codebase. Different runtime mode.

The Architecture Decision That Defines It

The dual deployment mode was the core architectural challenge. A single environment variable — DEPLOYMENT_MODE — switches the entire application context. In SaaS mode, subdomain routing identifies the tenant group, the super admin panel is active, and subscription gating controls feature access. In standalone mode, a fixed DEFAULT_GROUP_ID is injected at startup. No subscription checks. No subdomain routing. No super admin overhead.

This means enterprise clients get a fully white-labelled, self-hosted installation while the SaaS product evolves from the same repository.

Data Scoping

Every Prisma model carries a groupId. The request context sets it once on authentication — it is never re-queried from the database mid-request. Tenant isolation is enforced at the ORM layer, making it both fast and auditable. Any query missing a groupId scope would be caught immediately in review.

Real-Time Updates

Finance dashboards need to reflect live data. Socket.IO powers a real-time sidebar that updates automatically when a payroll run completes, a bank reconciliation is confirmed, or inventory levels change. No polling. No manual refresh.

CI/CD

GitHub Actions builds Docker images in parallel and pushes to GHCR on every push to main. The SaaS instance auto-deploys from the :latest tag. Standalone clients run Watchtower, which monitors the :stable tag and self-updates when a new image is promoted — zero manual intervention required for client upgrades.

Key Features

  • General Ledger with double-entry bookkeeping
  • Bank reconciliation module
  • Payroll with deduction management
  • Store inventory tracking
  • Full audit logging with change history
  • Per-tenant logo and colour theme branding
  • Subscription management (SaaS mode only)
  • Self-update via Watchtower (standalone mode)