- ✨ Introduction
- 🌍 The ODDYSEY Manifesto
- ⚙️ Tech Stack
- 🔋 Features
- 🖼 See It In Action
- ⚡ Quick Start
- 🐳 Docker Setup
- 🔐 Environment Variables
- 🧱 Project Structure
- 📡 Data & Integrations
- 🤝 Contributing
- 🛡️ Security
- 📝 License
- 🙏 Credits
WatchTower is an enterprise-grade, open-source stock market platform designed for serious traders and institutional investors. Built on modern architecture with Next.js 15, it delivers institutional-quality market data, analytics, and execution — without the Bloomberg Terminal price tag.
Built openly. Self-hosted. Fully yours.
Note: WatchTower is not a brokerage. Market data is powered by Finnhub and may be delayed based on provider rules and your configuration. Nothing here is financial advice.
We live in a world where professional-grade tools are locked behind enterprise paywalls. Where market intelligence is rationed by subscription tiers. Where the best analytics are reserved for institutional players.
We believe there's a better way.
Our Belief: Powerful tools should belong to everyone. Market intelligence should be open, auditable, and self-hostable. Developers and traders shouldn't need a Bloomberg Terminal budget to make informed decisions.
Our Mission: Build free, open-source tools that make a real difference:
- Platforms that professionals and individual traders can use without barriers.
- Code that is open, auditable, and extensible.
- Infrastructure you own — your data, your servers, your rules.
Our Promise: We will never lock features. We will never charge for access. We run on transparency, community, and the belief that the best software is built in the open.
Our Call: If you've ever wanted institutional-grade market tools without the institutional price tag — you're in the right place.
Because the future belongs to those who build it openly.
Core
| Technology | Role | |
|---|---|---|
| ⚡ | Next.js 15 | App Router, Server Components, Server Actions |
| 🎨 | Tailwind CSS + shadcn/ui | Styling + accessible component library |
| 🔷 | TypeScript | End-to-end type safety |
Auth & Data
| Technology | Role | |
|---|---|---|
| 🗄 | MongoDB | Database (via Mongoose) |
| 🔐 | Better Auth | Email/password authentication |
| 📈 | Finnhub | Real-time market data, news, fundamentals |
| 📊 | TradingView | Interactive chart widgets |
Automation & Comms
| Technology | Role | |
|---|---|---|
| ⚙️ | Inngest | Background jobs and event-driven workflows |
| 🤖 | Google Gemini | AI summaries and sentiment analysis |
| 📧 | Nodemailer | Alert and digest emails |
Authentication
- Email/password auth with Better Auth + MongoDB adapter
- Protected routes enforced via Next.js middleware
Global Search — ⌘K / Ctrl+K
- Instant symbol lookup with real-time suggestions as you type
- Add to watchlist directly from results
Watchlist & Portfolio
- Per-user watchlist stored in MongoDB (unique symbol per user)
- Total value, daily P&L, return %, top performer and biggest loser — live
- Price, change, market cap, sector, and exchange at a glance
Professional Charts
- TradingView candlestick, baseline, technicals, and advanced charts
- Multiple timeframes (1D → 1Y)
- Embedded natively — no iframe lag
Smart Alerts
- Upper/lower price thresholds
- Automated checking via Inngest background jobs (every 15 minutes)
- Email notifications on trigger
- Visual progress bars and status tracking
- Bulk filter by symbol or status
Market News
- Aggregated market news from Finnhub
- OG image scraping with 3 user-agent fallbacks (no more walls of publisher logos)
- Keyword-based Unsplash fallback images
- Paginated with reading time estimates
AI Insights
- Gemini-powered daily market digests
- Sentiment analysis on watchlist stocks
- Earnings summaries and personalized recommendations
Settings
- Profile, notifications, investment goals, risk tolerance, preferred industries
Event Architecture
- Inngest for reliable background workflows
- Scheduled alert checks every 15 minutes
- Daily digest generation at market close
- Automatic retries on failure
Privacy & Ownership
- No tracking, no analytics scripts
- Your data stays in your database
- Self-host for full control — GDPR-friendly by design
- Node.js 18+ and npm
- Free accounts on Finnhub, MongoDB Atlas
- Optional: Google AI Studio for AI features
- Gmail account for email alerts (or any SMTP provider)
git clone https://github.com/TheODDYSEY/watchtower_stock-tracker-app.git
cd watchtower_stock-tracker-app
npm install
cp .env.example .envOpen .env and fill in your keys (see Environment Variables).
# Start the app
npm run dev
# Start background jobs (separate terminal)
npx inngest-cli@latest devOpen localhost:3000 — you're live.
npm run build && npm startRun WatchTower and MongoDB with Docker Compose.
Prerequisites: Docker and Docker Compose installed.
docker-compose.yml includes two services:
watchtower(this app)mongodb(MongoDB with a persistent volume)
For the Docker setup, use a local MongoDB connection string:
MONGODB_URI=mongodb://root:example@mongodb:27017/watchtower?authSource=adminStart the stack:
# From the repository root
docker compose up -d mongodb && docker compose up -d --buildAccess the app at http://localhost:3000.
# Or build and run manually
docker build -t watchtower .
docker run -p 3000:3000 --env-file .env watchtowerNotes:
- The app service
depends_onthe mongodb service.- Data persists across restarts via the Docker volume.
- Use
authSource=adminin your connection string for the root user.
Create .env at the project root:
Hosted (MongoDB Atlas):
NODE_ENV=development
NEXT_PUBLIC_BASE_URL=http://localhost:3000
# Finnhub
NEXT_PUBLIC_FINNHUB_API_KEY=your_key
FINNHUB_API_KEY=your_key
# MongoDB (Atlas)
MONGODB_URI=mongodb+srv://user:pass@cluster.mongodb.net/watchtower
# Auth (generate secret: openssl rand -base64 32)
BETTER_AUTH_SECRET=your_secret
BETTER_AUTH_URL=http://localhost:3000
# Gemini (optional — powers AI features)
GEMINI_API_KEY=your_key
# Email alerts (Gmail app password)
NODEMAILER_EMAIL=you@gmail.com
NODEMAILER_PASSWORD=your_app_passwordLocal (Docker Compose) MongoDB:
NODE_ENV=development
NEXT_PUBLIC_BASE_URL=http://localhost:3000
# Finnhub
NEXT_PUBLIC_FINNHUB_API_KEY=your_key
FINNHUB_API_KEY=your_key
# MongoDB (Docker)
MONGODB_URI=mongodb://root:example@mongodb:27017/watchtower?authSource=admin
# Auth
BETTER_AUTH_SECRET=your_secret
BETTER_AUTH_URL=http://localhost:3000
# Gemini (optional)
GEMINI_API_KEY=your_key
# Email
NODEMAILER_EMAIL=you@gmail.com
NODEMAILER_PASSWORD=your_app_passwordNotes:
- Keep private keys server-side.
NEXT_PUBLIC_variables are exposed to the browser.- In production, prefer a dedicated SMTP provider over a personal Gmail.
- Do not hardcode secrets in the Dockerfile — use
.envand Compose.
app/
(auth)/
layout.tsx
sign-in/page.tsx
sign-up/page.tsx
(root)/
layout.tsx
page.tsx
stocks/[symbol]/page.tsx
api/inngest/route.ts
globals.css
layout.tsx
components/
ui/… # shadcn/radix primitives
Header.tsx
SearchCommand.tsx
WatchlistButton.tsx
…
database/
models/
mongoose.ts
lib/
actions/… # server actions (auth, finnhub, user, watchlist, alerts)
better-auth/…
inngest/… # client, functions, scheduled jobs
nodemailer/… # transporter, email templates
constants.ts
utils.ts
public/
assets/
images/ # logo
showcase/ # dashboard, watchlist, news, alerts, settings screenshots
Finnhub
Live prices, volume, day range, market cap, PE ratio, sector classification, pre/after-hours data, and market news. Set NEXT_PUBLIC_FINNHUB_API_KEY and FINNHUB_API_KEY. Free tiers may return delayed quotes; respect rate limits and API terms.
TradingView Embeddable widgets for candlestick charts, baseline charts, technicals, symbol info, and company financials — embedded natively, no iframe lag.
Better Auth + MongoDB Email/password with MongoDB adapter. Session validation via middleware; all routes are protected with public exceptions for sign-in, sign-up, and static assets.
Inngest Workflows:
user.created→ AI-personalized welcome email- Every 15 minutes → price alert checks
- Daily cron at market close → AI digest email per user
Local dev: npx inngest-cli@latest dev
Email (Nodemailer) Gmail transport. Update credentials or switch to your SMTP provider. Templates for alert triggers and daily digests.
Google Gemini AI-powered daily market digests, sentiment analysis on watchlist stocks, earnings summaries, and personalized recommendations. Entirely optional — the rest of the app works without it.
Add your env vars in the Vercel dashboard. Deploy takes ~2 minutes.
docker build -t watchtower .
docker run -p 3000:3000 --env-file .env watchtowerBugs, features, docs — all welcome. Whether you're a student, a self-taught dev, or a seasoned engineer, contributions are welcome.
git clone https://github.com/TheODDYSEY/watchtower_stock-tracker-app.git
git checkout -b feature/your-feature
git commit -m "feat: your feature"
git push origin feature/your-feature
# Open a PR- Open an issue to discuss ideas and bugs first
- Look for
good first issueorhelp wantedlabels - Keep PRs focused; add screenshots for UI changes
- Be kind — no gatekeeping
If you discover a vulnerability:
- Do not open a public issue
- Open a private security advisory on the GitHub repository
We'll coordinate responsible disclosure and patch promptly.
MIT — use it, modify it, ship it. See the file for details.
WatchTower builds on great open-source work:
- JavaScript Mastery — the Signalist tutorial that planted the seed
- Finnhub — real-time market data API
- TradingView — professional chart widgets
- shadcn/ui — accessible component library
- Inngest — dependable background jobs and workflows
- Better Auth — simple and secure authentication
Built and maintained by TheODDYSEY.
A ⭐ helps others find this project.





