The PreStartGo mobile app reads two per-platform build thresholds — a hard minimum build (below which the app must force upgrade) and a softer warning build (below which the app shows an "update available" banner). The thresholds are platform-wide, set by PreStartGo staff, and exposed through two HTTP surfaces:
This is a mobile-client concern. Third-party API integrations have no need to read or act on these
thresholds — they are documented here so mobile-app authors building against PreStartGo (including
the Flutter app in psg-mobile/) implement the contract consistently.
GET /api/v1/system/mobile-build-requirements
Pre-authentication — no Firebase token, no API key (the route blocks API keys at the middleware layer). Mobile clients hit this on cold start before they have a token, then cache the response locally for 6 hours.
Response — one row per platform (ios, android):
{
"success": true,
"data": [
{
"platform": "ios",
"minimumBuild": 142,
"warningBuild": 158,
"notes": null,
"updatedAt": "2026-05-21T03:00:00.000Z"
},
{
"platform": "android",
"minimumBuild": 140,
"warningBuild": 156,
"notes": null,
"updatedAt": "2026-05-21T03:00:00.000Z"
}
]
}
minimumBuild and warningBuild are integer build numbers (CFBundleVersion on
iOS, versionCode on Android). Both are non-negative integers; the server
rejects upserts where warningBuild < minimumBuild.
/api/v1/mobile/*Every response from the mobile API (including 4xx and 5xx) carries the current thresholds so the app can refresh its cache opportunistically without an extra round-trip:
| Header | Meaning |
|---|---|
X-Mobile-Minimum-Build | Block threshold — if |
X-Mobile-Warning-Build | Soft-warn threshold — if |
Both headers are integers. They are added by the server-side
mobile-build-headers middleware after the downstream route runs, so they
always reach the client even when the underlying response is an error.
X-App-PlatformThe middleware reads a single request header to pick the matching threshold row:
X-App-Platform: ios
| Value | Behaviour |
|---|---|
ios | Response headers populated from the iOS threshold row. |
android | Response headers populated from the Android threshold row. |
web-prototype | No response headers added — the Vite preview is dev/staging only and never subject to force-upgrade enforcement. |
If the header is missing or carries an unrecognised value, no headers are added — the dedicated endpoint remains authoritative for that client.
The server middleware caches thresholds in-process for 60 seconds. A staff threshold change propagates to every Cloud Run instance within one minute even without a pub/sub bus.
The mobile client should cache the dedicated-endpoint response for 6 hours. Combined with opportunistic refresh from response headers, this keeps the cold-start hit minimal while ensuring clients see threshold changes the next time they make a request.
GET /api/v1/system/mobile-build-requirements and store the
row for the running platform locally.X-Mobile-Minimum-Build and
X-Mobile-Warning-Build; if present, refresh the cached values.currentBuild < minimumBuild → block the app and show the
force-upgrade screen. The user cannot continue without updating.currentBuild < warningBuild → show a non-blocking banner prompting
the user to update.Header attachment on the server is best-effort and wrapped in a try/catch — a database hiccup never turns a successful mobile response into a failed one. Clients should treat missing headers as "no new information" rather than "thresholds were cleared", and continue using their cached values.