Skip to main content

Installer Bundle & Versioning

The CTMS platform is deployed to production servers using a self-contained install bundle — a single tarball that contains everything needed for a full deployment without requiring git, GitHub tokens, or network access to source repos.

What's in the Bundle

The bundle is assembled by a GitHub Actions workflow and packaged as zynctl-bundle-<version>.tar.gz. It includes:

ComponentPath in BundlePurpose
zynctl.shzynctl.shPlatform controller — bootstrap, deploy, operate
Environment template.env.exampleTemplate for .env.production
Docker Composedocker-compose.yml, docker-compose.prod.ymlCore service definitions
Caddycaddy/Reverse proxy configs (dev + prod)
OTEL + Fluent Bitconfig/otel/, config/fluent-bit/Observability pipeline configs
KrakenDctms-api-gateway/configs/API gateway template + entrypoint
Supabasesupabase/Full self-hosted Supabase stack (compose + volumes)
Frappefrappe-marley-health/Frappe compose + env sample + setup scripts
Demo datascripts/Seed data, patient loader, demo data JSON
VERSIONVERSIONBundle version stamp
zynctl.conf.examplezynctl.conf.exampleOptional configuration overrides

Versioning Scheme

Bundle releases use a date-stamped version format:

bundle-v{MAJOR}.{MINOR}.{YYYYMMDD}
SegmentMeaningExample
MAJORPlatform generation (currently 2)2
MINORSequential release number (increment by 1)35
YYYYMMDDRelease date20260315

Example: bundle-v2.35.20260315 → Platform gen 2, 35th release, built on 2026-03-15.

For non-tagged automatic builds (push to main), the version is auto-computed as v{MAJOR}.{run_number}.{YYYYMMDD} using the GitHub Actions run number.

Tagged Releases

For formal releases, create a git tag with the bundle-v prefix across all 4 repos:

TAG="bundle-v2.35.20260315"
MSG="fix: Marquez init, pipeline trigger semantics, env completeness"

# Tag all repos with the same version
for repo in ctms.devops ctms-web docs.zynomi.com ctms-data-pipeline-ai-analytics; do
cd /path/to/$repo && git tag "$TAG" -m "$MSG"
done

# Push all tags (ctms.devops triggers the bundle build)
for repo in ctms.devops ctms-web docs.zynomi.com ctms-data-pipeline-ai-analytics; do
cd /path/to/$repo && git push origin "$TAG"
done

Tagged builds will:

  • Use the tag version instead of auto-computed version
  • Create a GitHub Release with the tarball and SHA256 checksum attached
  • Appear under ctms.devops Releases

Repos That Get Bundle Tags

RepositoryWhy it gets tagged
ctms.devopsDocker Compose, configs, env — triggers build
ctms-webZynexa web app, API routes, OpenAPI spec
docs.zynomi.comDocumentation site, synced OpenAPI spec
ctms-data-pipeline-ai-analyticsdbt models, ingester, Cube.dev, MCP server

Non-tagged Builds

Pushes to main that modify bundle-relevant files trigger an automatic build. These are uploaded as workflow artifacts (retained for 30 days) but do not create a GitHub Release.

How to Trigger a Bundle Build

There are three ways to trigger the installer bundle workflow:

1. Automatic (Push to main)

Any push to main that modifies these paths automatically triggers a build:

  • zynctl.sh — Platform controller
  • .env.example — Environment template
  • docker-compose.yml / docker-compose.prod.yml — Service definitions
  • caddy/** — Reverse proxy configs
  • config/** — OTEL / Fluent Bit configs
  • ctms-api-gateway/configs/** — KrakenD gateway
  • supabase/** — Supabase stack
  • frappe-marley-health/** — Frappe stack
  • scripts/** — Demo data and setup scripts
  • scripts/frappe-setup/** — Frappe setup wizard (idempotent site configuration)

2. Manual Dispatch (GitHub UI)

  1. Go to Actions → Build and Publish Install Bundle
  2. Click "Run workflow"
  3. Select main branch
  4. Optionally enter a reason
  5. Click "Run workflow"

3. Manual Dispatch (CLI)

cd ctms.devops

# Trigger with default reason
gh workflow run build-install-bundle.yml

# Trigger with a custom reason
gh workflow run build-install-bundle.yml -f reason="Hotfix: refresh-token command added"

# Watch the run
gh run watch

4. Tagged Release

cd ctms.devops

# Create and push a version tag
git tag bundle-v2.5.20260303
git push origin bundle-v2.5.20260303

# This triggers the workflow AND creates a GitHub Release

Downloading a Bundle

From GitHub Releases (tagged builds)

# Download latest release
gh release download --repo zynomilabs/ctms.devops --pattern "zynctl-bundle-*.tar.gz"

# Download specific version
gh release download bundle-v2.5.20260303 --repo zynomilabs/ctms.devops

From Workflow Artifacts (non-tagged builds)

# List recent runs
gh run list --repo zynomilabs/ctms.devops --workflow build-install-bundle.yml

# Download artifact from a specific run
gh run download <run-id> --repo zynomilabs/ctms.devops

Deploying the Bundle

Once downloaded, deployment is straightforward:

# 1. Copy to server
scp zynctl-bundle-2.5.20260303.tar.gz root@<server-ip>:/root/

# 2. SSH in and extract
ssh root@<server-ip>
tar xzf zynctl-bundle-2.5.20260303.tar.gz
cd zynctl-bundle-2.5.20260303

# 3. Full deploy (bootstrap + deploy)
SERVER_HOST=<server-ip> ./zynctl.sh full-deploy

# 4. Or step-by-step
./zynctl.sh bootstrap # Install Docker, Compose, etc.
SERVER_HOST=<server-ip> ./zynctl.sh deploy # Deploy all stacks

After deployment, use zynctl.sh for day-to-day operations:

./zynctl.sh status           # Show running containers
./zynctl.sh health # Hit all health endpoints
./zynctl.sh refresh-token # Fix Frappe API token after restart
./zynctl.sh logs [service] # View container logs
./zynctl.sh update # Pull latest images + restart

Workflow File

The bundle build is defined in:

ctms.devops/.github/workflows/build-install-bundle.yml

Key steps:

  1. Compute version — from tag or auto-generated
  2. Assemble bundle — copy files into bundle directory
  3. Create tarballtar.gz + SHA256 checksum
  4. Upload artifact — always (30-day retention)
  5. Create GitHub Release — only for tagged builds