A family real estate renovation fund management web app built with Next.js 15 and Firebase.
- Project Tracking: Track renovation projects from planning through settlement
- Multi-Currency Support: Record transactions in any currency with automatic base currency conversion
- Capital Management: Track member contributions, withdrawals, and ownership percentages
- Flexible Profit Sharing: Configure per-project profit shares with support for work partners
- Settlement Wizard: Automatically calculate and distribute profits when projects complete
- Dad-Friendly UI: Clean, intuitive interface with helpful tooltips and explanations
- Framework: Next.js 15 (App Router) with TypeScript
- Database: Firebase Firestore
- Authentication: Firebase Auth (Email/Password + Google OAuth)
- Styling: Tailwind CSS v4
- Node.js 18+
- A Firebase project
- Go to Firebase Console
- Create a new project (or use an existing one)
- Enable Authentication:
- Go to Authentication > Sign-in method
- Enable "Email/Password"
- Enable "Google" (optional)
- Create a Firestore Database:
- Go to Firestore Database
- Create database in production mode
- Choose your preferred region
- Get your Firebase config:
- Go to Project Settings > General
- Scroll to "Your apps" and click the web icon (</>)
- Register your app and copy the config values
Create a .env.local file in the project root:
NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project-id.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project-id.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-sender-id
NEXT_PUBLIC_FIREBASE_APP_ID=your-app-idTo enable the "Add Member Manually" feature (creating placeholder accounts for family members who haven't registered), you need to set up the Firebase Admin SDK:
- Go to Firebase Console → Project Settings → Service Accounts
- Click "Generate new private key"
- Download the JSON file
- Add the entire JSON content to your
.env.localas a single line:
FIREBASE_SERVICE_ACCOUNT_KEY='{"type":"service_account","project_id":"your-project-id","private_key_id":"...","private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n","client_email":"...","client_id":"...","auth_uri":"...","token_uri":"...","auth_provider_x509_cert_url":"...","client_x509_cert_url":"..."}'Note: This is optional. Without it, members can still join the fund using the invite link.
To display property locations on a map in project details:
- Go to Google Cloud Console
- Create a new project or select an existing one
- Enable the following APIs:
- Maps JavaScript API
- Geocoding API
- Go to Credentials and create an API key
- Restrict the key to your domains and the above APIs
- Add to your
.env.local:
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=your-google-maps-api-keyNote: Without this key, a "View on Google Maps" link will be shown instead.
The security rules are defined in firestore.rules. Deploy them using one of these methods:
Option 1: Firebase Console (Manual)
- Go to Firebase Console → Firestore Database → Rules
- Copy the contents of
firestore.rulesand paste them - Click "Publish"
Option 2: Firebase CLI (Recommended)
# Install Firebase CLI if you haven't
npm install -g firebase-tools
# Login to Firebase
firebase login
# Initialize Firebase in your project (if not already done)
firebase init firestore
# Deploy rules
firebase deploy --only firestore:rulesSecurity Rules Summary:
- Users: Can only read/write their own user document
- Funds: Only fund owner and active members can read, only owner can modify
- Fund Members: Only fund members can see other members, owner manages memberships
- Projects: Only fund members can access, only owner can delete
- Transactions: Only fund members can access
How Membership Checks Work:
Fund member documents use a predictable ID format: {fundId}_{userId}. This allows security rules to efficiently check membership using exists() without needing to query the collection.
For example, to check if user abc123 is a member of fund xyz789, the rules check:
exists(/databases/.../fundMembers/xyz789_abc123)
# Install dependencies
npm install
# Run development server
npm run devOpen http://localhost:3000 in your browser.
src/
├── app/
│ ├── (auth)/ # Login/Register pages
│ ├── (dashboard)/ # Protected dashboard pages
│ ├── layout.tsx # Root layout with providers
│ └── providers.tsx # Auth & Fund context providers
├── components/
│ ├── ui/ # Reusable UI components
│ └── dashboard/ # Dashboard-specific components
└── lib/
├── firebase/ # Firebase config and helpers
├── hooks/ # Custom React hooks (useAuth, useFund)
├── types/ # TypeScript definitions
└── utils/ # Utility functions
- Sign up or log in
- You'll be prompted to create your first fund
- Enter a name and select your base currency
- Add family members via Settings > Members
- Go to Projects > New Project
- Enter project details (name, address, estimates)
- Select which members will participate
- Set profit shares for each participant (should total 100%)
Contributions: When members add money to the fund Withdrawals: When members take money out Project Investment: Fund money allocated to a project Project Expense: Costs during renovation Project Income: Revenue from sale or rent
- Mark the project as "Sold" once the property is sold
- Review the profit calculation
- Click "Settle Project" to distribute profits
- Profit distributions are automatically recorded
Work partners contribute labor instead of capital. They:
- Have a default profit share (typically 20%)
- Don't need to contribute capital to participate
- Receive profit distributions like other members
Profit = Total Income - Total Invested - Total Expenses
Profit is distributed according to each participant's profitSharePercent.
Transactions can be in any supported currency. Each transaction stores:
- Original amount and currency
- Converted amount in the fund's base currency
- Exchange rate used
MIT