Diti
Cross-platform, 100% local-first daily planning and multi-phase routine timer built with Flutter
Problem
Most productivity timers assume rigid, linear schedules and fail when real-world interruptions occur. Furthermore, popular tools frequently trap personal habit data in remote proprietary clouds, rely on intrusive telemetry, and lose active session state if the application is killed, closed, or the machine reboots.
Goals
- Develop a distraction-free, cross-platform productivity tool for Android and Linux Desktop with zero telemetry or cloud dependency
- Implement a crash-proof timer state engine capable of accurately reconstructing elapsed time across pauses, backgrounding, task termination, and system restarts
- Enable multi-phase routine workflows with negative overtime tracking to maintain realistic accountability without jarring alarms
- Establish a modular monorepo architecture with automated CI/CD, OWASP MASVS v2 security verification, and single-command Linux/Android distribution
Approach
Modular Monorepo Architecture
Crash-Proof Pure Dart State Engine
Local-First Drift Persistence
Multi-Platform Packaging & Distribution
Security & Testing Automation
Decisions
Pure Dart for timer_engine
Why: Decoupling the core timer state machine entirely from Flutter allows exhaustive unit testing without widget harnesses and ensures deterministic state transitions.
Tradeoff: Requires bridging platform lifecycles and background hooks explicitly via adapters.
Drift SQLite over Key-Value Stores
Why: Relational querying and schema migrations in Drift provide structured historical analytics, complex session aggregation, and compile-time type safety.
Tradeoff: Higher initial boilerplate than simple key-value databases like Hive or SharedPreferences.
Negative Overtime Tracking vs. Hard Alarms
Why: Counting into negative time when a rest interval expires encourages honest pacing without jarring anxiety, treating the user as an adult managing their own workflow.
Tradeoff: Requires state machine and UI logic to handle bidirectional time calculations.
Non-Root Linux Shell Installer
Why: Provides a curl | bash installer script configuring ~/.local/bin/diti, standard XDG desktop launcher entries, and self-updating capability without requiring sudo.
Tradeoff: Must handle various Linux environment path configurations and GTK dependencies.
Challenges
State Drift and Timer Survival Across Task Kills
Rather than relying on continuous active ticker loops, the engine snapshots reference timestamps (start, pause, and planned durations) into local storage, reconstructing the precise state and negative overtime upon reactivation.
Cross-Platform Notification & Backgrounding Differences
Unified Android foreground service notifications with Linux libnotify desktop daemons through a common notification adapter interface in diti_notifications.
Rigorous Mobile Security & Release Hardening
Automated MobSF static analysis, ProGuard/R8 obfuscation verification, and OWASP MASVS v2 alignment in GitHub Actions to secure release artifacts against vulnerabilities.
Outcomes
v1.0.0+ Shipped
Release Status
Production binaries deployed for Android (APK, AAB) and Linux Desktop (AppImage, native installer)
100% Local-First
Data Privacy
Zero network telemetry, zero third-party trackers, zero user accounts; database stored locally on device
Full CI/CD & MASVS v2
Test & Security Coverage
Unit, widget, golden, Patrol E2E, Linux integration, and automated vulnerability scanning on every PR
Learnings
The Architecture Angle (Pure Domain Engines)
Keeping core domain mechanics (like the timer state machine) in pure Dart with zero Flutter dependencies makes business logic trivially testable, completely portable, and immune to UI-layer churn.
The Local-First Paradigm (Drift & Offline Persistence)
Local-first architecture requires thinking differently about data lifecycles. Designing robust schema migrations and timestamp-based state recovery from day one proved essential for building software users can trust with their daily routines.
The Production Discipline (Automated Distribution & Security)
Setting up automated multi-platform release builds, Linux desktop packaging, and OWASP MASVS security scanning turned what could have been a painful release process into a single-tag, fully automated pipeline.