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>
This commit is contained in:
parent
b28c4aef81
commit
bdac8dc4fb
7 changed files with 188 additions and 181 deletions
45
AGENTS.md
45
AGENTS.md
|
|
@ -3,17 +3,17 @@
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build all tools (writes to dist/ only)
|
# Build all tools (writes to dist/ only; also regenerates website/releases/{index.html,manifest.json})
|
||||||
sh build.sh
|
sh build.sh
|
||||||
|
|
||||||
# Build single tool
|
# Build single tool
|
||||||
sh tool/build.sh # archive | transmittal | classifier | mdedit | landing
|
sh tool/build.sh # archive | transmittal | classifier | mdedit | landing
|
||||||
|
|
||||||
# Cut a stable release (auto-increments patch version, tags, writes to website/releases/)
|
# Cut a stable release (auto-increments patch version, tags <tool>-vX.Y.Z, uploads <tool>_vX.Y.Z.html to Codeberg)
|
||||||
sh tool/build.sh --release
|
sh tool/build.sh --release
|
||||||
sh tool/build.sh --release 1.2.0 # explicit version
|
sh tool/build.sh --release 1.2.0 # explicit version
|
||||||
|
|
||||||
# Cut an alpha/beta channel build (mutable, no git tag)
|
# Cut an alpha/beta channel build (tags <tool>-vX.Y.Z-{alpha,beta}.N, uploads to Codeberg as a prerelease)
|
||||||
sh tool/build.sh --release alpha
|
sh tool/build.sh --release alpha
|
||||||
sh tool/build.sh --release beta
|
sh tool/build.sh --release beta
|
||||||
|
|
||||||
|
|
@ -55,12 +55,10 @@ shared/
|
||||||
sourced by every tool's build.sh via: . "$root_dir/../shared/build-lib.sh"
|
sourced by every tool's build.sh via: . "$root_dir/../shared/build-lib.sh"
|
||||||
|
|
||||||
website/
|
website/
|
||||||
index.html current stable landing (root URL)
|
index.html hand-edited intro page (root URL)
|
||||||
releases/
|
releases/
|
||||||
<tool>_v<X>.<Y>.<Z>.html immutable stable release archives
|
index.html versions index, regenerated by build.sh from the Codeberg release list
|
||||||
<tool>_stable.html -> ... symlink to current stable (highest semver)
|
manifest.json <tool>-<channel> → tag map (regenerated by build.sh; consumed by the level-2 stub at runtime)
|
||||||
<tool>_alpha.html mutable; overwritten by --release alpha
|
|
||||||
<tool>_beta.html mutable; overwritten by --release beta
|
|
||||||
bootstrap/
|
bootstrap/
|
||||||
level1/<tool>.html same-origin level-1 stubs (4 tools, no landing)
|
level1/<tool>.html same-origin level-1 stubs (4 tools, no landing)
|
||||||
track-stable/<tool>.html level-2 stubs that track the current-stable channel
|
track-stable/<tool>.html level-2 stubs that track the current-stable channel
|
||||||
|
|
@ -73,7 +71,9 @@ bootstrap/
|
||||||
README.md install / channel / pin docs
|
README.md install / channel / pin docs
|
||||||
```
|
```
|
||||||
|
|
||||||
**Critical:** `dist/` files are gitignored but force-committed (`git add -f`). Never edit them directly.
|
**Critical:** `dist/` files are gitignored. They're the canonical built artifact for testing and the source for `--release` uploads to Codeberg, but they aren't checked in. Never edit them directly.
|
||||||
|
|
||||||
|
The per-version `<tool>_v<X.Y.Z>.html` artifacts and zddc-server binaries also aren't checked in — they live on Codeberg as release assets attached to git tags. `website/releases/` only contains `index.html` (versions index) and `manifest.json` (channel → tag map), both regenerated by `build.sh` from a Codeberg API call.
|
||||||
|
|
||||||
## Shared CSS (`shared/base.css`)
|
## Shared CSS (`shared/base.css`)
|
||||||
|
|
||||||
|
|
@ -177,7 +177,7 @@ After cutting a release, run `git push --tags` to publish the tag.
|
||||||
|
|
||||||
`$CODEBERG_TOKEN` must be exported before any `--release` invocation. The `promote_release` helper calls `publish_codeberg_release` which uses the token to create the release and upload the asset.
|
`$CODEBERG_TOKEN` must be exported before any `--release` invocation. The `promote_release` helper calls `publish_codeberg_release` which uses the token to create the release and upload the asset.
|
||||||
|
|
||||||
`landing/build.sh --release <version>` additionally writes `website/index.html` (the root URL of zddc.varasys.io) as a regular committed file — that page is hand-edited intro copy, not a release asset.
|
`website/index.html` (the root URL of zddc.varasys.io) is **hand-edited static content**, not built by `landing/build.sh`. The landing tool ships only as a Codeberg release asset; the self-contained install snippet curls `landing_v<ver>.html` to `<deployment-root>/index.html` at customer-deployment time.
|
||||||
|
|
||||||
### Channel discipline (MUST rules)
|
### Channel discipline (MUST rules)
|
||||||
|
|
||||||
|
|
@ -251,18 +251,30 @@ Go HTTP server sub-project living at `zddc/`. Replaces `caddy file-server --brow
|
||||||
|
|
||||||
### Build
|
### Build
|
||||||
|
|
||||||
```sh
|
zddc-server ships as a cross-compiled binary, not a container image. There's no Containerfile or compose file in this repo (the chart Dockerfiles in `tnd-zddc-chart` compile from source at deploy time, fetching the right tag from Codeberg).
|
||||||
# Build the container image (from the zddc/ directory)
|
|
||||||
podman build -t zddc-server zddc/
|
|
||||||
|
|
||||||
# Or inside the zddc/ directory:
|
```sh
|
||||||
podman build -t zddc-server .
|
# Compile a local binary for the host platform (requires Go 1.24+)
|
||||||
|
(cd zddc && go build -o zddc-server ./cmd/zddc-server)
|
||||||
|
|
||||||
|
# Or run directly without producing a binary
|
||||||
|
(cd zddc && go run ./cmd/zddc-server)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The repo's top-level `sh build.sh` cross-compiles the four release binaries (linux/amd64, darwin/amd64, darwin/arm64, windows/amd64) into `zddc/dist/` when Go is on PATH. It's silently skipped otherwise — the HTML tools build regardless.
|
||||||
|
|
||||||
### Run (development)
|
### Run (development)
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
ZDDC_DATA_DIR=/path/to/your/archive podman-compose -f zddc/podman-compose.yaml up --build
|
ZDDC_ROOT=/path/to/your/archive ZDDC_TLS_CERT=none ZDDC_ADDR=:8080 \
|
||||||
|
go run ./cmd/zddc-server
|
||||||
|
```
|
||||||
|
|
||||||
|
For a release binary (downloaded from Codeberg or built via `sh build.sh`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ZDDC_ROOT=/path/to/your/archive ZDDC_TLS_CERT=none ZDDC_ADDR=:8080 \
|
||||||
|
./zddc/dist/zddc-server-linux-amd64
|
||||||
```
|
```
|
||||||
|
|
||||||
### Key environment variables
|
### Key environment variables
|
||||||
|
|
@ -342,7 +354,6 @@ local path that fails loudly and visibly on the developer's terminal.
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
- No external test framework yet — Go unit tests run with `go test ./...` inside `zddc/` (requires Go 1.24+)
|
- No external test framework yet — Go unit tests run with `go test ./...` inside `zddc/` (requires Go 1.24+)
|
||||||
- The container image does NOT require Go on the host — the Containerfile uses a multi-stage build
|
|
||||||
- Portfolio files (`*.portfolio`) in the served tree appear as virtual group directories
|
- Portfolio files (`*.portfolio`) in the served tree appear as virtual group directories
|
||||||
- Every folder exposes a `.archive` virtual directory backed by the same global index — the depth in the URL only matters so HTML produced for offline use can reach `.archive/` via `../.archive/` relative links and have the browser resolve them before the request hits the server. The flat listing emits two redirect entries per tracking number: `<tracking>.html` (highest base rev) and `<tracking>_<rev>.html` (each specific base rev). Both redirect to the first chronologically received copy of the named revision. Modifier files (`<tracking>_<rev>+C1.html` etc.) remain reachable via the resolver but are not surfaced in the listing — they're return traffic, not primary documents. ACL is the only filter: the listing endpoint is gated by the contextPath's `.zddc` chain, and each entry is then filtered against the ACL of its resolved file's directory; per-target denials return 404 rather than 403 to avoid leaking that the tracking number exists in another subtree
|
- Every folder exposes a `.archive` virtual directory backed by the same global index — the depth in the URL only matters so HTML produced for offline use can reach `.archive/` via `../.archive/` relative links and have the browser resolve them before the request hits the server. The flat listing emits two redirect entries per tracking number: `<tracking>.html` (highest base rev) and `<tracking>_<rev>.html` (each specific base rev). Both redirect to the first chronologically received copy of the named revision. Modifier files (`<tracking>_<rev>+C1.html` etc.) remain reachable via the resolver but are not surfaced in the listing — they're return traffic, not primary documents. ACL is the only filter: the listing endpoint is gated by the contextPath's `.zddc` chain, and each entry is then filtered against the ACL of its resolved file's directory; per-target denials return 404 rather than 403 to avoid leaking that the tracking number exists in another subtree
|
||||||
- ACL is enforced via cascading `.zddc` YAML files; authentication is delegated to the upstream proxy via the `X-Auth-Request-Email` header (configurable with `ZDDC_EMAIL_HEADER`)
|
- ACL is enforced via cascading `.zddc` YAML files; authentication is delegated to the upstream proxy via the `X-Auth-Request-Email` header (configurable with `ZDDC_EMAIL_HEADER`)
|
||||||
|
|
|
||||||
|
|
@ -33,21 +33,21 @@ tool/
|
||||||
tool.html # Generated output — never edit this manually
|
tool.html # Generated output — never edit this manually
|
||||||
```
|
```
|
||||||
|
|
||||||
Website files (what `zddc.varasys.io` serves) are organized by channel:
|
Website files (what `zddc.varasys.io` serves) — committed in this repo as static assets, but the actual built tool HTML and zddc-server binaries live on Codeberg as release assets:
|
||||||
|
|
||||||
```
|
```
|
||||||
website/
|
website/
|
||||||
index.html # current stable landing tool (root URL)
|
index.html # hand-edited intro page (root URL)
|
||||||
releases/
|
releases/
|
||||||
<tool>_v<X>.<Y>.<Z>.html # immutable stable release archives
|
index.html # versions index, regenerated by build.sh from the Codeberg API
|
||||||
<tool>_stable.html -> ... # symlink to the highest-versioned stable
|
manifest.json # <tool>-<channel> → tag map, regenerated by build.sh; the level-2 stub fetches this
|
||||||
<tool>_alpha.html # mutable: overwritten on every --release alpha
|
|
||||||
<tool>_beta.html # mutable: overwritten on every --release beta
|
|
||||||
bootstrap/
|
bootstrap/
|
||||||
level1/<tool>.html # same-origin stubs for project subdirectories
|
level1/<tool>.html # same-origin stubs for project subdirectories
|
||||||
track-{alpha,beta,stable}/ # per-channel level-2 stubs (5 tools each)
|
track-{alpha,beta,stable}/ # per-channel level-2 stubs (5 tools each)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The per-version `<tool>_v<X.Y.Z>.html` files and zddc-server binaries are **not** committed — they live on Codeberg as release assets attached to git tags. Caddy at `zddc.varasys.io` reverse-proxies `/releases/<tag>/<asset>` to the corresponding Codeberg URL, so consumers (operators' bootstrap stubs, `zddc-use`, the chart Dockerfiles) only ever talk to `zddc.varasys.io`.
|
||||||
|
|
||||||
There is no `website/dev/`. To preview a build locally, open `dist/tool.html` directly via the dev server. To publish on `zddc.varasys.io`, cut a release.
|
There is no `website/dev/`. To preview a build locally, open `dist/tool.html` directly via the dev server. To publish on `zddc.varasys.io`, cut a release.
|
||||||
|
|
||||||
Vendor dependencies (bundled third-party libraries) live in `tool/vendor/` if present. The build script is responsible for inlining them into the output.
|
Vendor dependencies (bundled third-party libraries) live in `tool/vendor/` if present. The build script is responsible for inlining them into the output.
|
||||||
|
|
@ -69,7 +69,7 @@ Each topic has exactly one authoritative home; everything else links to it.
|
||||||
| Architecture & internal patterns | `ARCHITECTURE.md` (this file) | `AGENTS.md` |
|
| Architecture & internal patterns | `ARCHITECTURE.md` (this file) | `AGENTS.md` |
|
||||||
| Per-tool internal design quirks | `<tool>/README.md` | (linked from website intro tool cards) |
|
| Per-tool internal design quirks | `<tool>/README.md` | (linked from website intro tool cards) |
|
||||||
|
|
||||||
`website/index.html` is **hand-edited static content** (analogous to `reference.html`), not the landing-tool output. The landing tool ships only via `website/releases/landing_v<X>.html` — the self-contained install snippet copies `landing_stable.html` to `<deployment-root>/index.html` for customer sites where the project picker UI is actually useful (it queries `zddc-server` for the project list). The public website at `zddc.varasys.io/` has nothing to pick, so its root URL is the introduction page.
|
`website/index.html` is **hand-edited static content** (analogous to `reference.html`), not the landing-tool output. The landing tool ships only as a Codeberg release asset (`landing-v<X.Y.Z>` tag → `landing_v<X.Y.Z>.html` asset) — the self-contained install snippet curls the current-stable asset through Caddy at `zddc.varasys.io/releases/<tag>/landing_v<ver>.html` and saves it as `<deployment-root>/index.html` for customer sites where the project picker UI is actually useful (it queries `zddc-server` for the project list). The public website at `zddc.varasys.io/` has nothing to pick, so its root URL is the introduction page.
|
||||||
|
|
||||||
When updating documentation, prefer linking over duplicating. If you find yourself rewriting the file-naming convention in a tool's README, link to `reference.html` instead.
|
When updating documentation, prefer linking over duplicating. If you find yourself rewriting the file-naming convention in a tool's README, link to `reference.html` instead.
|
||||||
|
|
||||||
|
|
@ -85,35 +85,39 @@ Each tool's `build.sh`:
|
||||||
2. Reads JS files in declaration order, concatenates them
|
2. Reads JS files in declaration order, concatenates them
|
||||||
3. Processes `template.html` with `awk`, replacing `{{PLACEHOLDER}}` markers with the concatenated content and stripping CDN `<script>`/`<link>` tags
|
3. Processes `template.html` with `awk`, replacing `{{PLACEHOLDER}}` markers with the concatenated content and stripping CDN `<script>`/`<link>` tags
|
||||||
4. Writes the result to `dist/tool.html`
|
4. Writes the result to `dist/tool.html`
|
||||||
5. If `--release <channel-or-version>` was passed, calls `promote_release` to write the appropriate file under `website/releases/`
|
5. If `--release <channel-or-version>` was passed, calls `promote_release` to tag the commit and upload the dist HTML as a Codeberg release asset (via `shared/publish-codeberg-release.sh`).
|
||||||
|
|
||||||
The top-level `build.sh` at the repository root calls all five tool build scripts in sequence and then regenerates `website/bootstrap/` (level-1 stubs and per-channel level-2 stubs) so they always match what's in `releases/`.
|
The top-level `build.sh` at the repository root calls all five tool build scripts in sequence, regenerates `website/bootstrap/` (level-1 stubs and per-channel level-2 stubs), and then queries the Codeberg API once to rewrite `website/releases/index.html` and `manifest.json` so the website's versions index reflects current Codeberg state.
|
||||||
|
|
||||||
### Channels
|
### Channels
|
||||||
|
|
||||||
Three release channels:
|
Three release channels. Each `--release` invocation tags the commit and uploads the resulting HTML to Codeberg as a release asset; nothing is written under `website/releases/` other than the regenerated `index.html` / `manifest.json`.
|
||||||
|
|
||||||
- **Stable** — versioned, immutable. `--release [version]` writes `website/releases/<tool>_v<version>.html`, refreshes the `<tool>_stable.html` symlink, and tags `<tool>-v<version>` in git. Skips automatically when there is no source change since the last tag.
|
- **Stable** — versioned, immutable. `--release [version]` tags `<tool>-v<version>` in git and uploads `<tool>_v<version>.html` to the new Codeberg release. Skips automatically when there is no source change since the last stable tag.
|
||||||
- **Beta** — mutable. `--release beta` overwrites `website/releases/<tool>_beta.html` in place. No git tag; the on-page label is `beta · <date> · <sha>` so the source is recoverable from git history via the SHA.
|
- **Beta** — `--release beta` tags `<tool>-v<next-patch>-beta.N` (auto-incrementing counter) and uploads `<tool>_v<next-patch>-beta.N.html`. The Codeberg release is marked `prerelease: true`. On-page label: `vX.Y.Z-beta · <date> · <sha>`.
|
||||||
- **Alpha** — mutable, analogous to beta.
|
- **Alpha** — `--release alpha` tags `<tool>-v<next-patch>-alpha.N` and uploads, analogous to beta.
|
||||||
|
|
||||||
Stable releases do not automatically clobber `<tool>_alpha.html` / `<tool>_beta.html` — those keep whatever was last built into them. Use `./freshen-channel <tool> <channel>` (worktree-based, no manual `git checkout`) to drag a channel forward to current stable.
|
A plain `sh tool/build.sh` (no `--release`) is a dev build: it produces `dist/<tool>.html` only, with the on-page label `vX.Y.Z-alpha · <full-ts> · <sha>[-dirty]`. No tag, no Codeberg upload.
|
||||||
|
|
||||||
|
Stable releases do not automatically advance the alpha/beta channels. Use `./freshen-channel <tool> <channel>` (worktree-based, no manual `git checkout`) to cut a fresh `-alpha.N` / `-beta.N` from the current stable tag — channel discipline rule 4 says do this after every stable release.
|
||||||
|
|
||||||
The on-page `{{BUILD_LABEL}}` is rendered red+bold for dev/alpha/beta builds (`is_red=1`) and black for stable releases. The label format is:
|
The on-page `{{BUILD_LABEL}}` is rendered red+bold for dev/alpha/beta builds (`is_red=1`) and black for stable releases. The label format is:
|
||||||
|
|
||||||
| Build | Label |
|
| Build | Label |
|
||||||
|---------------|---------------------------------------------|
|
|--------------------|--------------------------------------------------------|
|
||||||
| dev | `Built: 2026-04-27 14:00:00 BETA` |
|
| dev (no `--release`) | `v0.0.6-alpha · 2026-04-27 14:00:00 · abc1234[-dirty]` |
|
||||||
| alpha | `alpha · 2026-04-27 · abc1234` |
|
| `--release alpha` | `v0.0.6-alpha · 2026-04-27 · abc1234` |
|
||||||
| beta | `beta · 2026-04-27 · abc1234` |
|
| `--release beta` | `v0.0.6-beta · 2026-04-27 · abc1234` |
|
||||||
| stable | `v0.0.5` |
|
| `--release [ver]` | `v0.0.5` |
|
||||||
|
|
||||||
|
`X.Y.Z` for non-stable labels is the **next-stable target** — patch+1 from the latest clean `<tool>-vX.Y.Z` tag. Dev builds use the full timestamp + `-dirty` marker so iterative work is distinguishable from a formal `--release alpha` cut (which stamps date-only and is committed-clean by definition).
|
||||||
|
|
||||||
### Two-level bootstrap
|
### Two-level bootstrap
|
||||||
|
|
||||||
Customer deployments under `zddc-server` use a two-level bootstrap pattern that keeps tool installation decoupled from publishing. See `bootstrap/README.md` for the full story; in short:
|
Customer deployments under `zddc-server` use a two-level bootstrap pattern that keeps tool installation decoupled from publishing. See `bootstrap/README.md` for the full story; in short:
|
||||||
|
|
||||||
- **Level 1**: per-project stub at `<project>/<tool>.html` that fetches `../<tool>.html` (always same-origin). One file per project per tool, never edited after install.
|
- **Level 1**: per-project stub at `<project>/<tool>.html` that fetches `../<tool>.html` (always same-origin). One file per project per tool, never edited after install.
|
||||||
- **Level 2** (optional): site admin replaces `<deployment-root>/<tool>.html` with a stub fetching `https://zddc.varasys.io/releases/<tool>_<channel>.html` — switches the whole site to a channel. Without it, `<deployment-root>/<tool>.html` is just the actual built tool HTML (self-contained install).
|
- **Level 2** (optional): site admin replaces `<deployment-root>/<tool>.html` with a stub that fetches `https://zddc.varasys.io/releases/manifest.json` to resolve `<tool>-<channel>` → tag, then fetches `https://zddc.varasys.io/releases/<tag>/<tool>_v<version>.html` (Caddy reverse-proxies to the Codeberg release-asset URL). Switches the whole site to a channel. Without it, `<deployment-root>/<tool>.html` is just the actual built tool HTML (self-contained install).
|
||||||
|
|
||||||
`document.write()` chains across both levels; origin stays at the deployment domain throughout. CORS only matters at level 2 (cross-origin to `zddc.varasys.io`); level 1 is same-origin.
|
`document.write()` chains across both levels; origin stays at the deployment domain throughout. CORS only matters at level 2 (cross-origin to `zddc.varasys.io`); level 1 is same-origin.
|
||||||
|
|
||||||
|
|
|
||||||
22
CLAUDE.md
22
CLAUDE.md
|
|
@ -16,18 +16,18 @@ If something in this CLAUDE.md conflicts with those, those win — and please up
|
||||||
This is a **monorepo of independent tools**, not one application:
|
This is a **monorepo of independent tools**, not one application:
|
||||||
|
|
||||||
- `archive/`, `transmittal/`, `classifier/`, `mdedit/`, `landing/` — five self-contained HTML tools, each compiled to a single inlined HTML file in its own `dist/`. Naming: the first four output `dist/tool.html`; **`landing/` outputs `dist/index.html`** (it's the project picker served at the root of `zddc-server`).
|
- `archive/`, `transmittal/`, `classifier/`, `mdedit/`, `landing/` — five self-contained HTML tools, each compiled to a single inlined HTML file in its own `dist/`. Naming: the first four output `dist/tool.html`; **`landing/` outputs `dist/index.html`** (it's the project picker served at the root of `zddc-server`).
|
||||||
- `zddc/` — Go HTTP server (separate sub-project, podman/podman-compose; Go 1.24+). Serves `ZDDC_ROOT/index.html` at `GET /` as the landing page; `Accept: application/json` on `/` returns the ACL-filtered project list.
|
- `zddc/` — Go HTTP server (separate sub-project; Go 1.24+). Serves `ZDDC_ROOT/index.html` at `GET /` as the landing page; `Accept: application/json` on `/` returns the ACL-filtered project list. Released as cross-compiled binaries on Codeberg (no container image — the chart Dockerfiles compile from source at deploy time).
|
||||||
- `shared/` — `base.css` plus shared JS modules (`zddc.js`, `hash.js`, `zddc-filter.js`, `theme.js`, `help.js`) included by every tool's build, and `build-lib.sh` (POSIX sh helpers sourced by every tool's `build.sh`)
|
- `shared/` — `base.css` plus shared JS modules (`zddc.js`, `hash.js`, `zddc-filter.js`, `theme.js`, `help.js`) included by every tool's build, `build-lib.sh` (POSIX sh helpers sourced by every tool's `build.sh`), and `publish-codeberg-release.sh` (the create-release-and-upload-asset helper used by both `build-lib.sh` and `zddc/release.sh`).
|
||||||
- `website/` — published artifacts: `index.html` (root URL), `releases/<tool>_v<X.Y.Z>.html` (immutable stable archives), `releases/<tool>_stable.html` (symlink to current stable), `releases/<tool>_{alpha,beta}.html` (mutable channel files), and `bootstrap/{level1,track-stable,track-beta,track-alpha}/<tool>.html` (per-channel level-2 stubs + same-origin level-1 stubs that the home-page install snippets curl into the operator's deployment dir). `--release` is the only path to publishing `releases/`; `bootstrap/` is regenerated by every plain `sh build.sh`. There is no `website/dev/`.
|
- `website/` — published artifacts: `index.html` (root URL), `releases/index.html` + `releases/manifest.json` (regenerated by `build.sh` from the Codeberg API; the manifest maps `<tool>-<channel>` → tag for runtime channel resolution), and `bootstrap/{level1,track-stable,track-beta,track-alpha}/<tool>.html` (per-channel level-2 stubs + same-origin level-1 stubs that the home-page install snippets curl into the operator's deployment dir). The actual built tool HTML and zddc-server binaries live on Codeberg as release assets — Caddy at `zddc.varasys.io` reverse-proxies `/releases/<tag>/<asset>` to the corresponding Codeberg URL. `bootstrap/` is regenerated by every plain `sh build.sh`. There is no `website/dev/`.
|
||||||
- `tests/` — Playwright specs (Chromium only, requires File System Access API). `tests/schema.spec.js` validates `transmittal.schema.json` against canonical fixtures via `ajv` (only dev dep besides Playwright)
|
- `tests/` — Playwright specs (Chromium only, requires File System Access API). `tests/schema.spec.js` validates `transmittal.schema.json` against canonical fixtures via `ajv` (only dev dep besides Playwright)
|
||||||
|
|
||||||
## Most-used commands
|
## Most-used commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sh build.sh # build all five HTML tools (dist/ only)
|
sh build.sh # build all five HTML tools (dist/ only) + regen releases index/manifest
|
||||||
sh tool/build.sh # build one (archive|transmittal|classifier|mdedit|landing)
|
sh tool/build.sh # build one (archive|transmittal|classifier|mdedit|landing)
|
||||||
sh tool/build.sh --release [version] # cut stable; tag, write website/releases/<tool>_v<ver>.html, refresh _stable symlink
|
sh tool/build.sh --release [version] # cut stable; tag <tool>-vX.Y.Z and upload <tool>_vX.Y.Z.html to Codeberg
|
||||||
sh tool/build.sh --release alpha|beta # cut channel build; overwrites website/releases/<tool>_<channel>.html (mutable, no tag)
|
sh tool/build.sh --release alpha|beta # cut channel build; tag <tool>-vX.Y.Z-{alpha,beta}.N and upload to Codeberg
|
||||||
./freshen-channel <tool> <channel> # rebuild alpha/beta from current stable tag (run after every stable release)
|
./freshen-channel <tool> <channel> # rebuild alpha/beta from current stable tag (run after every stable release)
|
||||||
npm test # all Playwright specs (build first!)
|
npm test # all Playwright specs (build first!)
|
||||||
npx playwright test <tool> # one spec
|
npx playwright test <tool> # one spec
|
||||||
|
|
@ -35,7 +35,6 @@ npx playwright test <tool> # one spec
|
||||||
|
|
||||||
# zddc/ Go server (separate sub-project, not part of sh build.sh)
|
# zddc/ Go server (separate sub-project, not part of sh build.sh)
|
||||||
(cd zddc && go test ./...) # unit tests (Go 1.24+)
|
(cd zddc && go test ./...) # unit tests (Go 1.24+)
|
||||||
podman build -t zddc-server zddc/ # build container image
|
|
||||||
sh zddc/release.sh [alpha|beta|stable] [<version>] # cut + publish zddc-server binaries to Codeberg release assets (default: alpha; auto-derives version)
|
sh zddc/release.sh [alpha|beta|stable] [<version>] # cut + publish zddc-server binaries to Codeberg release assets (default: alpha; auto-derives version)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -43,10 +42,11 @@ No lint/typecheck/format commands exist for the HTML tools — vanilla JS + POSI
|
||||||
|
|
||||||
## Things that bite if you forget
|
## Things that bite if you forget
|
||||||
|
|
||||||
- **`dist/` is gitignored but force-committed** (`git add -f tool/dist/tool.html`). Never hand-edit a `dist/` file.
|
- **`dist/` is gitignored.** `tool/dist/<tool>.html` is the canonical built artifact for testing and as the source for `--release` uploads. Never hand-edit a `dist/` file.
|
||||||
- **Never write to `website/index.html`, `website/releases/<tool>_v*.html`, `website/releases/<tool>_stable.html`, or `website/releases/<tool>_beta.html` directly** — promote via `sh tool/build.sh --release [version|alpha|beta]`. Stable releases write `website/releases/<tool>_v<ver>.html` (immutable) and refresh `<tool>_stable.html`; alpha/beta overwrite `<tool>_<channel>.html` in place.
|
- **Codeberg is the canonical store for release assets.** `--release` is the only path to publishing — it tags the commit and uploads the dist HTML (or zddc-server binaries) to Codeberg via `shared/publish-codeberg-release.sh`. Nothing under `website/releases/` other than `index.html` and `manifest.json` is checked in; the `*.html` per-version files and zddc-server binaries are gitignored. Don't reintroduce them.
|
||||||
- **Pre-release semver for alpha/beta.** On-page label embeds `vX.Y.Z-{alpha,beta}` where X.Y.Z is the next-stable target (patch+1 from latest clean `<tool>-vX.Y.Z` tag). zddc-server image tags additionally carry a `.N` counter (`v0.0.8-alpha.1`, `.2`, …) since every release is tagged; HTML tools omit the counter (alpha/beta cuts aren't tagged). Stable tags are clean `vX.Y.Z`.
|
- **`$CODEBERG_TOKEN` must be exported** before any `--release` invocation. Without it, `publish_codeberg_release` aborts with a clear error.
|
||||||
- **Alpha exception — every plain build dirties `website/releases/<tool>_alpha.html`.** Every `tool/build.sh` (no flags) mirrors the just-built dist file into `<tool>_alpha.html` as a real copy (not symlink — the canonical Caddy serves only `website/` and can't follow `../` paths). Side-effect: dev builds dirty those files; commit alongside the source change or `git checkout` to discard.
|
- **Pre-release semver for alpha/beta.** On-page label embeds `vX.Y.Z-{alpha,beta}` where X.Y.Z is the next-stable target (patch+1 from latest clean `<tool>-vX.Y.Z` tag). Every alpha/beta cut is tagged with a `.N` counter (`<tool>-v0.0.3-alpha.1`, `.2`, …) that resets when the next stable is cut. Stable tags are clean `<tool>-vX.Y.Z`.
|
||||||
|
- **Plain `sh tool/build.sh` is a dev build.** The on-page label says `vX.Y.Z-alpha · <full-ts> · <sha>[-dirty]` (full timestamp + dirty marker distinguish iterative dev work from a formal `--release alpha` cut), but no Codeberg upload happens. To publish, re-run with `--release alpha`.
|
||||||
- **Always build before running tests** — Playwright opens `dist/tool.html` via `file://`.
|
- **Always build before running tests** — Playwright opens `dist/tool.html` via `file://`.
|
||||||
- **`</` in JS string/template literals breaks inline `<script>`** embedding. `shared/build-lib.sh` provides `escape_js_close_tags`; every tool's `build.sh` runs JS through it before inlining.
|
- **`</` in JS string/template literals breaks inline `<script>`** embedding. `shared/build-lib.sh` provides `escape_js_close_tags`; every tool's `build.sh` runs JS through it before inlining.
|
||||||
- **All ZDDC parsing/formatting/hashing goes through `window.zddc`** (from `shared/zddc.js` + `shared/hash.js` + `shared/zddc-filter.js`). API: `parseFilename`, `parseFolder`, `parseRevision`, `formatFilename`, `formatFolder`, `compareRevisions`, `isValidStatus`, `splitExtension`, `joinExtension`, `crypto.{sha256Hex, sha256String, sha256File, bytesToHex}`, `filter.{parse, matches}`. File objects across tools use `trackingNumber` (string) and `extension` (string, **no leading dot** — use `zddc.joinExtension(name, ext)` to build a filename). Add edge cases to `tests/zddc.spec.js`, not per-tool tests.
|
- **All ZDDC parsing/formatting/hashing goes through `window.zddc`** (from `shared/zddc.js` + `shared/hash.js` + `shared/zddc-filter.js`). API: `parseFilename`, `parseFolder`, `parseRevision`, `formatFilename`, `formatFolder`, `compareRevisions`, `isValidStatus`, `splitExtension`, `joinExtension`, `crypto.{sha256Hex, sha256String, sha256File, bytesToHex}`, `filter.{parse, matches}`. File objects across tools use `trackingNumber` (string) and `extension` (string, **no leading dot** — use `zddc.joinExtension(name, ext)` to build a filename). Add edge cases to `tests/zddc.spec.js`, not per-tool tests.
|
||||||
|
|
|
||||||
10
README.md
10
README.md
|
|
@ -12,12 +12,12 @@ The name "Zero Day Document Control" comes from the convention itself — adopt
|
||||||
|
|
||||||
| Tool | What it does |
|
| Tool | What it does |
|
||||||
|------|--------------|
|
|------|--------------|
|
||||||
| **[Archive Browser](https://zddc.varasys.io/releases/archive_stable.html)** | Browse, search, and filter a project archive folder. Group by transmittal, export selections as ZIP. |
|
| **Archive Browser** | Browse, search, and filter a project archive folder. Group by transmittal, export selections as ZIP. |
|
||||||
| **[Transmittal Creator](https://zddc.varasys.io/releases/transmittal_stable.html)** | Self-contained HTML transmittal records with SHA-256 checksums and optional digital signatures. |
|
| **Transmittal Creator** | Self-contained HTML transmittal records with SHA-256 checksums and optional digital signatures. |
|
||||||
| **[Document Classifier](https://zddc.varasys.io/releases/classifier_stable.html)** | Spreadsheet-like bulk-renamer that copy/pastes with Excel and writes back to disk. |
|
| **Document Classifier** | Spreadsheet-like bulk-renamer that copy/pastes with Excel and writes back to disk. |
|
||||||
| **[Markdown Editor](https://zddc.varasys.io/releases/mdedit_stable.html)** | Browser-based markdown editor with YAML front matter, TOC, and direct local file access. |
|
| **Markdown Editor** | Browser-based markdown editor with YAML front matter, TOC, and direct local file access. |
|
||||||
|
|
||||||
Each tool is published in three channels (stable, beta, alpha) at `https://zddc.varasys.io/releases/<tool>_<channel>.html`. Append `?v=alpha` (or `?v=0.0.4`, etc.) to any URL to switch versions for one request. See [`bootstrap/README.md`](bootstrap/README.md) for the install / pin / audit story.
|
Each tool is published in three channels (stable, beta, alpha) as Codeberg release assets, browsable at <https://zddc.varasys.io/releases/>. Append `?v=alpha` (or `?v=0.0.4`, etc.) to any deployment URL to switch versions for one request. See [`bootstrap/README.md`](bootstrap/README.md) for the install / pin / audit story.
|
||||||
|
|
||||||
## File-naming convention
|
## File-naming convention
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,12 @@ A typical `zddc-server` deployment looks like this:
|
||||||
- **At deployment root** (`<ZDDC_ROOT>/<tool>.html`), put either:
|
- **At deployment root** (`<ZDDC_ROOT>/<tool>.html`), put either:
|
||||||
- the actual built tool HTML — fully self-contained install, no external
|
- the actual built tool HTML — fully self-contained install, no external
|
||||||
dependencies; or
|
dependencies; or
|
||||||
- a level-2 bootstrap — fetches a specific channel or pinned version from
|
- a level-2 bootstrap — resolves the desired channel against
|
||||||
`https://zddc.varasys.io/releases/<tool>_<channel|v…>.html`.
|
`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 site administrator switches the whole site to a channel by re-running
|
||||||
the `track-<channel>` install snippet from the home page — that overwrites
|
the `track-<channel>` install snippet from the home page — that overwrites
|
||||||
|
|
@ -74,15 +78,16 @@ pin, or pass a `?v=` URL parameter for a per-request override.
|
||||||
|
|
||||||
### 1. Permanent pin (edit the stub)
|
### 1. Permanent pin (edit the stub)
|
||||||
|
|
||||||
Each stub has one `fallback`/`upstream` constant. Edit it once and the
|
The level-2 stub resolves channels via `manifest.json` at runtime, so a
|
||||||
choice sticks for everyone using that file.
|
"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:
|
||||||
|
|
||||||
| URL | Behavior |
|
| To pin | Replace stub body with a fetch of |
|
||||||
|------------------------------------------------------------------|-----------------------------------------|
|
|-----------------------------------------|-------------------------------------------------------------------------|
|
||||||
| `https://zddc.varasys.io/releases/<tool>_stable.html` | current stable; auto-updates within stable |
|
| Exact stable version `vX.Y.Z` | `https://zddc.varasys.io/releases/<tool>-vX.Y.Z/<tool>_vX.Y.Z.html` |
|
||||||
| `https://zddc.varasys.io/releases/<tool>_beta.html` | latest beta build (mutable) |
|
| Specific alpha/beta build | `https://zddc.varasys.io/releases/<tool>-vX.Y.Z-alpha.N/<tool>_vX.Y.Z-alpha.N.html` |
|
||||||
| `https://zddc.varasys.io/releases/<tool>_alpha.html` | latest alpha build (mutable) |
|
| Channel default (current implementation)| Resolves `<tool>-<channel>` against `releases/manifest.json` at runtime |
|
||||||
| `https://zddc.varasys.io/releases/<tool>_v1.2.3.html` | pinned to exact stable version |
|
|
||||||
|
|
||||||
### 2. Per-request `?v=` parameter
|
### 2. Per-request `?v=` parameter
|
||||||
|
|
||||||
|
|
@ -123,10 +128,13 @@ grep -rn "fallback\|upstream" <ZDDC_ROOT>
|
||||||
|
|
||||||
A level-2 fetch is cross-origin (deployment → `zddc.varasys.io`). The
|
A level-2 fetch is cross-origin (deployment → `zddc.varasys.io`). The
|
||||||
upstream must serve `Access-Control-Allow-Origin: *` (or a list including
|
upstream must serve `Access-Control-Allow-Origin: *` (or a list including
|
||||||
your deployment origin) on the released HTML files. Verify with:
|
your deployment origin) on `manifest.json` and on each released asset.
|
||||||
|
Verify with:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -I https://zddc.varasys.io/releases/archive_stable.html | grep -i access-control
|
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.
|
Level-1 fetches are same-origin so no CORS is involved.
|
||||||
|
|
|
||||||
|
|
@ -207,9 +207,11 @@ compute_build_label() {
|
||||||
_next_stable=$(_next_stable_for_tool "$_tool")
|
_next_stable=$(_next_stable_for_tool "$_tool")
|
||||||
|
|
||||||
if [ "$_flag" != "--release" ]; then
|
if [ "$_flag" != "--release" ]; then
|
||||||
# Plain builds mirror to website/releases/<tool>_alpha.html, so they ARE
|
# Plain builds are dev builds — labeled as the alpha channel because
|
||||||
# alpha builds. Full timestamp (granular than date) and -dirty marker
|
# that's what the next formal cut would produce, but no Codeberg upload
|
||||||
# distinguish iterative dev builds from formal `--release alpha` cuts.
|
# happens until `--release alpha` is invoked. Full timestamp (granular
|
||||||
|
# than date) and -dirty marker distinguish iterative dev builds from
|
||||||
|
# formal `--release alpha` cuts (which stamp date-only).
|
||||||
_sha=$(git -C "$root_dir" rev-parse --short=7 HEAD 2>/dev/null || echo "unknown")
|
_sha=$(git -C "$root_dir" rev-parse --short=7 HEAD 2>/dev/null || echo "unknown")
|
||||||
if ! git -C "$root_dir" diff --quiet HEAD 2>/dev/null; then
|
if ! git -C "$root_dir" diff --quiet HEAD 2>/dev/null; then
|
||||||
_sha="${_sha}-dirty"
|
_sha="${_sha}-dirty"
|
||||||
|
|
|
||||||
206
zddc/README.md
206
zddc/README.md
|
|
@ -11,29 +11,35 @@ A purpose-built HTTPS file server for ZDDC document archives. Designed to replac
|
||||||
- **Virtual `.archive` index** — resolve the earliest revision of any tracked document by URL
|
- **Virtual `.archive` index** — resolve the earliest revision of any tracked document by URL
|
||||||
- **Filesystem watcher** — archive index updates automatically when files change
|
- **Filesystem watcher** — archive index updates automatically when files change
|
||||||
- **Flexible TLS modes** — self-signed, real certificates, or plain HTTP
|
- **Flexible TLS modes** — self-signed, real certificates, or plain HTTP
|
||||||
- **Podman-native** — multi-stage build, non-root runtime, SELinux-compatible volumes
|
- **Single static binary** — CGO-free, no runtime dependencies; cross-compiled to Linux/macOS/Windows
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```sh
|
zddc-server ships as a cross-compiled binary distributed via Codeberg release assets. The website at `zddc.varasys.io` reverse-proxies download URLs to Codeberg.
|
||||||
# Build the container image
|
|
||||||
podman build -t zddc-server .
|
|
||||||
|
|
||||||
# Run against your archive root
|
|
||||||
podman run --rm \
|
|
||||||
-v /srv/archive:/data:z \
|
|
||||||
-e ZDDC_ROOT=/data \
|
|
||||||
-p 8443:8443 \
|
|
||||||
zddc-server
|
|
||||||
```
|
|
||||||
|
|
||||||
Or with podman-compose:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
ZDDC_DATA_DIR=/srv/archive podman-compose up --build
|
# Download the latest stable binary for your platform from
|
||||||
|
# https://zddc.varasys.io/releases/ (page lists all platforms + channels)
|
||||||
|
curl -L -o zddc-server \
|
||||||
|
https://zddc.varasys.io/releases/zddc-server-vX.Y.Z/zddc-server-linux-amd64
|
||||||
|
chmod +x zddc-server
|
||||||
|
|
||||||
|
# Run against your archive root (HTTPS on :8443 with an in-memory self-signed cert)
|
||||||
|
ZDDC_ROOT=/srv/archive ./zddc-server
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Docker users:** Replace `podman` with `docker` and `podman-compose` with `docker-compose`. Remove the `:z` volume suffix (that is a SELinux/podman convention).
|
Or build from source (requires Go 1.24+):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://codeberg.org/VARASYS/ZDDC.git
|
||||||
|
cd ZDDC/zddc
|
||||||
|
go build -o zddc-server ./cmd/zddc-server
|
||||||
|
ZDDC_ROOT=/srv/archive ./zddc-server
|
||||||
|
```
|
||||||
|
|
||||||
|
For plain HTTP behind a reverse proxy, set `ZDDC_TLS_CERT=none` and `ZDDC_INSECURE_DIRECT=1` — see "TLS" below.
|
||||||
|
|
||||||
|
There is no Containerfile / Dockerfile / compose file in this repo. Operators who want to run zddc-server inside a container can write a minimal Dockerfile that copies the static binary into a `scratch` or `alpine` base, or use the chart Dockerfiles in `tnd-zddc-chart` (which compile from source at build time).
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
|
|
@ -43,6 +49,7 @@ ZDDC_DATA_DIR=/srv/archive podman-compose up --build
|
||||||
| `ZDDC_ADDR` | `:8443` | Bind address (host:port) |
|
| `ZDDC_ADDR` | `:8443` | Bind address (host:port) |
|
||||||
| `ZDDC_TLS_CERT` | *(empty)* | Path to PEM certificate file. `none` = plain HTTP (no TLS); empty = generate self-signed |
|
| `ZDDC_TLS_CERT` | *(empty)* | Path to PEM certificate file. `none` = plain HTTP (no TLS); empty = generate self-signed |
|
||||||
| `ZDDC_TLS_KEY` | *(empty)* | Path to PEM private key file. Required when `ZDDC_TLS_CERT` is a file path; ignored otherwise |
|
| `ZDDC_TLS_KEY` | *(empty)* | Path to PEM private key file. Required when `ZDDC_TLS_CERT` is a file path; ignored otherwise |
|
||||||
|
| `ZDDC_INSECURE_DIRECT` | *(empty)* | Must be `1` when `ZDDC_TLS_CERT=none` and the bind address is non-loopback. Acknowledges that an authenticating reverse proxy is in front of zddc-server; without it, plain-HTTP non-loopback startup is refused |
|
||||||
| `ZDDC_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
|
| `ZDDC_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
|
||||||
| `ZDDC_INDEX_PATH` | `.archive` | URL path segment name for the virtual archive index |
|
| `ZDDC_INDEX_PATH` | `.archive` | URL path segment name for the virtual archive index |
|
||||||
| `ZDDC_EMAIL_HEADER` | `X-Auth-Request-Email` | HTTP request header containing the authenticated user's email (the oauth2-proxy / nginx auth-request convention) |
|
| `ZDDC_EMAIL_HEADER` | `X-Auth-Request-Email` | HTTP request header containing the authenticated user's email (the oauth2-proxy / nginx auth-request convention) |
|
||||||
|
|
@ -73,16 +80,15 @@ middleware echoes the matched origin back per-request and sets
|
||||||
|
|
||||||
Set `ZDDC_TLS_CERT=none` to run without TLS. Recommended when an upstream reverse proxy
|
Set `ZDDC_TLS_CERT=none` to run without TLS. Recommended when an upstream reverse proxy
|
||||||
(nginx, Caddy, Traefik) terminates external TLS and talks to zddc-server over plain HTTP
|
(nginx, Caddy, Traefik) terminates external TLS and talks to zddc-server over plain HTTP
|
||||||
on a private network:
|
on a private network. zddc-server requires `ZDDC_INSECURE_DIRECT=1` for any non-loopback
|
||||||
|
bind in this mode — an explicit acknowledgement that an authenticating proxy sits in front:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
podman run --rm \
|
ZDDC_ROOT=/srv/archive \
|
||||||
-v /srv/archive:/data:z \
|
ZDDC_TLS_CERT=none \
|
||||||
-e ZDDC_ROOT=/data \
|
ZDDC_ADDR=:8080 \
|
||||||
-e ZDDC_TLS_CERT=none \
|
ZDDC_INSECURE_DIRECT=1 \
|
||||||
-e ZDDC_ADDR=:8080 \
|
./zddc-server
|
||||||
-p 8080:8080 \
|
|
||||||
zddc-server
|
|
||||||
```
|
```
|
||||||
|
|
||||||
When `ZDDC_TLS_CERT` / `ZDDC_TLS_KEY` are empty (or when using real certificates), zddc-server generates an ECDSA P-256
|
When `ZDDC_TLS_CERT` / `ZDDC_TLS_KEY` are empty (or when using real certificates), zddc-server generates an ECDSA P-256
|
||||||
|
|
@ -93,11 +99,10 @@ and uses this server only for encrypted in-datacenter transport.
|
||||||
To use a real certificate (e.g. from Let's Encrypt or an internal CA):
|
To use a real certificate (e.g. from Let's Encrypt or an internal CA):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
podman run --rm \
|
ZDDC_ROOT=/srv/archive \
|
||||||
-v /etc/ssl/zddc:/certs:z,ro \
|
ZDDC_TLS_CERT=/etc/ssl/zddc/server.crt \
|
||||||
-e ZDDC_TLS_CERT=/certs/server.crt \
|
ZDDC_TLS_KEY=/etc/ssl/zddc/server.key \
|
||||||
-e ZDDC_TLS_KEY=/certs/server.key \
|
./zddc-server
|
||||||
...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
@ -361,47 +366,32 @@ the actual built tool fetched by the self-contained install snippet, or a
|
||||||
level-1/level-2 bootstrap stub that fetches it. Then open it via the zddc-server URL;
|
level-1/level-2 bootstrap stub that fetches it. Then open it via the zddc-server URL;
|
||||||
the app will auto-connect and scan the directory tree.
|
the app will auto-connect and scan the directory tree.
|
||||||
|
|
||||||
## Container image
|
## Distribution
|
||||||
|
|
||||||
The runtime image is published to Codeberg's container registry via a
|
Each release is a Codeberg git tag (`zddc-server-vX.Y.Z` for stable, `zddc-server-vX.Y.Z-{alpha,beta}.N` for pre-releases) with four pre-built binaries attached as release assets:
|
||||||
local-build-and-push script (`release-image.sh` at the repo root). Each
|
|
||||||
release publishes cascading channel tags:
|
| File | Platform |
|
||||||
|
|---|---|
|
||||||
|
| `zddc-server-linux-amd64` | Linux (x86-64) |
|
||||||
|
| `zddc-server-darwin-amd64` | macOS (Intel) |
|
||||||
|
| `zddc-server-darwin-arm64` | macOS (Apple Silicon) |
|
||||||
|
| `zddc-server-windows-amd64.exe` | Windows (x86-64) |
|
||||||
|
|
||||||
|
All binaries are statically linked (CGO disabled), built with `-trimpath -ldflags="-s -w -X main.version=<ver>"`. No runtime dependencies.
|
||||||
|
|
||||||
|
Download URLs go through the website's Caddy proxy:
|
||||||
|
|
||||||
```
|
```
|
||||||
codeberg.org/varasys/zddc-server:X.Y.Z # immutable, exact version
|
https://zddc.varasys.io/releases/zddc-server-vX.Y.Z/zddc-server-linux-amd64
|
||||||
codeberg.org/varasys/zddc-server:stable # current stable
|
|
||||||
codeberg.org/varasys/zddc-server:beta # tracks stable-or-newer beta
|
|
||||||
codeberg.org/varasys/zddc-server:alpha # tracks beta-or-newer alpha
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`:latest` is intentionally not published — the project uses
|
(Caddy reverse-proxies that to the Codeberg release-asset URL — operators only ever talk to `zddc.varasys.io`.) Browse all versions at <https://zddc.varasys.io/releases/>.
|
||||||
stable/beta/alpha channel terminology consistently.
|
|
||||||
|
|
||||||
Pull and run:
|
There is no container image. The chart Dockerfiles in `tnd-zddc-chart` compile zddc-server from source at build time, fetching the right tag from Codeberg directly. If you want your own image, copy the static binary into a `FROM scratch` or `FROM alpine` base in a few lines.
|
||||||
|
|
||||||
```sh
|
|
||||||
podman run --rm -p 8443:8443 \
|
|
||||||
-v /srv/archive:/srv:Z \
|
|
||||||
-e ZDDC_TLS_CERT=none \
|
|
||||||
-e ZDDC_ADDR=:8080 \
|
|
||||||
-e ZDDC_INSECURE_DIRECT=1 \
|
|
||||||
codeberg.org/varasys/zddc-server:stable
|
|
||||||
```
|
|
||||||
|
|
||||||
The image:
|
|
||||||
|
|
||||||
- alpine-based, runs as non-root (UID 1000)
|
|
||||||
- exposes 8443 by default
|
|
||||||
- defaults `ZDDC_ROOT=/srv` (override or mount your archive there)
|
|
||||||
- bundles the landing + archive tool HTML at `/opt/zddc-server/web` for
|
|
||||||
self-contained demos (`ZDDC_ROOT=/opt/zddc-server/web`)
|
|
||||||
- declares `VOLUME /srv` so the operator's data mount is explicit
|
|
||||||
- ships a `HEALTHCHECK` for `docker run`; Kubernetes deployments override it
|
|
||||||
|
|
||||||
### Env-var contract (for chart consumers)
|
### Env-var contract (for chart consumers)
|
||||||
|
|
||||||
Downstream Helm charts and Compose files should set these explicitly rather
|
Downstream Helm charts and Compose files should set these explicitly:
|
||||||
than relying on image defaults:
|
|
||||||
|
|
||||||
| Variable | Typical value (behind ingress + SSO) | Purpose |
|
| Variable | Typical value (behind ingress + SSO) | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
|
@ -414,82 +404,74 @@ than relying on image defaults:
|
||||||
|
|
||||||
See "Environment Variables" above for the full list.
|
See "Environment Variables" above for the full list.
|
||||||
|
|
||||||
## Building
|
## Building from source
|
||||||
|
|
||||||
### Run as a container (build locally)
|
Requires Go 1.24+.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
podman build --target server -t zddc-server .
|
# Single binary for the host platform
|
||||||
|
(cd zddc && go build -o zddc-server ./cmd/zddc-server)
|
||||||
|
|
||||||
|
# All four release platforms (cross-compiled, statically linked)
|
||||||
|
sh build.sh # at the repo root — silently skips if Go isn't on PATH
|
||||||
|
# → outputs to zddc/dist/zddc-server-{linux,darwin,windows}-*
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compile native binaries (no Go installation required)
|
To run unit tests:
|
||||||
|
|
||||||
Use the `binaries` build target to cross-compile for all platforms using podman
|
|
||||||
as the build environment. Binaries are extracted directly to a local `dist/`
|
|
||||||
directory — no container runs on your host.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# From the zddc/ directory
|
(cd zddc && go test ./...)
|
||||||
mkdir -p dist
|
|
||||||
podman build --target binaries -o dist/ .
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This produces:
|
## Release tagging
|
||||||
|
|
||||||
| File | Platform |
|
`sh zddc/release.sh` is the canonical path. It tags the commit, cross-compiles the four binaries (native Go), and uploads them as Codeberg release assets via the shared `publish-codeberg-release.sh` helper.
|
||||||
|---|---|
|
|
||||||
| `dist/zddc-server-linux-amd64` | Linux (x86-64) |
|
|
||||||
| `dist/zddc-server-darwin-amd64` | macOS (Intel) |
|
|
||||||
| `dist/zddc-server-darwin-arm64` | macOS (Apple Silicon) |
|
|
||||||
| `dist/zddc-server-windows-amd64.exe` | Windows (x86-64) |
|
|
||||||
|
|
||||||
All binaries are statically linked (CGO disabled) — no runtime dependencies.
|
|
||||||
|
|
||||||
Run the binary directly:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Linux / macOS
|
sh zddc/release.sh # alpha cut, version auto-derived (default)
|
||||||
ZDDC_ROOT=/srv/archive ZDDC_TLS_CERT=none ZDDC_ADDR=:8080 ./dist/zddc-server-linux-amd64
|
sh zddc/release.sh alpha # same
|
||||||
|
sh zddc/release.sh beta # beta cut
|
||||||
# Windows (PowerShell)
|
sh zddc/release.sh stable # stable cut, patch++ from latest stable
|
||||||
$env:ZDDC_ROOT="C:\archive"; $env:ZDDC_TLS_CERT="none"; $env:ZDDC_ADDR=":8080"
|
sh zddc/release.sh stable 0.1.0 # stable cut, explicit version
|
||||||
.\dist\zddc-server-windows-amd64.exe
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Docker users:** Replace `podman build` with `docker build`. The `--target` and
|
**Default channel is `alpha`** so a stable-equivalent tag never appears by accident during active development. Pass `beta` to soak; pass `stable` only when deliberately promoting. The script tags the commit but does NOT push — finish with `git push origin <branch>` and `git push origin <tag>`.
|
||||||
> `-o` flags work identically in Docker BuildKit (enabled by default in Docker 23+).
|
|
||||||
|
|
||||||
## Release Tagging
|
Prerequisites:
|
||||||
|
|
||||||
Follow the repository convention: `zddc-server-vX.Y.Z`. Two coordinated
|
- Go 1.24+ on PATH.
|
||||||
steps — git tag for auditability, then local image build and push:
|
- `$CODEBERG_TOKEN` exported, scoped to write the VARASYS/ZDDC repo. Generate one at <https://codeberg.org/user/settings/applications>.
|
||||||
|
|
||||||
|
After the script returns successfully, regenerate the website's versions index from the new release list:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# 1. Tag the source.
|
sh build.sh
|
||||||
git tag zddc-server-v0.0.4
|
git add website/releases/index.html website/releases/manifest.json
|
||||||
git push origin zddc-server-v0.0.4
|
git commit -m "release: zddc-server vX.Y.Z"
|
||||||
|
git push origin main
|
||||||
# 2. Build and push the runtime image. Default cascade is alpha-only,
|
git push origin zddc-server-vX.Y.Z
|
||||||
# so `:stable` doesn't advance unless you deliberately promote.
|
|
||||||
sh release-image.sh 0.0.4 # → :0.0.4 :alpha (default)
|
|
||||||
sh release-image.sh 0.0.4 beta # → :0.0.4 :beta :alpha
|
|
||||||
sh release-image.sh 0.0.4 stable # → :0.0.4 :stable :beta :alpha
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Prerequisite: `podman login codeberg.org` (or `docker login`) once,
|
Single-developer / solo-release flow by design — no CI babysitting, no separate dashboard to debug. The script fails loudly and visibly on the developer's terminal if anything goes wrong.
|
||||||
authenticating with your Codeberg username and a personal token with
|
|
||||||
`package:write` scope, generated at
|
|
||||||
<https://codeberg.org/user/settings/applications>. The token is your
|
|
||||||
local credential — it never lives in the repo.
|
|
||||||
|
|
||||||
Single-developer / solo-release flow by design — no CI babysitting,
|
### Versioning
|
||||||
no separate dashboard to debug when the registry doesn't show what
|
|
||||||
you expected. See `release-image.sh` for what each tag publishes.
|
Pre-release semver. Stable cuts get clean `vX.Y.Z` tags. Alpha and beta cuts get `vX.Y.Z-alpha.N` / `vX.Y.Z-beta.N` where `X.Y.Z` is the next patch of the latest clean stable and `N` is a per-channel counter that resets when stable advances.
|
||||||
|
|
||||||
|
```
|
||||||
|
alpha → v0.0.8-alpha.1
|
||||||
|
alpha → v0.0.8-alpha.2
|
||||||
|
beta → v0.0.8-beta.1
|
||||||
|
alpha → v0.0.8-alpha.3 (alpha and beta count separately)
|
||||||
|
stable → v0.0.8 (counter resets at next-patch advance)
|
||||||
|
alpha → v0.0.9-alpha.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Pre-release semver ordering (`0.0.8-alpha.1 < 0.0.8-alpha.2 < 0.0.8-beta.1 < 0.0.8`) is honored by all standard tooling — Codeberg release sorting, `git tag --sort=-v:refname`, `sort -V`, npm, cargo — so consumers can pin or compare versions without surprises.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Notes:**
|
**Notes:**
|
||||||
|
|
||||||
- The container uses a multi-stage build
|
|
||||||
- The `.archive` virtual path resolves ZDDC tracking numbers to their earliest-received revision
|
- The `.archive` virtual path resolves ZDDC tracking numbers to their earliest-received revision
|
||||||
- ACL is enforced via bottom-up `.zddc` file evaluation
|
- ACL is enforced via bottom-up `.zddc` file evaluation
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue