`gitTally` is the name of another product in the git space, so the rename is a precaution; nothing about what the build system does changes. The name follows one rule: `Werkator` where it is prose, capitalized where it is a Kotlin type and its file, lowercase everywhere a machine reads it — the command, packages, paths, configuration keys and values, the Gitea check context. Environment variables keep their convention and are uppercase throughout. Every configuration file is still found under its pre-rename name (`ConfigFiles`): `.gittally.yml` at the repository root, in a build worktree and as committed on a branch, `.git/gittally/.gittally.yml` for the machine layer. The current name wins where both exist, and the old file is then ignored rather than merged — two files side by side are a half-done rename, not a layering. Without the fallback an installation that updated without renaming would not fail: a configuration that is not found leaves every setting at its default, so it would come up looking healthy while having forgotten its credentials and its builds. `docs/werkator-migrationsplan.md` lists what the fallback does not cover and has to be moved by hand — above all the state directory `.git/werkator/`, which holds the build history, the control token and the worktrees, and has no fallback of its own. `docs/migration-from-legacy.md` is deleted with this: it mapped the legacy script's environment variables, and every host it addressed has long since moved to the YAML configuration. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3.8 KiB
Rewrite Architecture Decisions
Status:
- proposed: 2026-07-07
- accepted: 2026-07-07
- rejected: -
- superseded: partially on 2026-07-07 — the "no managed nginx/TLS" part is revised by ADR 0005 (opt-in managed nginx/TLS container for hosts without a reverse proxy)
Decision [accepted, nginx part revised by ADR 0005]: JSON-file persistence behind a repository interface, server-rendered UI with JSON polling, no managed nginx/TLS by default — deployment via systemd user unit behind the host's reverse proxy.
Context and Problem Statement
The rewrite of legacy/werkator (bash) as a Kotlin/Spring application (see docs/plan/) required several cross-cutting architecture decisions.
They were proposed in docs/plan/README.md, validated step by step during implementation, and are summarized here as one record.
Technical Background
The legacy script kept all state in TSV/HTML files, patched its web UI with regex rewrites, and managed its own nginx+certbot Docker container. Its two structural defects — build status not observable during a build, and a web UI that could get stuck loading forever — had to be fixed by design, not by patching.
Considered Options
- Database persistence (SQLite) vs. JSON files behind a repository interface
- SPA frontend or server push (WebSocket/SSE) vs. server-rendered HTML with JSON polling
- Managed nginx/Let's Encrypt container vs. documented deployment behind an existing reverse proxy
Persistence: JSON files behind BuildResultRepository
Build results are persisted as a JSON file under .git/werkator/, accessed only through the BuildResultRepository interface.
Advantages
- No database dependency, no schema migrations; state stays inspectable with a text editor, like legacy.
- The volume is tiny (retention prunes per branch), so file rewrites are cheap.
- The interface keeps a later switch to SQLite possible without touching callers.
Disadvantages
- No queries or transactions; concurrent writers must be serialized in-process.
Web UI: server-rendered Thymeleaf plus JSON polling
Pages render the full state server-side; one hand-written JavaScript file polls JSON endpoints and re-renders table bodies.
Advantages
- No SPA framework and no frontend build pipeline.
- Fixes the legacy stuck-spinner defect by design: every fetch has a timeout and an explicit error badge, and status transitions are event-driven and observable while a build runs.
- Pages stay useful without JavaScript (initial render is complete).
Disadvantages
- Updates are only as fresh as the polling interval; no server push.
Deployment: no managed nginx, systemd user unit instead
nginx/Let's Encrypt container management was not ported; init --systemd generates a user unit running java -jar werkator.jar server, and docs/deployment.md documents the reverse-proxy setup with the host's certbot.
Advantages
- Removes the largest and most brittle legacy subsystem (container lifecycle, certificate renewal, config templating).
- Hosts usually already run a web server with TLS; one
serverblock suffices. - The generated unit replaces the legacy self-copy/self-update machinery with plain jar deployment.
Disadvantages
- HTTPS setup is a manual, host-specific step outside Werkator's control.
Decision Outcome
All three proposals from the plan were confirmed during implementation and are in force:
- JSON-file persistence behind
BuildResultRepository(steps 01, 05, 06). - Server-rendered HTML with polling JSON endpoints and explicit error states (steps 07–09).
- No nginx management; systemd user unit plus reverse-proxy documentation (step 12).
Related, previously decided in the same spirit: external systems are accessed by shelling out to the git and docker CLIs instead of SDK dependencies (steps 02, 11).