← Back to Projects

Pulse (Mobile Habit + Mood Tracker)

Offline-first mobile app with SQLite outbox sync, OAuth, push reminders, deep links, and share cards

Role
Solo
Focus
Offline-first sync, Outbox pattern, OAuth + account linking
Testing
Detox E2E (iOS), Sync idempotency tests, Deep link validation
Key Patterns
Mobile, Expo, Offline-first, SQLite
MobileExpoOffline-firstSQLiteSyncOAuthPushDetox

What it does

  • Tracks daily habits and mood check-ins with streaks and weekly insights
  • Works offline: updates local DB instantly and syncs when online
  • Supports onboarding, reminders (push), and deep links into specific habits/dates
  • Generates a shareable streak card image using native share sheet
  • Includes account linking for real-world auth UX

Architecture

┌────────────────────────┐      ┌────────────────────────┐
│  Expo Mobile App       │─────►│  Fastify API           │
│  (Today/Habits)        │      │  JWT + OAuth exchange  │
└───────────┬────────────┘      └───────────┬────────────┘
            │                               │
            │ SQLite (local)                │ Postgres
            ▼                               ▼
┌───────────────────────┐      ┌──────────────────────────┐
│  SQLite + Drizzle     │      │  Postgres                │
│  habits/mood/outbox   │      │  users/habits/checkins   │
└───────────┬───────────┘      └────────────┬─────────────┘
            │ outbox sync                   │
            ▼                               ▼
┌───────────────────────┐      ┌──────────────────────────┐
│  Sync Engine          │      │  Expo Push Service       │
│  (idempotent ops)     │      │  tokens + reminders      │
└───────────────────────┘      └──────────────────────────┘

Reliability & Guardrails

  • Local-first writes ensure UX is responsive and resilient to network outages
  • Outbox + idempotent op IDs prevent double-apply and enable safe retries
  • Permissions requested only when user opts in (push reminders onboarding step)
  • Deep links are validated defensively (invalid params fall back to safe routes)
  • Detox smoke test keeps core flow from regressing (first-run → today interaction)

How to demo in 2 minutes

  1. Start backend DB: docker compose up -d
  2. Run backend migrate/seed; start backend on :4000
  3. Start mobile: cd apps/mobile && npm start
  4. Sign in (demo user) → complete onboarding → toggle habits + set mood
  5. Go offline and toggle → reconnect → verify sync
  6. Open Insights → share a streak card → open deep link from share text

Links