Repository navigation
Architecture
CORE MDM has three parts: the web console, Firebase (Firestore + Auth), and the Android app. There is no always-on custom server in the command path — Firestore's real-time listeners are the transport.
Browser (coremdm.web.app)
│ signs in (Firebase Auth) and writes Firestore documents / queues commands
▼
Firebase Firestore /devices/{deviceId} (+ /devices/{deviceId}/commands)
│ real-time snapshot listeners
▼
MdmCommandService (Android foreground service)
│ claims & executes commands, applies policies
▼
DevicePolicyHelper → DevicePolicyManager (Android OS)
A single-file vanilla-JS SPA using the Firebase JS SDK (v10.12.2). It authenticates the admin, lists the devices they own (where ownerId == uid), and writes policy fields / queues commands directly to Firestore. No build step.
- Auth — identifies both the admin (in the browser) and the device (in the app). Email/password and Google.
-
Firestore — the single source of truth. Each device is a document at
/devices/{hardwareId}; commands live in acommandssubcollection. See Firestore Data Model. -
Security rules (
firestore.rules) enforce per-user ownership and let a device update only its own record. See Security Rules.
-
MdmCommandService— a foreground service that holds the live Firestore listeners, applies policies, and runs queued commands. It re-attaches automatically if a listener drops, and a 60-second heartbeat updateslastSeenand re-enrolls if needed. -
EnrollmentManager— derives the stable hardware ID and writes/updates the device document on sign-in. -
DeviceRegistry— all Firestore reads/writes: the device-doc listener, the command-queue listener,claimCommand(transaction), the installed-app inventory sync. -
DevicePolicyHelper— a thin wrapper over Android'sDevicePolicyManager; every restriction/command goes through here. -
AppPolicyManager— per-app hide/suspend. -
DnsVpnService— the DNS content filter VPN. -
PinManager— the PBKDF2-hashed in-app PIN. - Jetpack Compose UI: dashboard, login, PIN, apps, kiosk, filter, provisioning, telemetry.
- Console adds a doc to
/devices/{id}/commands:{ type, state: "pending", createdAt }. - The device's queue listener sees it and calls
claimCommand, a Firestore transaction that flipspending → executedonly if it's still pending. - If the transaction wins, the device runs the command (
lock/reboot/wipe/lockdown). - If the admin pressed Cancel first, the state is already
cancelled, the transaction aborts, and the device does nothing.
This guarantees a command runs at most once and can be cancelled in the window before pickup.
The console writes policies.<key> on the device doc. The device's doc listener diffs the policy map and applies only what changed, then re-asserts it on reconnect and on boot (BootReceiver). The Firestore field is the desired state; the device converges to it.
Firestore's snapshot listeners give sub-second push to the device over its existing authenticated connection, survive network changes, and queue writes while offline — so a command sent to an offline phone is delivered when it reconnects, with no custom infrastructure. The optional backend/ (Node) and admin-backend/ (Spring Boot) services exist for extras like WebRTC screen control, not for the core command path.
- Listener re-attach: if a Firestore listener errors, the service clears it and the heartbeat re-creates it.
-
Boot persistence:
BootReceiverrestarts the service and re-applies baseline restrictions, status-bar state, and uninstall protection. - Always-on content filter: on Device Owner, the VPN is registered as always-on, so it restarts itself after reboot.
CORE MDM — Repository · Console · Releases · Beta
Getting started
Using it
- Web Console Guide
- Commands and Command Queue
- Policies Reference
- App Management
- Content Filter and DNS
- Kiosk Mode
- PIN and Security
- Enrollment and Provisioning
How it works
Operations
Help