Pulp Engine v0.18.0 — Release Notes
Release and Deployment Maturity
Summary
Prior to this release, Pulp Engine had no immutable production artifact. Operators were required to clone the repository at a git tag, install all dependencies (including build toolchain), generate the Prisma client, and compile TypeScript on the production host. This made deployments slow, non-reproducible across hosts, and rollback ambiguous — “revert” meant re-checking out an older tag and rebuilding.
v0.18.0 introduces Docker-first packaging as the recommended deployment model:
- Multi-stage Dockerfile — builds a self-contained production image: compiled API code, production-only dependencies (workspace packages resolved), and the Puppeteer/Chromium binary, all bundled together
- GHCR publishing in
release.yml— every git tag push now builds and pushes a versioned image to GitHub Container Registry before creating the GitHub Release, so the image and the release note are always in sync - Deployment validation script —
scripts/validate-deploy.shprovides a scriptable post-deploy smoke test covering liveness, readiness, metrics, auth, and the render pipeline - Updated deployment guide — Docker quick start, postgres and file mode examples, migration command, rollback procedure, volume mount reference, container env var defaults
- Concrete rollback procedure — tied to the Docker image tag: rollback is
docker stop+docker run v0.PREV.Y, with no build step required - Release process checklist — per-release checklist covering pre-release, artifact, deployment, monitoring, and rollback
New files
| File | Purpose |
|---|---|
Dockerfile | Multi-stage production image (builder → runtime) |
.dockerignore | Excludes dev artifacts, tests, docs, and secrets from the build context |
scripts/validate-deploy.sh | Post-deployment validation script |
docs/release-checklist.md | Per-release process checklist (added at top of existing MVP checklist file) |
Changed files
| File | Change |
|---|---|
.github/workflows/release.yml | Added docker job (build + push to GHCR); release job now depends on docker succeeding |
apps/api/package.json | Moved prisma from devDependencies to dependencies |
docs/deployment-guide.md | Added Docker Deployment section; updated intro |
docs/runbook.md | Updated Rollback section (Docker-first with bare-metal fallback); added validate-deploy.sh reference to smoke tests section |
Docker image
Image: ghcr.io/OWNER/pulp-engine:v0.18.0
Tags: v0.18.0 (immutable) and latest (rolling)
Base: node:22-slim (runtime stage)
Default STORAGE_MODE: file (no database required)
Quick start
# File mode (no database)
docker run -d \
--name pulp-engine \
-p 3000:3000 \
-e API_KEY_ADMIN=your-secret-key \
-e STORAGE_MODE=file \
-e TEMPLATES_DIR=/templates \
-v /var/pulp-engine/templates:/templates:ro \
-v /var/pulp-engine/assets:/data/assets \
ghcr.io/OWNER/pulp-engine:v0.18.0
See docs/deployment-guide.md (Docker Deployment section) for postgres mode and full operator instructions.
Postgres migration — same artifact
Migrations now run from the same image tag that serves the API. No repo checkout required on the production host:
docker run --rm \
-e DATABASE_URL=postgres://user:pass@host:5432/pulp-engine \
ghcr.io/OWNER/pulp-engine:v0.18.0 \
node_modules/.bin/prisma migrate deploy \
--schema src/prisma/schema.prisma
This works because prisma was moved to production dependencies (from devDependencies) in this release. The Prisma schema and migration files are included in the image via pnpm deploy.
Chrome sandbox
PULP_ENGINE_DISABLE_SANDBOX=true is set automatically in the image — this is required for containerised Chrome (no kernel sandbox). Do not unset this variable in Docker/Kubernetes deployments.
Deployment validation script
scripts/validate-deploy.sh is a bash smoke test for post-deployment validation.
./scripts/validate-deploy.sh [BASE_URL] [API_KEY] [TEMPLATE_KEY]
| Check | Condition | What it validates |
|---|---|---|
GET /health | Always | Liveness |
GET /health/ready | Always | Readiness / storage reachable |
GET /metrics | Always | Prometheus endpoint + format |
GET /templates | API_KEY provided | Auth configured, template store queryable |
POST /render/html | API_KEY + TEMPLATE_KEY | Full HTML render pipeline |
Exits 0 on success, 1 on any failure. Suitable for use as a CI gate or deployment pipeline step.
Release workflow changes
The release.yml workflow now has two jobs:
docker— builds the multi-stage image and pushes toghcr.io/OWNER/pulp-engine:{tag}andghcr.io/OWNER/pulp-engine:latestrelease— creates the GitHub Release (depends ondockersucceeding)
The image and the GitHub Release are always in sync: if the Docker build fails, no release is created.
latest is updated on every tag push. See docs/release-checklist.md for the policy on patch releases from older branches.
Upgrade notes
Existing bare-metal (non-Docker) deployments: No changes required. The Dockerfile and release workflow additions are purely additive. Existing deployment and rollback procedures continue to work.
prisma moved to production dependencies: If you run pnpm install --prod directly (outside of Docker), prisma will now be included. This is a no-op change for most deployments — the CLI was already installed in the monorepo’s root node_modules.
CI: No changes to ci.yml. Tests, lint, and build steps are unchanged.
No database schema changes. No API breaking changes. No endpoint changes.
What is not in scope (planned follow-up)
- Multi-architecture Docker image (linux/arm64 support)
- Editor SPA container or CDN deployment guide
- Automatic migration in container entrypoint (init-container / K8s Job pattern)
- Helm chart / Kubernetes manifests
- Automated version bumping (changeset, semantic-release, or release-it)
- SQL Server migration from Docker image (requires
tsx— currently excluded from the production image)