Skip to content

adilio/Rhabbit

Repository files navigation

Rhabbit 🐇

Take it one hop at a time.

A calm, private habit tracker for a small circle of friends — part of the 4dl Apps family. Live at rhabbit.4dl.ca.

  • One-tap logging on a mobile-first Today screen, with undo everywhere
  • Forgiving progress — skips, pauses, and comebacks instead of guilt
  • Boolean, numeric, duration, and avoidance habits with flexible schedules (daily, chosen weekdays, or N times a week)
  • Spreadsheet import (.xlsx/.xls/.csv) with layout detection, preview, and one-tap undo — plus JSON/CSV export
  • Calendar history with backfill, per-habit heatmaps, plain-language insights
  • Installable PWA with offline support, dark and light themes

Stack

React 19 · TypeScript · Vite · Firebase (Google auth + Firestore with offline persistence) · SheetJS · vite-plugin-pwa · Netlify

Development

cp .env.example .env   # fill in Firebase web config
npm install
npm run dev

npm run build type-checks and produces dist/. Deploys run automatically from main via Netlify: a GitHub push webhook fires a Netlify build hook, and the buildbot clones over SSH with a read-only deploy key. If a deploy is ever needed by hand: npm run build && netlify deploy --prod --dir dist --no-build (local .env supplies the Firebase config).

Tests

npm test           # unit tests for dates, schedules, and stats
npm run test:rules # Firestore security rules, against the local emulator
npm run ci:verify  # everything CI runs: typecheck, both suites, build

test:rules boots the Firestore emulator, which needs a Java runtime on PATH. Homebrew's openjdk is keg-only, so it needs to be added explicitly:

brew install openjdk
export PATH="/opt/homebrew/opt/openjdk/bin:$PATH"   # add to ~/.zshrc to persist

The rules suite asserts denials as well as grants — cross-user reads, non-allowlisted accounts, unverified emails, and self-granting an allowlist entry. Changing firestore.rules without updating it should turn CI red.

Production uses rhabbit.4dl.ca as Firebase's auth domain and Netlify proxies /__/auth/* to the Firebase Hosting auth helpers. Keep rhabbit.4dl.ca in Firebase Authentication's authorized domains and keep https://rhabbit.4dl.ca/__/auth/handler in the Google OAuth web client's authorized redirect URIs. Local development continues to use the VITE_FIREBASE_AUTH_DOMAIN value from .env.

Access control

Rhabbit is open to Adil's close friends. If you know him personally, reach out to ask for access. Server-side Firestore rules (firestore.rules) only admit Google accounts whose verified email exists in the allowlist collection — add or remove emails in the Firebase console (doc ID = email, contents can be empty). Each person's habit data remains private to their account.

Data model

users/{uid}                    profile: displayName, timezone, weekStartsOn
users/{uid}/habits/{id}        name, type, target, schedule, timeOfDay, …
users/{uid}/entries/{habitId_date}   status, value, note — one doc per day
users/{uid}/importBatches/{id} filename, counts — enables import undo
allowlist/{email}              presence = access (console-managed)

Entries key on a local date string (2026-07-19), so history never shifts when the device timezone changes.

About

Habit tracker app, one hop at a time

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages