AMT
Back to Projects

Diti

Cross-platform, 100% local-first daily planning and multi-phase routine timer built with Flutter

Oct 2026 - PresentLead Developer & Maintainer
FlutterDartDriftSQLiteRiverpodLinux DesktopAndroidGitHub ActionsPatrolOWASP MASVS

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

Decoupled the codebase into specialized packages under packages/ (timer_engine, diti_database, diti_notifications, diti_tracker) to isolate domain rules from platform APIs and UI components.

Crash-Proof Pure Dart State Engine

Engineered timer_engine as a pure Dart library without Flutter dependencies, maintaining timestamp-based state snapshots to compute exact elapsed and negative overtime intervals resilient against app lifecycle interruptions.

Local-First Drift Persistence

Implemented diti_database using Drift SQLite with compile-time query verification and non-destructive schema migrations, persisting routines and history locally to ~/Documents/diti.db on Linux.

Multi-Platform Packaging & Distribution

Created automated GitHub Actions release pipelines producing Android Universal & ARM64 APKs, Play Store App Bundles (AAB), Linux AppImages, tarball binaries, and a curl-based Linux installer script.

Security & Testing Automation

Enforced end-to-end quality gates via Patrol mobile tests, Linux desktop integration suites, MobSF APK security analysis, secret scanning (Gitleaks), and OWASP MASVS v2 compliance audits.

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.