A mobile-first PWA for tracking recurring class attendance and billing cycles within a household.
Live: https://lesson-loop-project.web.app
Stack: React + Vite + TypeScript + Firebase Auth + Cloud Firestore + vite-plugin-pwa
npm install
npm run dev # emulators + Vite dev server (uses .env.emulator, no setup needed)
npm run seed # seed test data into emulators
npm run dev:prod # run against production Firebase (needs .env.local)See .env.example for required environment variables.
For one-off historical data loads (e.g. backfilling attendance and payments):
- Download a service account key from Firebase Console → Project Settings → Service accounts → Generate new private key and save it to
secrets/(gitignored). - Create a data file at
scripts/prod/seed-<name>-data.jsonand a script atscripts/prod/seed-<name>-prod.ts(both gitignored — keep personal/financial data out of git). - Run:
GOOGLE_APPLICATION_CREDENTIALS=secrets/<key-file>.json npx tsx scripts/prod/seed-<name>-prod.ts
Attendance docs use deterministic IDs (
personId_activityId_date) so re-running is safe. Payment docs use auto-IDs — run once only to avoid duplicates.
npm run build
firebase deploy --only hosting # frontend only
firebase deploy --only firestore:indexes # composite indexes only
firebase deploy --only firestore:rules,firestore:indexes # rules + indexes
firebase deploy --only firestore:rules,firestore:indexes,hosting # everythingFirestore requires a composite index whenever a query filters on one field and sorts by another (e.g. payments filters on activityId and sorts by paidDate; attendance filters on activityId and sorts by date). Index definitions live in firebase/firestore.indexes.json and only need to be deployed once — they persist until explicitly removed.
src/app/ auth + navigation context
src/screens/ Dashboard, Activity, Insights, Settings
src/services/ Firestore read/write per domain
src/domain/ pure business logic (billing cycles)
src/types/ domain types
firebase/ Firestore rules and indexes
scripts/ emulator seed script
Agreed requirements that are not yet implemented are tracked in docs/requirements.md.
App icon: Sitar icons by Magnific – Flaticon