A paper trading app — invest fake money in real stocks using live market data. Track your portfolio, research stocks with historical price charts, and practice trading without any financial risk.
- Google SSO — sign in with your Google account; each account gets its own independent portfolio
- Portfolio dashboard — view all your holdings with live prices, 24h change, and total P&L
- Stock search — search any US equity by name or ticker symbol
- Stock detail page — interactive price history chart (1D / 5D / 1M / 3M / 1Y ranges) with buy and sell forms
- Buy & sell — whole shares only; trades execute at the live market price
- Deposit fake money — add up to $1,000,000 to your account at any time (new accounts start with $1,000)
- Transaction history — paginated log of every buy, sell, and deposit
- Price caching — stock prices are cached server-side for 5 minutes to stay within API limits
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript |
| Styling | Tailwind CSS |
| Database | SQLite via Prisma 7 + libsql adapter |
| Auth | NextAuth v5 (Google OAuth, JWT sessions) |
| Stock data | yahoo-finance2 (no API key required) |
| Charts | Recharts |
| Unit tests | Vitest + Testing Library |
| E2E tests | Playwright |
- Node.js 18+
- A Google OAuth 2.0 client (create one here)
git clone <repo-url>
cd stocks
npm installCopy .env and fill in your values:
cp .env .env.localDATABASE_URL="file:./prisma/dev.db"
AUTH_SECRET="<generate with: openssl rand -base64 32>"
AUTH_GOOGLE_ID="<your Google client ID>"
AUTH_GOOGLE_SECRET="<your Google client secret>"In your Google Cloud Console, add these to your OAuth 2.0 client:
Authorised JavaScript origins:
http://localhost:3000
Authorised redirect URIs:
http://localhost:3000/api/auth/callback/google
npx prisma migrate devThis creates prisma/dev.db and runs all migrations.
npm run devOpen http://localhost:3000. You'll be redirected to the login page — sign in with Google to get started.
| Command | Description |
|---|---|
npm run dev |
Start the development server with hot reload |
npm run build |
Build for production |
npm run start |
Start the production server (requires a build first) |
npm test |
Run all unit tests |
npm run test:watch |
Run unit tests in watch mode |
npm run test:coverage |
Run unit tests with coverage report |
npm run test:e2e |
Run end-to-end tests (requires a production build) |
npm run test:e2e:ui |
Open Playwright's interactive test runner |
Unit tests use Vitest and mock all external dependencies (database, Yahoo Finance). No server or network access needed.
npm test68 tests covering:
- Stock data library (cache hit/miss, history, search)
- All API route handlers (auth guards, validation, business logic)
E2E tests use Playwright and run against a real local server with a separate test database (prisma/test.db).
Step 1 — build the app:
npm run buildStep 2 — run the tests:
npm run test:e2eThe test suite will:
- Run Prisma migrations against
prisma/test.db - Seed a test user (
test@papertrade.dev, $10,000 starting balance) - Authenticate via the test credentials provider (only active outside production)
- Run all specs: auth redirects, portfolio, deposit, search, buy, sell, transactions
To open the interactive Playwright UI instead:
npm run test:e2e:uisrc/
├── app/
│ ├── page.tsx # Portfolio dashboard
│ ├── login/page.tsx # Login page
│ ├── stock/[ticker]/page.tsx # Stock detail + chart + trade form
│ ├── search/page.tsx # Stock search
│ ├── transactions/page.tsx # Transaction history
│ └── api/
│ ├── auth/[...nextauth]/ # NextAuth handlers
│ ├── portfolio/ # GET portfolio + live prices
│ ├── trade/ # POST buy/sell
│ ├── deposit/ # POST add fake money
│ ├── transactions/ # GET paginated history
│ └── stocks/
│ ├── quote/ # GET current price (cached)
│ ├── history/ # GET OHLC time series
│ └── search/ # GET symbol search
├── components/
│ ├── Header.tsx # Navigation bar
│ ├── StockChart.tsx # Recharts area chart
│ ├── TradeForm.tsx # Buy/sell form
│ ├── DepositModal.tsx # Add funds modal
│ └── Providers.tsx # SessionProvider wrapper
├── lib/
│ ├── db.ts # Prisma client singleton
│ └── stocks.ts # Yahoo Finance wrapper + price cache
├── auth.ts # Full NextAuth config (Node.js)
├── auth.config.ts # Lightweight auth config (Edge-safe)
└── proxy.ts # Next.js 16 middleware (route protection)
prisma/
├── schema.prisma # Database schema
├── migrations/ # SQL migration history
├── dev.db # Development database
└── test.db # Test database (created on first test run)
tests/
├── unit/
│ ├── lib/stocks.test.ts
│ └── api/
│ ├── portfolio.test.ts
│ ├── trade.test.ts
│ ├── deposit.test.ts
│ ├── transactions.test.ts
│ └── stocks-routes.test.ts
└── e2e/
├── global.setup.ts # DB seed + auth setup
├── seed.ts # Test user seeder
├── auth.spec.ts
├── portfolio.spec.ts
├── trade.spec.ts
└── transactions.spec.ts
| Table | Purpose |
|---|---|
User |
Account with cash balance (default $1,000) |
Account |
OAuth provider accounts (managed by NextAuth) |
Session |
Auth sessions (managed by NextAuth) |
Portfolio |
Current stock holdings per user |
Transaction |
Immutable log of every BUY, SELL, and DEPOSIT |
PriceCache |
Server-side cache of stock quotes (5-minute TTL) |
A floating chat widget available on every page, powered by Google Gemini 2.0 Flash.
The bot has access to four tools it calls automatically as needed:
| Tool | What it does |
|---|---|
get_stock_quote |
Live price, daily change, open/high/low |
get_stock_history |
Price trend summary for a given time range |
get_stock_news |
Recent news articles via Yahoo Finance search |
get_portfolio |
User's current holdings and cash balance |
The bot always knows your portfolio context but won't limit suggestions to stocks you can currently afford — you can always deposit more or sell existing positions.
Adding more news sources: Open src/lib/gemini.ts and append a new entry to the newsSources array. Each source is just an async function (query: string) => Promise<NewsArticle[]>.
To use the AI advisor, add your Gemini API key to .env:
GEMINI_API_KEY="your-key-here"Get a free key at aistudio.google.com.