Track real-time stock prices, build personalized watchlists, get AI-powered market insights, and receive daily news summaries - all in one sleek, dark-themed dashboard.
- About
- Features
- Screenshots
- Tech Stack
- Architecture
- Getting Started
- Project Structure
- Core Modules
- API Integrations
- Database Schema
- Deployment
- Contributing
- License
Signalist is a full-stack stock market intelligence platform designed for retail investors who want a centralized hub for market data, personal watchlists, and AI-driven insights. Instead of juggling multiple tabs and services, Signalist brings together live charts, company fundamentals, personalized alerts, and daily AI-generated market summaries into a single, cohesive experience.
Whether you're a growth investor tracking tech stocks or a conservative investor monitoring blue-chip dividends, Signalist adapts to your investment profile and delivers the information that matters to you.
- Retail Investors looking for a clean, all-in-one market dashboard
- Day Traders who need quick access to live charts and technical analysis
- Passive Investors who want daily summaries without constant monitoring
- Students & Learners exploring stock markets with real data
A four-widget dashboard powered by TradingView showing market overview, sector heatmaps, top stories, and major index quotes - all updating in real time.
Instant stock search via a command palette. Type any symbol or company name and get results from Finnhub's global database. Results show symbol, company name, exchange, stock type, and whether the stock is already in your watchlist.
Add any stock to your watchlist with one click. The watchlist page enriches each entry with live data - current price, daily change percentage, market capitalization, and P/E ratio - all fetched from Finnhub in real time.
Each stock gets a dedicated page with six TradingView widgets: symbol info, advanced candlestick chart, technical analysis indicators, company profile, baseline chart, and financials breakdown.
Full email/password authentication with a profile-based onboarding flow. During sign-up, users specify their country, investment goals, risk tolerance, and preferred industry - data that powers personalized AI features.
- Welcome Email - On sign-up, Google Gemini generates a personalized introduction based on the user's investment profile
- Daily News Summary - A scheduled job fetches news for each user's watchlist, sends the articles to Gemini for summarization, and delivers a formatted HTML email every day at 12:00 PM UTC
Replace the placeholders below with actual screenshots of your application.
| Screen | Preview |
|---|---|
| Dashboard | screenshots/dashboard.png |
| Sign Up | screenshots/sign-up.png |
| Sign In | screenshots/sign-in.png |
| Stock Search | screenshots/stock-search.png |
| Stock Details | screenshots/stock-details.png |
| Watchlist | screenshots/watchlist.png |
| Email Notification | screenshots/email-notification.png |
| Layer | Technology | Purpose |
|---|---|---|
| Framework | Next.js 15 (App Router) | Server components, routing, API routes |
| Language | TypeScript 5 | Type safety across the entire codebase |
| UI Library | React 19 | Component-based user interface |
| Styling | Tailwind CSS 4 | Utility-first CSS with custom dark theme |
| Components | Radix UI + Shadcn/ui | Accessible, composable UI primitives |
| Forms | React Hook Form | Performant form handling with validation |
| Notifications | Sonner | Toast notifications |
| Authentication | Better Auth | Session-based email/password auth |
| Database | MongoDB Atlas + Mongoose | Cloud-hosted NoSQL database |
| Stock Data | Finnhub API | Quotes, search, company profiles, news |
| Charts | TradingView Widgets | Embedded financial charts and analysis |
| Task Queue | Inngest | Serverless background jobs and cron |
| AI | Google Gemini 2.5 Flash | Personalized content generation |
| Nodemailer (Gmail SMTP) | Transactional email delivery | |
| Deployment | Vercel | Serverless hosting with edge network |
| Build Tool | Turbopack | Fast development builds |
┌─────────────────────────────────────────────────────────────┐
│ Client (Browser) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
│ │Dashboard │ │ Search │ │Watchlist │ │Stock Detail│ │
│ │(Widgets) │ │(Cmd + K) │ │ (Table) │ │ (6 Charts) │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────────┘ │
│ │ │ │ │ │
│ └──────────────┴─────────────┴──────────────┘ │
│ │ │
│ TradingView CDN │
└───────────────────────────┬─────────────────────────────────┘
│
┌───────▼────────┐
│ Next.js App │
│ (App Router) │
│ │
│ Server Actions │
│ Middleware │
│ API Routes │
└──┬────┬────┬───┘
│ │ │
┌──────────┘ │ └──────────┐
│ │ │
┌───────▼──────┐ ┌─────▼──────┐ ┌──────▼──────┐
│ Better Auth │ │ Finnhub API│ │ Inngest │
│ (Sessions) │ │ (Stocks) │ │ (Jobs/AI) │
└───────┬──────┘ └────────────┘ └──────┬──────┘
│ │
┌───────▼──────┐ ┌───────▼──────┐
│MongoDB Atlas │ │ Google Gemini│
│ (Database) │ │ (AI Model) │
└──────────────┘ └───────┬──────┘
│
┌───────▼──────┐
│ Nodemailer │
│ (Gmail SMTP) │
└──────────────┘
- Node.js 18.17 or later
- npm 9 or later
- A MongoDB Atlas cluster (create one free)
- A Finnhub API key (register free)
- A Google Gemini API key (get one)
- A Gmail App Password for email delivery (how to create)
- (Optional) An Inngest account for background job management (sign up)
# Clone the repository
git clone https://github.com/aridepai17/SIGNALIST.git
# Navigate to the project directory
cd SIGNALIST/realtimestockmarket
# Install dependencies
npm installCreate a .env file in the realtimestockmarket directory with the following variables:
# App
NODE_ENV=development
NEXT_PUBLIC_BASE_URL=http://localhost:3000
# MongoDB
MONGODB_URI=mongodb+srv://<username>:<password>@<cluster>.mongodb.net/?appName=<app>
# Authentication (Better Auth)
BETTER_AUTH_SECRET=<generate-a-random-secret-string>
BETTER_AUTH_URL=http://localhost:3000
# Finnhub Stock API
FINNHUB_API_KEY=<your-finnhub-api-key>
# Google Gemini AI
GEMINI_API_KEY=<your-gemini-api-key>
# Email (Gmail SMTP via Nodemailer)
NODEMAILER_EMAIL=<your-gmail@gmail.com>
NODEMAILER_PASSWORD=<your-gmail-app-password>| Variable | Required | Description |
|---|---|---|
MONGODB_URI |
Yes | MongoDB Atlas connection string |
BETTER_AUTH_SECRET |
Yes | Random string used to sign session tokens |
BETTER_AUTH_URL |
Yes | Base URL of the application |
FINNHUB_API_KEY |
Yes | API key from Finnhub for stock data |
GEMINI_API_KEY |
Yes | Google Gemini API key for AI features |
NODEMAILER_EMAIL |
Yes | Gmail address for sending emails |
NODEMAILER_PASSWORD |
Yes | Gmail App Password (not your regular password) |
NEXT_PUBLIC_BASE_URL |
Yes | Public-facing base URL |
Note: For
BETTER_AUTH_SECRET, you can generate a secure random string with:openssl rand -base64 32
# Start the development server (with Turbopack)
npm run devOpen http://localhost:3000 in your browser.
To run Inngest functions locally (email jobs, cron tasks):
# In a separate terminal
npx inngest-cli@latest devrealtimestockmarket/
│
├── app/ # Next.js App Router
│ ├── (auth)/ # Auth route group (public)
│ │ ├── layout.tsx # Auth layout with session redirect
│ │ ├── sign-in/page.tsx # Sign-in form
│ │ └── sign-up/page.tsx # Sign-up form with profile onboarding
│ ├── (root)/ # Protected route group
│ │ ├── layout.tsx # Root layout with auth guard & header
│ │ ├── page.tsx # Dashboard (TradingView widgets)
│ │ ├── watchlist/page.tsx # Watchlist table with live data
│ │ └── stocks/[symbol]/ # Stock detail page
│ │ └── page.tsx # Symbol-specific charts & info
│ ├── api/inngest/route.ts # Inngest webhook handler
│ ├── layout.tsx # Root HTML layout (fonts, metadata)
│ └── globals.css # Global styles & CSS variables
│
├── components/
│ ├── forms/ # Form field components
│ │ ├── InputField.tsx # Text/password input with validation
│ │ ├── SelectField.tsx # Dropdown select with options
│ │ ├── CountrySelectField.tsx # Country picker with flag icons
│ │ └── FooterLink.tsx # "Don't have an account?" link
│ ├── ui/ # Shadcn/ui base components
│ │ ├── button.tsx
│ │ ├── dialog.tsx
│ │ ├── dropdown-menu.tsx
│ │ ├── input.tsx
│ │ ├── table.tsx
│ │ └── ...
│ ├── Header.tsx # App header with nav, search, user menu
│ ├── NavItems.tsx # Navigation links
│ ├── SearchCommand.tsx # Cmd+K search modal
│ ├── TradingViewWidget.tsx # Generic TradingView widget renderer
│ ├── WatchlistButton.tsx # Add/remove from watchlist toggle
│ ├── WatchlistTable.tsx # Watchlist data table
│ └── UserDropdown.tsx # User avatar & dropdown menu
│
├── database/
│ ├── models/
│ │ └── watchlist.model.ts # Mongoose watchlist schema
│ └── mongoose.ts # MongoDB connection singleton
│
├── hooks/
│ ├── useDebounce.ts # Debounce hook for search input
│ └── useTradingViewWidget.tsx # TradingView script loader hook
│
├── lib/
│ ├── actions/
│ │ ├── auth.actions.ts # Sign-up, sign-in, sign-out server actions
│ │ ├── finnhub.actions.ts # Stock search, news fetching
│ │ ├── watchlist.actions.ts # Watchlist CRUD operations
│ │ └── user.actions.ts # User queries for email notifications
│ ├── better-auth/
│ │ └── auth.ts # Better Auth initialization
│ ├── inngest/
│ │ ├── client.ts # Inngest client with Gemini AI step
│ │ ├── functions.ts # Welcome email & daily news jobs
│ │ └── prompts.ts # AI prompt templates
│ ├── nodemailer/
│ │ ├── index.ts # Nodemailer transport setup
│ │ └── templates.ts # HTML email templates
│ ├── constants.ts # Popular stocks, TradingView configs
│ └── utils.ts # Date ranges, article formatting, cn()
│
├── middleware/
│ └── index.ts # Route protection middleware
│
├── types/
│ └── global.d.ts # Global TypeScript type definitions
│
├── public/
│ └── assets/
│ ├── icons/ # SVG icons (logo, star, nav icons)
│ └── images/ # Static images (dashboard preview)
│
├── .env # Environment variables (not committed)
├── next.config.ts # Next.js configuration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── components.json # Shadcn/ui configuration
├── eslint.config.mjs # ESLint 9 configuration
└── package.json # Dependencies and scripts
Signalist uses Better Auth for session-based email/password authentication stored in MongoDB.
How it works:
- User signs up with email, password, and profile details (country, goals, risk tolerance, industry)
- Better Auth creates a user record in the
usercollection and issues a session cookie - Middleware on protected routes validates the session cookie before allowing access
- Auth layouts redirect authenticated users away from
/sign-inand/sign-up, and unauthenticated users away from protected pages
Key files:
lib/better-auth/auth.ts— Auth instance initialization (lazy-loaded, cached)lib/actions/auth.actions.ts— Server actions for sign-up, sign-in, sign-outmiddleware/index.ts— Session cookie validation on protected routesapp/(auth)/layout.tsx— Redirects logged-in users to dashboardapp/(root)/layout.tsx— Redirects guests to sign-in
The search system uses Finnhub's symbol search API with intelligent caching and a command palette UI.
How it works:
- User presses
Cmd/Ctrl + Kto open the search modal - Input is debounced (300ms) before firing a request
- If the query is empty, the top 10 popular stocks are shown (profiles cached for 1 hour)
- If a query is provided, Finnhub's
/searchendpoint returns matching symbols (cached for 30 minutes) - Each result is cross-referenced with the user's watchlist to show an "in watchlist" indicator
Popular stocks library: 80+ pre-configured symbols spanning US markets (AAPL, GOOGL, TSLA...), Indian markets (RELIANCE.NS, TCS.NS...), and Chinese markets (BABA, JD...).
Key files:
components/SearchCommand.tsx— Command palette with debounced searchlib/actions/finnhub.actions.ts—searchStocks()with cachinglib/constants.ts—POPULAR_STOCK_SYMBOLSarray
Users can build a personal watchlist that persists across sessions and enriches each stock with live market data.
How it works:
- User clicks the watchlist button on any stock (search results or detail pages)
- Server action creates/removes a document in the
watchlistcollection - The watchlist page fetches all saved symbols and enriches each with three parallel Finnhub API calls:
/quote— Current price, daily change percentage/stock/profile2— Company name, market capitalization/stock/metric— P/E ratio and other financial metrics
- Data is formatted for display (e.g., market cap as
$2.87T,$156.42B, or$892.31M)
Key files:
lib/actions/watchlist.actions.ts— CRUD operations + data enrichmentcomponents/WatchlistButton.tsx— Toggle button componentcomponents/WatchlistTable.tsx— Data table with live metricsdatabase/models/watchlist.model.ts— Mongoose schema
Each stock gets a dedicated page with six TradingView embedded widgets providing comprehensive market analysis.
Widgets displayed:
| Widget | Description |
|---|---|
| Symbol Info | Current price, daily change, volume |
| Advanced Chart | Interactive candlestick chart with drawing tools |
| Technical Analysis | Buy/sell indicators and oscillators |
| Company Profile | Business description, sector, employees |
| Baseline Chart | Price performance against baseline |
| Financials | Revenue, earnings, balance sheet data |
Symbol format handling: Indian exchange symbols are automatically converted for TradingView compatibility (e.g., RELIANCE.NS becomes NSE:RELIANCE, TCS.BO becomes BSE:TCS).
Key files:
app/(root)/stocks/[symbol]/page.tsx— Stock detail pagecomponents/TradingViewWidget.tsx— Generic widget rendererhooks/useTradingViewWidget.tsx— Script injection hook
The main dashboard displays four TradingView widgets in a responsive grid layout.
| Widget | Content |
|---|---|
| Market Overview | Tabbed view of Financial, Technology, and Services sectors |
| Stock Heatmap | Color-coded sector performance map |
| Top Stories | Timeline of latest market news |
| Market Quotes | Live quotes for major indices (S&P 500, NASDAQ, Dow Jones, etc.) |
Key files:
app/(root)/page.tsx— Dashboard pagelib/constants.ts— Widget configuration objects
Signalist uses Inngest for background job orchestration and Google Gemini for AI-powered content generation.
User Signs Up
│
▼
Inngest receives "app/user.created" event
│
▼
Gemini generates personalized intro
(based on country, goals, risk, industry)
│
▼
HTML template populated with AI content
│
▼
Nodemailer sends via Gmail SMTP
Cron triggers at 12:00 PM UTC daily
│
▼
Fetch all users from MongoDB
│
▼
For each user:
├── Fetch watchlist symbols
├── Fetch news for those symbols (Finnhub)
├── Fall back to general news if no watchlist
├── Send articles to Gemini for summarization
├── Gemini returns formatted HTML summary
└── Nodemailer sends personalized email
AI prompts are designed to produce concise, actionable market summaries with sections for market overview, top gainers/losers, and a "bottom line" takeaway.
Key files:
lib/inngest/client.ts— Inngest client with Gemini AI middlewarelib/inngest/functions.ts— Job definitions (welcome email, daily news)lib/inngest/prompts.ts— AI prompt templateslib/nodemailer/index.ts— Email transport setuplib/nodemailer/templates.ts— HTML email templates
| Endpoint | Purpose | Cache TTL |
|---|---|---|
/search?q= |
Symbol search | 30 minutes |
/quote?symbol= |
Real-time price & change | 60 seconds |
/stock/profile2?symbol= |
Company info & market cap | 1 hour |
/stock/metric?symbol= |
P/E ratio & financial metrics | 1 hour |
/company-news?symbol= |
Company-specific news articles | 5 minutes |
/news?category=general |
General market news | 5 minutes |
Embedded via external scripts from s3.tradingview.com. All widgets use the dark theme (colorTheme: "dark") with transparent backgrounds to match the app's design system.
- Model:
gemini-2.5-flash-lite(cost-effective, low latency) - Use cases: Welcome email personalization, daily news summarization
- Integration: Via Inngest AI step middleware
| Field | Type | Description |
|---|---|---|
userId |
String |
References the Better Auth user ID |
symbol |
String |
Stock ticker symbol (uppercase) |
company |
String |
Company name at time of addition |
addedAt |
Date |
Timestamp of when the stock was added |
createdAt |
Date |
Mongoose auto-generated |
updatedAt |
Date |
Mongoose auto-generated |
Indexes: Compound unique index on (userId, symbol) prevents duplicate entries.
| Collection | Purpose |
|---|---|
user |
User accounts (email, name, hashed password) |
session |
Active sessions linked to users |
account |
Auth provider accounts |
verification |
Email verification tokens |
- Push the repository to GitHub
- Import the project in Vercel
- Set the Root Directory to
realtimestockmarket - Add all environment variables in the Vercel dashboard (Settings > Environment Variables)
- Important: In MongoDB Atlas, whitelist
0.0.0.0/0under Network Access to allow Vercel's dynamic serverless IPs
Vercel serverless functions use dynamic IP addresses. To ensure connectivity:
- Go to MongoDB Atlas > Network Access
- Click Add IP Address
- Select Allow Access from Anywhere (
0.0.0.0/0) - Confirm
This is the standard approach for serverless deployments. Your database is still protected by the username/password in your connection string.
- Create an account at inngest.com
- Connect your Vercel deployment
- The
/api/inngestroute auto-registers functions - The daily news cron job (
0 12 * * *) runs automatically once connected
Contributions are welcome. To contribute:
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature) - Commit your changes (
git commit -m "feat: add your feature") - Push to the branch (
git push origin feature/your-feature) - Open a Pull Request
Please follow the existing code style and commit message conventions (feat:, fix:, docs:, etc.).
This project is open source. See the repository for license details.
Built with Next.js, MongoDB, Finnhub, TradingView, Inngest, and Google Gemini






