feat(server): /api/client/version + /api/client/apk endpoints (#397 phase 1)
Phase 1 of the in-app update flow — server side. Endpoints serve the bundled Android APK + sidecar version file from /app/client/. Returns 404 gracefully when files aren't present, so dev environments and pre-CI-wiring images degrade cleanly to "no update available." - internal/api/client_assets.go: handleClientVersion + handleClientAPK. Both unauthenticated (matches /healthz) so install flow doesn't depend on a live session. APK served with proper application/vnd.android.package-archive Content-Type + http.ServeContent so Range requests work for resumable downloads on flaky networks. - Path resolves to /app/client/ by default; MINSTREL_CLIENT_APK_DIR env var overrides for dev. - Dockerfile creates /app/client/ + commented COPY hooks for the CI sequencing phase. - Tests cover all four states: missing apk, apk-but-no-version, both present (200 with correct shape), apk stream (200 with correct Content-Type + body bytes). Phases 2 (Flutter client provider + banner + install intent + Android manifest changes) and 3 (CI sequencing to bake the APK into the image) land in follow-up commits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,11 @@ func Mount(r chi.Router, pool *pgxpool.Pool, logger *slog.Logger, events *playev
|
||||
api.Post("/auth/register", h.handleRegister)
|
||||
api.Post("/auth/forgot-password", h.handleForgotPassword)
|
||||
api.Post("/auth/reset-password", h.handleResetPassword)
|
||||
|
||||
// Self-hosted in-app update channel (#397). Unauthenticated so
|
||||
// the install flow doesn't depend on a live session.
|
||||
api.Get("/client/version", h.handleClientVersion)
|
||||
api.Get("/client/apk", h.handleClientAPK)
|
||||
api.Group(func(authed chi.Router) {
|
||||
authed.Use(auth.RequireUser(pool))
|
||||
authed.Post("/auth/logout", h.handleLogout)
|
||||
|
||||
Reference in New Issue
Block a user