Skip to content

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

87 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HabitFlow

Build better habits, one day at a time.

HabitFlow is a personal habit tracking and journaling web application designed to help people build consistent routines, track progress over time, and reflect on their growth. Live at tryhabitflow.com.


Features

Core

  • Habit tracking with daily completion, streaks, and progress visualization
  • Customizable habits with frequency, time slots, weekly goals, and color coding
  • Push notifications via Firebase Cloud Messaging for habit reminders
  • Pomodoro timer for focused work sessions linked to habits
  • Journal for daily reflections and notes
  • Milestones that celebrate streak achievements automatically

Visualization & Insights

  • Dashboard with state-aware "up next" card, today's habits, and weekly heatmap
  • Calendar view with monthly heatmap, day-detail panel, and statistics
  • Analytics page with completion charts, streak summaries, and habit comparisons
  • Timeline of habit history and milestone unlocks

Account & Privacy

  • Secure authentication via Clerk (email + Google OAuth)
  • Data export — download all your data as JSON anytime
  • Account deletion — full data removal across Convex and Clerk
  • Privacy Policy and Terms of Service built into the app
  • Production-ready monitoring via Sentry for error tracking

Tech stack

Layer Technology
Frontend Next.js 16 (App Router), React 19, TypeScript
Styling Tailwind CSS, shadcn/ui components
Backend Convex (database + serverless functions + real-time sync)
Auth Clerk (with custom JWT integration to Convex)
Notifications Firebase Cloud Messaging
Monitoring Sentry (error tracking + session replay)
Hosting Vercel (frontend), Convex Cloud (backend)
Domain & DNS Cloudflare
Testing Playwright (e2e), 33+ tests covering auth, habits, calendar, journal, pomodoro

Architecture

┌─────────────────────┐
│   Next.js Client    │  React UI, server components, MDX legal pages
│   (Vercel)          │
└──────────┬──────────┘
           │ WebSocket (real-time)
           ▼
┌─────────────────────┐
│   Convex Backend    │  Serverless functions, document DB, real-time sync
│   (Convex Cloud)    │
└──────────┬──────────┘
           │ JWT validation
           ▼
┌─────────────────────┐
│   Clerk Auth        │  User management, JWT issuance, OAuth providers
└─────────────────────┘

┌─────────────────────┐
│   Firebase FCM      │  Push notifications (called from Convex cron)
└─────────────────────┘

┌─────────────────────┐
│   Sentry            │  Error tracking + session replay
└─────────────────────┘

Data flow example: marking a habit complete

  1. User clicks the completion button in the UI
  2. React component calls a Convex mutation via WebSocket
  3. Convex validates the user's Clerk JWT
  4. Mutation writes a row to habitCompletions and updates streak in userMilestones
  5. Convex pushes the update to all connected clients in real-time
  6. UI updates instantly without a full page reload

Database schema

Convex tables (defined in convex/schema.ts):

  • users — Clerk user mapping with profile data
  • habits — habit definitions (title, frequency, color, time slots)
  • habitCompletions — completion records per habit per date
  • userMilestones — streak achievements and best streaks
  • dailyCheckIns — daily reflection prompts
  • pomodoroSessions — pomodoro timer records linked to habits
  • journalEntries — daily journal text
  • pushTokens — FCM device tokens
  • reminderLog — audit log for push notifications (idempotency)

All tables are scoped per-user via indexes (by_user, by_user_date, etc.) — data isolation is enforced at the query layer, not just in application logic.


Local development

Prerequisites

  • Node.js 20+
  • npm or pnpm
  • A Clerk account (free tier)
  • A Convex account (free tier)
  • A Firebase project (for push notifications, optional for basic dev)

Setup

# Clone and install
git clone https://github.com/<your-username>/habit-tracker.git
cd habit-tracker
npm install

# Set up Convex (creates dev deployment)
npx convex dev

# Set up environment variables
cp .env.local.example .env.local
# Fill in your Clerk and Convex keys

