feat(public): version/health surfacing + typed brand block #77

Merged
whitlocktech merged 2 commits from feat/public-version-and-brand into main 2026-07-19 17:38:22 +00:00
Member

What & why

The last two v1 prerequisites for the Android app (docs/android/PLAN.md §8 items 4 & 6). Two focused commits:

1. feat(public): version/health surfacing (§8.4)
A small backend identity/version descriptor so a client can positively recognize a Runic Gateway backend on first-run and run a version-mismatch guard, instead of inferring from an incidental shape.

  • New config/version.js: { service: 'runic-gateway', api: 'v1', server: <pkg> }.
  • GET /public/status now includes a version block (the app already calls this on first-run → identity + version in one round trip).
  • New DB-free GET /public/version — canonical target for the version guard and a cheap liveness check.
  • Swagger: PublicVersion schema; version on PublicStatus; /version annotated.

2. feat(public): type the brand block (§8.6)
Branding was already returned by GET /public/settings (the brand block: name/accent/logo/hero/favicon, per-shard from BRAND_*). This makes it first-class in the OpenAPI contract so the app's codegen produces typed branding instead of an untyped map.

  • Swagger: add Brand + PublicSettings schemas; /public/settings now references PublicSettings (was additionalProperties: true). Brand documents that asset fields may be site-relative (resolve against the base URL).
  • No behavior change to the response — it already carried brand; this types and guards it.

How it was tested

  • New unit tests pass individually: test/publicVersion.test.js (config shape + DB-free /public/version → 200) and test/publicBrand.test.js (full brand contract; BRAND_* defaults; admin site_title/contact_email overrides; accentInt never leaked). The wider suite shows zero assertion failures; changes are strictly additive (no existing test imports the new modules; the suite doesn't load swagger.js). CI runs the authoritative npm test.
  • Live smoketest against the running server + MariaDB:
    • GET /public/version{"service":"runic-gateway","api":"v1","server":"1.0.0"}
    • GET /public/status → carries the same version block
    • GET /public/settingsbrand with all 10 theming fields; name reflects the admin site_title override

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

  • No AI tools were used to produce this contribution.
  • AI tools were used. Tool(s): Claude Code (Claude Opus 4.8). I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a Co-Authored-By trailer.

License

  • I agree that my contribution is licensed under this project's license (GNU GPL v3.0 or later), and I have the right to contribute it.

Docs counterpart updates BACKEND_DESIGN.md (the /public rows) and marks PLAN §8 items 4 & 6 done — with this, all v1 prerequisites are complete (only post-v1 push remains).

🤖 Generated with Claude Code

https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr

## What & why The last two v1 prerequisites for the Android app (docs/android/PLAN.md §8 items 4 & 6). Two focused commits: **1. `feat(public): version/health surfacing` (§8.4)** A small backend identity/version descriptor so a client can positively recognize a Runic Gateway backend on first-run and run a version-mismatch guard, instead of inferring from an incidental shape. - New `config/version.js`: `{ service: 'runic-gateway', api: 'v1', server: <pkg> }`. - `GET /public/status` now includes a `version` block (the app already calls this on first-run → identity + version in one round trip). - New **DB-free** `GET /public/version` — canonical target for the version guard and a cheap liveness check. - Swagger: `PublicVersion` schema; `version` on `PublicStatus`; `/version` annotated. **2. `feat(public): type the brand block` (§8.6)** Branding was already returned by `GET /public/settings` (the `brand` block: name/`accent`/logo/hero/favicon, per-shard from `BRAND_*`). This makes it first-class in the OpenAPI contract so the app's codegen produces **typed** branding instead of an untyped map. - Swagger: add `Brand` + `PublicSettings` schemas; `/public/settings` now references `PublicSettings` (was `additionalProperties: true`). `Brand` documents that asset fields may be site-relative (resolve against the base URL). - No behavior change to the response — it already carried `brand`; this types and guards it. ## How it was tested - New unit tests pass individually: `test/publicVersion.test.js` (config shape + DB-free `/public/version` → 200) and `test/publicBrand.test.js` (full brand contract; `BRAND_*` defaults; admin `site_title`/`contact_email` overrides; `accentInt` never leaked). The wider suite shows **zero assertion failures**; changes are strictly additive (no existing test imports the new modules; the suite doesn't load `swagger.js`). CI runs the authoritative `npm test`. - **Live smoketest** against the running server + MariaDB: - `GET /public/version` → `{"service":"runic-gateway","api":"v1","server":"1.0.0"}` - `GET /public/status` → carries the same `version` block - `GET /public/settings` → `brand` with all 10 theming fields; `name` reflects the admin `site_title` override ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) - [ ] No AI tools were used to produce this contribution. - [x] AI tools were used. Tool(s): `Claude Code (Claude Opus 4.8)`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it. --- Docs counterpart updates `BACKEND_DESIGN.md` (the `/public` rows) and marks PLAN §8 items 4 & 6 done — with this, all v1 prerequisites are complete (only post-v1 push remains). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr
wtclaude added 2 commits 2026-07-19 17:18:35 +00:00
Expose a small backend identity/version descriptor (§8.4 of the Android plan)
so a client can positively recognize a Runic Gateway backend on first-run and
run a version-mismatch guard, instead of inferring from an incidental shape.

- New config/version.js: { service: 'runic-gateway', api: 'v1', server: <pkg> }.
- GET /public/status now includes a `version` block (the app already calls this
  on first-run, so it gets identity + version in one round trip).
- New GET /public/version: a lightweight, DB-free identity endpoint — the
  canonical target for the version guard and a cheap liveness check.
- Swagger: PublicVersion schema + version on PublicStatus; /version annotated.
- test/publicVersion.test.js covers the config shape and the DB-free 200.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr
feat(public): type the brand block so mobile clients get typed theming
All checks were successful
PR Checks / client-build (pull_request) Successful in 9m29s
PR Checks / server-tests (pull_request) Successful in 10m30s
PR Checks / bot-install (pull_request) Successful in 9m21s
c35509e8b3
Branding is already returned by GET /public/settings (the `brand` block:
name/colors/logo/hero/favicon, per-shard from BRAND_*). §8.6 of the Android
plan asks to confirm it — this makes it a first-class part of the contract so
the app's OpenAPI codegen produces typed branding instead of an untyped map.

- Swagger: add Brand + PublicSettings schemas; /public/settings now references
  PublicSettings (was additionalProperties:true). Brand documents that asset
  fields may be site-relative paths (resolve against the base URL).
- test/publicBrand.test.js locks the brand theming contract the app depends on
  (all fields present; BRAND_* defaults; admin site_title/contact_email
  overrides; accentInt never leaked).

No behavior change to the response — it already carried `brand`; this types and
guards it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr
whitlocktech approved these changes 2026-07-19 17:23:15 +00:00
whitlocktech scheduled this pull request to auto merge when all checks succeed 2026-07-19 17:23:21 +00:00
whitlocktech merged commit 030414f13d into main 2026-07-19 17:38:22 +00:00
whitlocktech deleted branch feat/public-version-and-brand 2026-07-19 17:38:23 +00:00
Sign in to join this conversation.
No description provided.