- Validate and prepare access links in apps/frontend - Add session, ended, and unauthorized routes with polling - Copy full public access URLs from the admin links page
4.4 KiB
4.4 KiB
Illusory IOTAM
A SaaS platform that lets users run specific Android applications on hosted Docker-Android instances — instead of on their own device. Users get a unique link, install a PWA, and are streamed a live Android session from the cloud.
Currently in alpha. Greenfield. Subject to change.
How It Works
- Admin generates a unique link and assigns it to a specific Android app on a specific device.
- User opens that link in their browser — served by
apps/frontend. - During the loading flow,
apps/frontendvalidates the link and asksapps/orchestratorto reset the assigned Android session and launch the leased app. - If that device is already in use by another end user, the link fails instead of taking over the session.
- User is prompted to install the PWA.
- User opens the PWA — they are routed into a live stream of their assigned Android app session.
- Admin manages the entire fleet from
apps/main(the dashboard), which communicates withapps/orchestratorrunning on each VPS to control Docker-Android containers.
Implementation Checklist
Foundation
- Monorepo setup (Turborepo + pnpm)
- Shared packages:
@pkg/logic,@pkg/db,@pkg/logger,@pkg/result,@pkg/keystore,@pkg/settings - PostgreSQL with Drizzle ORM
- Redis (Valkey) via
@pkg/keystore - OpenTelemetry end-to-end (logs, traces, metrics → SigNoz)
- Auth system (Better Auth — email/password, magic link, 2FA/TOTP, sessions)
- User management (roles, bans, account operations)
- Notifications system (priority, archiving, bulk ops)
- Admin dashboard shell (
apps/main— SvelteKit) - Background task tracking schema (task table)
Device Management (Orchestrator + Admin)
- Device schema — DB model for a device (host VPS, container ID, status,
inUse, assigned session, etc.) - Device domain in
@pkg/logic— controller + repository + errors - Orchestrator command interface — secured Hono routes the admin dashboard calls:
POST /devices/:id/start— start a Docker-Android containerPOST /devices/:id/stop— stop a containerPOST /devices/:id/restart— restart a containerGET /devices— list all devices and their current statusGET /devices/:id— page to view the device in more detail (info, live stream feed with ws-scrcpy)
- Device allocation logic — atomically mark a device as
inUsewhen a validated link starts a session - Device release logic — clear
inUsewhen a session ends or fails during setup - Admin dashboard: Devices page — list fleet, show status, trigger start/stop/restart
- Internal API key auth between
apps/mainandapps/orchestrator
Link Management (Admin + Front App)
- Link schema — DB model (unique token, expiry, status, linked device ID, leased app identity)
- Link domain in
@pkg/logic— controller + repository + errors - Admin dashboard: Links page — generate links, view detail, configure linked device + leased app, revoke, delete
apps/frontend: validate incoming link token on requestapps/frontend: during loading, reject the link if the assigned device is alreadyinUseapps/frontend: callapps/orchestratorserver-side to clean/reset the device and launch the leased app before handing off the sessionapps/frontend: return appropriate error page for invalid/expired/revoked links- Front: keep on checking for link status change, if it gets revoked, we cutoff the connection
PWA & User Session Flow (apps/frontend)
apps/frontend: serve static PWA shell (HTML + manifest + service worker)apps/frontend: wait/loading page — just for show with a 3-5s durationapps/frontend: PWA install prompt flow (beforeinstallprompt handling)apps/frontend: session binding — tie the PWA launch to the user's allocated deviceapps/frontend: route/proxy authenticated PWA requests to the Android instance stream
Android Streaming (scrcpy + ws-scrcpy)
- Docker-Android image setup and validation on VPS
- ws-scrcpy WebSocket server running per container, exposed via orchestrator
apps/frontend: scrcpy client embedded in PWA — renders the Android stream in browser- Input forwarding (touch/keyboard events → scrcpy → Android container)
- Session timeout + stream teardown on inactivity