Skip to content
← All projects

Private Investment Portal

A single-user, security-first portal that tracks crypto, Indian mutual funds and NSE/BSE stocks, and calls my phone when the market dips.

  • Next.js 16
  • TypeScript
  • PostgreSQL
  • Drizzle
  • Docker
  • Caddy
  • AWS EC2
  • GitHub Actions

The code is private because it runs against my own accounts. I'm happy to walk through it in an interview.

I wanted alerts I couldn't sleep through when a position moved sharply, and I didn't want my holdings sitting in a third-party app. So I built my own portal, treated it like a production service, and deployed it behind my own domain.

What it does

  • Tracks holdings across crypto (CoinGecko), Indian mutual funds (MFAPI) and NSE/BSE stocks (Upstox) behind a pluggable price-provider interface.
  • Average-cost holdings with realised and unrealised P&L, plus CSV import of past transactions.
  • Alert rules for sharp dips or spikes within a window, 24h change thresholds and price targets.
  • Alerts go out as Telegram messages with Acknowledge and Mute buttons, and escalate to a voice call for the serious ones.

Alerting that doesn't cry wolf

  • Edge-triggered evaluation with per-rule cooldowns, so a sustained dip fires once instead of every minute.
  • Quiet hours and a daily summary, all in IST.
  • A background worker holds a Postgres advisory lock, so only one instance evaluates rules even if two are running.
  • A dead-man's-switch ping tells me if the worker itself stops.

Security, as if it held someone else's money

  • Mandatory TOTP 2FA, Argon2id password hashing and database-backed sessions.
  • Login rate limiting and lockout, keyed on the client IP that the reverse proxy overwrites, so it can't be spoofed.
  • Nonce-based Content Security Policy, CSRF origin checks on every mutation, and an audit log.
  • Third-party API tokens encrypted at rest. Postgres is bound to loopback only, and containers run read-only with all capabilities dropped.

Shipping it

  • CI runs lint, typecheck, tests and a build on every push. Merges to main build an image to GHCR.
  • Deploys use GitHub OIDC → a narrowly scoped AWS role → SSM Run Command. There are no SSH keys and no long-lived AWS credentials in CI.
  • The deploy script health-checks the new containers and rolls back automatically if they fail.
Next projectInvestment Tracker Platform