A lightweight shared ledger app built with Expo, React Native, and TypeScript. Track purchases, categorize entries by source, and keep totals synced through Firebase.
This project was built as a small practical app for tracking money between people without spreadsheet overhead. It is also an exploration of using Expo with a minimal TypeScript codebase and Firebase-backed persistence.
- Purchase entries — record amount, note, date, person, and purchase source
- Balance settle — one-tap zero the balance with a counter-entry
- People and source management — add or remove people and purchase sources
- PDF sharing — generate and share a ledger PDF from native devices
| Technology | Version | Role |
|---|---|---|
| Expo | ~54.0.33 | App runtime and tooling |
| React | 19.1.0 | UI library |
| React Native | 0.81.5 | Native UI framework |
| React Native Web | ^0.21.0 | Web rendering |
| TypeScript | ~5.9.2 | Language |
| Firebase | ^12.13.0 | Firestore persistence |
-
Use the project Node version:
nvm use
-
Install dependencies:
npm install
-
Start the Expo dev server:
npm run start
Create a .env file from .env.example to enable Firestore sync:
cp .env.example .envThe app reads EXPO_PUBLIC_FIREBASE_* variables and stores entries in Firestore ledger collections keyed by stable person IDs. People are stored in the top-level people collection, and purchase source options are stored in purchaseSources.
The app does not create default people or sources. Add them through Settings, or pre-populate Firestore yourself.
Firebase configuration is required. If Firebase variables are missing, the app shows an unconfigured state and disables ledger actions instead of saving locally.
To build this app for your Android phone, you'll need a Firebase project and an Expo account.
Create a Firebase project at https://console.firebase.google.com, then enable Firestore Database. Copy your project's Web App config values (apiKey, authDomain, projectId, etc.).
The .env file is used for local development only — native builds use variables stored on EAS. Set your Firebase config:
npx eas-cli env:create production --scope project --visibility plaintext --force --name EXPO_PUBLIC_FIREBASE_API_KEY --value "your-api-key"
npx eas-cli env:create production --scope project --visibility plaintext --force --name EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN --value "your-auth-domain"
npx eas-cli env:create production --scope project --visibility plaintext --force --name EXPO_PUBLIC_FIREBASE_PROJECT_ID --value "your-project-id"
npx eas-cli env:create production --scope project --visibility plaintext --force --name EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET --value "your-storage-bucket"
npx eas-cli env:create production --scope project --visibility plaintext --force --name EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID --value "your-sender-id"
npx eas-cli env:create production --scope project --visibility plaintext --force --name EXPO_PUBLIC_FIREBASE_APP_ID --value "your-app-id"nvm use
npx eas-cli build --platform android --profile preview --non-interactiveOpen the returned URL on your phone, or scan the QR code, to install the APK.
On push to main, tests run automatically via GitHub Actions. If they pass, an EAS build is triggered. To enable this, add an EXPO_TOKEN secret to your GitHub repo (generate one at https://expo.dev/settings/access-tokens).