Files
cms/Dockerfile
zooqueen 1b74e601b0 feat(cms/admin): Hanzo mark as the admin tab icon
The admin declared no `admin.meta.icons`, so every view fell back to the
favicons bundled in packages/ui. Point the deployed app (apps/hanzo-demo) at the
canonical Hanzo mark, kept as two SVGs in the app's public/ dir so the ink
inverts with the tab bar: black for a light tab, white for a dark one. Path data
is copied verbatim from @hanzo/logo dist/favicon.svg.

The mark stays at the app level rather than in packages/ui, which is
brand-neutral on purpose so cms.lux.network and cms.zoo.ngo keep their own.

`next build` leaves public/ out of the standalone tree and server.js chdir's to
its own directory, so the Dockerfile copies the folder next to server.js.

Also drop `admin.meta.title`: every view spreads admin.meta over its own title,
so it rendered "Hanzo CMS — Hanzo CMS" on every page and lost the view name. The
suffix alone gives "Dashboard — Hanzo CMS". The landing page now draws the local
mark instead of a remote one and links to docs.hanzo.ai.
2026-08-13 22:49:16 -07:00

57 lines
2.8 KiB
Docker

# cms.hanzo.ai — @hanzo/cms (Hanzo headless CMS; MIT fork owned in-tree).
#
# The deployed image runs `node apps/hanzo-demo/server.js` (the operator CR's
# command). That server.js only exists from a Next standalone build, which in
# this pnpm monorepo lands at .next/standalone/apps/hanzo-demo/server.js. This
# multi-stage build produces exactly that, CGO-free, and copies the standalone
# tree + static assets into a slim runner.
#
# Built by Hanzo CI/platform (hanzoai/ci reads hanzo.yml), never on a dev box.
# pnpm is pinned to 10.27 (engines gate) via corepack.
# ---- deps + build ----------------------------------------------------------
FROM node:22-bookworm-slim AS builder
WORKDIR /app
ENV PNPM_HOME=/pnpm
ENV PATH=$PNPM_HOME:$PATH
ENV NEXT_TELEMETRY_DISABLED=1
# Node heap headroom: in-workspace the @hanzo/cms* packages resolve to raw src,
# so the webpack build graph is large.
ENV NODE_OPTIONS=--max-old-space-size=8192
RUN corepack enable && corepack prepare [email protected] --activate
# Whole workspace (Turbopack/webpack resolve @hanzo/cms* from src via workspace
# links; the app's next.config roots file-tracing at the workspace).
COPY . .
RUN pnpm install --frozen-lockfile
# Build ONLY the app + its real dependency graph (turbo --filter), producing the
# standalone bundle (next build --webpack — Turbopack can't do the .js->.tsx
# workspace remap; see apps/hanzo-demo/next.config.ts). This is exactly the
# validated-green command (14/14 tasks); `build:all` is avoided because it also
# builds unrelated tooling (@tools/scripts) that isn't needed for the image.
RUN pnpm turbo build --filter @hanzo/cms-demo
# ---- runner ----------------------------------------------------------------
FROM node:22-bookworm-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
RUN groupadd --system --gid 1001 nodejs && useradd --system --uid 1001 --gid nodejs nextjs
# Next standalone output (monorepo layout: server.js is nested under the app
# path, and the traced node_modules ride alongside it at the workspace root).
COPY --from=builder --chown=nextjs:nodejs /app/apps/hanzo-demo/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/apps/hanzo-demo/.next/static ./apps/hanzo-demo/.next/static
# Uploaded media rides S3 (hanzo-cms bucket), so public/ holds only the brand
# marks the admin <link rel="icon"> points at. `next build` does not fold public/
# into the standalone tree, and server.js chdir's to its own dir, so the folder
# has to be copied next to server.js or the tab icon 404s.
COPY --from=builder --chown=nextjs:nodejs /app/apps/hanzo-demo/public ./apps/hanzo-demo/public
USER nextjs
EXPOSE 3000
# Matches the operator CR command exactly: `node apps/hanzo-demo/server.js`.
CMD ["node", "apps/hanzo-demo/server.js"]