Skip to content

Repository files navigation

Financial Planner 2026

A full-stack web application built for Hirumi University students and staff to plan their personal finances using the 50/30/20 budgeting framework, backed by Firebase for authentication and data storage, with a secure admin dashboard for survey management.


Table of Contents


Product Requirements Document (PRD)

Purpose

Help individuals — particularly university students — understand and plan their monthly finances using a structured, guided survey experience. The tool collects profile information, income, and spending data, then models savings growth toward retirement (pension at age 55).

Target Users

  • Primary: University students (undergraduate, postgraduate, diploma) in Malaysia
  • Secondary: Employed individuals, self-employed, government servants, retirees
  • Admin: Financial advisors or administrators who review survey responses

Core Features

FeatureDescription
Google Sign-InFederated auth via Google for all regular users
Multi-Step Survey5-step guided form: Profile → Income → Needs → Wants → Savings
50/30/20 FrameworkAutomatic budget split — 50% Needs, 30% Wants, 20% Savings
Live ProjectionsCompound interest calculations per investment vehicle
Profile Auto-FillName and email pre-populated from Google account
DOB Calendar PickerInteractive calendar with auto-calculated age and years-to-pension
Firestore PersistenceSurvey responses and user profiles saved to Firestore
Admin DashboardEmail/password secured portal with analytics and export
XLSX ExportFull Firestore dataset downloadable as Excel
Mobile SupportRedirect-based Google auth on mobile devices
SweetAlert2 UXPolished confirmation dialogs for destructive/key actions

Non-Goals (Out of Scope)

  • Payment or transaction processing
  • Multi-currency support
  • Real-time investment data feeds
  • Email notifications

Tech Stack

LayerTechnologyVersion
FrameworkNext.js (App Router)16.1.6
LanguageTypeScript5.7.3
RuntimeReact19.2.4
StylingTailwind CSS4.2.0
Component Libraryshadcn/ui + Radix UILatest
Backend / AuthFirebase (Auth + Firestore)12.10.0
AnimationGSAP3.14.2
DialogsSweetAlert211.26.22
Date Pickerreact-day-picker9.13.2
Excel Exportxlsx (SheetJS)0.18.5
ChartsRecharts2.15.0
Formsreact-hook-form + zod7.54.1 / 3.24.1
Package Managernpm
HostingFirebase Hosting (webframeworks)

Architecture

┌─────────────────────────────────────────────────┐
│ Browser / Client │
│ │
│ ┌──────────────┐ ┌───────────────────┐ │
│ │ User App │ │ Admin Portal │ │
│ │ / │ │ /admin │ │
│ └──────┬───────┘ └────────┬──────────┘ │
│ │ Google Auth │ Email/Password │
└─────────┼───────────────────────┼───────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────┐
│ Firebase Services │
│ │
│ ┌────────────────────┐ ┌─────────────────────┐│
│ │ Authentication │ │ Cloud Firestore ││
│ │ - Google Provider │ │ - /users/{uid} ││
│ │ - Email/Password │ │ - /surveys/{id} ││
│ └────────────────────┘ └─────────────────────┘│
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ Firebase Hosting (SSR via webframeworks) │ │
│ └────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘

Component Architecture

app/
├── page.tsx → renders <FinancialPlanner />
└── admin/
└── page.tsx → renders admin login + <AdminDashboard />
components/
├── financial-planner/
│ ├── financial-planner.tsx → Main state orchestrator
│ ├── login-screen.tsx → Google auth (popup/redirect)
│ ├── step-profile.tsx → Step 1: personal info
│ ├── step-income.tsx → Step 2: monthly income
│ ├── step-needs.tsx → Step 3: 50% needs allocation
│ ├── step-wants.tsx → Step 4: 30% wants allocation
│ ├── step-savings.tsx → Step 5: 20% savings + projections
│ ├── step-progress.tsx → Progress bar / stepper UI
│ ├── success-modal.tsx → Completion screen
│ └── types.ts → FormData interface
│
├── admin/
│ ├── admin-dashboard.tsx → Dashboard with sidebar + analytics
│ ├── analytics-cards.tsx → Summary stat cards
│ ├── survey-data-table.tsx → Paginated responses table
│ ├── survey-detail-modal.tsx → View individual survey
│ ├── interest-rates-table.tsx→ Reference rate display
│ ├── mock-data.ts → Fallback data structure
│ └── types.ts → Admin-specific types
│
└── ui/ → shadcn/ui primitives (Button, Card, etc.)
lib/
├── firebase.ts → Firebase app + auth + db init
└── utils.ts → cn() Tailwind class merge helper

Project Structure

FinancialPlanner/
├── app/
│ ├── layout.tsx Metadata, favicon, root layout
│ ├── globals.css Global Tailwind styles
│ ├── page.tsx User app entry point
│ └── admin/
│ └── page.tsx Admin portal entry point
├── components/
│ ├── financial-planner/ Survey app components
│ ├── admin/ Admin dashboard components
│ └── ui/ Reusable UI primitives
├── lib/
│ ├── firebase.ts Firebase initialization
│ └── utils.ts Utility functions
├── hooks/
│ ├── use-mobile.ts Mobile detection hook
│ └── use-toast.ts Toast notification hook
├── public/
│ └── form.png Favicon / app icon
├── styles/
│ └── globals.css Additional global styles
├── .env.local Firebase config keys (gitignored)
├── firebase.json Firebase project config (hosting + rules)
├── .firebaserc Project alias (financial-planner-fb427)
├── firestore.rules Firestore security rules
├── firestore.indexes.json Firestore composite indexes
├── next.config.mjs Next.js configuration
├── tailwind.config.* Tailwind CSS configuration
└── tsconfig.json TypeScript configuration

User Flows

Regular User Flow

1. Land on app (/)
│
▼
2. Login Screen
- Click "Sign in with Google"
- Desktop: signInWithPopup
- Mobile (width < 768px): signInWithRedirect → getRedirectResult on mount
│
▼
3. Google OAuth completes
- User doc created/merged in Firestore: users/{uid}
{ uid, name, email, lastLogin }
│
▼
4. Step 1 — Profile & Timeline
- Name (auto-filled, editable)
- Email (auto-filled, read-only for Google users)
- Gender, HP No, Date of Birth (calendar picker)
- Occupation (+ Student Level sub-dropdown if student)
- Live display: current age + years until pension (55)
- Required field validation before proceeding
│
▼
5. Step 2 — Monthly Income
- Enter gross monthly income (MYR)
- Displays 50/30/20 target split
│
▼
6. Step 3 — Needs (50% target)
- PTPTN, Housing, Car, Personal Loan, Others
- Live total vs target comparison
│
▼
7. Step 4 — Wants (30% target)
- Dining, Entertainment, Travel, Shopping, Hobbies
- Free-text notes field
- Custom line items (name + amount)
│
▼
8. Step 5 — Savings (20% target)
- Allocate across: KWSP, Gold, Mutual Funds, ASB, Tabung Haji
- Live compound interest projections per vehicle
- Total projected pension fund displayed
│
▼
9. Complete Survey
- SweetAlert2 confirmation dialog
- Survey document written to Firestore: surveys/{autoId}
- Success modal displayed
│
▼
10. Start Over (optional)
- SweetAlert2 confirmation
- Form resets to initial state
- Returns to Step 1

Admin Flow

1. Navigate to /admin
│
▼
2. Admin Login
- Email: admin@financialplanner.com
- Password: [secure password set in Firebase Console]
- signInWithEmailAndPassword
- Validates user.email === "admin@financialplanner.com"
- SweetAlert2 welcome / error alerts
│
▼
3. Admin Dashboard loads
- GSAP page-load animation
- Fetches all documents from Firestore surveys collection
│
├── Overview Tab
│ - Analytics cards (total surveys, avg income, avg savings, etc.)
│ - Recharts visualizations
│
├── Survey Responses Tab
│ - Paginated table (GSAP row animations)
│ - Search / filter
│ - View individual survey (detail modal)
│ - Export row as CSV (SweetAlert2 confirm)
│
└── Export All (XLSX)
- SweetAlert2 confirm with loading state
- Fetches all Firestore surveys
- Generates .xlsx file via SheetJS
- Downloads to browser
│
▼
4. Logout
- SweetAlert2 confirmation
- Firebase signOut()
- Returns to admin login screen

Firebase Data Model

Collection: users

Document ID: {uid} (Firebase Auth UID)

{
"uid": "string",
"name": "string",
"email": "string",
"lastLogin": "Timestamp"
}

Collection: surveys

Document ID: auto-generated

{
"userId": "string",
"submittedAt": "Timestamp",
"profile": {
"name": "string",
"email": "string",
"gender": "string",
"hpNo": "string",
"dateOfBirth": "Timestamp | null",
"occupation": "string",
"studentLevel": "string"
},
"monthlyIncome": "number",
"needs": {
"ptptn": "number",
"housing": "number",
"car": "number",
"personal": "number",
"others": "number"
},
"wants": {
"dining": "number",
"entertainment": "number",
"travel": "number",
"shopping": "number",
"hobbies": "number",
"notes": "string",
"customItems": [{ "name": "string", "amount": "number" }]
},
"savings": {
"kwsp": "number",
"gold": "number",
"mutualFunds": "number",
"asb": "number",
"tabungHaji": "number"
},
"savingsAllocations": { ... },
"projectedPensionTotal": "number"
}

Authentication Model

RoleMethodCondition
Regular UserGoogle OAuthAny Google account
AdminEmail / Passwordemail === "admin@financialplanner.com"

Mobile vs Desktop Auth

// login-screen.tsxconstisMobile=window.innerWidth<768if(isMobile){awaitsignInWithRedirect(auth,googleProvider)// Result handled in useEffect via getRedirectResult()}else{awaitsignInWithPopup(auth,googleProvider)}

Firestore Security Rules Summary

/users/{userId}
read: owner OR admin
write: owner only
/surveys/{surveyId}
create: any signed-in user
read: admin only
update/delete: NEVER

Savings Engine

Located in components/financial-planner/step-savings.tsx.

Investment Vehicles & Annual Returns

VehicleReturn Rate
KWSP (EPF)6% p.a.
Gold10% p.a.
Mutual Funds8% p.a.
ASB6% p.a.
Tabung Haji5% p.a.

Projection Formula

Uses the Future Value of an Annuity formula:

$$FV = P \times \frac{(1 + r)^n - 1}{r}$$

Where:

  • $P$ = monthly contribution (MYR)
  • $r$ = monthly interest rate ($\text{annual rate} \div 12$)
  • $n$ = total months until pension age (55)

Age is derived from the user's date of birth. CURRENT_YEAR = 2026.


Admin Dashboard

Analytics Cards

Calculated in real-time from Firestore survey data:

  • Total survey submissions
  • Average monthly income
  • Average savings rate
  • Most common occupation
  • Age distribution

Features

  • GSAP Animations: Page-load fade-in, table row staggered entrance
  • Recharts: Bar/pie charts for income and savings distribution
  • Pagination: Client-side with configurable page size
  • Row Export: Per-survey CSV download
  • Bulk Export: Full dataset as .xlsx via SheetJS

Environment Variables

Create a .env.local file at the project root. Never commit this file.

NEXT_PUBLIC_FIREBASE_API_KEY=your_api_keyNEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.comNEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_idNEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.comNEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_idNEXT_PUBLIC_FIREBASE_APP_ID=your_app_id

All values are found in the Firebase Console under Project Settings → Your Apps → SDK setup and configuration.


Local Development

Prerequisites

  • Node.js 18+
  • npm

Setup

# 1. Clone or download the projectcd FinancialPlanner
# 2. Install dependencies
npm install
# 3. Create environment variables# Copy the .env.local template above and fill in your Firebase keys# 4. Start the development server
npm run dev

App runs at http://localhost:3000
Admin portal at http://localhost:3000/admin

