Claude 9558f8e782 icon: transparent corners, so the tile is a tile
The app icon is flattened onto black because iOS rejects an alpha channel, and
copying that straight over made every dock tile an opaque black square. The tile
wants the frame's own rounded edge with the corners cut away — which is what the
icon this replaces already had, and what tile: bare means.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 06:28:44 +01:00
2026-08-18 01:16:07 +00:00

Kiosk

Build, sign and install Officer's iOS and Android apps on your own registered devices. What EAS does, self-hosted.

  • A catalogue of builds, newest per app per platform, with an Install button that hands itms-services:// to iOS or a plain URL to Android.
  • A per-user key that authorises artefact downloads. Held in memory by the app and re-read on demand, so rotating one costs nothing.
  • Device records — who owns which iPhone or iPad, and whether Apple knows about it yet.

Status — read before installing

Nothing here has run. Ported on 2026-08-18 from the standalone service that was called OAS. The authenticated API and the two panels exist and typecheck; no endpoint has answered a request.

What works, in principle

GET /apps, GET /apps/:appName, GET /key, POST /key/rotate, GET /install/:appName/:platform/:version, POST /installs, and the device and build verbs. All under /api/kiosk, all requiring a platform session.

What is missing, and why

Installing will not work yet. Four requests in the flow arrive with no session — iOS installd fetching the manifest and the .ipa, the device posting its UDID, and Safari downloading a .mobileconfig — and a plugin cannot serve an unauthenticated route today. UNPROTECTED_API_PREFIXES is hardcoded in the platform and plugin routers mount only behind the account gate.

So GET /install/... returns a correct-looking URL pointing at a route that does not exist. That is deliberate: the URL shape is what the mobile app builds against, and it stops being a dead end the day the platform gains unauthenticatedPaths. Those routes then land in api/public.ts, kept separate from api/router.ts so the two surfaces cannot be confused by anyone reading either.

Enrolment is not ported for the same reason — it is entirely public routes.

Artefacts arrive by rsync, into $OFFICER_ROOT/data/kiosk/. The plugin records metadata about files already on disk; it does not accept uploads, because the platform's shared upload route caps at 5MB and no .ipa will ever satisfy that.

Notes

  • PUBLIC_URL must be HTTPS with a certificate iOS already trusts. It fetches the manifest and binary itself and declines silently otherwise, which looks exactly like a broken build.
  • Table names are prefixed kiosk_. There are no migrations — see the note at the top of db/schema.ts.
  • The plugin is currently appName: kiosk. If the plugin storefront takes that name, this one is renamed; see docs/kiosk-ecosystem.md in the platform.
S
Description
Officer Kiosk — build, sign and install iOS and Android apps on your own devices
Readme
2.2 MiB
Languages
TypeScript 100%