build: make Dockerfile Coolify-ready

- add .dockerignore: without it the build context shipped .env.local
  (PB_TOKEN + CIPC passwords), node_modules and the full .git history
- bake NEXT_PUBLIC_PB_URL / NEXT_PUBLIC_BASE_URL / NEXT_PUBLIC_APP_URL
  as build args; NEXT_PUBLIC_PB_URL was read by client components but
  never supplied, so browser-side PocketBase calls would break
- docker-compose: same build args + Telegram runtime env
- document that agent-browser / PDFD sidecar routes stay on the PC
This commit is contained in:
sjcoetzeesj-coder 2026-10-18 15:30:20 +02:00
parent 11d0178ab1
commit 9ccd36ec93
3 changed files with 110 additions and 17 deletions

67
Workflow/.dockerignore Normal file
View file

@ -0,0 +1,67 @@
# ─────────────────────────────────────────────────────────────────
# .dockerignore — keep the build context small and secret-free.
#
# Critical: without this file the whole local working tree is sent to
# the Docker daemon, including .env.local (PB_TOKEN, CIPC passwords),
# node_modules and the full .git history.
# ─────────────────────────────────────────────────────────────────
# --- secrets: never let these reach the build context ---------------
.env
.env.*
!.env.example
# --- deps, build output, git history ----------------------------------
node_modules
.next
out
dist
build
*.tsbuildinfo
.git
.gitignore
.gitattributes
# --- logs & runtime state --------------------------------------------
*.log
*.log.err
*.tmp
.runtime
.dev-screenshots
npm-debug.log*
# --- local databases --------------------------------------------------
*.sqlite
*.sqlite3
*.db
# --- secrets inside scripts/ ------------------------------------------
# Playwright storage state = live CIPC/SARS session cookies.
scripts/storage_state.json
# --- scratch, compiled python, debug artefacts ------------------------
__pycache__
**/__pycache__
*.py[cod]
*.bin
scripts/.scratch
scripts/_scratch
scripts/_backup_ufc_docs
scripts/_*.png
scripts/sars_login_*.png
scripts/_upload_probe.pdf
_probe*.json
_junction_backup*.json
# --- docs, samples and one-off probes (not needed to serve the app) ---
docs
scratch-*
Sample_*.docx
Sample_*.pdf
*.preview-p*.png
.preview-p*.png
workpage*.png
desktop.ini
Thumbs.db
*.bak
*.bak.*

View file

@ -1,5 +1,5 @@
# ─────────────────────────────────────────────────────────────────
# Workflow PocketBase Frontend — Dockerfile
# Workflow PocketBase Frontend — Dockerfile (Coolify-ready)
#
# Multi-stage build for a small production image:
# - deps: install everything
@ -9,14 +9,23 @@
#
# Image runs as non-root user `nextjs` on port 3000.
#
# Build context: project root (where package.json lives).
# Example:
# docker build -t workflow-frontend .
# docker run --rm -p 3000:3000 \
# -e NEXT_PUBLIC_BASE_URL=https://workflow.example.co.za \
# -e PB_URL=https://pb.agent.apphub.co.za \
# -e PB_TOKEN=... \
# workflow-frontend
# Build context: this folder (where package.json lives).
# Local: docker build -t workflow-frontend .
# docker run --rm -p 3000:3000 \
# -e PB_URL=https://pb.agent.apphub.co.za \
# -e PB_TOKEN=... \
# workflow-frontend
#
# Coolify: set "Dockerfile" as the build pack, port 3000, and configure
# Build Arguments (NEXT_PUBLIC_PB_URL, NEXT_PUBLIC_BASE_URL,
# NEXT_PUBLIC_APP_URL) + Runtime Environment (PB_URL, PB_TOKEN,
# TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, ONBOARDING_TOKEN_PEPPER).
# See docker-compose.yml for the same contract in one place.
#
# NOTE — routes that shell out to local Windows tooling do NOT work in
# this Linux image: the CIPC/BizPortal routes drive agent-browser and the
# BizPortal sidecar, and PDF rendering expects a Windows Chrome or the
# PDFD_URL sidecar. They stay on the PC; host them separately.
# ─────────────────────────────────────────────────────────────────
# ─── 1. Deps ─────────────────────────────────────────────────────
@ -34,14 +43,26 @@ WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Required at build-time so Next.js bakes the public URL into the
# client bundle. PB_TOKEN is NOT required here — it's only read
# server-side at runtime.
# Required at build-time so Next.js bakes them into the client bundle.
# Next.js INLINES every NEXT_PUBLIC_* at build time — if they are missing
# here, the browser bundle ships with an empty PocketBase URL and every
# client-side PB call fails. Set them as Build Arguments in Coolify.
#
# NEXT_PUBLIC_PB_URL — read by components/CipcAnnualReturns.tsx and
# components/DocumentsPanel.tsx
# NEXT_PUBLIC_BASE_URL — read by app/onboarding/new/page.tsx (link the
# client sends in the onboarding e-mail)
# NEXT_PUBLIC_APP_URL — absolute app URL used in appointment e-mails
#
# Server-only secrets (PB_URL, PB_TOKEN, TELEGRAM_*, ONBOARDING_TOKEN_PEPPER)
# are NOT needed here — they are read at runtime, never bundled.
ARG NEXT_PUBLIC_PB_URL
ARG NEXT_PUBLIC_BASE_URL
ENV NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL}
# Disable telemetry; speeds up build; we don't need it.
ENV NEXT_TELEMETRY_DISABLED=1
ARG NEXT_PUBLIC_APP_URL
ENV NEXT_PUBLIC_PB_URL=${NEXT_PUBLIC_PB_URL} \
NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL} \
NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL} \
NEXT_TELEMETRY_DISABLED=1
RUN npm run build

View file

@ -16,8 +16,11 @@ services:
context: .
dockerfile: Dockerfile
args:
# Bake the public URL into the client bundle at build time.
# Baked into the CLIENT bundle by Next.js at build time — all three
# must be set or browser-side PocketBase calls get an empty URL.
NEXT_PUBLIC_PB_URL: ${NEXT_PUBLIC_PB_URL:-https://pb.agent.apphub.co.za}
NEXT_PUBLIC_BASE_URL: ${NEXT_PUBLIC_BASE_URL:-http://localhost:3000}
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
image: workflow-frontend:latest
container_name: workflow-frontend
restart: unless-stopped
@ -29,6 +32,8 @@ services:
PB_URL: ${PB_URL:?Set PB_URL in .env}
PB_TOKEN: ${PB_TOKEN:?Set PB_TOKEN in .env}
ONBOARDING_TOKEN_PEPPER: ${ONBOARDING_TOKEN_PEPPER:-}
TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN:-}
TELEGRAM_CHAT_ID: ${TELEGRAM_CHAT_ID:-}
NODE_ENV: production
PORT: 3000
HOSTNAME: 0.0.0.0