π CI/CD β
The current Flowcontrol pipeline is split into three concerns:
- Continuous integration in GitHub Actions
- Container image publication to GitHub Container Registry (GHCR)
- Runtime deployment through Portainer
GitHub Actions no longer deploys the application stack directly. The repo-side flow ends after documentation is published and application images are pushed to GHCR. Portainer is the deployment layer that consumes those images for the staging and production stacks.
Important:
- staging is configured to auto-deploy from the published staging tags
- production is not auto-deployed from GitHub
- production is rolled forward manually in Portainer by updating
APP_VERSIONandIMAGE_TAGand then triggering the stack update
πΏ Branch model β
developmentis the main integration branch.stagingis the protected pre-release branch.masteris the protected production branch.
In practice this means:
- pushes to
developmentrun the development pipeline - pull requests to
stagingandmasterrun validation only - pushes to
stagingandmasterare treated as post-merge release events
πΊοΈ Workflow map β
| Workflow | Trigger | Purpose |
|---|---|---|
development-pipeline.yml | push to development | Runs documentation deploy, Java CI, client CI, and development SonarQube analysis |
protected-branch-ci.yml | pull_request to staging or master | Validates release candidates before merge |
protected-branch-publish.yml | push to staging or master | Verifies approved merge state and publishes application images to GHCR |
reusable-java-ci.yml | workflow_call | Runs mvn verify for one Java module and smoke-builds its Docker image locally with Jib |
reusable-client-ci.yml | workflow_call | Installs the frontend, builds it, and smoke-builds the client Docker image |
documentation-deploy.yml | workflow_call | Builds the VitePress site and deploys it to GitHub Pages |
maintenance.yml | schedule | Keeps the self-hosted runners active |
π Pipeline flow β
The diagram below shows where GitHub Actions stops and where Portainer takes over.
PlantUML source: ci-cd-portainer-flow.puml
π§ͺ Continuous integration β
π¨ development β
The Development Pipeline workflow runs on every push to development.
It currently does the following:
- builds and deploys the documentation site to GitHub Pages
- runs Java CI for
eureka-service,gateway,article,farmer,maintenance,notification, andtransport - runs the client CI workflow
- prepares a development SonarQube instance on a self-hosted runner
- runs SonarQube analysis for
article,farmer,notification,transport, andmaintenance
Important details:
- there is currently no separate pull request workflow for
development - the SonarQube report jobs on
developmentusecontinue-on-error: true, so the development quality gate is informative and does not block the branch - this workflow does not publish application images
π‘οΈ staging and master pull requests β
The Protected Branch CI workflow runs only for pull requests targeting staging or master.
This workflow is validation-only:
- Java modules run through
mvn verify - each Java module also smoke-builds its container image locally with Jib
- the client is installed and built
- the client Docker image is smoke-built locally
- no images are pushed from pull request runs
This separation is intentional. Release branches are validated before merge, but publishing only happens after the approved pull request is merged.
π¦ Continuous deployment β
π·οΈ Image publication β
The Protected Branch Image Publish workflow runs on pushes to staging and master.
Before any image is published, the workflow verifies that:
- the pushed commit is associated with a merged pull request into the target branch
- that pull request has at least one effective
APPROVEDreview
If that verification fails, image publication stops.
When verification succeeds, the workflow publishes GHCR images for:
eureka-servicegateway-servicearticle-modulefarmer-modulemaintenance-modulenotification-moduletransport-moduleflowcontrol-client
π§ͺ Staging tags β
After a merge into staging, each published image receives these tags:
stagingstaging-<short-sha><version>-staging<version>-staging-<short-sha>
These tags are intended for the staging stack and allow both stable and traceable staging deployments.
π Production tags β
After a merge into master, each published image receives one immutable version tag:
<version>
Production image publication is therefore version-based rather than branch-based.
β Portainer handoff β
Portainer is now responsible for the actual application rollout.
The important boundary is:
- GitHub Actions validates code and publishes images
- Portainer handles the runtime rollout behavior per environment
In practice:
- staging auto-deploys from the published staging tags
- production does not auto-deploy after the
masterpublish - production is updated manually in Portainer by setting the intended
APP_VERSIONandIMAGE_TAGand then clicking the update/redeploy action so Portainer pulls the selected image version
Portainer configuration itself is not stored in these workflow files, so the GitHub pipeline documentation should be read as "build and publish in GitHub, deploy in Portainer".
For the runtime stack model itself, see Deployment.
π Documentation deployment β
Documentation is deployed separately from the application stack.
On pushes to development, the reusable documentation-deploy.yml workflow:
- installs the documentation dependencies in
documentation/site - builds the VitePress site
- publishes the static output to GitHub Pages
This means documentation updates go live from development without waiting for a staging or master release.
π Runners β
The pipeline uses a mix of GitHub-hosted and self-hosted runners:
ubuntu-latestis used for documentation builds, reusable Java CI, reusable client CI, and GHCR publishing- self-hosted runners are used for the development SonarQube setup and analysis jobs
maintenance.ymlruns daily at03:00 UTConactions-runner-1andactions-runner-2to keep those runners active
β Typical release flow β
- Feature work is merged into
development. - A push to
developmentruns documentation deployment, Java/client CI, and development SonarQube analysis. - A pull request from
developmenttostagingrunsProtected Branch CI. - After that pull request is approved and merged, the push to
stagingrunsProtected Branch Image Publish. - GHCR receives the staging tags and Portainer auto-deploys the staging environment from those tags.
- A pull request from
stagingtomasterrunsProtected Branch CI. - After that pull request is approved and merged, the push to
masterpublishes immutable version tags to GHCR. - For production, someone updates
APP_VERSIONandIMAGE_TAGin Portainer and triggers the stack update so the production environment pulls the released version.