Overlays the complete 80-file src/react surface (all 58 panels, globe island, variant tabs, analyst dock, finance terminal, OIDC PKCE callback) onto the live origin/main backend (v2.4.51 AI-plane + events-stream fixes, kept intact). The React surface is served ONLY to sessions that opt in via ?react (sticky cookie, cmd/world canaryHandler); the vanilla build stays the default — nothing changes for anyone until we flip it. @hanzogui/shell 7.6.1 (monochrome focus ring + world surface). All gates green: typecheck:react, build:react (221kB gz), vanilla build, canary server tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
79 lines
3.9 KiB
Docker
79 lines
3.9 KiB
Docker
# world.hanzo.ai — Vite SPA + same-origin /api/* data backend, one Go binary.
|
|
#
|
|
# The SPA fetches SAME-ORIGIN /api/* (runtime.ts resolves to the current origin),
|
|
# so world.hanzo.ai (and every *.hanzo.app fork) must serve /api/* itself. The
|
|
# old static-only image (hanzoai/static) had no /api, so every data + live-video
|
|
# request fell through to the SPA index.html — the app showed no data and no
|
|
# video. This image fixes that: cmd/world serves BOTH the static build (with SPA
|
|
# fallback for client routes) AND the ~48 /api/* endpoints (internal/world),
|
|
# each a faithful Go port of the original edge function.
|
|
#
|
|
# Built on Hanzo's own hardware (platform.hanzo.ai -> arcd / in-cluster
|
|
# BuildKit), never on GitHub builders.
|
|
#
|
|
# Build (BuildKit, on-cluster):
|
|
# --opt=context=https://github.com/hanzoai/world.git#<sha>
|
|
# --opt=filename=Dockerfile
|
|
# --output=type=image,name=ghcr.io/hanzoai/world:<tag>,push=true
|
|
#
|
|
# Data-source API keys (all optional; a missing key degrades that endpoint to a
|
|
# clean empty payload, never a 5xx) are injected as env at deploy time from KMS:
|
|
# YOUTUBE_API_KEY (live-video reliability; scrape fallback needs no key),
|
|
# FRED_API_KEY, FINNHUB_API_KEY, NASA_FIRMS_API_KEY, EIA_API_KEY,
|
|
# ACLED_ACCESS_TOKEN, CLOUDFLARE_API_TOKEN, WINGBITS_API_KEY, WS_RELAY_URL,
|
|
# HANZO_AI_KEY (+ HANZO_AI_BASE / HANZO_AI_MODEL) for the AI endpoints.
|
|
|
|
# ---- web stage: Vite static build (-> /app/dist) -------------------------
|
|
FROM node:20-bookworm-slim AS web
|
|
WORKDIR /app
|
|
COPY package.json package-lock.json ./
|
|
RUN npm ci
|
|
COPY . .
|
|
# vite.config.ts: default base '/', default outDir 'dist'. VITE_VARIANT defaults
|
|
# to the full layer set; no build-time secrets are required (the runtime API base
|
|
# is same-origin, resolved in the browser).
|
|
ARG VITE_MAPBOX_TOKEN
|
|
ENV VITE_MAPBOX_TOKEN=$VITE_MAPBOX_TOKEN
|
|
RUN npm run build
|
|
# The @hanzo/gui (Tamagui) React rewrite, built to /app/dist-react as the opt-in
|
|
# canary surface. Served only to sessions that pass ?react (see cmd/world:
|
|
# canaryHandler); the vanilla dist above stays the default.
|
|
RUN npm run build:react
|
|
|
|
# ---- go stage: build the static server binary (CGO-free) -----------------
|
|
# go 1.26: go.mod requires >= 1.26.4 (github.com/hanzoai/sqlite drop-in). The
|
|
# binary stays CGO-free — with CGO_ENABLED=0, hanzoai/sqlite selects its vendored
|
|
# pure-Go engine (zero modernc.org/* in the module graph). That engine gates FTS5
|
|
# behind the `sqlite_fts5` build tag, which the store's items_fts virtual table
|
|
# needs — so the build below MUST carry `-tags sqlite_fts5` or Open degrades.
|
|
FROM golang:1.26-alpine AS gobuild
|
|
WORKDIR /src
|
|
# git: go resolves the PRIVATE indirect dep github.com/hanzoai/csqlite 'direct'
|
|
# (not via the module proxy), which needs the git binary + an https credential.
|
|
# alpine ships neither, so add git and mount the gh_token BuildKit secret that
|
|
# hanzoai/ci passes (--secret id=gh_token); the mount is a no-op for public builds.
|
|
RUN apk add --no-cache git
|
|
ENV GOPRIVATE=github.com/hanzoai,github.com/luxfi,github.com/zooai
|
|
# Deps: hanzo-kv client (go-redis) + embedded SQLite (modernc). Download once for
|
|
# a cached layer before the source is copied.
|
|
COPY go.mod go.sum ./
|
|
RUN --mount=type=secret,id=gh_token \
|
|
if [ -s /run/secrets/gh_token ]; then \
|
|
git config --global url."https://x-access-token:$(cat /run/secrets/gh_token)@github.com/".insteadOf "https://github.com/"; \
|
|
fi; \
|
|
go mod download
|
|
COPY cmd ./cmd
|
|
COPY internal ./internal
|
|
RUN CGO_ENABLED=0 GOOS=linux go build -tags sqlite_fts5 -trimpath -ldflags="-s -w" -o /out/world ./cmd/world
|
|
|
|
# ---- final stage: minimal image running the Go binary --------------------
|
|
FROM alpine:3.20
|
|
RUN apk add --no-cache ca-certificates tzdata \
|
|
&& adduser -D -H -u 10001 world
|
|
COPY --from=gobuild /out/world /usr/local/bin/world
|
|
COPY --from=web /app/dist /srv
|
|
COPY --from=web /app/dist-react /srv-react
|
|
USER world
|
|
EXPOSE 3000
|
|
ENTRYPOINT ["/usr/local/bin/world", "--root=/srv", "--react-root=/srv-react", "--addr=:3000"]
|