Skip to main content

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

ResourceFilePurpose
aws_ecr_repository.nessie_vizecr.tfECR repo for the sidecar image
aws_lb_target_group.nessie_viznessie_ui_alb.tfALB target group for port 19121
aws_lb_listener_rule.nessie_viznessie_ui_alb.tfPath-based routing (/viz*)
SG ingress for 19121nessie_alb.tfALB → sidecar connectivity
CORS originnessie_s3.tfhttps://nessie.app.autointel.ai in bucket CORS

Environment variables (sidecar container)

VariableSource
NESSIE_VIZ_HOSTED"true"
AUTH0_DOMAINvar.auth0_domain
AUTH0_VIZ_CLIENT_IDvar.auth0_viz_client_id
AUTH0_API_AUDIENCEvar.auth0_api_audience

Docker image

deployments/aws/docker/nessie-viz/Dockerfile — Python 3.13, copies nessie_viz.py + viz/ assets. Built and pushed to ECR by the build_viz_image CI job (triggered by changes to viz source files).

Auth0 setup (manual, one-time)

Create a Single Page Application in Auth0:

SettingValue
Allowed Callback URLshttps://nessie.app.autointel.ai/viz/
Allowed Logout URLshttps://nessie.app.autointel.ai/viz/
Allowed Web Originshttps://nessie.app.autointel.ai
Grant TypesAuthorization 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

  1. Create Auth0 SPA application, note client ID.
  2. Set AUTH0_VIZ_CLIENT_ID in GitHub Actions variables and auth0_viz_client_id in Terraform tfvars.
  3. Merge PR (CI builds viz image, pushes to ECR with prod tag).
  4. terraform apply (creates ECR repo, viz-reader role, sidecar container, ALB routing).
  5. Verify at https://nessie.app.autointel.ai/viz/.

Verification

  1. Visit https://nessie.app.autointel.ai/viz/ — should redirect to Auth0 login.
  2. After login — table tree loads, run a SELECT query, data returns (vended creds).
  3. Local nessie viz still works unchanged (local mode is unaffected).
  4. Load a table with a reader token and confirm s3:PutObject is denied (RBAC scoping).