A shared expense tracker PWA for Asha, Ajit, and Nishant travelling together, with optional expense splitting with a friend (Hitesh). Expenses entered on any device sync to a shared Google Sheet in real time.
- Add, edit, and delete expenses in INR or CHF
- Automatic CHF → INR conversion at a configurable rate
- Budget ring gauge showing overall spend vs. budget
- Per-category spend bars with warning thresholds
- Split expenses with a friend — 50/50 or 75/25 (family:friend), or "Full owe" when the friend pays upfront
- Friend balance card — running net of what the friend owes us (or we owe them), shown in CHF with INR in brackets
- Fixed costs in History — collapsible section showing Sheet1 fixed-cost items alongside variable entries
- Shared Google Sheets backend — all three users stay in sync
- Works offline; syncs when back online
- Installable as a home screen app (PWA) on iOS and Android
- Frontend — React 18 (CDN), JSX via Babel standalone, vanilla CSS
- Backend — Google Apps Script deployed as a Web App
- Storage — Google Sheets (server), localStorage (offline cache)
- Hosting — GitHub Pages, deployed via GitHub Actions
- PWA — Service Worker + Web App Manifest
- A Google account with a Google Sheet set up (see Sheet structure below)
- Google Apps Script deployed as a Web App (setup instructions)
- A GitHub account with the repo set to public
The Google Sheet needs three tabs:
| Tab | Purpose |
|---|---|
Sheet1 |
Budget categories — columns: Category, Category Type (Fixed/Variable), Budgeted Amount, Comments, Actual Amount |
Expenses |
Auto-created by the app on first write — 11 columns including split/friend fields |
Settings |
Auto-created by the app on first write — stores CHF rate, warning threshold, friend name |
git clone https://github.com/YOUR_USERNAME/exp-tracker.git
cd exp-trackerEdit index.html and set the real values:
window.TRACKER_API_URL = 'https://script.google.com/macros/s/YOUR_DEPLOYMENT_ID/exec';
window.TRACKER_SECRET = 'your-secret-here';Then serve locally:
python3 -m http.server 8080Important: Do not commit
index.htmlwith real values. Rungit update-index --skip-worktree index.htmlafter editing to prevent accidental commits.
Secrets are injected at deploy time via GitHub Actions and are never stored in the repository.
-
Add two secrets in GitHub repo → Settings → Secrets and variables → Actions:
TRACKER_API_URL— your Apps Script Web App URLTRACKER_SECRET— a random secret string (generate withpython3 -c "import secrets; print(secrets.token_urlsafe(24))")
-
Set the same secret in Apps Script → Project Settings → Script Properties:
- Key:
TRACKER_SECRET, Value: same string as above
- Key:
-
Enable GitHub Pages with source set to GitHub Actions (repo Settings → Pages)
-
Push to
main— GitHub Actions deploys automatically
Open the GitHub Pages URL in Safari (iOS) or Chrome (Android) → tap the share/menu button → Add to Home Screen.
├── index.html # Entry point — loads scripts, wires React root, settings panel
├── store.js # State management, Google Sheets sync, localStorage cache
├── compass-app.jsx # Main UI — dashboard, add expense, history, friend balance
├── tweaks-panel.jsx # Settings drawer (CHF rate, warning threshold, friend name)
├── Code.gs # Google Apps Script backend (lives in Apps Script, not deployed via git)
├── sw.js # Service worker for offline caching
├── manifest.json # PWA manifest
├── .github/
│ └── workflows/
│ └── deploy.yml # GitHub Actions deploy pipeline
└── HOW_IT_WORKS.md # Full codebase walkthrough for developers
For a detailed explanation of how every file works, the full data flow, and the security model, see HOW_IT_WORKS.md.
Private — for personal use by Asha, Ajit & Nishant.