Expense Management is a Firebase + React web app for collaborative expense tracking, with a Hebrew RTL UI. It supports shared boards, one-level board hierarchies ("super boards" with sub-boards), invites, and Excel export.
🌐 Live app: https://of8-expense-management.web.app/
- Overview
- Features
- Boards vs. Super Boards
- Access Model (Direct vs. Inherited)
- Invitation Flow
- Architecture
- Project Structure
- Setup
- Development
- Deployment
- Security & Privacy Notes
- Release Status
- License
The app is designed for small groups (families, roommates, partners) who manage shared spending. Each board has members, transactions, and optional hierarchy relationships. Data is stored in Firestore and updates in real time.
- Authentication: Email/password and Google sign-in.
- Boards: Create, rename, delete, and view shared boards.
- Super boards: Group regular boards under one parent board (one-level hierarchy).
- Invitations: Board owners can invite by email; invitees can accept or decline.
- Membership model:
directMemberUids: explicitly invited to a board.memberUids: effective access (direct + inherited from parent board).
- Inherited access: Membership flows down from a super board to its sub-boards.
- Transactions: Create, edit, and delete transactions on regular boards.
- Amounts: Positive and negative amounts are supported (useful for refunds/credits).
- Future dates: Optional
transactionDateaccepts validYYYY-MM-DDdates, including future dates. - Excel export:
- Regular board: single worksheet export.
- Super board: multi-sheet export (one sheet per sub-board) + optional summary sheet.
- Account management: Update nickname, sign out, and delete account (with server-side cleanup).
- Regular board: A board without
subBoardIds; it contains transactions directly. - Super board: A board with one or more
subBoardIds; it aggregates totals from sub-boards and does not show a transaction-entry view. - Sub-board: A board with
parentBoardIdset.
Hierarchy is intentionally one level:
- A board can be top-level, or a child of one parent board.
- A sub-board cannot itself have sub-boards.
This project uses two membership fields:
directMemberUids= users directly added to that board.memberUids= users with effective access to that board.
Behavior:
- Direct membership on a super board grants inherited access to descendant sub-boards.
- Direct membership on a sub-board does not grant access to its parent.
- Removing a direct member cascades membership recalculation through descendants.
- Board owner sends an invite by email.
- Invite document is created under
boards/{boardId}/invites. - Invitee sees incoming invites and can accept/decline.
- Accepting adds membership and deletes the invite.
- Declining deletes the invite.
Notes:
- Invites include
expiresAtand are treated as pending while the document exists. - Functions enforce ownership/auth checks before invite and membership mutations.
- Frontend: React 19 + Vite 8 + React Router 7 + Tailwind CSS 4.
- Backend: Firebase Cloud Functions (Node.js 22 runtime).
- Data/Auth: Firestore + Firebase Authentication.
- Hosting: Firebase Hosting.
- Security controls: Firestore Security Rules, App Check integration in the client, and callable functions with
enforceAppCheck: true.
ExpenseManagement/
├── src/
│ ├── components/ # UI and board/collaborator components
│ ├── context/ # Auth and theme providers
│ ├── firebase/ # Firebase client modules (auth, boards, invites, users, config)
│ ├── hooks/ # Data hooks (boards, transactions, incoming invites)
│ └── pages/ # Route pages (auth, boards, board view, legal pages)
├── functions/ # Callable Cloud Functions for invite/member/account flows
├── firestore.rules # Firestore authorization and validation rules
├── firebase.json # Hosting targets, headers, and Firebase service config
└── .github/workflows/ # Deploy + CodeQL workflows
- Node.js 22+ (recommended for local dev, including functions)
- npm
- Firebase project with:
- Authentication
- Cloud Firestore
- Cloud Functions
- Hosting
- App Check (recommended/enabled for production)
git clone https://github.com/OrF8/ExpenseManagement.git
cd ExpenseManagement
npm ci
npm --prefix functions ciCopy .env.example to .env:
cp .env.example .envRequired variables:
VITE_FIREBASE_API_KEYVITE_FIREBASE_AUTH_DOMAINVITE_FIREBASE_PROJECT_IDVITE_FIREBASE_STORAGE_BUCKETVITE_FIREBASE_MESSAGING_SENDER_IDVITE_FIREBASE_APP_IDVITE_RECAPTCHA_V3_SITE_KEY
Optional preview deployment file:
cp .env.preview.example .env.previewAdditional preview variables:
VITE_APPCHECK_DEBUG(optional)VITE_APPCHECK_DEBUG_TOKEN(optional)FIREBASE_PROJECT_ID(required for preview deploy script)
npm run devVite dev server: http://localhost:5173
npm run build
npm run previewPreview server: http://localhost:4173
- Frontend linting is configured via ESLint:
npm run lint- Functions package currently has a placeholder lint script (
Skipping lint).
GitHub Actions workflow .github/workflows/deploy.yml:
- builds the frontend,
- deploys Functions + Hosting to Firebase,
- authenticates with Google via Workload Identity Federation (OIDC).
npm run build
firebase deploy --only functions,hosting --project <project-id>To deploy Firestore rules explicitly:
firebase deploy --only firestore:rules --project <project-id>A PowerShell script is provided for preview channels:
npm run deploy:preview -- -PrNumber <pr-number>This script:
- loads
.env.preview, - deploys functions,
- builds with
--mode preview, - deploys a Firebase Hosting preview channel.
- Firestore rules restrict board reads/writes to authorized users and owners by role.
- Invite and membership mutations are handled through callable functions instead of broad client-side user reads.
- Callable functions are configured with App Check enforcement.
- Account deletion is handled server-side to remove owned data and membership links.
- This is a collaborative app: data shared to a board is visible to that board’s members.
For vulnerability reporting, see SECURITY.md.
Current release target: v1.1.1.
Notable release focus:
- hierarchy-aware collaboration,
- Excel export improvements (including super-board multi-sheet export),
- documentation refresh and version alignment.
See CHANGELOG.md for release notes.
This project is licensed under the MIT license. For more information, see the LICENSE file.