Tauri 2 + React + TypeScript desktop app for sharing coffee profiles over any local network. The WiFi is the DNS — every device with ESPresso open hosts a pot, and pots on the same network find each other automatically via mDNS.
There is no hub device (the ESP32 is optional). Every app instance:
- Hosts a pot server — a WebSocket server on port 8080 (8081–8086 if
busy), advertised as
_espresso._tcp.local.over mDNS with a unique hostname likeespresso-<id>.local. - Discovers peers — every 15s it browses mDNS for other pots on the current WiFi and joins each one (a mesh).
- Exchanges profiles — on connect, pots greet with
hello+ a full store snapshot. Profile updates are broadcast to the whole mesh and persisted to local SQLite (profiles.db).
Profiles converge across the network: you see everyone's profile, can add them as contacts, and your history keeps everything you've ever seen.
src-tauri/src/
├── lib.rs # Tauri commands, events, backend setup
├── models.rs # serde data models (Profile, Contact, Device, HostInfo)
├── db.rs # SQLite (rusqlite) with PRAGMA user_version migrations
├── mdns.rs # mDNS discovery + advertising (mdns-sd)
├── server.rs # PotServer: WS pot server, store, broadcast, hello+snapshot
└── ws.rs # PotHub: hosts the server, joins peers, source-tagged store
src/
├── App.tsx # thin React shell consuming commands/events
├── lib/espresso.ts # typed invoke() + event wrappers
└── screens/ # presentational screens
- Database —
rusqlite(bundled SQLite) at the app data dir. The old plugin-sql schema is detected and backed up toprofiles.db.bak-<ts>before installing the clean schema. - Profile store — every profile entry is tagged with its source (local / incoming client / outgoing peer), so when a peer's connection drops, only the profiles it contributed are removed. Full-store syncs use replace-by-source semantics, which makes the mesh converge — including removals.
- Events — the backend emits
connection://status,profiles://updated(live mesh),contacts://updated,devices://updatedanddiscovery://done.
- Server → client on connect:
{ "type": "hello", "device_id": "…" }then{ "type": "profiles", "data": [ { "device_id", "name", "role", "bio" } ] }(full store snapshot). - Broadcasts:
{ "type": "profiles", "data": [...] }whenever the store changes. - Client → server: either a single profile
{ "device_id", "name", "role", "bio" }(also compatible with an ESP32-style pot) or a full-storeprofilesmessage for mesh sync.
npm install
npm run tauri devOpen ESPresso on two devices on the same WiFi to see profiles sync. On a single machine you can also run two instances to test the mesh.