The /openapi.yaml route does res.sendFile(../docs/openapi.yaml) -> /app/docs/openapi.yaml in
the container, but the Dockerfile copied server/, frontend/, VERSION, scripts/ and never docs/,
so the spec 404'd in every deployed build (Redoc's /docs page loaded but couldn't fetch the
spec). Served fine from a dev checkout only because the repo has docs/ on disk. Verified in a
built image: /app/docs/openapi.yaml present, GET /openapi.yaml -> 200 text/yaml.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- .github/workflows/release.yml: on a v* tag - verify the tag matches VERSION
(fail-fast guard), run tests, build a source tarball + the unsigned Tizen .wgt
and publish a GitHub Release with generated notes, and build+push a multi-arch
(amd64 + arm64) image to ghcr.io/screentinker/screentinker:<version> + :latest.
The Release (artifacts) and the docker push are independent jobs, so an
arm64/QEMU docker failure does not block the GitHub Release and is re-runnable.
Nothing deploys to prod. APK-build-in-CI left as a TODO (keystore secret).
- Dockerfile + .dockerignore: multi-stage node:20-slim image with server +
frontend + VERSION + scripts; DATA_DIR=/data volume for db/uploads/jwt-secret.
Verified to build, boot, serve the dashboard + web player, and persist state.
- docker-compose.example.yml: /data volume, SELF_HOSTED, a node-fetch healthcheck
against /api/status, and an admin-lockout recovery note (reset-admin.js).
- server.js: resolve the OTA APK from DATA_DIR first (a container can mount one
at /data/ScreenTinker.apk), fall back to the legacy in-repo path, 404 gracefully.
- ci.yml: bump checkout/setup-node to v6 (clears the Node-20 action deprecation).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>