echo-backend is the launcher and business-logic tier (Tier 2) of the echo reference application — a Wanderland engine that launches Nextflow runs as Kubernetes Jobs and proxies observability reads from foxfire for the frontend. It runs on Kubernetes (CoreWeave dev/prod, OrbStack local) and is reached in-cluster by the frontend.
POST /runs — launch a Nextflow fibfizz run: render a driver Job manifest and apply it fire-and-forget; returns a run id.POST /graphql — forward a GraphQL query to foxfire and return { data, errors }, so the frontend reads run/task/cost through the backend it already calls.GET /health — liveness.The frontend talks to one backend, and runs are launched by something that holds cluster credentials and business logic rather than the browser. echo-backend is that seam: it turns a UI action into a Kubernetes Job and curates what the UI reads from the receiver. It also demonstrates that the deploy machinery is workload-agnostic — a Wanderland engine uses the same pipeline as a static site or a JVM service.
Wanderland::Engine. Boundaries: launch_run (renders the driver Job and dispatches the k8s-pack k8s_job launch primitive with wait: false), foxfire_graphql (HTTP proxy to foxfire's /graphql), and the core health.launch_run builds a batch/v1 Job: the advaita/nf-driver image, serviceAccountName: nextflow-runner, the shared nextflow-work RWX PVC at /work, ttlSecondsAfterFinished, and env FOXFIRE_URL=<receiver>/events/signed, FOXFIRE_KEY_ID, and FOXFIRE_SIGNING_KEY (via secretKeyRef to the foxfire-signing-key Secret). The run id (echo-<utc>-<hex>) is both the Job name and the Nextflow -name.!Env.kubectl (shell, to apply the Job) and http (to reach foxfire).advaita/echo-backend (ECR), the engine-service image (ruby:3.4-slim + the kubectl binary; clones wanderland-core + wanderland-k8s-pack as siblings; boots wanderland --type http config.yml). Built and pushed by echo-backend/vivarta.yml.http), probes /health, serviceAccountName: nextflow-launcher./api/* proxy.vivarta-echo.| Env | Context | Image stage |
|---|---|---|
| local | orbstack |
build → ECR |
| dev | useast13-dev |
build → ECR |
| prod | useast13-prod |
promote (k8s_live_image) |
config.yml: routes /runs (launch_run) + /graphql (foxfire_graphql); adapters kubectl + http; route args via !Env with defaults — DRIVER_IMAGE, NF_NAMESPACE, NF_SERVICE_ACCOUNT, NF_WORK_PVC, FOXFIRE_URL, KUBE_CONTEXT, FOXFIRE_KEY_ID, FOXFIRE_SIGNING_KEY_SECRET, FOXFIRE_SIGNING_KEY_REF.FOXFIRE_URL → the in-cluster receiver (http://foxfire.vivarta-echo.svc.cluster.local:9311).echo-backend/vivarta.yml (containerized_deployment; docker_build → ECR; k8s_provisioner). git-sha image tag.echo-backend/k8s/infra/launcher-rbac.yaml — nextflow-launcher ServiceAccount + Role (create/get/list/watch/delete batch/jobs) + RoleBinding. Applied once per cluster.FOXFIRE_SIGNING_KEY must be a PKCS#8 EC P-256 PEM (BEGIN PRIVATE KEY). The nf-foxfire plugin loads it with Java's KeyFactory, which reads PKCS#8; Ruby/OpenSSL's default EC to_pem is SEC1 (BEGIN EC PRIVATE KEY), which Java won't load — convert with openssl pkcs8 -topk8 -nocrypt. The receiver verifies with the SPKI public key of the same pair (keys: { <key_id>: <spki-pem> }).
| Dependency | Use | Endpoint / id |
|---|---|---|
| foxfire | GraphQL reads (proxied) | foxfire.vivarta-echo.svc.cluster.local:9311/graphql |
| nf-driver | image launched as a Job | advaita/nf-driver |
| wanderland-k8s-pack | k8s_job launch primitive |
runtime dependency |
| Kubernetes API | create driver Jobs | via nextflow-launcher SA |
foxfire-signing-key Secret |
signing key injected on the Job | secretKeyRef; provisioned from SSM (open) |
| Dependent | Use |
|---|---|
| echo-frontend | POSTs /api/runs (launch) and /api/graphql (reads) through nginx |
The frontend cannot launch runs or read history (both route through the backend). Driver Jobs already created continue and still ship to foxfire. Blast radius is new launches plus the UI read path.
vivarta-examples (echo-backend/). Ruby / wanderland-core engine; boundaries under lib/echo/boundaries/. Uncommitted as of 2026-07-01.FOXFIRE_SIGNING_KEY via secretKeyRef to foxfire-signing-key assumes that Secret exists (PKCS#8 PEM from SSM) per cluster; the SSM→Secret sync is not built: TBD.