diff --git a/docs/superpowers/specs/2026-06-03-gui-build-version-badge-design.md b/docs/superpowers/specs/2026-06-03-gui-build-version-badge-design.md new file mode 100644 index 0000000..9fb65cf --- /dev/null +++ b/docs/superpowers/specs/2026-06-03-gui-build-version-badge-design.md @@ -0,0 +1,95 @@ +# GUI build-version badge + +**Date:** 2026-06-03 +**Status:** approved (design) +**Area:** `VERSION`, `build.sh`, `Dockerfile`, `src/presa_mano/version.py`, `src/presa_mano/main.py`, `web/index.html`, `web/app.js` + +## Problem + +`src/` and `web/` are baked into the Docker image (no bind-mount), so code changes only take effect after an image rebuild. There is no visible indicator of which build the running container serves, so a stale deployment is invisible — exactly the confusion behind "non vedo modifiche alla GUI". We want a version shown in the GUI header that increments on every build, plus the build time. + +## Decisions (locked) + +- **Version string:** `V..` (e.g. `V1.0.1`), **patch auto-increments every build**; build time shown too. +- **Injection:** a build wrapper script passes the version + build time as Docker build args. +- **Placement:** a pill badge in the GUI header, build time in its tooltip. + +## Components + +### `VERSION` (tracked file, repo root `presa-mano/VERSION`) +Plain text `major.minor.patch`, initialized to `1.0.0`. Single source of truth for the number; persists across builds via the file on disk. The build script rewrites it (left as an uncommitted working-tree edit — the script does NOT auto-commit). + +### `build.sh` (repo root, executable) +``` +1. cd to script dir; ensure VERSION exists (else seed 1.0.0) +2. parse current major.minor.patch +3. bump: default patch++; arg `minor` → minor++/patch=0; `major` → major++/minor=patch=0 +4. write new VERSION +5. BUILD_TIME = $(date -u +"%Y-%m-%d %H:%M UTC") +6. (cd compose dir) docker compose build --build-arg APP_VERSION= --build-arg BUILD_TIME="" presa-mano +7. docker compose up -d presa-mano +8. echo deployed version +``` +The compose file lives one level up (`/opt/docker/robotserver/docker-compose.yml`); the script resolves that dir and runs compose there. Usage: `./build.sh [patch|minor|major]` (default patch). + +### `Dockerfile` +Add late (before `CMD`), so changing them doesn't bust the dependency layers: +``` +ARG APP_VERSION=dev +ARG BUILD_TIME=unknown +ENV APP_VERSION=${APP_VERSION} +ENV BUILD_TIME=${BUILD_TIME} +``` +Also `COPY VERSION ./` (cheap, makes the file fallback work inside the container too). + +### `src/presa_mano/version.py` +```python +def build_info() -> dict: + """{'version', 'build_time'}. Prefer env (set at Docker build); fall back to + the VERSION file + '(local)' for `uv run` dev.""" +``` +- `version` = `APP_VERSION` env if set, else ` (local)` (or `0.0.0 (local)` if the file is unreadable). +- `build_time` = `BUILD_TIME` env if set, else `(local)`. +- `VERSION` file resolved as `Path(__file__).resolve().parents[2] / "VERSION"`. + +### `src/presa_mano/main.py` +```python +from .version import build_info + +@app.get("/api/version", tags=["meta"]) +def version() -> dict: + return build_info() +``` + +### `web/index.html` +In the header, next to `#activeRobotPill`, add: +```html +V— +``` +(reuses the existing pill styling). + +### `web/app.js` +Add and call once at startup (alongside `refreshHomeRobotSelector()`): +```javascript +async function refreshAppVersion() { + try { + const r = await api('GET', '/api/version'); + const pill = $('appVersionPill'); + if (pill) { pill.textContent = `V${r.version}`; pill.title = `build ${r.build_time}`; } + } catch {} +} +refreshAppVersion(); +``` + +## Testing + +- Unit test `tests/test_version.py` for `build_info()`: + - env set (`APP_VERSION`, `BUILD_TIME` via monkeypatch) → returns exactly those. + - env unset (monkeypatch.delenv) → `version` ends with `(local)` and contains the `VERSION` file content; `build_time == "(local)"`. +- Frontend: manual — after `./build.sh` the badge increments and the tooltip shows the new build time. + +## Out of scope (YAGNI) + +- git SHA / dirty flag (user chose version+time only). +- Auto-commit of the VERSION bump. +- Frontend-vs-backend version mismatch warning.