A full-stack mobile expense tracking application with advanced group splitting features, built with modern technologies.
- β Track income and expenses with categories
- β View balance, income, and expense summaries
- β Beautiful dashboard with visual insights
- β Delete individual or all transactions
- β Create and join groups using unique 6-character codes
- β Share group codes with friends
- β Add expenses on behalf of friends - flexible "Paid By" selector with animated modal
- β Smart split options: Equal or custom split amounts
- β Edit expenses - modify description, amount, category, and splits
- β Delete expenses - remove expenses with confirmation dialog
- β Balance tracking - see who owes whom
- β Settle up - mark debts as paid between members
- β Leave groups - with automatic debt validation
- β Edit profile name - updates automatically across all groups and expenses
- β Real-time sync - name changes reflect everywhere instantly
- β View member since date and email
- β
Real-time notifications for:
- New members joining groups
- Expense additions and updates
- Expense deletions
- Member leaving groups
- Settlement confirmations
- β Beautiful, clean design with multiple themes (Coffee, Forest, Purple, Ocean)
- β Smooth animations and transitions
- β Animated bottom sheet modals
- β Intuitive navigation with Expo Router
- β Loading states and error handling
- β Category-based expense organization
- Framework: Expo (SDK 54) + React Native
- Navigation: Expo Router (file-based routing)
- Authentication: Firebase Auth
- UI: React Native components with custom styling
- State Management: React Hooks
- Notifications: Expo Notifications
- Runtime: Node.js
- Framework: Express.js
- Database: Firestore (via Firebase Admin SDK)
- Rate Limiting: Upstash Redis
- Cron Jobs: node-cron (keep-alive ping)
- Real-time: Push notifications via Expo
ETApp/
βββ app/ # Expo mobile application
β βββ app/ # App screens (file-based routing)
β β βββ (auth)/ # Authentication screens
β β βββ (root)/ # Main app screens
β β β βββ groups/ # Group management screens
β β βββ _layout.jsx # Root layout
β βββ components/ # Reusable components
β βββ constants/ # Colors, API URLs, etc.
β βββ hooks/ # Custom React hooks
β βββ utils/ # Utility functions
β βββ assets/ # Images, fonts, etc.
β
βββ backend/ # Express API server
βββ src/
βββ config/ # Database, Redis, Cron config
βββ controllers/ # Route handlers
β βββ groupsController.js
β βββ transactionsController.js
β βββ notificationsController.js
β βββ usersController.js
βββ middleware/ # Rate limiting
βββ routes/ # API routes
βββ utils/ # Push notifications
- Node.js: 20.19.x or newer (required for Expo SDK 54)
- npm: Comes with Node.js
- Expo CLI: Installed globally or via npx
- Firebase Project: Firestore + Firebase Auth enabled
- Redis: Upstash for rate limiting
git clone <repository-url>
cd ETAppcd backend
npm installcd app
npm installEXPO_PUBLIC_FIREBASE_API_KEY=...
EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN=...
EXPO_PUBLIC_FIREBASE_PROJECT_ID=...
EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET=...
EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=...
EXPO_PUBLIC_FIREBASE_APP_ID=...# Firebase Admin
FIREBASE_SERVICE_ACCOUNT_JSON={"type":"service_account","project_id":"..."}
UPSTASH_REDIS_REST_URL=your_upstash_redis_url
UPSTASH_REDIS_REST_TOKEN=your_upstash_redis_token
API_URL=https://your-api-url.com/api/health
PORT=5001
NODE_ENV=developmentNote:
.envfiles are git-ignored for security. Never commit sensitive credentials.
cd backend
npm run devServer runs on http://localhost:5001
cd app
npx expo startThen choose:
- Press
afor Android emulator - Press
ifor iOS simulator - Scan QR code with Expo Go app for physical device
GET /api/health- Server health status
GET /api/transactions/:userId- Get user's transactionsGET /api/transactions/summary/:userId- Get income/expense summaryPOST /api/transactions- Create new transactionPUT /api/transactions/:id- Update an existing transactionDELETE /api/transactions/:id- Delete transactionDELETE /api/transactions/user/:userId- Delete all user transactions
amountmust be a non-zero number (positive = income, negative = expense).dateis optional on create/update; when omitted on create, server timestamp is used.datecannot be invalid or in the future.- Summary values are stored and computed in cents (
balanceCents,incomeCents,expensesCents) for precision.
POST /api/groups- Create new groupPOST /api/groups/join- Join group via codePOST /api/groups/leave- Leave groupGET /api/groups/user/:userId- Get user's groupsGET /api/groups/:groupId- Get group detailsGET /api/groups/:groupId/members- Get group members
POST /api/groups/:groupId/expenses- Add expense to groupPUT /api/groups/expenses/:expenseId- Update expenseDELETE /api/groups/expenses/:expenseId- Delete expenseGET /api/groups/:groupId/expenses- Get group expensesGET /api/groups/expenses/:expenseId/splits- Get expense splits
GET /api/groups/:groupId/balance/:userId- Get user's balance in groupPOST /api/groups/settle- Settle up between users
POST /api/notifications/register- Register push tokenPOST /api/notifications/unregister- Unregister push token
PUT /api/users/profile- Update user name across all groupsGET /api/users/profile/:userId- Get user profile info
The app supports multiple color themes (configurable in app/constants/colors.js):
- Coffee (warm browns) π€
- Forest (greens) π
- Purple (purples) π
- Ocean (blues) π (default)
When a friend pays but asks you to log it:
- Tap "Add Expense" in any group
- Tap the "Paid By" selector at the top
- Beautiful modal slides up showing all group members
- Select your friend who actually paid
- Fill in expense details normally
- Expense is recorded as paid by your friend
Change your name once, see it update everywhere:
- Go to Profile screen
- Tap the pencil icon next to your name
- Edit and save
- Name updates automatically in:
- All group memberships
- All past expenses
- All balance calculations
- All notifications
- Equal Split: Automatically divides expense equally
- Custom Split: Manually enter amounts (validates totals match)
- Real-time calculation display
- Visual feedback for incorrect splits
Only the person who paid can delete:
- Open expense detail
- Scroll to bottom
- Tap "Delete Expense" (red button)
- Confirm deletion
- All group members are notified
cd app
npx expo install --fix
npx expo start -ccd app
npx expo start --clear- Verify
FIREBASE_SERVICE_ACCOUNT_JSON(orGOOGLE_APPLICATION_CREDENTIALS) is set for the backend - Ensure Firestore is enabled in your Firebase project
- If deployed, confirm the host has access to Google credentials
- Verify Upstash Redis credentials
- Check
backend/src/middleware/rateLimiter.js - Temporarily disable for local development (not recommended)
- Ensure device/emulator supports notifications
- Check notification permissions in device settings
- Verify push token registration in database
- iOS: 13.0 or later
- Android: API level 21 (Android 5.0) or later
- Tested on: iPhone 12+, Pixel 5+, various Android devices
- β Firebase Auth ID token authentication
- β Rate limiting on all API endpoints
- β Firestore access via Firebase Admin SDK
- β Authorization checks (users can only modify their own data)
- β Environment variable protection
- β HTTPS in production
- Recommended: Render, Railway, or Heroku
- Set all environment variables
- Set
NODE_ENV=production - Database: Firestore (Firebase)
- Build with EAS (Expo Application Services)
- Submit to App Store / Google Play
- Configure app.json with proper bundle identifiers
Firestore collections (high level):
users/{uid}+users/{uid}/transactions/*groups/{groupId}+ subcollectionsmembers/*,expenses/*,splits/*groupCodes/{code}(join-code mapping)userTokens/{uid}(Expo push token)
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit changes (
git commit -m 'Add AmazingFeature') - Push to branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Built with β€οΈ by the ETApp team
- Expo team for the amazing framework
- Firebase for authentication and Firestore
- Upstash for Redis rate limiting
- React Native community