# Run the dev server
npm run dev

Open http://localhost:3000.

Required environment variables

# Convex
NEXT_PUBLIC_CONVEX_URL=

# Clerk
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=

# Sentry (optional in dev)
NEXT_PUBLIC_SENTRY_DSN=

Server-side env vars (set via npx convex env set):

CLERK_JWT_ISSUER_DOMAIN=    # Clerk Frontend API URL
FIREBASE_PROJECT_ID=
FIREBASE_CLIENT_EMAIL=
FIREBASE_PRIVATE_KEY=

Testing

Playwright e2e suite covers auth flows, habit lifecycle, calendar, journal, pomodoro, and account management.

# Run all e2e tests
npm run test:e2e

# Run a specific spec
npx playwright test e2e/habit-lifecycle.spec.ts

# Open the Playwright UI
npx playwright test --ui

Tests use a dedicated Clerk test user and real Convex dev deployment. Test data is auto-cleaned between runs via a dev-only cleanup endpoint.


Deployment

Production stack

  • Frontend auto-deploys to Vercel from the main branch
  • Backend deploys via npx convex deploy (one-time push to production Convex)
  • Custom domain routed through Cloudflare DNS to Vercel

Deploy command

# Deploy Convex production functions
npx convex deploy

# Vercel auto-deploys on `main` push
git push origin main

Project structure

habit-tracker/
├── app/                          # Next.js App Router
│   ├── (auth)/                   # Sign-in/sign-up pages
│   ├── (dashboard)/              # Authenticated app pages
│   ├── legal/                    # Public privacy/terms pages
│   └── api/                      # Server routes (FCM, dev cleanup)
├── components/                   # React components
│   ├── dashboard/                # Dashboard UI (up-next, today's habits)
│   ├── calendar/                 # Calendar grid, day panel, stats
│   ├── habits/                   # Habit forms, list, completion UI
│   ├── legal/                    # Legal page renderer (MDX)
│   ├── layout/                   # App shell, footer, nav
│   └── ui/                       # shadcn/ui primitives
├── convex/                       # Convex backend
│   ├── schema.ts                 # Database schema
│   ├── habits.ts                 # Habit mutations and queries
│   ├── notifications.ts          # FCM cron logic
│   ├── deleteAccount.ts          # Account deletion flow
│   ├── export.ts                 # Data export HTTP action
│   └── auth.config.ts            # Clerk JWT configuration
├── content/legal/                # Privacy/terms MDX content
├── e2e/                          # Playwright tests
├── lib/                          # Shared utilities
└── public/                       # Static assets

PWA Support

HabitFlow is a Progressive Web App. Users can install it to their home screen for a native-like experience.

Android (Chrome):

  1. Open tryhabitflow.com in Chrome
  2. Tap the install banner, or Menu → Install app

iOS (Safari):

  1. Open tryhabitflow.com in Safari
  2. Tap Share → Add to Home Screen

Features:

  • Offline support — cached pages load without internet via service worker (public/sw.js)
  • Home screen icon (generate real icons with npx pwa-asset-generator public/logo.svg public/icons)
  • Fullscreen standalone mode (no browser chrome)
  • iOS splash screens — placeholder paths in <head>; generate images with npx pwa-asset-generator or appsco.pe/developer/splash-screens

Lighthouse PWA checklist:

  • Web app manifest (public/manifest.json)
  • Service worker with offline fallback (public/sw.js)
  • theme-color meta tag
  • apple-mobile-web-app-capable meta tag
  • Real 192×192 and 512×512 PNG icons (placeholders in public/icons/)
  • Real iOS splash screen images (placeholders in public/splash/)

Roadmap

  • AI habit coach with personalized insights based on user data
  • Stripe billing for Pro tier (unlimited habits, AI features)
  • Capacitor wrapper for App Store and Play Store presence

License

This project is currently private. Licensing terms TBD.


Contact

