Building Offline-First Desktop Agents: The TimePerch Architecture
When we set out to build TimePerch, a workforce analytics platform, we faced a fundamental challenge: how do you build software that works reliably when the network doesn't?
This is the story of how we architected a 5-layer polyglot system that handles network instability without data loss.
The Problem
Traditional employee monitoring tools assume a stable internet connection. But reality is messier:
Any of these scenarios can cause data loss with a naive "always-online" architecture. We needed something better.
The Solution: Local-First Architecture
We adopted a Local-First design philosophy: all data is written to local storage first, then synchronized to the cloud when connectivity is available.
Layer 1: Desktop Agent (Rust + Tauri)
The client is built with Rust and Tauri for maximum performance with minimum resource usage:
Every event (clock-in, activity log, screenshot) is committed to SQLite immediately. The user sees instant feedback regardless of network state.
Layer 2: Sync Engine (Go)
A dedicated Go service handles synchronization between local SQLite and the cloud:
The sync engine runs as a background process, completely decoupled from the UI. Users can work offline for days; when connectivity returns, everything syncs automatically.
Layer 3: Reporting Core (FastAPI + Celery + Pandas)
Heavy data processing happens asynchronously on the server:
This separation means the desktop agent stays lightweight—all the heavy lifting happens server-side.
Layer 4: Dashboard (SvelteKit)
The admin dashboard provides real-time visibility:
Layer 5: Infrastructure (Supabase)
We chose Supabase for centralized services:
Key Lessons
1. Embrace Eventual Consistency
Not everything needs to be real-time. For most analytics use cases, data that's a few seconds (or minutes) old is perfectly acceptable.
2. Design for Failure
Every network call will fail eventually. Build retry logic from day one, not as an afterthought.
3. Keep the Client Dumb
The desktop agent's job is to collect data and store it locally. All business logic lives on the server where it's easier to update.
4. Use the Right Tool for Each Layer
We didn't try to build everything in one language:
Results
The TimePerch architecture handles:
This architecture pattern is applicable to any desktop application that needs to work offline. If you're building something similar, let's talk.