
TaskForge (Project Management SaaS)
Full-stack project management platform with realtime collaboration, background job processing, and a native desktop client.
Problem
Small teams kept outgrowing their task boards: the moment two people edited the same sprint, someone's changes vanished, and "refresh to see what's new" became the de-facto sync protocol. TaskForge set out to make team task management feel live — every board open in every browser (and the desktop app) reflects a change within a second of it happening, including changes made by background jobs like recurring-task rollovers.
That realtime requirement drove everything else: state had to live server-side with a single source of truth, updates had to fan out cheaply, and slow work (emails, digests, scheduled rollovers) had to happen off the request path so the UI never waits on it.
Architecture
The Next.js frontend and the Tauri desktop shell are the same client core speaking to a Django REST Framework API. PostgreSQL holds the canonical state; Redis sits beside it doing double duty as cache and message broker; Celery workers consume the queue for everything that shouldn't block a request. Realtime updates fan out over websockets backed by Redis pub/sub, so an edit made in one client lands in every other open board without polling.
Tech decisions & trade-offs
Why Celery over cron
Recurring-task rollovers look like a cron job at first — until you need retries, visibility, and on-demand execution. Cron gives you a time trigger and nothing else: a failed run is silent, a backlog is invisible, and "run this rollover now because an admin clicked a button" means duplicating the script path. Celery puts scheduled work and request-triggered work on the same queue with the same retry policy, the same monitoring, and the same workers. Celery beat covers the schedule; everything else comes free. The trade-off is operational surface — one more long-running process to deploy — which is real but paid once.
Why Redis for both cache and queue
Running one Redis instance as both cache and Celery broker is a deliberate simplification. The workloads are friendly to each other: cache reads are hot but tolerate eviction, queue entries are small and short-lived. Using one store means one connection pool, one thing to monitor, and one mental model — and Redis pub/sub falls out of the same box to power the websocket fan-out. The honest trade-off: at much larger scale you'd split them so a cache stampede can't add latency to job dispatch. For a small team's workload, the simplicity wins decisively.
Why Tauri over Electron
The desktop client exists for system-tray presence, native notifications, and an always-running shell — not for bundling a second browser. Tauri renders through the OS webview instead of shipping Chromium, which is the whole story in one number: the TaskForge installer is ~8 MB with Tauri versus ~120 MB for the Electron equivalent, with idle memory usage to match. The cost is webview variance — WebKit on macOS, WebView2 on Windows — so a handful of CSS features needed fallbacks that Electron's pinned Chromium would have papered over. For an app that's a companion shell around a web core, that's a cheap price for a 15× smaller download.