Skip to content

Architecture

Ndakita Build is a whitelabeled layer on ERPNext v15, delivered as a multi-tenant service. Each tenant is a construction small or medium enterprise running several concurrent projects.

Components

                 ┌──────────────────────────┐
  Browser  ───▶  │  ndakita_group_site       │   Marketing website and sign-up
                 │  (public web application)  │
                 └────────────┬─────────────┘
                              │  HTTPS, public endpoints (no secret)
                              ▼
                 ┌──────────────────────────┐
                 │  ndakita_build_platform   │   Provisioning, lifecycle, billing
                 │  (platform service)        │   Metadata database only
                 └────────────┬─────────────┘
                              │  bench CLI (subprocess)      │  Frappe REST (per tenant)
                              ▼                              ▼
                 ┌──────────────────────────────────────────────────┐
                 │  Frappe Bench (one site + dedicated database each) │
                 │  {slug}.<base-domain>   for every tenant           │
                 │  each site runs the ndakita_build app + ERPNext    │
                 └──────────────────────────────────────────────────┘
  • ndakita_group_site — the public website and the sign-up form. It calls only the platform's public endpoints and holds no secret.
  • ndakita_build_platform — orchestrates the system: creates tenant sites, tracks lifecycle and billing, and serves payment webhooks. Its database stores only tenant metadata, never ERP business data.
  • ndakita_build — the construction ERP itself (DocTypes, custom fields, reports, labour and payment workflows). Installed on every tenant site.

Tenancy model

Each tenant is provisioned as a dedicated Frappe site with its own database. This provides database-level isolation rather than row-level filtering, so no query can span tenants. Tenants are not represented as companies inside a shared site.

Branding follows a product-brand model: every tenant's ERP interface displays the Ndakita Build identity (login page, application header, favicon, loading screen). A tenant's own logo appears only on generated documents. Branding is applied automatically during provisioning.

Platform API surface

Endpoint Authentication Purpose
POST /public/signup none (rate limited) Create a tenant record and start provisioning
GET /public/slug-availability none (rate limited) Live availability check in the sign-up form
GET /public/tenants/{id}/status none Poll provisioning status; reveals the site URL when ready
GET/POST /tenants/* API key Administrative lifecycle: list, suspend, restore, reprovision
POST /webhooks/{mpesa,stripe} signature Payment callbacks

Sign-up to login flow

  1. A visitor completes the sign-up form on the marketing website.
  2. POST /public/signup creates a tenant record with status provisioning and starts provisioning asynchronously so the request returns immediately.
  3. Provisioning runs the standard sequence: create the site, install ERPNext, the Ndakita Build application, and the whitelabel layer; run the setup wizard with the correct localisation; migrate (which seeds construction defaults); verify the installation; and configure web routing. On success the tenant moves to trial.
  4. The form polls the status endpoint until trial, then presents the tenant's https://{slug}.<base-domain> address.
  5. The tenant opens the address and signs in as their administrator.

Tenant lifecycle

provisioning → trial → pending → active → grace → suspended → cancelled

A separate provisioning_failed state captures build failures. The states are defined in the platform models and mirrored in the marketing site's types. Suspension blocks login while preserving data; cancellation exports data before removing the site.

Design principles

  • ERPNext and Frappe core are never modified; the system extends them through hooks, fixtures, and overrides.
  • The platform never accesses tenant databases directly; it uses the bench CLI for provisioning and the Frappe REST API for tenant data.
  • Provisioning is asynchronous and idempotent; a failed tenant can be re-provisioned safely.
  • Tenant-facing interfaces contain no references to the underlying frameworks.