transformable-container

PocketBase-backed deploy API for a single static site. Zip deploy, list revisions, rollback.

What is transformable-container?

transformable-container is a Docker image that runs PocketBase with custom hooks to provide a simple deploy API for a single static site. You upload a zip of your built site; the API extracts it, keeps revision history, and updates a current symlink so your web server (e.g. Nginx) always serves the latest release.

API at a glance

  • POST /api/site/deploy — Upload a zip (multipart file, optional message)
  • GET /api/site/revisions — List current revision and recent history
  • POST /api/site/rollback — Repoint current to a previous revision

All routes require Authorization: Bearer <SITE_DEPLOY_TOKEN>. The container writes releases under the mounted site path and manages the current symlink; Nginx (or another proxy) serves from that path.

How Cursor made this site

This single-page site was created by Cursor (AI-assisted editor) in the repo’s site-build/ directory. No Node or build step: one index.html using Tailwind and Alpine from the CDN.

  • Tailwind CSS — Loaded via the Play CDN (cdn.tailwindcss.com) for utility-first styling.
  • Alpine.js — Loaded from Cloudflare cdnjs for the tabbed sections you’re using now (no framework build).
  • Content explains the project, how Cursor built the page, and how it’s deployed as a transformable.app Portainer stack.

The repo’s skills.md documents the deploy API (base URL, Bearer token, deploy/rollback/revisions). Cursor (or another agent) builds the site in site-build/, zips it to site-build/site.zip, and runs ./scripts/deploy.sh to POST the zip to the running PocketBase deploy API.

Deployed as a transformable.app Portainer stack

This site is deployed by running the transformable-container image as a Portainer stack on transformable.app (or any host). The stack defines the service, volumes, and environment; Nginx on the host serves the static files and proxies the PocketBase API and Admin UI.

Stack overview

  • Image: ghcr.io/transformable-app/transformable-container:latest (built by GitHub Actions)
  • Port: 8090 for PocketBase (bind to 127.0.0.1; Nginx proxies /api/ and /_/)
  • Volumes: pb_data for PocketBase data; host path (e.g. /home/forge/site.example.com) mounted as /site for releases and current
  • Environment: SITE_DEPLOY_TOKEN (required), SITE_URL (optional), SITE_ROOT (default /site)

Nginx’s root is set to the site path plus current (e.g. /home/forge/site.example.com/current). Deploys and rollbacks update the symlink so the next request serves the new release. Full Nginx and stack examples are in the repo’s README.md and docs/DEPLOY.md.