Micro Queue Butler
The Inspiration
Every day, we're surrounded by small waits such as laundry cycles, cooking timers, oven countdowns, microwave beeps. I found myself as a parent and partner managing my own home mentally juggling multiple timers, sometimes forgetting about them entirely especially laundry π. The cognitive load of tracking these "micro waits" was surprisingly draining.
I wanted to build something that would remember for me. Not just a simple timer app, but an intelligent assistant that learns my patterns. If I always wash my darks for 45 minutes, why should I have to set that timer every time?
The vision was simple: "Your phone knows what you're waiting for, so you don't have to."
What I Learned
Full-Stack Dart Development
Building both the frontend and backend in Dart was a revelation. Using Serverpod for the backend meant I could share types, leverage the same language paradigms, and maintain a cohesive mental model across the entire stack. The auto-generated API client eliminated the tedium of writing HTTP boilerplate.
Real-Time Communication Patterns
I dove deep into streaming architectures. The app doesn't just poll for updates, it maintains a persistent connection using Serverpod's message channels or streaming methods. When a timer completes on the server, clients receive the event instantly via pub/sub:
Channel: queue-completed-{userId}
The Mathematics of Smart Estimates
The "Smart Estimate" feature uses historical data to predict durations. The algorithm is elegantly simple. As users complete more tasks, the estimate converges toward their true preference.
Clean Architecture Principles
I implemented proper separation of concerns:
| Layer | Responsibility |
|---|---|
| Presentation | UI, animations, user input |
| Domain | Business logic, services |
| Data | Repositories, API clients, data sources |
This made the codebase testable and maintainable.
How I Built It
The Tech Stack
- Frontend: Flutter 3.32+ with Provider for state management
- Backend: Serverpod 3.2.3 (Dart-based backend framework)
- Database: PostgreSQL 16 with pgvector extension
- Cache: Redis for real-time capabilities
- Infrastructure: Docker Compose for local development
The Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Flutter App β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Screens β Repositories β Data Sources β Serverpod Clientβ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Serverpod Server β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Endpoints β Services β Database Operations β
β β β
β FutureCall System (scheduled tasks) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key Implementation Details
FutureCalls for Timer Completion: When a user creates a queue event, the server schedules a FutureCall to fire after the specified duration. This allows timer completion to happen server-side, even if the app is closed.
Real-Time Streaming: The app subscribes to a completion event stream:
client.queueEvent.streamCompletedEvents(userId)
Gamification Elements: I added streaks and statistics to encourage consistent usage; tracking consecutive days with completed tasks, weekly totals, and average wait times.
Challenges I Faced
1. Notification Reliability
Getting notifications to fire reliably when the app is in the background was tricky. I had to carefully orchestrate the server-side FutureCall system with client-side local notifications. The solution involved broadcasting completion events through Serverpod's message channels, which the Flutter app listens to and converts into local push notifications.
2. State Synchronization
Keeping the UI in sync with real-time server events required careful management of StreamSubscription lifecycles and proper disposal to prevent memory leaks. Pull-to-refresh also needed to coexist gracefully with streaming updates.
3. Smart Estimate Edge Cases
The averaging algorithm needed to handle:
- Case-insensitive title matching
- New tasks with no history (fallback to manual input)
- Outliers that could skew the average
4. Animation Choreography
I wanted active timers to have a visual "pulse" (a blinking animation indicating they're counting down). Coordinating AnimationController instances with countdown timers and ensuring smooth UI updates every second took iteration to get right.
The Result
Micro Queue Butler is a functional, full-stack Dart application that demonstrates:
- End-to-end type safety across client and server
- Real-time streaming for instant updates
- Background task scheduling with FutureCalls
- Pattern-based intelligence that learns from user behavior
- Clean architecture that scales
It solves a real problem I face daily and now using it for a couple of days my laundry never sits forgotten in the washer.
Built with Flutter & Serverpod for the Serverpod Hackathon
Built With
- dart
- flutter
- postgresql
- serverpod