The IntelliPlan desktop app is a real native application — not a PWA shortcut and not a browser bookmark — built with Electron and packaged with electron-builder. It lives in theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/UAnirudh/IntelliPlan/llms.txt
Use this file to discover all available pages before exploring further.
desktop/ directory and delivers capabilities that a browser tab simply cannot provide: OS notifications that fire whether or not any window is open, a system tray entry showing your next scheduled session, a global keyboard shortcut reachable from any application, and persistent sign-in that survives quitting and restarting. It targets Windows, macOS, and Linux from one codebase and produces platform-native installers for each.
Why a Native App
The web app is rendered inside the window — you get the same feature set — but the following only exist in the desktop build:| Capability | Why it needs a native app |
|---|---|
| OS notifications | Fire whether or not a window is open. The browser Notification API only works while the page is alive, so a closed tab means a missed session reminder. |
| Tray “up next” | The next scheduled session is visible without opening anything. Refreshes every minute and on wake from sleep. |
| Global shortcut | Ctrl/Cmd+Shift+S starts a study session from any application, no Alt-Tab required. |
| Persistent session | Sign in once. The session survives quitting and restarting the app. |
| Offline handling | A dropped connection shows a real reconnecting message instead of Chromium’s error page. |
| Deep links | intelliplan://active opens straight to the session screen from any other app. |
Running Locally
Start against production
electron . with IP_TARGET unset, so the window loads https://intelliplan.tech.Building Installers
Each platform must be built on its own runner — electron-builder cannot produce a signed macOS build from Windows, and.github/workflows/desktop-release.yml enforces this in CI.
- Windows
- macOS
- Linux
- All platforms (CI)
dist/. Artifact names follow the pattern IntelliPlan-Setup-{version}-{arch}.exe.Publishing a Release
Tagging triggers the CI workflow, which builds all three platforms and attaches the installers to a GitHub Release. The IntelliPlan website’s/download page reads the latest release from the GitHub API and lists whatever assets it finds — no filenames to keep in sync, and a platform that failed to build is simply absent rather than a dead link.
The tag must start with
desktop-v. The release script desktop_releases.py only considers tags matching that prefix, so a web or extension tag is never mistaken for a desktop build.electron-builder Configuration
Four fields indesktop/package.json are load-bearing for packaging:
desktop/package.json (build section, abridged)
Why these four package.json fields matter
Why these four package.json fields matter
| Field | Why |
|---|---|
homepage | deb and rpm builds refuse to run without it |
author.email | Becomes the deb/rpm maintainer field; also required |
repository | electron-builder warns and cannot infer the publish target |
build.publish | Without a provider, update-info generation dereferences null |
Code Signing
Builds are unsigned by default — no certificate is in the repo. CI setsCSC_IDENTITY_AUTO_DISCOVERY=false to stop electron-builder scanning the runner’s keychain. Signing turns on by adding repository secrets; nothing in the code changes.
- Windows — Azure Trusted Signing
- macOS — Developer ID
Azure Trusted Signing (~$10/month) is the recommended route. An OV
.pfx certificate is signed but still triggers SmartScreen until reputation builds — buying little over unsigned. An EV certificate requires a hardware token a CI runner cannot hold.| Secret | Value |
|---|---|
AZURE_CODE_SIGNING_ACCOUNT | Trusted Signing account name |
AZURE_CODE_SIGNING_PROFILE | Certificate profile name |
AZURE_CODE_SIGNING_ENDPOINT | Region endpoint (e.g. https://eus.codesigning.azure.net) |
AZURE_TENANT_ID | App registration tenant |
AZURE_CLIENT_ID | App registration client ID |
AZURE_CLIENT_SECRET | App registration secret |
SHA256SUMS.txt covering the platforms that built. It lets a student verify a download arrived intact and is the only integrity signal an unsigned build has.
Google Sign-In
Google refuses to run OAuth inside an embedded browser view — hardest of all against Family Link supervised accounts, which is a large share of the student population this app serves. The desktop app never shows Google’s sign-in page in the Electron window. Instead it uses a PKCE-based redirect flow through the system browser:App generates a PKCE challenge
startGoogleSignIn() invents a verifier, keeps it in memory, and opens https://intelliplan.tech/login/google?desktop=<challenge> in the system browser.Browser completes Google's OAuth flow
The user signs in as normal through their real browser. The callback server sees the stored challenge, mints a one-time code, and redirects to
intelliplan://auth?code=….The one-time code travels in a deep-link URL that any local program could intercept. It is only half a credential — redeeming it also requires the PKCE verifier, which never leaves the Electron process. Codes are single-use, expire in two minutes, and are stored only as SHA-256. Rules live in
desktop_auth.py, tested in tests/test_desktop_auth.py.Security Model
The renderer process is fully sandboxed:contextIsolation: true, nodeIntegration: false, sandbox: true. Page scripts reach the main process only through the three functions exposed in src/preload.js.
Key security decisions
Key security decisions
No generic IPC channel. A bridge that forwards arbitrary channel names from page script is the standard path to remote code execution in Electron apps. The
notify() bridge accepts a title, a body, and a same-app path — a full URL is rejected outright, so page script cannot ask the main process to navigate the window to an external destination.Navigation is pinned to the app’s origin. Any link to a different origin opens in the system browser. This keeps stray links out of the application shell and is also required for Google sign-in, which refuses to run in an embedded view.Permission allowlist. Notifications, media (for the focus check-in), fullscreen, and sanitised clipboard writes are allowed. Everything else is denied without prompting.Known Limitations and Roadmap
Auto-update (not yet enabled)
Auto-update (not yet enabled)
electron-updater is already listed as a dependency in desktop/package.json and fits the existing electron-builder config. What it still needs is a release feed to publish to.Code signing (not yet configured)
Code signing (not yet configured)
The CI workflow reads signing credentials from repository secrets and signs automatically when they are set. Nothing in the code needs to change — the only missing piece is the certificate. See the Code Signing section above for the exact secrets required per platform.
ARM64 Windows installer limitation
ARM64 Windows installer limitation
electron-builder 26.15.3 produces an ARM64 NSIS installer that reports success but writes no executable. The ARM64 build ships as a .zip instead. The x64 installer works correctly on ARM64 hardware (Snapdragon X1E80100 verified) under Windows’ x64 translation layer, at some cost in performance. Restore arm64 to build.win.target[0].arch when upstream fixes the issue.Icon sharpness
Icon sharpness
Icons are currently the 512 px PWA icon. Platform-native
.icns (macOS) and .ico (Windows) sets would render more crisply at small sizes, particularly in the taskbar and Start Menu.Platform Build Matrix
| Platform | Installer Format | Architectures | Notes |
|---|---|---|---|
| Windows | NSIS installer (.exe) | x64 | Verified working on ARM64 hardware via translation |
| Windows | Zip (.zip) | arm64 | No shortcuts; no auto-update; native binary |
| macOS | DMG (.dmg) + Zip | x64, arm64 | Hardened runtime; notarisation ready |
| Linux | AppImage (.AppImage) | x64, arm64 | Self-contained, no install required |
| Linux | Debian package (.deb) | x64, arm64 | Installs via dpkg -i |
| Linux | RPM package (.rpm) | x64 | For Fedora / RHEL-based distributions |