feat(public): version/health surfacing for the app first-run probe

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
This commit is contained in:
2026-07-19 11:47:26 -05:00
parent 93a2c0d55f
commit 90c8eae20f
6 changed files with 182 additions and 2 deletions

View File

@@ -1662,7 +1662,7 @@
"Public"
],
"summary": "Site mode / status",
"description": "Current site mode (live or maintenance) so the client can show the maintenance page.",
"description": "Current site mode (live or maintenance) so the client can show the maintenance page, plus a version block (service id + API/server versions) for a client first-run probe and version-mismatch guard.",
"responses": {
"200": {
"description": "Site status",
@@ -1680,6 +1680,27 @@
}
}
},
"/api/v1/public/version": {
"get": {
"tags": [
"Public"
],
"summary": "Backend identity + version",
"description": "Lightweight, DB-free descriptor of this backend: a stable service id and the API/server versions. A client uses it to recognize a Runic Gateway backend on first-run and to run a version-mismatch guard. Doubles as a cheap liveness check.",
"responses": {
"200": {
"description": "Backend version",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PublicVersion"
}
}
}
}
}
}
},
"/api/v1/public/contact": {
"post": {
"tags": [
@@ -13907,6 +13928,78 @@
"example": ""
}
}
},
"version": {
"$ref": "#/components/schemas/PublicVersion"
}
}
}
}
},
"PublicVersion": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"description": {
"type": "string",
"example": "Backend identity + version (GET /public/version; also embedded in /public/status)."
},
"properties": {
"type": "object",
"properties": {
"service": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "runic-gateway"
},
"description": {
"type": "string",
"example": "Stable backend identifier for first-run recognition."
}
}
},
"api": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "v1"
},
"description": {
"type": "string",
"example": "API contract version (matches the /api/v1 mount)."
}
}
},
"server": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "1.0.0"
},
"description": {
"type": "string",
"example": "Server package version (informational)."
}
}
}
}
}

View File

@@ -575,6 +575,16 @@ const doc = {
properties: {
mode: { type: 'string', enum: ['live', 'maintenance'], example: 'live' },
status_message: { type: 'string', example: '' },
version: { $ref: '#/components/schemas/PublicVersion' },
},
},
PublicVersion: {
type: 'object',
description: 'Backend identity + version (GET /public/version; also embedded in /public/status).',
properties: {
service: { type: 'string', example: 'runic-gateway', description: 'Stable backend identifier for first-run recognition.' },
api: { type: 'string', example: 'v1', description: 'API contract version (matches the /api/v1 mount).' },
server: { type: 'string', example: '1.0.0', description: 'Server package version (informational).' },
},
},
// Delete/mutation acknowledgements — each echoes the affected resource key