# Electron desktop shell — handoff

## Summary

The desktop app wraps the Cinny/Paarrot web UI in Electron: custom title bar, system tray, deep links (`paarrot://`), auto-updates, plugin filesystem access, screen capture for calls, and the local HTTP API server.

## User-facing behavior

- Frameless/custom **title bar** with window controls (Windows/Linux)
- Minimize to **tray**; close may minimize instead of quit (platform config)
- `paarrot://` URL protocol for room links
- Auto-update checks (electron-updater)
- Plugins read/write under `%APPDATA%\paarrot\`

## Architecture

```
electron/main.js (main process)
  → BrowserWindow → Vite dev server or built cinny dist
  → IPC: plugins, screen capture, clipboard, updates
  → PaarrotAPIServer
  → Tray + protocol handler paarrot://
preload / contextBridge → window.electron in renderer
```

## Key files

| Path | Role |
|------|------|
| `electron/main.js` | Main process entry |
| `electron/api-server.js` | Local HTTP API |
| `electron/preload.js` (if exists) | IPC bridge |
| `electron-builder.json5` | Packaging config |
| `package.json` (root) | `npm run dev`, build scripts |
| `dev-app-update.yml` | Update channel config |
| `cinny/src/app/components/title-bar/TitleBar.tsx` | Custom title bar UI |
| `build-resources/` | Linux after-install, icons |

## Data model

| Store | Tool | Contents |
|-------|------|----------|
| `electron-store` | main.js | Window bounds, user prefs |
| UserData | Electron | plugins, caches |

Protocol: `PROTOCOL_SCHEME = 'paarrot'` in main.js

## Dependencies

- `electron`, `electron-updater`, `electron-store`
- `electron-builder` for CI releases
- Vite dev server port **38347**; static server **44548** in dev

## Integration points

- **local-api**: started with main window
- **Plugins**: filesystem paths under `paarrot` app name
- **Voice calls**: `desktopCapturer` for screen share
- **Deep links**: pending deep link queue until client ready

## Testing

### Manual

1. `npm run dev` — window loads, title bar draggable.
2. Register `paarrot://` link; opens correct room.
3. Tray icon present; restore from tray.
4. Build installer; auto-update check (staging).
5. Install plugin to AppData path; loader finds it.

### Automated

- CI: `.gitea/workflows/build.yml`

## Known issues & gotchas

- `isDev` detection: `NODE_ENV` or `!app.isPackaged`
- Protocol registration differs Windows vs Linux (`after-install.sh`)
- Single instance lock for deep links — see `pendingDeepLink` in main.js
- Title bar hit-testing CSS sensitive on Windows 11

## Future work

- macOS menu bar parity
- Code signing documentation for Windows
- Consolidate magic ports into shared config

## Related docs

- [local-api HANDOFF](../local-api/HANDOFF.md)
- Root [README.md](../../../../README.md) — build instructions

## Add your extra things here

- Dev URLs: `VITE_DEV_SERVER = http://localhost:38347`, `PORT = 44548`
- App userData folder name: `paarrot` (matches plugin paths in README)
