Project
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
- Expo (React Native)
- TypeScript
- Expo Router
- SQLite + Drizzle
- Fastify API
- Postgres
- JWT
- Detox
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 and 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
- 1Start backend DB: docker compose up -d
- 2Run backend migrate/seed; start backend on :4000
- 3Start mobile: cd apps/mobile && npm start
- 4Sign in (demo user) → complete onboarding → toggle habits + set mood
- 5Go offline and toggle → reconnect → verify sync
- 6Open Insights → share a streak card → open deep link from share text