Oracle3
Open-source trading engine and MCP server for prediction markets. Fee-aware no-arbitrage trading across related contracts, live on Kalshi, Polymarket and Solana or on paper.
An open-source investment portfolio tracker
Translation pending
FinanceTypeScript · CSSGitHub @PanagiotisKaralioliosOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Personal investing tracker with watchlist, portfolio analytics, and corporate events tracking. Built with Next.js 15, tRPC v11, Prisma, and InfluxDB.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Built with Next.js App Router, tRPC v11, Prisma/PostgreSQL, shadcn/ui, and InfluxDB for fast timeseries. Auth is powered by Better Auth (Prisma adapter) with email/password, magic links, 2FA, and Discord OAuth.Read the full README ↗An opinionated personal investing tracker
Built with Next.js App Router, tRPC v11, Prisma/PostgreSQL, shadcn/ui, and InfluxDB for fast timeseries. Auth is powered by Better Auth (Prisma adapter) with email/password, magic links, 2FA, and Discord OAuth.
Getting Started • Features • Documentation • Contributing
/api/mcp) for external agents — see docs/mcp.md| Layer | Technology |
|---|---|
| Frontend | Next.js 15 (App Router) • React 19 |
| API | tRPC v11 + React Query (RSC + CSR hydration) |
| Database | Prisma + PostgreSQL |
| Auth | Better Auth (email/password, magic link, 2FA, Discord) |
| UI | shadcn/ui + TailwindCSS 4 • TanStack Table v8 |
| Charts | Recharts |
| Timeseries | InfluxDB 2.x (daily_bars + event measurements) |
graph TB
A[Client: React 19 + Next.js 15] --> B[tRPC v11]
B --> C[API Routers]
C --> D[Prisma ORM]
C --> E[InfluxDB Client]
D --> F[(PostgreSQL)]
E --> G[(InfluxDB 2.x)]
C --> H[Better Auth]
H --> F
Key components:
src/app/*; dashboard shell in src/app/(dashboard)/layout.tsxsrc/server/api/routers/*, composed in src/server/api/root.tsdb (Prisma) and session from Better Auth in src/server/api/trpc.tssrc/server/influx.tssrc/server/jobs/ingest-yahoo.ts with helpers in yahoo-lib.tssrc/trpc/react.tsx; RSC callers via src/trpc/server.tsExample API usage:
// Server (RSC)
import { api } from "@/trpc/server";
const me = await api.account.getMe.query();
// Client (CSR)
import { api } from "@/trpc/react";
const { data } = api.watchlist.list.useQuery();
./start-database.sh)./start-influxdb.sh, or bring your own local/remote)1️⃣ Install dependencies
bun install
2️⃣ Create and fill .env
See the Environment variables section below. For a smoke test you can set placeholders and use SKIP_ENV_VALIDATION=1 while you iterate.
3️⃣ Start the databases (dev helpers)
./start-database.sh # Postgres 16
./start-influxdb.sh # InfluxDB 2.x
For local dev, make sure INFLUXDB_URL points at the local instance —
INFLUXDB_URL=http://localhost:8086 in .env.local (org/bucket/token stay
as in your .env). ./start-influxdb.sh reads those values and provisions
the container to match.
4️⃣ Generate and apply Prisma schema
bun run db:generate
5️⃣ Start the dev server
bun run dev
🎉 Open http://localhost:3000
Validated in src/env.js via @t3-oss/env-nextjs. Server-side vars are required unless noted.
DATABASE_URL: Postgres connection URL (required)BETTER_AUTH_SECRET: Secret for Better Auth JWT/cookies (required in production)BETTER_AUTH_URL: Public base URL of the app (default: http://localhost:3000)PASSWORD_PEPPER: Extra pepper for hashing local passwords (required)EMAIL_SERVER: Nodemailer connection string (e.g. SMTP URI) (required)EMAIL_FROM: From address for transactional emails (required)NEXT_PUBLIC_SITE_URL: Public site URL exposed to client (default: http://localhost:3000)AUTH_DISCORD_ID, AUTH_DISCORD_SECRET: Discord OAuth credentials (required if enabling Discord)INFLUXDB_URL (default http://localhost:8086)INFLUXDB_ORGINFLUXDB_BUCKETINFLUXDB_TOKENDATABASE_URL (Postgres, repeated for clarity)YAHOO_API_URL (base URL, default https://query2.finance.yahoo.com/v8/finance; code appends /chart/<symbol>, so do not include /chart) — FX ingestion also sources rates from YahooPOLYGON_API_URL, POLYGON_API_KEY — required by the env schema (src/env.js, z.string()), so the app fails validation on boot without them unless SKIP_ENV_VALIDATION=1; note no code path consumes them yetCLOUDFLARE_* (R2 image storage) — the R2 feature is optional, but CLOUDFLARE_ACCESS_KEY_ID/CLOUDFLARE_ACCOUNT_ID/CLOUDFLARE_BUCKET_NAME/CLOUDFLARE_SECRET_ACCESS_KEY are required by src/env.js and fail validation on boot unless SKIP_ENV_VALIDATION=1 (CLOUDFLARE_R2_PUBLIC_URL is the only optional one)NEXT_PUBLIC_* for Ads/Analytics (Umami/GA/AdSense) are optional and stubbed in E2E tests💡 Tip: during early setup, export
SKIP_ENV_VALIDATION=1to bypass strict checks until you've filled everything in.
| Command | Description |
|---|---|
bun run db:generate | Generate/apply in dev (migrate dev) |
bun run db:migrate | Deploy migrations |
bun run db:push | Push schema (no migrations) |
bun run db:studio | Prisma Studio (defaults to port 5000) |
Schema: prisma/schema.prisma
Relevant models: User, Account, Session, WatchlistItem, Transaction, Goal, ApiKey and Better Auth support tables TwoFactor, Verification, VerificationToken. (FX rates are no longer a Postgres model — the FxRate table was dropped and rates now live in the InfluxDB fx_rates measurement.)
| Measurement | Fields | Tags | Purpose |
|---|---|---|---|
daily_bars | open, high, low, close, volume | symbol | OHLCV data |
dividends | amount | symbol | Dividend events |
splits | numerator, denominator, ratio | symbol | Stock split events |
capital_gains | amount | symbol | Capital gain distributions |
Helper code: src/server/influx.ts
bun run ingest:yahoo
What it does:
WatchlistItemsbun run ingest:fx
What it does:
fx_rates measurement (idempotent by measurement+tag+timestamp)E2E tests with Playwright:
# Install browsers once
bun run test:e2e:install
# Run headless
bun run test:e2e
# Run headed or with the UI
bun run test:e2e:headed
bun run test:e2e:ui
Config: playwright.config.ts (uses a built-in dev server unless PW_SKIP_WEBSERVER=1).
Comprehensive Postman collections are available in the postman/ directory for testing all API endpoints.
Collections include:
Quick start:
# Import into Postman
# 1. Open Postman
# 2. Import postman/Invest-igator-API.postman_collection.json
# 3. Import postman/Invest-igator.postman_environment.json
# 4. Configure environment variables (baseUrl, etc.)
# 5. Sign in via Better Auth endpoints
📚 See postman/README.md for detailed usage instructions
All endpoints are documented with:
bun run check # Biome
bun run typecheck # TypeScript
docker build -t invest-igator:local .
docker run --rm -p 3000:3000 \
-e SKIP_ENV_VALIDATION=1 \
-e DATABASE_URL=postgresql://user:pass@host:5432/db \
-e BETTER_AUTH_SECRET=change-me-to-a-random-32char-min-secret \
-e PASSWORD_PEPPER=change-me \
-e EMAIL_SERVER=smtp://user:pass@mail:587 \
-e [email protected] \
-e INFLUXDB_URL=http://influx.example.com:8086 \
-e INFLUXDB_ORG=... \
-e INFLUXDB_BUCKET=... \
-e INFLUXDB_TOKEN=... \
invest-igator:local
SKIP_ENV_VALIDATION=1is included becausesrc/env.jsalso requiresAUTH_DISCORD_ID/AUTH_DISCORD_SECRET,CLOUDFLARE_*andPOLYGON_API_KEY. Provide those too and dropSKIP_ENV_VALIDATIONonce all vars are set.
This repo includes a Compose file that runs:
invest-igator: the app container (published on port 3311)db: internal Postgres 16scheduler: Ofelia to run ingestion jobs inside the app container on a cronQuick start:
cp .env.example .env # if you have one; otherwise create .env from the vars above
# Fill DATABASE_URL, BETTER_AUTH_SECRET, PASSWORD_PEPPER, INFLUXDB_*, EMAIL_*,
# CLOUDFLARE_*, AUTH_DISCORD_*, POLYGON_API_KEY (all required by src/env.js;
# the compose default SKIP_ENV_VALIDATION=1 lets it boot before they're all set)
docker compose up -d
Notes:
INFLUXDB_URL at your own instance. To run it inside the stack, uncomment the optional influxdb service in docker-compose.yml and set INFLUXDB_URL=http://influxdb:8086.ingest-yahoo daily at 02:15 UTC, ingest-fx at 06:00/18:00 UTC and the AI-quota sweep every 5 minutes (Ofelia schedules have a leading seconds field)bun user (uid 1000), not root; in /app only .next is writable by it (plus its own home directory and /tmp). Each Ofelia job sets user: bun too, since Ofelia's job-exec defaults to rootStop and remove:
docker compose down -v
.
├── prisma/
│ ├── schema.prisma # 🗄️ Relational models (User, WatchlistItem, Transaction, etc.)
│ └── migrations/ # 📦 Schema migrations
├── src/
│ ├── server/
│ │ ├── api/
│ │ │ ├── root.ts # 🔗 tRPC router composition
│ │ │ ├── trpc.ts # ⚙️ Context, middleware, procedures
│ │ │ └── routers/ # 🧩 Feature routers (watchlist, transactions, admin, etc.)
│ │ ├── jobs/
│ │ │ ├── ingest-yahoo.ts # 📈 Yahoo Finance ingestion job
│ │ │ ├── ingest-fx.ts # 💱 FX rates ingestion job
│ │ │ └── yahoo-lib.ts # 🛠️ Yahoo data helpers
│ │ ├── auth/
│ │ │ └── permissions.ts # 🔐 Better Auth permissions helpers
│ │ ├── db.ts # 🗃️ Prisma client singleton
│ │ ├── influx.ts # 📊 InfluxDB client & helpers
│ │ ├── fx.ts # 💰 FX rate conversion utilities
│ │ └── r2.ts # ☁️ Cloudflare R2 storage client
│ ├── app/
│ │ ├── (dashboard)/ # 🏠 Protected dashboard routes
│ │ │ ├── watchlist/ # 📊 Watchlist with charts and date filtering
│ │ │ ├── portfolio/ # 💼 Portfolio analytics
│ │ │ ├── transactions/ # 📈 Transaction management with sorting
│ │ │ ├── account/ # 👤 Account settings with API Keys tab
│ │ │ └── admin/ # 🔐 Admin section
│ │ │ ├── users/ # 👥 User management page
│ │ │ └── audit-logs/ # 📋 Audit logs page
│ │ ├── (auth)/ # 🔑 Auth routes (login, signup, verify-request)
│ │ ├── api/ # 🌐 API endpoints (tRPC, auth, email verification)
│ │ └── layout.tsx # 🎨 Root layout with providers
│ ├── components/
│ │ ├── ui/ # 🧱 shadcn/ui primitives (incl. DateRangePicker, Skeleton)
│ │ ├── ads/ # 📢 AdSense integration
│ │ ├── consent/ # ✅ Cookie consent provider
│ │ └── theme/ # 🌓 Theme provider
│ ├── hooks/
│ │ ├── use-debounce.ts # ⏱️ Debounce hook (300ms)
│ │ └── use-currency.ts # 💱 Currency utilities
│ ├── trpc/
│ │ ├── react.tsx # ⚛️ Client-side tRPC hooks
│ │ ├── server.ts # 🖥️ Server-side tRPC helpers
│ │ └── query-client.ts # 📡 React Query configuration
│ ├── lib/
│ │ ├── auth.ts # 🔒 Better Auth instance
│ │ ├── api-key-permissions.ts # 🔑 API key permission framework
│ │ ├── api-key-utils.ts # 🔧 API key generation & validation
│ │ └── utils.ts # 🔧 Utility functions (cn, etc.)
│ └── env.js # ✔️ Environment validation (@t3-oss/env-nextjs)
├── tests/
│ └── e2e/ # 🧪 Playwright E2E tests
├── docker/
│ └── entrypoint.sh # 🐳 Container startup script (migrations, server)
├── Dockerfile # 📦 Multi-stage build (deps, builder, runner)
├── docker-compose.yml # 🐙 Compose stack (app, db, scheduler)
├── start-database.sh # 🗄️ Dev Postgres script
└── start-influxdb.sh # 📊 Dev InfluxDB 2.x script
Quick pointers:
src/app/(dashboard)/layout.tsxsrc/app/(dashboard)/_components/app-sidebar.tsxsrc/server/api/trpc.ts, src/trpc/react.tsx, src/trpc/server.tssrc/lib/api-key-permissions.tssrc/lib/api-key-utils.tssrc/server/api/routers/api-keys.tssrc/server/api/middleware/with-api-key.tssrc/app/(dashboard)/account/_components/api-keys-*.tsxsrc/server/api/routers/admin.tssrc/app/(dashboard)/admin/_components/user-management-table.tsx, audit-logs-table.tsxsrc/server/influx.tssrc/server/jobs/ingest-yahoo.tssrc/server/api/routers/watchlist.tssrc/components/ui/date-range-picker.tsx, src/components/ui/skeleton.tsxsrc/hooks/use-debounce.tsInvest-igator supports programmatic API access via API keys with granular permission control.
read-only: Read access to all non-admin endpointsfull-access: Read + write + delete for all user resourcesportfolio-manager: Portfolio, transactions, and goals managementcustom: Build your own permission setx-api-key header in your API calls# Get your user profile
curl https://your-app.com/api/trpc/account.getMe \
-H "x-api-key: your_api_key_here"
# Get FX rates matrix
curl https://your-app.com/api/trpc/fx.matrix \
-H "x-api-key: your_api_key_here"
# List watchlist items
curl https://your-app.com/api/trpc/watchlist.list \
-H "x-api-key: your_api_key_here"
| Issue | Solution |
|---|---|
| ❌ Env validation failing at boot | Set SKIP_ENV_VALIDATION=1 temporarily and fill missing vars (see src/env.js) |
| ❌ Prisma migrate errors | Ensure Postgres is reachable; try prisma migrate reset in dev |
| ❌ Influx writes fail | Verify INFLUXDB_URL/ORG/BUCKET/TOKEN and token has write permissions |
| ❌ Emails not sending | Verify EMAIL_SERVER URI and that your provider allows SMTP from containers |
| ❌ 401s in tRPC | Confirm cookies are set and BETTER_AUTH_URL matches your external origin |
PRs are welcome! Before submitting:
✅ Run bun run check (Biome linting)
✅ Run bun run typecheck (TypeScript)
✅ Include/update E2E tests where relevant
Quick demo dataset:
Add a few symbols to your watchlist and run the Yahoo ingest job; the watchlist add flow also triggers a background ingest for that symbol.