Hosting the Iceberg Visualizer
The visualizer runs locally via nessie viz with no hosting — see the
design doc. The hosted variant adds browser-only access
for users without the repo/uv toolchain.
Architecture
The hosted visualizer runs as a sidecar container in the existing Nessie ECS task.
Same ALB, same domain (nessie.app.autointel.ai), path-based routing splits traffic:
ALB (nessie.app.autointel.ai)
├── /viz* → nessie-viz target group (sidecar:19121)
└── /* (default) → nessie target group (nessie:19120)
The sidecar proxies catalog requests to localhost:19120 (Nessie on the same task),
keeping all catalog traffic same-origin — no Nessie CORS needed.
Auth
Auth0 PKCE (public SPA client). The browser authenticates directly via auth0-spa-js
and attaches Authorization: Bearer <token> to every fetch. The sidecar forwards the
header to Nessie as-is — Nessie validates it via its existing service OIDC tenant.
S3 credentials
Nessie vends short-lived, per-table-scoped S3 credentials in the loadTable REST
response. DuckDB requests them via ACCESS_DELEGATION_MODE 'vended_credentials' at
ATTACH time. A reader token gets read-only creds; service/admin get read-write.
No separate AWS secret or STS endpoint needed.
Infrastructure
Terraform resources
| Resource | File | Purpose |
|---|---|---|
aws_ecr_repository.nessie_viz | ecr.tf | ECR repo for the sidecar image |
aws_lb_target_group.nessie_viz | nessie_ui_alb.tf | ALB target group for port 19121 |
aws_lb_listener_rule.nessie_viz | nessie_ui_alb.tf | Path-based routing (/viz*) |
| SG ingress for 19121 | nessie_alb.tf | ALB → sidecar connectivity |
| CORS origin | nessie_s3.tf | https://nessie.app.autointel.ai in bucket CORS |
Environment variables (sidecar container)
| Variable | Source |
|---|---|
NESSIE_VIZ_HOSTED | "true" |
AUTH0_DOMAIN | var.auth0_domain |
AUTH0_VIZ_CLIENT_ID | var.auth0_viz_client_id |
AUTH0_API_AUDIENCE | var.auth0_api_audience |
The service
services/ai_nessie_viz/ — a shell around packages/ai_nessie, which owns the
server and the SPA. Only the deployment specifics live in the service: bind-all, the
in-task Nessie address, and the AUTH0_* names the task definition supplies. It is
built like every other image in the repo — pants package services/ai_nessie_viz/src:pex, then a venv materialized from the pex — by the generic
build_service_image CI job, which discovers it from services/*/pyproject.toml.
Its build.yaml declares registry: (the nessie-viz ECR repo, which does not
match the service name) and sidecar: true, so CI pushes the image without rolling
anything. This is a sidecar in the nessie service, and rolling it would restart
the Nessie catalog. A new image is collected on the next deployment of that task.
ai_core must stay out of the image. ai_nessie depends on it for the CLI's
device-flow auth, but nothing reachable from main() imports it, so Pants leaves
ai_core (and pyiceberg, boto3, polars) out of the pex.
services/ai_nessie_viz/tests/test_image_surface.py fails if that stops holding.
Auth0 setup (manual, one-time)
Create a Single Page Application in Auth0:
| Setting | Value |
|---|---|
| Allowed Callback URLs | https://nessie.app.autointel.ai/viz/ |
| Allowed Logout URLs | https://nessie.app.autointel.ai/viz/ |
| Allowed Web Origins | https://nessie.app.autointel.ai |
| Grant Types | Authorization Code (PKCE) |
Note the Client ID and set it as:
- GitHub Actions variable:
AUTH0_VIZ_CLIENT_ID - Terraform variable:
auth0_viz_client_id
The existing Login post-login Action already injects roles into access tokens — the viz SPA gets the same RBAC claim as the CLI device flow.
Deploy order
- Create Auth0 SPA application, note client ID.
- Set
AUTH0_VIZ_CLIENT_IDin GitHub Actions variables andauth0_viz_client_idin Terraform tfvars. - Merge PR (CI builds viz image, pushes to ECR with
prodtag). terraform apply(creates ECR repo, viz-reader role, sidecar container, ALB routing).- Verify at
https://nessie.app.autointel.ai/viz/.
Verification
- Visit
https://nessie.app.autointel.ai/viz/— should redirect to Auth0 login. - After login — table tree loads, run a SELECT query, data returns (vended creds).
- Local
nessie vizstill works unchanged (local mode is unaffected). - Load a table with a
readertoken and confirms3:PutObjectis denied (RBAC scoping).