Skip to content

Example: the Talon API

The generic recipe is in Onboard an app. This page is Talon filled in on this Project Loom node. Same workloads/<app>/{base,overlays} shape, same Infisical wiring, same canary as Penvoice — the platform doesn’t care that it’s a second Go app. Where it’s worth calling out: unlike Penvoice, Talon has no client in this node’s Keycloak. It verifies its own passwords and issues its own session, so Keycloak plays no part in it at all.

flowchart LR
    Push([push app staging]) --> CI[checks → GHCR sha]
CI --> Stg[overlays/staging newTag]
Stg --> Argo[Argo CD]
Promo[Promote] --> Prod[overlays/prod same digest]
Inf[Infisical GUI] -->|operator|Sec[(talon-api-env)]
Sec --> RO[Rollout]
Argo --> RO

Staging host test.api.mytalon.co.zw, prod api.mytalon.co.zw. Namespaces talon-staging / talon-prod. The browser holds an httpOnly session cookie; the API is the only party that ever sees a password or a session token. Sessions live in the app’s own Postgres tables (CNPG, not a separate store) since this runs 2 replicas behind a canary and an in-process session map wouldn’t survive that.

ApplicationSet rows in apps/workloads.yaml. Files under workloads/talon/base/ plus overlay patches (namespace, host, Infisical slug, image tag). Identical layout to Penvoice’s.

Infisical project talon, cells staging and prod, each holding FRONTEND_URL (the web origin for that environment) and DEFAULT_PASSWORD. Git has projectId + slug only. Not in Infisical: DB_URL (CNPG uri) and the container port (SERVER_PORT, hardcoded in the Rollout, same role as Penvoice’s API_PORT).

The app runs its embedded migrations on boot (golang-migrate, advisory-locked, so replicas starting together are safe), then seeds any missing baseline stores and the tadmin super admin. /healthz is process-only and backs the liveness probe; /readyz pings Postgres and backs readiness, so a database outage takes pods out of rotation without restarting them. A 5s preStop sleep keeps a terminating pod serving until Traefik drops its endpoint.

Same Infisical project, a third cell: dev. talon-api’s .infisical.json points at the same projectId as the overlays, defaultEnvironment: dev; infisical run -- air replaces manually-exported vars. dev holds all four keys, including DB_URL and SERVER_PORT (no CNPG, no shared manifest locally). Recipe: Onboard → Secrets § Wire local dev.

IntelliJ: a committed Shell Script run config (.run/Air - Development.run.xml, wrapping the same infisical run -- air), the same one Penvoice uses.

Prod: 25→50→75, 60s pauses. Staging: one replica, weight 100. Same strategy as Penvoice. The canary shape lives in the platform pattern, not the app.