Skip to content

Deployment & Orchestration Guide

Business M supports a highly flexible deployment model, allowing you to run all domain capabilities inside a unified monolith topology or as decoupled, distributed macroservices. This guide outlines all available orchestration layers and deployment tracks.


Track Target Environment Purpose Core Technologies
Track 1: Dev Services Local Machine Launching databases & sidecars in background for local process running (m dev) Docker Compose (dev/)
Track 2: Local Containers Local Machine Full containerized building & integration testing of all services locally Docker Compose (dev/*.local.yml)
Track 3: Prod VM Compose Single-VM / Staging Production-grade deployment with SSL and host-isolated databases Docker Compose (deploy/compose)
Track 4: Prod Kubernetes Kubernetes / Enterprise Auto-scaling, highly resilient enterprise deployments Helm Chart (deploy/helm)
Track 5: Desktop & LAN App Windows / macOS / Linux Desktop native installation for single users or offline LAN server setups Tauri & Binary Sidecars (apps/business-local)

When developing Business M locally on your machine, you normally run the application code directly on your host using the m dev command. To support this, you only need to run the underlying database and sidecar engines in the background.

All development compose files have been organized into the deploy/compose/dev/ folder to keep the workspace root clean.

The monolithic Indie track uses PostgreSQL for relational storage, Valkey (Redis) for state caching, and NATS for event messaging. To spin these up:

Terminal window
docker compose -f deploy/compose/dev/dev.compose.yml up -d
  • Postgres Port: 5432 (with database schema auto-configured)
  • Valkey Port: 6379
  • NATS Port: 4222

2.2 Macroservices Dev Infrastructure (Integrated KurrentDB)

Section titled “2.2 Macroservices Dev Infrastructure (Integrated KurrentDB)”

Monolith local development uses standard PostgreSQL for event streams. However, distributed macroservices use specialized engines—TigerBeetle for financial ledger entries and KurrentDB (EventStoreDB) for event sourcing.

To launch the macroservice dev sidecars locally:

Terminal window
# Spins up PostgreSQL, Valkey, NATS, TigerBeetle, and KurrentDB
docker compose -f deploy/compose/dev/dev.compose.yml \
-f deploy/compose/dev/macroservices.compose.yml \
up -d
  • TigerBeetle Port: 3000 (attached to a bridge network)
  • KurrentDB Port: 2113 (backed by persistent kurrent_data volume)

If you want to compile the container images and run the entire stack inside Docker locally (for integration tests or pre-deployment validation), you can leverage the local compose override configurations (*.local.yml).

Because the compose files reside in a subdirectory, they are pre-configured with a build context of ../../../ to correctly find and package the codebase from the repository root.

Build and run the full Monolith backend and sidecar services in containers:

Terminal window
docker compose -f deploy/compose/dev/dev.compose.yml \
-f deploy/compose/dev/compose.yml \
-f deploy/compose/dev/compose.local.yml \
up --build -d

3.2 Run Macroservices Locally in Containers

Section titled “3.2 Run Macroservices Locally in Containers”

Build and execute the distributed services in containers, coordinated behind a local Traefik proxy:

Terminal window
docker compose -f deploy/compose/dev/dev.compose.yml \
-f deploy/compose/dev/macroservices.compose.yml \
-f deploy/compose/dev/macroservices.local.yml \
up --build -d
  • Traefik Entrypoint Portal: http://localhost:8080 (automatically stripping paths and routing traffic between shell, finance, and wms according to gateway routing maps).

4. Track 3: Production Single-VM Docker Compose

Section titled “4. Track 3: Production Single-VM Docker Compose”

For production deployments on a single virtual machine (VM) or VPS, use the production compose suite located under deploy/compose/.

  • Host Network Isolation: Keeps your backend databases (PostgreSQL, Redis, NATS, TigerBeetle, KurrentDB) strictly internal. No database ports are bound to the public host interface, preventing external scanning.
  • Scalability Enabled: Application containers do not have static container_name fields. You can scale workers or API gateway pods natively via --scale (e.g. --scale app=3).
  • Automated SSL/TLS: Traefik v3 proxy handles Let’s Encrypt certificate acquisition automatically via ACME HTTP-01 challenges and routes secure HTTPS (port 443) traffic.
  • Database Schema Auto-Migrations: Unified Postgres and keeper migration jobs run automatically on startup to keep database schemas updated.
  1. Navigate to the production compose directory:
    Terminal window
    cd deploy/compose
  2. Copy the production environment example and fill in secure values:
    Terminal window
    cp prod.env.example .env
    # Open .env and customize DOMAIN, ACME_EMAIL, and POSTGRES_PASSWORD

Business M’s multi-layer security model is configured entirely through environment variables set in your .env file.

Value Adapter When to Use
implicit (default) ImplicitTenantAdapter All self-hosted single or multi-company deployments
header HeaderTenantAdapter Behind a trusted internal gateway (not for public SaaS)
registry RegistryTenantAdapter Full SaaS multi-tenant with cryptographic fact verification

For a standard production single-tenant deployment, no M_TENANT_MODE configuration is needed. The default implicit mode uses the local CompanyMember DocType to manage which companies each user can access.

Value When to Use
local (default) Single-DB deployments (all deployment tracks unless SaaS)
shared Shared-cluster multi-tenant; framework injects tenant_id column
dedicated Per-tenant dedicated DB, URL fetched from control plane

If using M_TENANT_MODE=registry, add one of the following to your .env:

Terminal window
# Option 1: Provide the Ed25519 public key directly (air-gapped / pinned key)
TENANT_REGISTRY_PUBLIC_KEY=base64encodedpublickey==
# Option 2: Point at the Tenant Registry — key is fetched on startup
TENANT_REGISTRY_URL=https://registry.yourdomain.com

Deploy the secure Monolith stack with automated SSL proxying:

Terminal window
docker compose -f docker-compose.base.yml -f docker-compose.monolith.yml -f docker-compose.traefik.yml up -d

Deploy the distributed microservices stack:

Terminal window
docker compose -f docker-compose.base.yml -f docker-compose.macroservices.yml -f docker-compose.traefik.yml up -d

4.5 Optional: Add Event Sourcing (KurrentDB)

Section titled “4.5 Optional: Add Event Sourcing (KurrentDB)”

If you configure EVENT_STORE_TYPE=kurrent in your .env file, append the specialized KurrentDB compose file to spin up the secure event store:

Terminal window
docker compose -f docker-compose.base.yml \
-f docker-compose.macroservices.yml \
-f docker-compose.kurrentdb.yml \
-f docker-compose.traefik.yml \
up -d

5. Track 4: Production Kubernetes via Helm

Section titled “5. Track 4: Production Kubernetes via Helm”

For highly-available, cloud-scale deployments, Business M provides a production-grade Helm chart under deploy/helm/business-m.

The primary switch in the Helm chart is the .Values.mode setting, which dictates which topology to build inside your cluster:

  • mode: monolith: Deploys a single application pod, monolith workers, and Postgres/Valkey/NATS services.
  • mode: macroservices: Deploys separate pods for shell, finance, wms, m-india, WMS workers, and keeper services, managed behind a unified Ingress.

Install the chart in monolith mode:

Terminal window
helm install business-m deploy/helm/business-m --set mode=monolith

Install the chart in macroservices mode:

Terminal window
helm install business-m deploy/helm/business-m --set mode=macroservices

5.4 Key Configuration Values (in values.yaml)

Section titled “5.4 Key Configuration Values (in values.yaml)”

You can fully customize databases and sidecar modes inside values.yaml:

# Mode Select: 'monolith' or 'macroservices'
mode: monolith
# Subchart Dependencies (bundled inside the chart)
postgres:
enabled: true
user: "admin"
database: "business_m"
persistence:
size: 8Gi
valkey:
enabled: true
auth:
password: "securepassword"
nats:
enabled: true
jetstream:
enabled: true
# Keeper Backends (double-entry engine type: 'postgres' or 'tigerbeetle')
keepers:
ledgerType: "postgres"
# Optional External Sidecars
externalConfig:
database:
url: "postgresql+asyncpg://user:pass@host:5432/dbname"
tigerbeetle:
addresses: "tb-cluster-ip:3000"

When running in macroservices mode, the Helm chart automatically configures advanced PathPrefix rules. Ingress strip-prefix controllers redirect API calls (e.g. /api/finance/... and /api/wms/...) directly to their respective pods, serving decoupled endpoints under a single domain seamless to the web client.


6. Track 5: Desktop & LAN Native App (Tauri)

Section titled “6. Track 5: Desktop & LAN Native App (Tauri)”

For single-desktop offline usage or localized office LAN deployments, Business M provides the business-local native application wrapper, supporting Windows, macOS, and Linux.

The Tauri app (apps/business-local/) compiles into a native installer, wrapping the web frontend alongside pre-compiled backend binary sidecars (PostgreSQL, Redka, NATS, Traefik, and the monolith backend).

When the user launches the application, Tauri automatically orchestrates the execution of eight background service processes:

  • PostgreSQL (relational database engine)
  • Redka (high-performance SQLite-backed, Redis-compatible caching engine)
  • NATS (event messaging broker)
  • Traefik (local routing and SSL gateway proxy)
  • Monolith (the core web server backend)
  • Worker (background queues queue consumer running m worker)
  • Book Keeper (double-entry bookkeeping ledger service)
  • Stock Keeper (inventory tracking and valuation service)

All engines bind purely to localhost, creating a fast, zero-configuration local single-desktop environment. On exit, Tauri clean-terminates all sidecar processes.

To package the native desktop installers:

  1. Navigate to the tauri application folder:
    Terminal window
    cd apps/business-local
  2. Install frontend dependencies:
    Terminal window
    pnpm install
  3. Compile the target package (requires Rust and the Tauri CLI tools installed on the host):
    Terminal window
    pnpm tauri build
    This outputs native installers (.deb/.rpm on Linux, .msi on Windows, or .dmg/.app on macOS) under src-tauri/target/release/bundle/.

business-local can easily be toggled into LAN Server Mode, allowing other machines in the same office or local network to securely connect:

  • Custom SSL Certificate Integration: You can load your secure LAN SSL certificates (lan.crt and lan.key) directly through the desktop application’s user interface. For CLI-only or headless environments, you can simply place your lan.crt and lan.key files in the dedicated configuration directory.
  • Automated Traefik Service: Once the certificate files are loaded or placed, the bundled Traefik sidecar automatically picks them up, configures the routes, and serves the encrypted HTTPS endpoints, ensuring a completely zero-config secure proxy setup.

In addition to direct downloads from GitLab Releases, Linux desktop packages are automatically published to the project’s native GitLab Debian Package Registry (apt repository) during CI/CD release pipelines.

This allows Debian/Ubuntu users to configure the repository in their package manager for automated updates.

6.4.1 Adding the Repository to sources.list

Section titled “6.4.1 Adding the Repository to sources.list”

To configure the APT source, download the registry’s public GPG signing key and add the repository entry (no token required since the repository is public):

Terminal window
PROJECT_ID="79588051"
# Import GPG signing key
curl -sL "https://gitlab.com/api/v4/projects/${PROJECT_ID}/packages/debian/repository.key" | gpg --dearmor | sudo tee /usr/share/keyrings/business-m-archive-keyring.gpg > /dev/null
# Add repository list entry
echo "deb [signed-by=/usr/share/keyrings/business-m-archive-keyring.gpg] https://gitlab.com/api/v4/projects/${PROJECT_ID}/packages/debian stable main" | sudo tee /etc/apt/sources.list.d/business-m.list
Terminal window
# Update local package index
sudo apt-get update
# Install the application
sudo apt-get install business-local

7. Automated Releases & Container Versioning

Section titled “7. Automated Releases & Container Versioning”

To ensure absolute clarity, reliability, and security in production deployments, Business M utilizes a centralized GitLab CI/CD release workflow.

The meta-version of the entire platform is authoritatively governed by the business-m-shell package (apps/business-m/pyproject.toml). Any commit that affects global code automatically bumps the shell version (e.g., from 0.1.0 to 1.0.0).

When a release prepare runs:

  • m release prepare synchronizes the bumped meta-version into release-config.json sync targets:
    • Helm Chart (Chart.yaml): Automatically updates the appVersion (injecting the current platform meta-version to pull matched container images). The chart version itself is kept completely independent and is bumped manually by developers for template-only adjustments.
    • Production Compose (prod.env.example): Automatically updates the default IMAGE_TAG to point to the new release tag instead of latest.

To prevent human error during independent versioning, the GitLab CI pipeline implements an automated Version Guard (lint-helm-version job in the lint stage):

  • Change Detection: It automatically scans the commit diff to see if any Helm files (templates, helper templates, or values.yaml) have been modified compared to the main branch.
  • Enforced Bump: If chart configurations were modified but the version field inside Chart.yaml remains identical to main, the build is failed with a clear validation error.
  • Duplicate Push Protection: The GitLab registry enforces strict unique constraints and rejects duplicate pushes, ensuring that once validated, a published Helm package version is immutable.

To balance unified global deployments with independent package agility, all microservice container images compiled in CI are dual/triple-tagged:

  1. Release-Library Tag (<business-m-version>-<lib-version>): e.g., finance:1.16.0-0.8.2 The definitive production tag. It explicitly maps the core gateway shell version (1.16.0) with the specific service library version (0.8.2).
  2. Global Meta-Version Tag (<business-m-version>): e.g., finance:1.16.0 Allows Helm charts or standard compose files to pull all microservice images under a single synchronized release version.
  3. Library-Specific Tag (<lib-version>): e.g., finance:0.8.2 Used for granular dependency tracking of individual service updates.
  4. Latest Tag (latest): Assigned automatically on default branch (main) builds.

Every git-tagged release of the platform automatically compiles and distributes three public channels in GitLab:

  1. Public Helm Chart Registry (Recommended): Published directly to the GitLab Helm Package Registry, enabling anonymous public discovery and standard installation without any 401 basic authentication blocks:
    Terminal window
    helm repo add business-m https://gitlab.com/api/v4/projects/79588051/packages/helm/stable
    helm repo update
    helm install business-m business-m/business-m --version <version>
    (For private operator teams or OCI-specific workflows, the packaged chart is also mirrored to the OCI registry at oci://registry.gitlab.com/castlecraft/business-m/charts/business-m which requires standard container registry credentials).
  2. VM Compose Release Tarball: Bundles all files under deploy/compose/ (excluding local dev configurations) into a zipped package business-m-compose.tar.gz and pushes it to the GitLab Generic Packages Registry:
    Terminal window
    curl -L -O https://registry.gitlab.com/castlecraft/business-m/packages/generic/business-m-compose/<version>/business-m-compose.tar.gz
    This allows VM operators to download, extract, and start the production stack with a single command without cloning the entire monorepo.
  3. Desktop & LAN Native Installers (Tauri): Automatically compiles the native Linux GUI application alongside its five pre-compiled binary sidecars (orchestrating eight background service processes) into optimized, offline-ready desktop installers:
    • AppImage: A portable, zero-installation single file that functions exactly like a click-and-run binary.
    • .deb package: A standard installer for Debian/Ubuntu environments that handles menus, icons, and system layout automatically.
    • These artifacts are compiled via the automated build-desktop-linux job in .gitlab/ci/desktop.yml on release tags, or manually on main branch builds.