YSight
A probabilistic decision engine that helps people make high-stakes life choices
More screenshots
Career moves, relocations, financial decisions — YSight uses the same techniques quantitative analysts use: Monte Carlo simulation, Bayesian updating, and risk-adjusted utility theory. Instead of gut feel or a spreadsheet, users model their uncertainty as probability distributions and let the math surface what actually matters.
The premise: most big decisions aren't uncertain because we lack information — they're uncertain because multiple variables interact in non-obvious ways. A job offer might have a higher salary but also higher layoff risk. YSight simulates 20,000 possible futures and tells you which path wins after accounting for both.
Technical highlights
Simulation engine — Custom NumPy Monte Carlo core supporting seven probability distributions (Normal, LogNormal, Beta, Gamma, Student-T, Bernoulli, Uniform). Each variable has a role (income, cost, risk, wellbeing, one-time) that determines how samples compose into a net present value stream. Risk variables trigger a catastrophic-event model: a Bernoulli shock that wipes 60% of that year's accumulated cashflow when it fires. CARA (Constant Absolute Risk Aversion) utility with a user-controlled λ parameter means two options with identical expected values but different volatilities will produce different winners depending on risk preference.
Sensitivity analysis — Tornado chart built by perturbing each variable ±20%, re-running a reduced simulation, and ranking by NPV impact. Implemented server-side in O(2V × sims) — fast enough to run reactively as a "TweakAndRerun" mini-form on the Results page.
Bayesian updating — Normal-Normal conjugate updates persist to the database with a full history timeline. Users can log real-world observations as their decisions unfold, watch the posterior distribution tighten, and get a calibration alert when observations consistently confirm (or surprise) the prior.
AI integration — Claude Sonnet generates variable suggestions for a given decision context, synthesises AI summaries of simulation results, powers a decision-coach chat interface, and writes viral one-line hooks for publicly shared decisions. All LLM calls use asyncio.wait_for with a configurable timeout to prevent event-loop stalls under load.
Authentication — JWT-based email/password auth with httpOnly cookies, bcrypt hashing, 5-attempt/15-minute brute-force lockout per ip:email key, refresh-token rotation with revocation-on-reuse (token theft detection), and full password-reset via Brevo transactional email.
Payments — Stripe one-time Checkout (no subscription). Free tier: 3 choices, 1,000 simulations. Premium (€29 lifetime): 10 choices, 20,000 simulations. Webhook handler verifies Stripe-Signature over raw bytes before any JSON parsing, uses ON CONFLICT DO UPDATE for idempotent payment persistence, and returns HTTP 500 on DB failure so Stripe retries — ensuring a completed payment is never lost.
Data layer — PostgreSQL via asyncpg with a JSONB codec registered globally so Python dicts round-trip transparently. Schema bootstrapped idempotently on every startup via CREATE TABLE IF NOT EXISTS and DO $$ BEGIN ALTER TABLE … EXCEPTION WHEN duplicate_column THEN NULL; END $$ blocks — zero manual migrations.
Real-time FX conversion — Backend proxy to the ECB's frankfurter.dev API with a 24-hour PostgreSQL cache and a static fallback table. Frontend formatCurrency reads the live exchange rate and converts all EUR-baseline values to the user's active locale (7 supported: EUR_DE, EUR_FR, GBP_UK, CHF_CH, NOK_NO, SEK_SE, USD_US).
Deployment — Multi-stage Dockerfile: Node 20 builds the React SPA, Python 3.11 serves both the API and the pre-built assets from a single Railway container. GitHub-connected for automatic deploys on push to main. Health check at /health with a 300-second startup window.
Product features (shipped)
- Decision Builder with 3-step guided flow, AI variable suggestions per option, and inline Bayesian update controls
- 10 EU-localised decision templates (job, move, master's, startup, buy vs. rent, kids, bootcamp, remote, FIRE, pet)
- Results page: winner banner, AI synthesis, NPV histogram, yearly cashflow chart, tornado sensitivity, WhyWinsCard (explains the win pattern in plain English), TweakAndRerun form
/explorepublic gallery with trending / recent / AI-generated hooks, 5-category tabs, Hall of Decisions- Social graph: fork any public decision, preserving full lineage; dagre-rendered DAG lineage tree on share pages
- Head-to-head
/comparepage with CARA-adjusted verdict + Claude AI synthesis - Streak tracking (consecutive weeks simulating), milestone celebrations with sharable PNG cards
- Weekly trending email digest (APScheduler cron + Brevo), opt-in on signup
- Full locale picker in the header with server-side preference persistence
What makes it interesting to build
The hardest design decision was the composition model for simulation variables. A "risk" variable that wipes cashflows must run after income and cost variables have accumulated — but if it runs in a naive loop, it changes the model semantics entirely. The solution (sort variables by role, applying risk shocks last) sounds simple but took several iterations to reason about correctly with vectorised NumPy arrays across (n_sims, horizon_years) shaped matrices.
The most satisfying engineering challenge was the token verification architecture: refresh tokens store only a jti hash in the database, and when a revoked token is presented again, the system immediately revokes all tokens for that user — the classic "refresh token reuse = account compromise" signal, handled in three database rows.
Numbers
- ~6,000 lines of Python across 15 backend modules
- ~8,000 lines of TypeScript across 14 pages and 20+ components
- 25 database tables covering users, decisions, simulations, shares, payments, Bayes history, lineage, rate limits, FX cache, and more
- 40+ API endpoints under
/api - Simulation engine benchmarks at ~200ms for 20,000 runs × 5 variables × 10 years on a single Railway instance
Stack: Python / FastAPI / PostgreSQL / React / TypeScript / Stripe / Claude AI