Built by Arun Kumar Kulkarni — arunkulkarni2000@gmail.com

For questions about HabitFlow as a product, see the Privacy Policy and Terms of Service.

This is a Next.js project bootstrapped with create-next-app.

Getting Started

First, run the development server:

npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev

Open http://localhost:3000 with your browser to see the result.

You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.

This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.

Learn More

To learn more about Next.js, take a look at the following resources:

You can check out the Next.js GitHub repository - your feedback and contributions are welcome!

End-to-End Tests (Playwright)

CI not yet configured — run npm run test:e2e locally before pushing changes that touch core flows (auth, habit CRUD, navigation, pomodoro, journal).

Prerequisites

  1. Clerk test instance — create a dedicated test user in your Clerk test environment (never the production instance).
  2. Environment variables — copy .env.local and add:
# Clerk test instance keys (use sk_test_… / pk_test_…)
CLERK_SECRET_KEY=sk_test_...
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...

# Dedicated e2e test user (must exist in your Clerk test instance)
# No password needed — Clerk Backend API creates a sign-in token from the email alone
E2E_CLERK_USER_EMAIL=testuser@gmail.com

# Convex dev deployment URL
NEXT_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud

Running tests locally

# Run the full suite (headless, reuses existing dev server if running)
npm run test:e2e

# Interactive UI mode — great for debugging, step-through, timeline view
npm run test:e2e:ui

# Headed mode — watch Chromium execute the tests
npm run test:e2e:headed

What's tested

File Hyperedge protected Critical god nodes
e2e/auth.spec.ts Authentication flow DashboardPage, Clerk
e2e/habit-lifecycle.spec.ts Habit CRUD Flow + Optimistic completion loop HabitCard, useHabits, useOptimisticCompletion
e2e/navigation.spec.ts Dashboard data layer, Global provider stack DashboardPage, useHabits
e2e/pomodoro.spec.ts Pomodoro UI system usePomodoro
e2e/journal.spec.ts Journal Entry module upsertEntry, listEntries
e2e/admin-reminders.spec.ts FCM cron hardening (idempotency, error isolation) reminderLog, devTriggerReminders

Debugging a failing test

# View the HTML report after a run (opens in browser)
npx playwright show-report

# Re-run a single file with trace recording enabled
npx playwright test e2e/habit-lifecycle.spec.ts --trace on

# Open a trace zip (shows screenshots + network + DOM snapshots)
npx playwright show-trace test-results/<test-name>/trace.zip

Test data isolation

Tests that create habits prefix their names with E2E_. After each test, cleanupTestHabits() calls /api/dev/cleanup-test-data which runs the deleteTestHabits Convex mutation (hard-blocked in production) to bulk-delete all E2E_ prefixed habits in under 100ms.

Adding CI later

Set the env vars above as CI secrets and add a workflow step:

- run: npm run test:e2e
  env:
    PLAYWRIGHT_BASE_URL: http://localhost:3000
    CI: true
    # ... all vars listed in playwright.config.ts header

Account deletion and data export

Accessible from Settings → Danger Zone (/settings).

What gets exported

A single JSON file (habitflow-export-YYYY-MM-DD.json) with schema version 1:

{
  "_exportVersion": 1,
  "_exportedAt": "<ISO timestamp>",
  "_userId": "<Clerk user ID>",
  "data": {
    "user": { ... },
    "habits": [ ... ],
    "habitCompletions": [ ... ],
    "userMilestones": [ ... ],
    "dailyCheckIns": [ ... ],
    "pomodoroSessions": [ ... ],
    "pushTokens": [ ... ],
    "journalEntries": [ ... ],
    "reminderLog": [ ... ]
  }
}

The export is generated on demand by the Convex HTTP action GET /export-user-data (registered in convex/http.ts). No file is stored — the response streams directly to the browser.

What gets deleted

