Overview
Project: Signalist
Repo: Ujjwal5705/Signalist
Tech Stack: Next.js, TypeScript, TailwindCSS, Better Auth, MongoDB, Finnhub API, Inngest, Gemini, Email, Nodemailer
Signalist is an AI-powered stock market platform built for investors who want more than a dashboard. It lets users track real-time prices, manage watchlists, set precision alerts, and receive AI-generated market summaries—while an admin layer handles stock management, news publishing, and user activity monitoring.
The core challenge was not just "wrapping financial data in a nice UI." It was building a system that could react to market events in real time, generate grounded AI insights without hallucinating price data, and deliver personalized alerts reliably at scale—while keeping the experience fast enough for daily trading decisions.
Problem
Retail investors and market watchers face a fragmented experience across existing tools:
- Real-time price data is scattered across platforms with inconsistent update frequencies
- Alerts are either too primitive (price only) or buried behind paywalls
- Company insights—PE ratios, EPS, analyst ratings, filings—require jumping between multiple sources
- AI summaries, where they exist, aren't grounded in live data and quickly go stale
- Developers who want to build financial tools face high integration overhead across auth, data, email, and AI layers
The existing workflow for a serious investor means eight tabs open, manual copy-paste, and a lot of missed signals.
Solution
Signalist compresses that fragmented workflow into a single workspace. A user lands on their dashboard, and the system:
- Fetches live market data from Finnhub—prices, candlestick history, PE ratios, EPS, analyst ratings, and recent filings
- Maintains a personalized watchlist with per-user alert thresholds for price changes and volume spikes
- Fires event-driven workflows via Inngest when thresholds are crossed—sending instant email notifications through Nodemailer
- Generates AI-powered digests using Gemini—daily summaries, earnings notifications, and sentiment scores grounded in real company data
- Surfaces admin controls for managing the stock universe, publishing market news, and monitoring engagement metrics
Every alert is traced back to a real price event. Every AI summary is generated against live data retrieved at request time—not cached opinions.
Architecture
Signalist is built as a full-stack Next.js application with clearly separated concerns across data, auth, workflows, and AI.
-
Frontend (Next.js / TypeScript / Shadcn / TailwindCSS): A clean, component-driven interface with interactive line and candlestick charts, an intelligent stock search, a watchlist manager, and a company insights panel. Shadcn provides the accessible component primitives; TailwindCSS handles all layout and responsive behavior. Admin routes are gated and rendered separately from the user-facing workspace.
-
Authentication (Better Auth): Framework-agnostic auth with built-in support for email/password login, social sign-on, and multi-factor authentication. All protected routes validate session tokens before rendering any financial data.
-
Database (MongoDB): Stores users, watchlists, alert configurations, stock metadata, news, and admin activity logs in flexible JSON-like documents. Dynamic schemas made it practical to iterate on alert structures and user preferences without migrations.
-
Real-Time Data Layer (Finnhub API): The source of truth for all market data. Price feeds, historical OHLCV data, fundamental metrics, and analyst ratings are all fetched from Finnhub and cached appropriately to respect rate limits while keeping dashboards current.
-
Event-Driven Workflow Engine (Inngest): The backbone of Signalist's automation layer. Inngest manages alert scheduling, price threshold checks, AI digest generation, and earnings notifications as reliable background jobs—decoupled from the request cycle entirely.
-
AI Layer (Gemini): Powers market summaries, daily digests, and sentiment analysis. All prompts are constructed with live Finnhub data in context, ensuring outputs are grounded in current company performance rather than training-time knowledge.
-
Email Delivery (Nodemailer): Handles all transactional email—price alerts, daily digests, earnings reports—via SMTP with OAuth2 support.
Challenges
1. Real-Time Alert Reliability
Price alerts cannot miss. A threshold breach that doesn't trigger a notification destroys trust immediately. I built the alert pipeline on top of Inngest's durable execution model—each check is a retryable event, not a fire-and-forget cron job. If an email delivery fails, the workflow retries without re-evaluating the threshold or double-firing.
2. Grounding AI Summaries in Live Data
Gemini, like any LLM, will generate plausible-sounding financial commentary based on training data that is months or years out of date. Every AI summary call in Signalist first fetches current Finnhub data for the relevant tickers—price, EPS, analyst ratings, recent news—and injects it directly into the prompt. The model is explicitly instructed to reason only from the provided context. The result is a summary that reflects today's numbers, not a stale prior.
3. Decoupling Workflows from the Request Cycle
Early versions tried to do too much in a single API route—fetch data, check alerts, send emails, generate summaries—all synchronously. This made response times unpredictable and created silent failure modes when any downstream call timed out. Moving all automation to Inngest background functions meant the API layer returned immediately, and heavy processing happened reliably in the background with full observability.
4. Admin vs. User Separation at Scale
The admin dashboard—stock management, news publishing, user monitoring—shares the same Next.js app as the user-facing product. Separating concerns required a clean role model in Better Auth, server-side route guards on every admin API, and a completely distinct UI section. Any overlap in data access would have been a security boundary violation, not just a UX problem.
Learnings
Building a financial platform on top of live data and event-driven workflows forced a reliability discipline that simple CRUD apps don't require. You cannot get away with synchronous pipelines when an alert that fires two hours late is worthless.
The biggest shift was moving from request-first to event-first thinking. The user action that triggers an alert is not the same as the moment the alert condition is met—and conflating the two is where most financial notification systems fail. Inngest made it possible to separate those concerns cleanly, making the whole system more predictable and easier to debug.