Skip to main content

CI/CD & Versioning

All CTMS Docker images are built by GitHub Actions and published to Docker Hub (zynomi/*). No builds happen on production servers — zynctl.sh deploy only pulls pre-built images.


Repositories

RepositoryWhat it builds
ctms.devopsAPI Gateway, ctms-init, Supabase Seed, Frappe, Install Bundle
hb-life-science-webZynexa (main CTMS app)
ctms-data-pipeline-ai-analyticsCube.js, MCP Server, ODM API, Ingester, dbt
docs.zynomi.comProduct documentation site

Workflows

Docker Image Builds

ImageWorkflowRepoPath TriggerTag Prefix
zynomi/zynexadocker-build.ymlhb-life-science-webmain, developv*.*.*
zynomi/ctms-api-gatewaybuild-ctms-api-gateway.ymlctms.devopsctms-api-gateway/**api-gateway-v*.*.*
zynomi/ctms-initbuild-ctms-init.ymlctms.devopsscripts/frappe-seed/**ctms-init-v*.*.*
zynomi/ctms-supabase-seedbuild-ctms-supabase-seed.ymlctms.devopsscripts/supabase-seed/**supabase-seed-v*.*.*
zynomi/frappe-marley-healthbuild-frappe-marley-health.ymlctms.devopsfrappe-marley-health/**frappe-v*.*.*
zynomi/ctms-cubedocker-build-ctms-cube.ymlctms-data-pipelinectms-cube/**cube-v*.*.*
zynomi/ctms-mcp-serverdocker-build-ctms-mcp-server.ymlctms-data-pipelinectms-mcp-server/**v*.*.*
zynomi/ctms-odm-apidocker-build-ctms-odm-api.ymlctms-data-pipelinectms-odm-xml-pdf-generator/**v*.*.*
zynomi/ctms-ingesterdocker-build-ctms-ingester.ymlctms-data-pipelinectms-ingester/**v*.*.*
zynomi/ctms-dbtdocker-build-ctms-dbt.ymlctms-data-pipelinectms-dbt/**v*.*.*
zynomi/product-docsdocker-build.ymldocs.zynomi.commain, developv*.*.*

Install Bundle

ArtifactWorkflowTriggerOutput
zynctl-bundle-*.tar.gzbuild-install-bundle.ymlCompose/config changes, bundle-v*.*.* tagGitHub Release tarball

Data Pipeline (Scheduled)

WorkflowScheduleStages
dbt-lakehouse-pipeline.ymlDaily 2 AM UTCingesterdbt-build (or full-pipeline)

Semantic Versioning

All images follow semver (MAJOR.MINOR.PATCH). Versioned releases are triggered by git tags.

Tag Conventions

Since ctms.devops hosts multiple services in one repo, each service has its own tag prefix:

api-gateway-v1.2.0    →  zynomi/ctms-api-gateway:1.2.0
ctms-init-v1.0.3 → zynomi/ctms-init:1.0.3
supabase-seed-v1.1.0 → zynomi/ctms-supabase-seed:1.1.0
frappe-v1.0.0 → zynomi/frappe-marley-health:1.0.0
bundle-v2.3.0 → zynctl-bundle-2.3.0.tar.gz (GitHub Release)

Single-service repos use plain v*.*.*:

v1.5.0  →  zynomi/zynexa:1.5.0, 1.5, 1

Image Tags per Push

Every push to main produces multiple tags:

TagExamplePurpose
latestzynomi/zynexa:latestAlways points to newest main build
1.{run_number}zynomi/zynexa:1.42Auto-incrementing build number
Short SHAzynomi/zynexa:a1b2c3dTrace back to exact commit
Semver (on tag push)zynomi/zynexa:1.5.0Immutable release version

Creating a Release

# Tag a service in ctms.devops
git tag api-gateway-v1.2.0
git push origin api-gateway-v1.2.0

# Tag in single-service repos
git tag v1.5.0
git push origin v1.5.0

# Create a bundle release
git tag bundle-v2.4.0
git push origin bundle-v2.4.0 # → GitHub Release with tarball

How Workflows Work

  1. Push to main with matching path filter triggers the build
  2. docker/metadata-action generates tags from branch/tag/SHA
  3. docker/build-push-action builds with Buildx + registry-level caching
  4. Image pushed to Docker Hub under zynomi/*
  5. PR builds compile but never push — only main/develop/tag pushes publish

Required Secrets

Set in Repository → Settings → Secrets → Actions:

SecretDescription
DOCKER_USERNAMEDocker Hub username
DOCKER_TOKENDocker Hub access token

Build Caching

All workflows use Docker Buildx with registry-level caching (type=registry). Unchanged layers are reused, so incremental builds are fast.

ScenarioBehavior
No code changesFully cached (seconds)
App code changesOnly final layers rebuild
Dependency changesDependency + app layers rebuild

Multi-Architecture

ctms.devops workflows build for linux/amd64 + linux/arm64. Other repos build linux/amd64 only.