A unified investor dashboard that aggregates traditional and alternative financial data into one seamless web application. MarketSleuth is my attempt and my case study of a modern full stack saas project, it provides real-time market data, insider trading filings, dividend and options income projections, sentiment analysis, custom stock scanners, earnings/events monitoring, a trade journal, alerts, user settings, and extensible data-source management.
you can take a look at the demo here: https://marketsleuth.wuaze.com/
| Layer | Technology |
|---|---|
| Backend | Laravel 12, PHP 8.2, MySQL, Redis |
| Auth | JWT (tymon/jwt-auth), per-device refresh tokens |
| Frontend | React, Vite, Tailwind CSS, Framer Motion, Lucide-React |
| Containerization | Docker Compose (PHP-FPM, Nginx, MySQL, Redis, Node) |
- Database (MySQL): Primary persistence for users, journal entries, scanners, option positions, dividends, earnings/events, alerts, settings, data sources
- Cache (Redis): Stores rate-limiting counters, queue jobs, and can be extended for response caching (e.g. market tickers)
- Queues & Scheduler: Laravel's job queue for heavy fetch tasks; scheduled Artisan commands (
fetch:form4,fetch:dividends,fetch:options,scan:run) run periodically to keep alt-data fresh - **Migration Patches: the laravel backend contains a healthy amount of migration patch to not only scaffold the database with the relevent tables but to at times enhance the said tables
JWT Access Tokens with 15-minute TTL; Refresh Tokens stored in refresh_tokens table (30-day TTL), revocable per-device.
Endpoints:
POST /api/register→ Create new user (rate-limited, email DNS-validated, strong password enforced)POST /api/login/POST /api/refresh/POST /api/logout/POST /api/logout-allGET /api/me→ Returns authenticated user profile
Live quotes & history served via MarketDataController from third-party APIs, optionally cached in Redis.
Endpoints:
GET /api/market/tickersGET /api/market/ticker/{symbol}GET /api/market/ticker/{symbol}/history
- Artisan Job:
fetch:form4 {ticker}retrieves SEC Form 4 filings and stores inform4_records - API Endpoint:
GET /api/tickers/{symbol}/insidersreturns count + recent filings
- Dividend Fetcher:
fetch:dividends {ticker}pulls monthly ex-dividend data; stored individend_records - Options Fetcher:
fetch:options {ticker}(Polygon.io integration) populatesoption_positions
Endpoints:
GET /api/income/dividends/{symbol}→ Total & monthly projections + raw recordsGET /api/income/options/{symbol}→ Positions array + yield/income summary
- Scanner Model: User-defined JSON criteria stored in
scannerstable - Execution:
php artisan scan:run {scannerId}filters Tickers via criteria (e.g. dividend yield, insider buys)
Protected API:
GET /api/scanners→ List user's scannersPOST /api/scanners→ Create newGET /api/scanners/{id}/results→ Run & return matches
Built-in Public Scanners:
GET /api/scanners/high-dividendGET /api/scanners/insider-activity
Events Models: EarningEvent and AnalystAction track upcoming earnings and analyst upgrades/downgrades.
Endpoints:
GET /api/events/earnings/upcomingGET /api/events/analyst/{symbol}GET /api/events/all
- Journal Entries:
journal_entriestable for buy/sell/note entries (quantity, price, P&L, tags, attachments) - Alerts: User-configured records in
alertstable; trigger based on events or thresholds
CRUD Endpoints (protected): /api/journal and /api/alerts
Simulation Endpoint: POST /api/options/simulate reads from option_positions to calculate P/L for a given ticker, strike, expiry.
User Settings (protected):
GET /api/settings/profile,PUT /api/settings/profile→ View/update name & emailPUT /api/settings/password→ Change password
Data Sources (public view; admin edit):
GET /api/data-sources&GET /api/data-sources/{id}- Admin-only:
POST/PUT/DELETEto manage feed configurations
- Scheduler enqueues fetch jobs overnight (via
routes/console.phpscheduling) - Fetchers write to SQL tables;
option_positionsanddividend_recordsare used by projection endpoints - Redis holds ephemeral rate-limiter keys and job queues; can be extended to cache API responses (e.g. market ticks)
- Frontend uses a custom React hook (
useDashboardData) to orchestrate parallel fetches of all card-level APIs, handles loading/error states, and triggers re-fetch on "Refresh Data"
- Artisan:
php artisan fetch:form4 AAPL→ Fetch & store filings inform4_records - Cache: Optionally store "latest fetch timestamp" in Redis for freshness indicator
- API:
GET /api/tickers/AAPL/insidersqueries MySQL for count & recent records - Frontend:
useDashboardDatacalls endpoint, populatesdata.insider, renders a card
- DashboardHeader: Search bar + refresh button → calls
refreshData()to re-run all fetches - Sidebar: Global navigation reflecting implemented features
- DashboardCard: Generic card component handles loading, error, main metric, and optional details list
- OptionsSummary & IncomeSummary: Detailed breakdown UIs for options and dividend projections
and i think thats all folks, thank you for taking the time to read this!
