Ship a change
Getting a merged change onto dev, then promoting it to UAT and prod. The Shell runs its own pipeline — .github/workflows/ci-cd.yml in veni-shell — on top of the platform's GitOps model. Where this page and the platform page differ, the workflow file is what runs.
The one thing to know first: merging to develop builds but does not deploy. Deploying to dev is a deliberate second step.
What each push does
| You push | CI does | Deploys? |
|---|---|---|
develop | Quality gate, build + push dev-<sha>, Trivy scan | No |
release/dev | Rewrites newTag in the dev overlay, commits it back | Dev, via ArgoCD |
v*.*.*-rc.* tag | Retags dev-<sha> → rc tag | UAT, if gated on |
v*.*.* tag | Retags dev-<sha> → release tag | Prod, if gated on |
(manual) workflow_dispatch | Deploys an existing tag | Dev |
The quality gate runs typecheck, lint and test for both api and ui, and all of them block. Build and deploy jobs depend on it, so a failure stops everything downstream.
Deploy to dev
Merge your PR into
develop. CI builds and pushesregistry.venizia.ai/shell-api:dev-<sha>andshell-ui:dev-<sha>, then scans them. No cluster is touched.Release it, either way:
bashgit push origin develop:release/dev # CI bumps the overlay from origin/develop's shaOr Actions → CI/CD → Run workflow, optionally pinning a tag like
dev-abc1234(empty = latestdevelopbuild).
CI rewrites newTag in deploy/k8s/overlays/dev/kustomization.yaml and commits it to release/dev as chore(k8s/dev): shell → dev-<sha> [skip ci]. ArgoCD app shell-dev (auto-sync, tracks release/dev) reconciles it.
CI never runs kubectl against dev by design — an imperative change would be reverted by Argo self-heal.
Migrations ride along: deploy/k8s/base/api/migrate-job.yaml is an ArgoCD PreSync hook, so it completes before the new pods roll, and a failing migration fails the sync.
Lands on veni.dev.venizia.ai (API: shell-api.dev.venizia.ai).
Promote to UAT and prod
Both are promote, not rebuild — the exact dev-<sha> bytes validated in dev get retagged, so what ships is what was tested.
git tag v1.2.0-rc.1 <sha> && git push origin v1.2.0-rc.1 # → UAT
git tag v1.2.0 <sha> && git push origin v1.2.0 # → prodThe tagged commit must already have been built on develop — its dev-<sha> image has to exist, or the promote job fails with an explicit error.
Both deploys are gated: the repo variable DEPLOY_UAT_ENABLED / DEPLOY_PROD_ENABLED must be "true", and the KUBECONFIG_NONPROD / KUBECONFIG_PROD secret must exist. Otherwise the job is inert. Unlike dev, these use kubectl set image directly, wait for the rollout, then smoke-test the homepage.
UAT: shell.uat.venizia.ai · Prod: app.veni.ai
Roll back dev
Re-run the deploy with a known-good tag — Actions → CI/CD → Run workflow, tag dev-<older-sha> — or edit newTag in the dev overlay on release/dev and push.
A rollback does not undo a migration; the PreSync hook only rolls forward. If the bad change carried a migration, write a new one that reverses it.
Change an environment variable
Three places, and missing one is the usual cause of "works locally, broken in dev":
| Where | File |
|---|---|
| Local stack | docker-compose.yml |
| Documented default | api/.env.example (Configure) |
| Cluster | deploy/k8s/overlays/<env>/api-env-patch.yaml (or ui-env-patch.yaml) |
Secrets never go in git. They come from Vault through the External Secrets Operator — deploy/k8s/overlays/<env>/external-secrets.yaml. Dev extracts secret/veni/dev/shell/api via the shared vault-backend ClusterSecretStore; add the key in Vault and it syncs on the refresh interval. Don't reference a per-app vault-shell store — it isn't provisioned, and doing so yields SecretSyncedError.
Ship a docs change
These pages live in VENIZIA-AI/veni-docs, not in veni-shell. Shell pages are develop/shell/*.md.
PR into dev. The validate workflow runs npm run validate and npm run build on every PR — a dead page link fails it. On merge, it builds and pushes veni-docs-ui:latest, which the dev overlay pins, and the site picks it up on the next reconcile.
What goes where: the veni-shell README is orientation plus the commands that live in that repo; anything conceptual or reference-level belongs here. See Documenting a project in the docs repo.
Common snags
| Symptom | Fix |
|---|---|
Merged to develop, nothing deployed | Working as designed — develop only builds. Push release/dev or run the workflow manually. |
| Promote job: "Source image … not found" | The tagged commit was never built on develop. Tag a commit that has a dev-<sha> image. |
| Tag pushed, UAT/prod didn't move | The deploy is gated — check repo vars DEPLOY_UAT_ENABLED / DEPLOY_PROD_ENABLED and that the KUBECONFIG_* secret exists. |
| Argo sync stuck | Usually the PreSync migrate Job failing — read that Job's logs first. |
SecretSyncedError on an ExternalSecret | The Vault key is missing, or the store reference is wrong (see above). |
| A new image didn't roll out | Nothing auto-detects a tag — the overlay's newTag must change and be committed. |
| Rolled back, still broken | A rollback doesn't revert a migration. Write a forward migration that undoes it. |
Check what's deployed
newTag in deploy/k8s/overlays/<env>/kustomization.yaml on the release/dev branch is what dev is meant to be running. The tag is dev-<sha>, where the sha is the develop commit it was built from.
See also
- Run — run it locally before you ship it.
- Deployment — the platform-wide GitOps model, environments and promotion.