Account deletion is permanent and immediate. There is no recovery window. The following are hard-deleted in this order:

  1. reminderLog rows
  2. pushTokens rows
  3. pomodoroSessions rows
  4. dailyCheckIns rows
  5. journalEntries rows
  6. userMilestones rows
  7. habitCompletions rows
  8. habits rows
  9. Convex _storage blob (profile image, if one was uploaded)
  10. users row
  11. Clerk user record (via Clerk Admin API)

If the Clerk user deletion fails (network error, API outage), the Convex data is already gone. The error is logged to Sentry but not surfaced to the user. Their next sign-in attempt would create a fresh Convex user row.

Convex environment variable required

Account deletion calls the Clerk Admin REST API. Set CLERK_SECRET_KEY in Convex's environment (separate from .env.local):

npx convex env set CLERK_SECRET_KEY sk_test_...

For developers: testing deletion locally

The destructive deletion test is skipped by default. To run it manually with an ephemeral Clerk test user:

RUN_DESTRUCTIVE_TESTS=1 npm run test:e2e -- e2e/account-deletion-destructive.spec.ts

See e2e/account-deletion-destructive.spec.ts for full prerequisites and setup.

FCM Cron Testing

The habit reminder cron (sendHabitReminders, fires every minute) is hardened with idempotency, error isolation, and a dev-only manual trigger.

Manual trigger — /admin/reminders page

Navigate to http://localhost:3000/admin/reminders in development. Two independent guards protect this page:

  • Next.js page returns 404 when NODE_ENV === "production" — the page never renders in a production build.
  • Convex actions (devTriggerReminders, triggerRemindersNow) throw unless ALLOW_DEV_TRIGGERS === "true" is set in the Convex deployment's env vars. Convex always runs with NODE_ENV=production internally, so the Next.js env is not a reliable gate at the Convex layer — this explicit flag is.

Three buttons are available:

Button What it does
Dry Run Walks through the scan logic and logs what would be sent, but makes no FCM calls and writes no reminderLog entries.
Mock Send Skips FCM entirely and treats every send as successful. Does write reminderLog entries — use this to test idempotency without real Firebase credentials.
Real Send Calls FCM for real. Requires FIREBASE_PROJECT_ID, FIREBASE_CLIENT_EMAIL, and FIREBASE_PRIVATE_KEY to be set in Convex env vars (see below).

The bottom of the page shows the last 20 reminderLog entries so you can confirm what fired and what was skipped.

Verifying idempotency

  1. Click Mock Send once — entries appear in the log table.
  2. Click Mock Send again immediately — the row count must not increase. The idempotency check (wasReminderSent) finds the existing sent/stale_token row in reminderLog and skips the re-send.

Setting Convex env vars

All of these must be set in Convex (not .env.local) because Convex actions run in an isolated runtime that only sees Convex env vars.

Enable the manual trigger in dev:

npx convex env set ALLOW_DEV_TRIGGERS true

Do not set ALLOW_DEV_TRIGGERS in your production Convex deployment. Even if the flag were accidentally set, the Next.js page additionally hides itself when NODE_ENV=production, so the UI would never expose the buttons.

Firebase credentials (required for Real Send and the production cron):

npx convex env set FIREBASE_PROJECT_ID  your-project-id
npx convex env set FIREBASE_CLIENT_EMAIL service-account@your-project.iam.gserviceaccount.com
npx convex env set FIREBASE_PRIVATE_KEY  "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"

The private key must use literal \n escape sequences (not actual newlines) when stored via npx convex env set. The cron unescapes them at runtime.

reminderLog table

Field Purpose
habitId + date + timeSlot + pushTokenId Idempotency key (index: by_habit_date_slot_token)
outcome sent / stale_token / error — only sent and stale_token block re-sends
sentAt Timestamp for the admin UI

Rows are cleaned up automatically at 3 AM UTC daily (7-day retention) via the cleanup-reminder-logs cron registered in convex/crons.ts.

Deploy on Vercel

The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.

Check out our Next.js deployment documentation for more details.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages