1. Product Overview
TL;DR
FinQuest is an AI-powered financial education platform that helps beginner investors learn through personalized modules while tracking their portfolios. Users complete an onboarding quiz, add their stock positions, and receive AI-generated learning suggestions based on their goals and portfolio. The platform uses gamification (XP, levels, streaks, badges) to motivate consistent learning. All core features are dynamic, pulling real-time market data and generating personalized content.
Jobs To Be Done (JTBD)
-
As a beginner investor, I want to add my holdings and see real-time portfolio analytics, so that I can understand my overall performance and diversification.
-
As a beginner investor, I want to receive a learning pathway tailored to my goals and knowledge, so that I can learn finance concepts in a structured and relevant way.
-
As a learner, I want to test my understanding through quizzes, so that I can reinforce what I've learned and track progress.
-
As a beginner investor, I want AI to highlight learning modules based on my portfolio and goals, so that I can focus on knowledge that's most useful to my situation.
-
As a learner, I want to earn streaks and badges for completing modules, so that I stay motivated to return and continue learning consistently.
Core Customer User Journeys (CUJs)
CUJ 1: Portfolio Setup and Analytics
Description: From the dashboard or portfolio page, the user clicks a button and enters the ticker of a new position. They enter the quantity and average cost and click a button to add the position to their portfolio. The portfolio is updated with the new position and the user is redirected to the portfolio page where they can see their updated portfolio and view analytics about their portfolio based on real-time price data.
Implementation:
- Frontend:
app/web/components/AddPositionDialog.tsx - Backend:
app/services/api/src/finquest_api/routers/portfolio.py-POST /api/portfolio/positions - Service:
app/services/api/src/finquest_api/services/portfolio.py-create_position_from_avg_cost() - Data Source: Real-time prices via yfinance integration
Status: ✅ Fully Dynamic - Real-time market data, live portfolio calculations
CUJ 2: Personalized Learning Pathway
Description: When signing up, the user answers a short onboarding quiz about their financial goals and current knowledge (e.g., saving for retirement, risk tolerance, familiarity with investing terms). The AI generates a personalized pathway with beginner-friendly modules. The user sees their recommended first module and clicks on it to begin learning. The user reads the module and completes a series of multiple choice questions to test their understanding. At the end of the module, the user sees a congratulatory popup and is prompted to continue to the next module.
Implementation:
- Onboarding:
app/web/pages/onboarding.tsx - Learning Pathway:
app/web/components/LearningPathway.tsx - Module Viewer:
app/web/components/ModuleViewer.tsx - Backend Module Generation:
app/services/api/src/finquest_api/services/module_generator.py - Backend API:
app/services/api/src/finquest_api/routers/modules.py
Status: ✅ Fully Dynamic - AI-generated modules based on user profile and portfolio
CUJ 3: Adaptive AI Learning Suggestions
Description: The user is able to view personalized suggestions on their dashboard about their portfolio based on their financial goals. These suggestions are generated by AI and the user can click "Start Module" to view the suggested AI generated module in the "Learning" page.
Implementation:
- Frontend Widget:
app/web/components/SuggestionsWidget.tsx - Backend Suggestion Generator:
app/services/api/src/finquest_api/services/suggestion_generator.py - Backend API:
app/services/api/src/finquest_api/routers/users.py-GET /api/v1/users/suggestions - AI Integration:
app/services/api/src/finquest_api/services/llm/service.py
Status: ✅ Fully Dynamic - AI analyzes user profile and portfolio to generate personalized suggestions
CUJ 4: Gamification
Description: Every day that the user completes a learning module, a streak counter is incremented and the user sees a congratulatory message. The user can view their streak counter on the dashboard and in the "Profile" page.
Implementation:
- Gamification Context:
app/web/contexts/GamificationContext.tsx - Gamification Service:
app/services/api/src/finquest_api/services/gamification.py - Backend API:
app/services/api/src/finquest_api/routers/gamification.py - UI Components:
app/web/components/XPBar.tsx,app/web/components/StreakIndicator.tsx
Status: ✅ Fully Dynamic - Real-time XP tracking, streak calculations, badge evaluation
2. MVP Development
Initial Hypothesis
Core Problem: Beginner investors lack accessible, personalized financial education that connects learning to their actual portfolio. Existing platforms either focus solely on portfolio tracking or offer generic educational content that doesn't adapt to individual needs.
Initial Product Idea: A financial education platform that combines portfolio tracking with AI-powered personalized learning modules. The platform would analyze a user's portfolio and financial goals to generate tailored educational content.
Key Assumptions:
- Users want to learn about finance in the context of their actual investments
- Gamification (XP, streaks, badges) will increase engagement and retention
- AI can effectively generate personalized, relevant educational content
- Real-time portfolio analytics are essential for user value
- A single platform combining education and tracking is more valuable than separate tools
Initial Architecture Vision:
- Frontend: Next.js with React (ADR-001)
- Backend: FastAPI (ADR-002)
- Database: PostgreSQL with Prisma ORM (ADR-003) - Later pivoted
- Market Data: yfinance (ADR-004)
- Authentication: JWT/OAuth2 (ADR-005)
- AI: OpenAI API (ADR-006) - Later pivoted to Gemini
- Hosting: Vercel + Render + Supabase (ADR-007)
Key Learnings and Pivots
Pivot 1: Database and ORM (ADR-009)
Initial Decision (ADR-003): PostgreSQL with Prisma ORM for type-safe queries
Learning: Prisma is TypeScript-centered and doesn't have strong Python community libraries. Since our backend is Python-based (FastAPI), we needed a Python-native ORM.
Pivot: Switched to Supabase + SQLAlchemy
- Supabase provides built-in authentication, database, and storage
- SQLAlchemy is Python-native and integrates seamlessly with FastAPI
- This simplified our architecture by consolidating authentication and database into one platform
Impact: Reduced complexity, faster development, better Python ecosystem alignment
Source: architecture/adrs/adr-009.md
Pivot 2: AI Provider (ADR-006 → Implementation)
Initial Decision (ADR-006): OpenAI API for AI integration
Learning: During implementation, we evaluated multiple LLM providers. Gemini 2.0 Flash offered better cost-effectiveness and structured output capabilities for our use case.
Pivot: Implemented Google Gemini 2.0 Flash
- Better structured output support for generating modules and suggestions
- More cost-effective for our use case
- Provider-agnostic architecture allows future switching
Impact: Lower costs, better structured output, maintained flexibility
Implementation:
Pivot 3: Frontend Component Library (ADR-010)
Initial Consideration: Multiple options including Tailwind CSS, Chakra UI, Material UI
Learning: Needed a React-based component library with comprehensive components and good design system. Mantine offered the best balance of features, ease of use, and extensibility.
Decision: Mantine UI
- Large set of components
- Good design system
- Easy integration with Next.js
- Plugin ecosystem for additional functionality
Impact: Faster UI development, consistent design system
Learning: Dynamic Content Requirements
Initial Assumption: Some content could be static or pre-seeded
Learning: Through user testing and development, we realized that the core value proposition requires all CUJs to be fully dynamic:
- Portfolio analytics must use real-time market data
- Learning modules must be AI-generated and personalized
- Suggestions must adapt to portfolio changes
- Gamification must track real user actions
Impact: All core features implemented as fully dynamic, no static placeholders in critical paths
Final MVP
The final MVP feature set was prioritized based on validated user needs and technical feasibility:
1. Portfolio Tracking & Analytics (Priority: Critical)
Why: Core value proposition - users need to see their actual investments. Without this, the platform has no context for personalization.
Validation:
- Directly addresses JTBD #1
- Enables all other features (suggestions, learning)
- Real-time data via yfinance provides immediate value
Implementation: Fully dynamic with real-time price fetching, multi-currency support, and historical snapshots.
2. AI-Powered Learning Modules (Priority: Critical)
Why: Differentiates from generic educational platforms. Personalization based on user profile and portfolio creates unique value.
Validation:
- Addresses JTBD #2 and #4
- AI generation allows infinite content variety without manual creation
- Country-specific content addresses localization needs
Implementation: Fully dynamic - modules generated on-demand using Gemini LLM, tailored to user's country, goals, and portfolio.
3. Adaptive Suggestions (Priority: High)
Why: Connects portfolio analysis to learning. Users don't know what to learn - AI identifies gaps and opportunities.
Validation:
- Addresses JTBD #4
- Creates engagement loop: portfolio → suggestions → learning → portfolio improvement
- Demonstrates AI value clearly
Implementation: Fully dynamic - analyzes portfolio snapshots and user profile to generate contextual suggestions.
4. Gamification System (Priority: High)
Why: Increases engagement and retention. Financial education is a long-term journey requiring consistent motivation.
Validation:
- Addresses JTBD #5
- Proven pattern in education apps
- Streaks encourage daily engagement
Implementation: Fully dynamic - tracks all user actions, calculates XP/levels/streaks in real-time, evaluates badges automatically.
5. Onboarding Flow (Priority: Medium)
Why: Collects essential user data for personalization. Without this, AI cannot generate relevant content.
Validation:
- Enables all personalization features
- Standard UX pattern users expect
- One-time investment with ongoing value
Implementation: Multi-step form collecting financial goals, experience, risk tolerance, country, etc.
Features Not Included (Future Considerations)
- Social features (leaderboards, sharing)
- Advanced portfolio analytics (options, derivatives)
- Mobile native apps
- Real-time notifications
- Payment integration
Rationale: These features don't address core JTBDs and would add complexity without validating core value proposition.
3. Functional and Dynamic MVP
Core Functionality
The MVP is fully operational and demonstrates all core functionality:
✅ Authentication & User Management
- Email/password and Google OAuth sign-up and login
- User profile creation and management
- Session management with JWT tokens
✅ Portfolio Management
- Add positions (ticker, quantity, average cost)
- Real-time portfolio analytics (value, P/L, allocations)
- Historical portfolio snapshots with configurable granularity
- Multi-currency support with FX conversion
✅ AI-Powered Learning
- Personalized module generation based on user profile and portfolio
- Country-specific content (30+ countries supported)
- Interactive quizzes with instant feedback
- Learning pathway visualization
✅ Adaptive Suggestions
- AI-generated suggestions analyzing portfolio and goals
- Automatic module generation for each suggestion
- Suggestion regeneration when pathway is completed
✅ Gamification
- XP and leveling system (10 levels)
- Daily learning streaks
- Achievement badges (learning, streak, portfolio milestones)
- Real-time notifications (XP gains, level ups, badges)
Dynamic vs. Static Content
Fully Dynamic Components
Portfolio Data:
- Real-time Prices: Fetched from yfinance API on-demand
- Implementation:
app/services/api/src/finquest_api/services/pricing.py
- Implementation:
- Portfolio Calculations: Computed from transactions using average cost method
- Implementation:
app/services/api/src/finquest_api/services/portfolio.py-_compute_positions()
- Implementation:
- Historical Snapshots: Generated on-demand using historical price data
- Implementation:
app/services/api/src/finquest_api/jobs/snapshots.py
- Implementation:
- FX Rates: Fetched from yfinance for currency conversion
- Implementation:
app/services/api/src/finquest_api/services/fx.py
- Implementation:
AI-Generated Content:
- Learning Modules: Generated by Gemini LLM based on user profile and portfolio
- Implementation:
app/services/api/src/finquest_api/services/module_generator.py - Trigger: When suggestions are generated or when pathway is completed
- Implementation:
- Suggestions: Generated by analyzing user profile and portfolio snapshot
- Implementation:
app/services/api/src/finquest_api/services/suggestion_generator.py - Trigger: After onboarding completion, when all suggestions are completed
- Implementation:
User Data:
- Gamification Stats: Calculated in real-time from user actions
- Implementation:
app/services/api/src/finquest_api/services/gamification.py
- Implementation:
- Learning Progress: Tracked per module completion
- Implementation:
app/services/api/src/finquest_api/db/models.py-ModuleCompletion,ModuleAttempt
- Implementation:
UI Components:
- Portfolio Charts: Render live data from API
- Implementation:
app/web/components/ValueChart.tsx
- Implementation:
- Suggestions Widget: Displays AI-generated suggestions
- Implementation:
app/web/components/SuggestionsWidget.tsx
- Implementation:
- Gamification UI: Updates in real-time based on events
- Implementation:
app/web/contexts/GamificationContext.tsx
- Implementation:
Static/Pre-seeded Components
Badge Definitions:
- Pre-seeded badge definitions in database
- Implementation:
app/services/api/scripts/seed_badges.py - Note: Badge definitions are static, but badge awards are dynamic based on user actions
UI Text & Labels:
- Static text for labels, buttons, headings
- Country names, currency codes
- Note: These are UI elements, not data - all user-facing data is dynamic
Configuration:
- XP reward values (static constants)
- Level thresholds (static constants)
- Implementation:
app/services/api/src/finquest_api/services/gamification.py-XP_REWARDS,LEVEL_THRESHOLDS
CUJ Implementation Status
All four core CUJs are fully dynamic:
- ✅ CUJ 1 (Portfolio Setup): Real-time market data, live calculations
- ✅ CUJ 2 (Learning Pathway): AI-generated modules, dynamic quiz scoring
- ✅ CUJ 3 (AI Suggestions): AI analysis of portfolio and profile
- ✅ CUJ 4 (Gamification): Real-time XP/streak/badge tracking
4. Test Coverage
Code Coverage
Backend (FastAPI):
- Testing Framework: pytest with pytest-cov
- Configuration:
app/services/api/pytest.ini - Coverage: 79.68%
Frontend (Next.js):
- Testing Framework: Vitest with React Testing Library
- Coverage Tool: v8 (via Vitest)
- Configuration:
app/web/vitest.config.ts - Coverage: 89.46%
E2E Testing:
- Framework: Playwright
- Configuration:
app/web/playwright.config.ts - Tests:
app/web/e2e/login.spec.ts
Continuous Integration (CI)
Backend CI Pipeline:
- Workflow:
.github/workflows/api-ci.yml - Jobs:
- Linting (ruff)
- Unit tests with coverage reporting
- LLM service tests
- Coverage Reports: HTML and JSON artifacts uploaded
Frontend CI Pipeline:
- Workflow:
.github/workflows/web-ci.yml - Jobs:
- Unit tests with coverage
- Linting and type checking
- E2E tests (Playwright)
Code Quality Tools
Backend:
- Linter: ruff (Python)
- Type Checking: Python type hints with mypy (implicit)
- Configuration:
app/services/api/pyproject.toml
Frontend:
- Linter: ESLint
- Type Checking: TypeScript compiler
- Configuration:
app/web/eslint.config.mjs,app/web/tsconfig.json
CI Run Link
Links to recent successful GitHub Actions CI run with test execution and coverage reports:
- Frontend web app: CI run with 89.46% coverage
- Backend API: CI run with 79.68% coverage
5. Demo Recording
Video Submission
Untitled.3.mp4
Accompanying Write-up
To test the app, try out this typical flow:
- Signup as a new user
- complete the onboarding form
- Enter information about your portfolio in the
portfoliotab - Go to the
learntab to see the list of personalized modules to help you achieve your financial goals - Read through the first module and attempt the quiz
The important work we've done that can be noticed in the onboarding flow:
- Smooth onboarding experience
- Historical finance data fetching for portfolio performance analytics
- Hyperpersonalized and actionable AI learning modules and quizzes
- Gamification element for an engaging user experience
6. Deployment Documentation
Supabase setup
- Create a new project in Supbase
- In
Settings > API, copy the following and note down to set up environment variables for frontend and backend deployments:
Project URL → NEXT_PUBLIC_SUPABASE_URL (web) / SUPABASE_URL (API)
anon public key → NEXT_PUBLIC_SUPABASE_ANON_KEY (web) / SUPABASE_KEY (API)
JWT Secret → SUPABASE_JWT_SECRET (API only)
- Configure Google OAuth redirect by creating a project on the Google Auth Platform and adding whatever the frontend production URL will be as the redirect URL
Backend deployment instructions
- Create a new Blueprint in Render and connect this GitHub repository. Render should detect the
render.yamlconfiguration in the root directory containing deployment configuration details. - Upon creation, navigate to the
Environmentpage and create environment variables for every key inapp/services/api/.env.example. This involves pasting the previously mentioned Supabase variables, as well as API keys from Google Gemini. - Redeploy the service to ensure the environment variables take effect
- Copy the production deployment URL to pass to the frontend
Frontend deployment instructions
- Create a new web project on Vercel and connect this repository
- Ensure the Framework Preset is set to Next.js and change the root directory to
app/web - Add in all the environment variable keys listed in
app/web/.env.exampleand paste in the backend deployment URL asNEXT_PUBLIC_API_URL, Supabase values, and settingNEXT_PUBLIC_SITE_URLto the frontend deployment URL
Current Deployment Architecture:
- Frontend: Vercel (automatic deployments from GitHub)
- Backend: Render (FastAPI service)
- Database: Supabase PostgreSQL (serverless)
- Authentication: Supabase
Reference Documentation:
- Backend README:
app/services/api/README.md - Frontend README:
app/web/README.md
7. Final Architecture Diagram
The final MVP architecture diagram reflects the architecture of the final MVP:
Diagram: architecture/final-diagram.png
Architecture Components and Code Integration
The following list provides links to different sections of code which integrate with the different architecture components:
FRONTEND (Next.js on Vercel)
- Frontend Application Entry Point - Next.js application initializes with Auth and Gamification providers, sending API requests with JWT tokens to the FastAPI backend.
- Frontend API Client - Frontend makes HTTPS requests to FastAPI backend endpoints, including JWT tokens in Authorization headers for authenticated requests.
- Frontend Authentication Context - Frontend authenticates users with Supabase Auth service and manages JWT tokens for API requests.
- Frontend Gamification Context - Frontend sends gamification events (quiz completion, module completion, login) directly to the Gamification router in the backend API.
BACKEND API (FastAPI on Render)
- FastAPI Main Application - FastAPI application receives API requests from frontend, validates JWT tokens, and routes requests to appropriate domain routers.
- Auth Router - Auth router sends sign up/login requests to Supabase Auth and validates JWT tokens for protected endpoints.
- Portfolio Router - Portfolio router requests price data from MARKET DATA service and triggers snapshot generation in BACKGROUND JOBS service.
- Users Router - Users router calls AI SERVICES to generate personalized suggestions based on user profile and portfolio data.
- Modules Router - Modules router calls AI SERVICES to generate learning modules and stores module content and user progress in PostgreSQL.
- Gamification Router - Gamification router receives events from frontend and updates gamification statistics in PostgreSQL database.
- JWT Validation Utilities - Backend validates JWT tokens from Supabase Auth and retrieves or creates user records in PostgreSQL based on authenticated user ID.
AI SERVICES (Integrated in FastAPI)
- LLM Service Interface - Provider-agnostic LLM service interface that routes requests to the configured LLM provider (Gemini or OpenAI).
- Gemini Provider - Gemini provider makes LLM API calls to external Google Gemini service and returns structured responses for module and suggestion generation.
- Module Generator - Module generator uses the LLM service to generate personalized learning modules based on user profile and stores them in PostgreSQL.
- Suggestion Generator - Suggestion generator analyzes user portfolio and profile using the LLM service to generate personalized learning suggestions and stores them in PostgreSQL.
MARKET DATA (yfinance Integration)
- Pricing Service - Pricing service fetches real-time stock prices from external yfinance API and caches them in PostgreSQL database to reduce API calls.
- Instruments Service - Instruments service resolves instrument symbols via yfinance API and creates or updates instrument records in PostgreSQL database.
- FX Service - FX service fetches foreign exchange rates from yfinance API for currency conversion in portfolio calculations.
BACKGROUND JOBS (Snapshot Generation)
- Snapshot Generator - Snapshot generator creates historical portfolio valuation snapshots using historical price data and stores them in PostgreSQL database.
Data Storage (PostgreSQL on Supabase)
- Database Models - SQLAlchemy ORM models define all database tables (users, portfolios, transactions, modules, suggestions, gamification stats) that store application data.
- Database Session Management - Database session manager creates connection pool to Supabase PostgreSQL database and provides session dependency injection for all backend services.
Authentication Service (Supabase Auth)
- Backend Supabase Client - Backend initializes Supabase client to validate JWT tokens from Supabase Auth service for protected API endpoints.
- Frontend Supabase Client - Frontend initializes Supabase client to authenticate users with Supabase Auth service and receive JWT tokens for API requests.