Firebase Console Setup Required

  1. Authentication → Sign-in method

    • Enable Google provider
    • Enable Email/Password provider
  2. Firestore Database

    • Create database in production mode
    • Deploy rules: firebase deploy --only firestore:rules
  3. Create admin account

    • In Firebase Console → Authentication → Users → Add user
    • Email: admin@financialplanner.com
    • Set a secure password

Deployment

This project uses Firebase Hosting with the webframeworks experiment for SSR support.

# 1. Install Firebase CLI
npm install -g firebase-tools
# 2. Login
firebase login
# 3. Enable webframeworks (required for Next.js SSR)
firebase experiments:enable webframeworks
# 4. Initialize (already done — firebase.json and .firebaserc exist)# firebase init hosting ← skip if files already exist# 5. Deploy everything
firebase deploy
# Or deploy only hosting
firebase deploy --only hosting
# Or deploy only Firestore rules
firebase deploy --only firestore:rules

Firebase Project

  • Project ID: financial-planner-fb427
  • Hosting URL: https://financial-planner-fb427.web.app

Libraries Reference

LibraryPurpose
nextSSR framework, app router, API routes
react / react-domUI rendering
typescriptStatic typing
tailwindcssUtility-first CSS
shadcn/uiPre-built accessible component system
@radix-ui/*Headless UI primitives (used by shadcn)
firebaseClient SDK — Auth + Firestore
firebase-adminServer SDK — used in scripts (e.g. set admin role)
gsapPage load and table animations
sweetalert2Confirmation and alert dialogs
react-day-pickerCalendar component for date of birth
date-fnsDate formatting and arithmetic
xlsx (SheetJS)Generate and download Excel files
rechartsChart components for admin analytics
react-hook-formForm state management
zodSchema validation
@hookform/resolverszod adapter for react-hook-form
lucide-reactIcon library
clsx + tailwind-mergeConditional class name utilities
sonnerToast notifications
next-themesDark/light mode theming
vaulDrawer (bottom sheet) component
cmdkCommand palette component
embla-carousel-reactCarousel component
react-resizable-panelsResizable panel layouts
input-otpOTP input component
animejsInstalled but replaced by GSAP in production
three3D graphics (installed, available for future use)
@vercel/analyticsUsage analytics (optional)

Security Notes

  • .env.local is gitignored — never commit Firebase keys
  • firestore.rules enforces server-side access control
  • Admin email is validated both client-side (in the React component) and enforced by Firestore rules
  • Survey documents are immutable — update and delete are disabled in Firestore rules
  • financialplanner.json (Firebase Admin SDK service account key) is gitignored
  • Firebase API keys in NEXT_PUBLIC_* variables are safe to expose client-side — security is enforced by Firestore rules and Firebase Auth, not by keeping keys secret

Known Limitations

  • Pension projection uses a fixed retirement age of 55 (Malaysian standard)
  • Annual return rates are estimates and not live market data
  • Admin portal supports a single admin account only
  • No password reset flow for the admin account (use Firebase Console)
  • Mobile redirect auth requires the app to be served over HTTPS in production

Last updated: April 2026

Financial Planner

A Next.js financial planning app with Google user sign-in, multi-step survey flow, Firestore persistence, and an admin dashboard with real data export.

Features

  • Google-only user sign-in
  • Multi-step financial survey with live calculations
  • Firestore persistence for users and surveys
  • Admin dashboard with Email/Password auth and XLSX export

Local Setup

npm install
npm run dev

Open http://localhost:3000

Firebase Setup

  1. Create a Firebase project
  2. Enable Authentication providers:
    • Google (for users)
    • Email/Password (for admin)
  3. Enable Firestore (production mode is recommended with rules)
  4. Add Firebase config to .env.local

Admin Access

Firestore Collections

  • users/{uid}: user profiles
  • surveys/{surveyId}: survey responses

Deployment (Firebase Hosting SSR)

firebase login
firebase deploy --only firestore:rules
firebase deploy --only hosting

Notes

  • Firestore rules are in firestore.rules
  • Hosting config is in firebase.json

About

Full-stack financial planning platform built with Next.js and Firebase. Features secure Google OAuth, dynamic multi-step survey flows, Firestore persistence, and a dedicated admin dashboard for real-time data export.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages