ZDDC/bootstrap/README.md
ZDDC bdac8dc4fb docs: clean up drift left over from the Codeberg release-assets refactor
The 2dc9ad2 commit ("refactor: distribute via Codeberg release assets,
drop the upstream image") rewrote AGENTS.md and CLAUDE.md but left
several pre-existing references to the old write-to-website/releases
flow and the now-removed Containerfile / podman-compose / release-image.sh.
This sweeps the rest:

- CLAUDE.md
  - drop "podman/podman-compose" from the zddc/ blurb (no Containerfile)
  - drop the broken `podman build -t zddc-server zddc/` command
  - rewrite the "Most-used commands" table so --release semantics match
    actual behavior (tag + Codeberg upload, not file write)
  - rewrite "Things that bite": replace "never write to website/releases/"
    and the obsolete "alpha exception" bullet with the new rules
    ($CODEBERG_TOKEN required, dist files no longer force-tracked, etc.)
  - rewrite the website/ description in "Repo shape" to reflect that
    only index.html + manifest.json live there now

- ARCHITECTURE.md
  - rewrite the website/ directory tree (no more <tool>_v*.html, _stable
    symlinks, or _alpha/_beta files)
  - rewrite "Channels" section: every cut now tags + uploads to Codeberg,
    alpha/beta have .N counters and matching tags, no more in-place
    overwrites
  - rewrite the build-label table: dev builds carry the next-stable
    target as a -alpha pre-release suffix with full timestamp + dirty
    marker (was: "Built: <ts> BETA")
  - update level-2 bootstrap description: resolves channel via
    manifest.json, fetches /releases/<tag>/<asset>, not a flat URL
  - update landing-tool description: ships only as Codeberg release
    asset, not a committed website/releases/landing_v<X>.html

- AGENTS.md
  - update website/ tree to the post-refactor layout
  - replace the two-step podman build / podman-compose run blocks under
    zddc-server with a Go build + go run quickstart (no container in
    this repo)
  - drop the "Containerfile uses a multi-stage build" note from the
    "Notes" list (Containerfile is gone)
  - drop the stale "landing/build.sh writes website/index.html" note —
    website/index.html is now hand-edited, not produced by landing's
    build

- README.md (top-level)
  - tools table no longer links to /releases/<tool>_stable.html
    (those URLs return 404 post-refactor); link to the releases page
    once instead

- bootstrap/README.md
  - update the "permanent pin" URL examples and CORS verification
    snippet to use /releases/<tag>/<asset> URLs (Caddy → Codeberg)
    instead of the old flat /releases/<tool>_<channel>.html pattern
  - explain that channel resolution is via manifest.json now

- zddc/README.md
  - rewrite Quick Start: download a release binary or build from source,
    no `podman build`
  - rewrite TLS examples to invoke ./zddc-server directly instead of
    `podman run ... zddc-server` (image name no longer exists)
  - mention ZDDC_INSECURE_DIRECT in the env-var table and the plain-HTTP
    example — startup is refused without it on non-loopback binds
  - replace the "Container image" section with "Distribution" (binaries
    on Codeberg, no image) and the "Building" section with go build
    instructions
  - replace "Release Tagging" with documentation of zddc/release.sh
    (the canonical replacement for release-image.sh, which is gone)

- shared/build-lib.sh
  - fix the comment claiming "plain builds mirror to website/releases/"
    — they don't anymore

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 08:01:20 -05:00

6.7 KiB

Deployment bootstrap

ZDDC tools (archive, transmittal, classifier, mdedit, landing) are single-file HTML bundles. The bootstrap pattern lets you install once on a deployment and update by editing a few lines, without re-uploading multi-megabyte HTML files.

End users install via a short copy-paste shell snippet from the home page's "Install on your server" section. The snippet uses curl to fetch either the current stable HTMLs (self-contained) or tiny level-2 stubs (channel trackers) into the deployment directory. The published stubs live under https://zddc.varasys.io/bootstrap/:

  • bootstrap/level1/<tool>.html — same-origin level-1 stubs (4 tools, no landing — landing only lives at deployment root).
  • bootstrap/track-{stable,beta,alpha}/<tool>.html — per-channel level-2 stubs (5 tools each).

Both directories are produced by the project's top-level build.sh from bootstrap/level{1,2}.html.tmpl.

The two-level model

A typical zddc-server deployment looks like this:

<ZDDC_ROOT>/
  index.html                # landing tool (or bootstrap)
  archive.html              # archive tool (or bootstrap; site-wide channel switch lives here)
  transmittal.html
  classifier.html
  mdedit.html
  <project-A>/
    archive.html            # level-1 bootstrap → fetches ../archive.html
    transmittal.html
    classifier.html
    mdedit.html
    <project files…>
  <project-B>/
    archive.html            # level-1 bootstrap (or pinned to a specific version)
    …
  • Level-1 stubs at <project>/<tool>.html always fetch the same-origin ../<tool>.html. They never touch zddc.varasys.io. Install them once; they don't need to change.
  • At deployment root (<ZDDC_ROOT>/<tool>.html), put either:
    • the actual built tool HTML — fully self-contained install, no external dependencies; or
    • a level-2 bootstrap — resolves the desired channel against https://zddc.varasys.io/releases/manifest.json (or skips that step for an explicit ?v=X.Y.Z pin) and fetches the asset from https://zddc.varasys.io/releases/<tag>/<tool>_v<X.Y.Z>.html. Caddy at zddc.varasys.io reverse-proxies that to the corresponding Codeberg release-asset URL.

The site administrator switches the whole site to a channel by re-running the track-<channel> install snippet from the home page — that overwrites the root <tool>.html files with the matching level-2 stubs. A single project can override one tool by editing just <project-X>/<tool>.html (replace the relative upstream URL with an absolute zddc.varasys.io URL).

Why two levels

The level-1 stubs let projects share a single source of truth for "which build of the archive tool runs here." Switching channels is one file change at the root; pinning a single project is one file change in that directory.

document.write() chains across both levels: level-1 fetches and writes, the new document's level-2 script runs and writes again, the third write is the actual tool. Origin stays at the deployment domain throughout, so File System Access API, crypto.subtle, and localStorage all work and preferences stay scoped to the deployment.

Pinning options

There are two ways to choose a version: edit the stub for a permanent pin, or pass a ?v= URL parameter for a per-request override.

1. Permanent pin (edit the stub)

The level-2 stub resolves channels via manifest.json at runtime, so a "pin to current stable" is the default — no editing required. To pin this single tool to a specific version permanently, replace the level-2 stub with one that bypasses the manifest:

To pin Replace stub body with a fetch of
Exact stable version vX.Y.Z https://zddc.varasys.io/releases/<tool>-vX.Y.Z/<tool>_vX.Y.Z.html
Specific alpha/beta build https://zddc.varasys.io/releases/<tool>-vX.Y.Z-alpha.N/<tool>_vX.Y.Z-alpha.N.html
Channel default (current implementation) Resolves <tool>-<channel> against releases/manifest.json at runtime

2. Per-request ?v= parameter

Both stub levels honor a ?v= URL parameter. The parameter survives the document.write() chain, so it flows through level-1 → level-2 → upstream automatically.

URL parameter Behavior
?v=0.0.4 (or ?v=v0.0.4) tries <tool>_v0.0.4.html locally, then upstream
?v=alpha switches to alpha channel
?v=beta switches to beta channel
?v=latest latest stable
(omitted) the default baked into the stub

When level-1 has ?v=…, it tries ../<tool>_<suffix>.html first (useful when the admin has staged specific versions locally) and falls back to ../<tool>.html if 404 — which then forwards the parameter via level-2 if one is installed. So the same URL works whether the version is staged locally, served by a level-2 stub, or both.

Stable releases are immutable. Alpha and beta channel files are overwritten in place each time their channel is rebuilt; expect them to change without notice. The build label rendered on the tool page tells you what you are running (date + commit SHA for alpha/beta, version number for stable).

Auditing what's installed

Every stub contains a fallback (level-1) or upstream (level-2) constant. To see what each tool / project on the deployment points at:

grep -rn "fallback\|upstream" <ZDDC_ROOT>

CORS prerequisite (level-2 only)

A level-2 fetch is cross-origin (deployment → zddc.varasys.io). The upstream must serve Access-Control-Allow-Origin: * (or a list including your deployment origin) on manifest.json and on each released asset. Verify with:

curl -I https://zddc.varasys.io/releases/manifest.json    | grep -i access-control
curl -I https://zddc.varasys.io/releases/archive-v0.0.2/archive_v0.0.2.html \
  | grep -i access-control

Level-1 fetches are same-origin so no CORS is involved.

Templates

level1.html.tmpl and level2.html.tmpl are the source of truth. The project's top-level build.sh substitutes {{TOOL}}, {{TOOL_TITLE}}, {{CHANNEL}}, and {{FAVICON}} to produce the per-tool stubs published under website/bootstrap/level1/ and website/bootstrap/track-<channel>/, which the install snippets curl from https://zddc.varasys.io/bootstrap/.