Cost Model
Parent: Architecture · Companion: decisions/supabase-db-auth.md · Status: estimate, prices verified via public pricing pages on 2026-07-04. Ranges are deliberate — this is a planning tool, not an invoice. Re-verify LLM prices before launch; they churn quarterly.
As built (all 8 phases shipped): the operational budgets settled in doc 05 are $20/mo house-key cap · $10/mo per-user virtual key · $2/day chat · alert at 80% — this page is the planning model those caps were sized against. Two shipped choices make the current bill smaller than the steady-state modeled below: market data stayed on yfinance and news is Finnhub free tier (the Tiingo line is $0 until the paid upgrade), and dev runs the whole gateway on a free Gemini key. Backups are Supabase Pro's own daily backups (no self-run backup infra) and observability is OTel wiring with no hosted backend — neither adds a line item.
1. Assumptions (read first)
All volume assumptions come from design 01 unless noted:
- News: ~150 articles/day embedded (title+snippet, ~100–200 tokens each); ~40 stories/day synthesized, avg ~1.5 synthesis calls/story (re-synthesis at count thresholds 1/3/8) → ~60 calls/day. Each call: ~10 title+snippet pairs + instructions ≈ 2–3k tokens in, structured output ≈ 300–500 tokens out.
- Market recap (shared): 1 run/day, ~3–5k in / ~1k out; ~30 runs/mo.
- Daily agent (per user): ~5–9k in / ~2–3k out per run — fact pack ~3–6k plus system prompt and tool round trips (aligned with design 02 §5.5) — ~22 trading days/mo.
- Recap personalization (per user): ~1–2k in / ~500 out per briefing — incremental tokens of the daily agent's markets section (same run, same mid tier, user key per design 02 §5.5); shown as its own line for visibility.
- Chat (per user): light/medium/heavy = ~10/50/150 messages/day, 30 days/mo. Per user message, including tool-call round trips that re-send context: ~6–12k tokens in (midpoint 9k), ~0.5–1k out (midpoint 0.75k). This is the single most important assumption in the whole model.
- Action verification: deterministic transaction matching — zero LLM cost by design.
- Month = 30 days; trading month = 22 days. No prompt caching or batch discounts assumed (both exist and only make these numbers smaller — see §8).
- Prices are standard-tier list prices in USD per million tokens ("/M").
2. LLM price reference (verified 2026-07-04)
Chat/completion models
| Tier | Model | Input /M | Output /M | Notes |
|---|---|---|---|---|
| Cheap | GPT-5 nano | $0.05 | $0.40 | cheapest usable extraction class |
| Cheap | GPT-5 mini | $0.25 | $2.00 | the workhorse cheap tier |
| Cheap | Gemini 3.1 Flash-Lite | $0.25 | $1.50 | comparable to mini |
| Cheap | Claude Haiku 4.5 | $1.00 | $5.00 | priciest "cheap"; strong quality |
| Mid | GPT-5 / 5.1 | $1.25 | $10.00 | |
| Mid | Gemini 3.5 Flash | $1.50 | $9.00 | near-frontier quality, mid price |
| Mid | Gemini 3.1 Pro | $2.00 | $12.00 | ≤200k context pricing |
| Mid | Claude Sonnet 5 | $2.00→$3.00 | $10.00→$15.00 | intro pricing until 2026-08-31 |
| Best | GPT-5.5 | $3.00 | $20.00 | |
| Best | Claude Opus 4.8 | $5.00 | $25.00 | modeled best-tier default |
| Best | Claude Fable 5 | $10.00 | $50.00 | premium ceiling; not a default |
Sources: Calcis OpenAI rate card, Anthropic pricing roundups + Sonnet 5 announcement, Gemini rate summaries. Batch APIs are ~50% off everywhere; Anthropic cache reads are ~90% off input.
Embeddings
text-embedding-3-small: $0.02/M ($0.01/M batch) — OpenAI model page. At our volumes embeddings are a rounding error, which is why the design keeps re-embedding cheap and swappable. As built (phase 6): the shipped model is gemini/gemini-embedding-001 @ 1536 dims on the free Gemini key — $0 today; the swappability paid off immediately.
3. Shared layer (house key) — monthly
| Job | Volume/mo | Tokens/mo (in / out) | Model tier | Cost/mo |
|---|---|---|---|---|
| Article embeddings | ~4,500 articles | ~0.7M / — | text-embedding-3-small | ~$0.01–0.02 |
| Story synthesis | ~1,800 calls | ~4–5M / ~0.6–0.9M | cheap (nano→mini span) | ~$0.50–3 |
| Generic market recap | ~30 runs | ~0.12M / ~0.03M | cheap | ~$0.02–0.10 |
| Shared total | ≈ $1–3/mo (≤$8 even on Haiku) |
This validates the hypothesis: cheap-tier models are the right call for the entire shared layer, and the whole layer costs less than a coffee per month regardless of user count. It is consistent with design 01's envelope ($0.05–0.15/day for synthesis).
The one quality floor to watch: structured extraction accuracy on story synthesis — tickers[], event_type, importance drive story routing into daily briefings, so extraction errors propagate into user-facing insights. The eval set (story → expected tickers/event_type, design 01 §6) is the gate. Recommended tier per job:
| Job | Recommendation |
|---|---|
| Embeddings | text-embedding-3-small — no reason to pay 6.5× for -large at this corpus size |
| Story synthesis | mini-class (GPT-5 mini / Gemini 3.1 Flash-Lite) as default; downgrade to nano-class only if the extraction eval holds; upgrade to Haiku 4.5 if it doesn't. The spread is $0.5–8/mo — buy accuracy, it's cheap |
| Generic recap | nano-class — freeform prose over pre-ranked stories, no structured extraction risk |
4. Per-user layer — monthly
Defaults per job (each user can override per job; LiteLLM makes this config): daily agent = mid (GPT-5-class), recap personalization = mid (runs inside the daily agent call — design 02 §5.5), chat = best (Opus 4.8-class), verification = none.
| Job | Math at defaults | Cost/user/mo |
|---|---|---|
| Daily agent | 22 × (7k in @ $1.25 + 2.5k out @ $10) ≈ 22 × $0.034 | ~$0.60–0.90 |
| Recap personalization | 22 × (1.5k @ $1.25 + 0.5k @ $10) ≈ 22 × $0.007 | ~$0.10–0.20 |
| Action verification | deterministic — no LLM calls | $0.00 |
| Chat (the dominant variable) | per message ≈ 9k @ $5 + 0.75k @ $25 ≈ $0.06 | light ~$19 · medium ~$96 · heavy ~$288 |
Per-user totals (chat model choice shown because best-tier pricing spans 2.5×):
| Variant | Light (10/day) | Medium (50/day) | Heavy (150/day) |
|---|---|---|---|
| Defaults (best chat = Opus 4.8) | ~$20 | ~$95–100 | ~$290 |
| Defaults, best chat = Gemini 3.1 Pro ($2/$12) | ~$8–9 | ~$38–40 | ~$115 |
| All-cheap (everything mini-class) | ~$1.5 | ~$6 | ~$18 |
| All-premium (everything Opus 4.8-class) | ~$21–22 | ~$98 | ~$290+ |
Two readings of this table:
- Chat is 90–99% of per-user spend at defaults. Everything else — the briefing, personalization, verification — rounds to about $1/user/mo. The architecture's "deterministic facts, generated words" principle is what keeps the non-chat lines this small: contexts are compact fact packs, not raw data dumps.
- Under BYOK these per-user costs sit on the user's own provider key (with LiteLLM budget caps), not the house key. House-key exposure is then only the shared layer (§3) plus infra (§5) — the product's marginal LLM cost per user is ~$0.
5. Infrastructure — monthly
| Item | Choice | Cost/mo | Notes / source |
|---|---|---|---|
| App DB + auth | Supabase Free → Pro | $0 → $25 | Pro when it's the daily driver; $10 credit covers Micro compute (decision doc, pricing) |
| Lake object storage | Cloudflare R2 | ~$0 | Free tier: 10 GB + 1M writes + 10M reads/mo, zero egress. Our lake is tiny: 5y EOD prices for a few hundred tickers is tens of MB of Parquet; news raw+curated ≈ 25–50 MB/mo; per-user snapshots are KB/day. Years of runway ≈ single-digit GB; paid rate $0.015/GB-mo thereafter (R2 pricing) |
| Python brain + LiteLLM | small VPS (Hetzner CPX22-class, 2 vCPU/4 GB) or Fly.io shared VMs | ~$6–15 | Hetzner ≈ €8/mo; Fly ≈ $2/machine + egress, realistically $8–15 for two small always-on services |
| Web app | on the v1 box (Caddy serves Next.js, per doc 05 §9); Fly/Railway or Vercel Pro at scale-out | $0 → ~$20 | v1 ships no separate web host — the VPS line above covers it. At multi-user scale-out move to Fly/Railway or Vercel Pro ($20/user/mo, $20 usage credit); if a serverless platform (Vercel) hosts the web tier, check function-duration limits on the /brain/* SSE chat proxy first (pricing) |
| Market data + news | Tiingo Power | $30 ($25/mo if annual $300) | Verified current: individual $30/mo, News API included, EOD + corporate actions included; fundamentals is an add-on. Note: design 01 said "~$10/mo" — outdated, actual is $30 (Tiingo pricing). Internal-commercial tier $50/mo; redistribution licensing beyond that needs review before multi-user launch |
| News fallback (dev) | Finnhub free tier | $0 | 60 calls/min, company news, personal use only (Finnhub pricing) — fine for dev, not for a commercial product |
| Domain | any registrar | ~$1 (~$10–15/yr) |
Infra subtotal: dev/lean (all free tiers + yfinance) ≈ $7–16/mo; solo steady state ≈ $60–70/mo; multi-user adds a web host (Fly/Railway or Vercel Pro) and the Tiingo commercial tier.
As built (phase 8): the hosting target is AWS EC2 (t4g.small ARM, ≈$12–15/mo — the "small VPS" line above), runbook committed; news shipped on Finnhub free and prices stayed yfinance, so the $30 Tiingo line is deferred until the paid-data upgrade — the running system's infra bill is the dev/lean column plus Supabase Pro when it becomes the daily driver.
6. Scenario totals
Steady state, defaults, house key pays everything (no BYOK). Chat mix assumed all-light for the headline; the medium/heavy spread is in §4.
| Line | Solo (1 user) | 10 users | 100 users |
|---|---|---|---|
| Shared LLM (§3) | ~$2 | ~$2–4 | ~$3–6 |
| Supabase | $25 | $25 | $30–75 (Small→Medium compute) |
| R2 | ~$0 | ~$0 | ~$0–1 |
| VPS (brain + LiteLLM) | ~$10 | ~$10 | ~$15–30 |
| Web hosting | $0 (on the VPS) | ~$20 (Fly/Railway or Vercel Pro) | ~$20 (Fly/Railway or Vercel Pro) |
| Tiingo + domain | ~$31 | ~$51 (commercial) | ~$51+ (license review) |
| Fixed subtotal | ~$70 | ~$110 | ~$120–185 |
| Per-user LLM (light chat, defaults) | ~$20 | ~$200 | ~$2,000 |
| Total (house key) | ~$85–95/mo | ||
| Total if BYOK (users pay own LLM) | ~$70 |
How to read it:
- Fixed costs amortize hard: ~$70/user solo → ~$11/user at 10 → ~$1–2/user at 100. The shared layer (news, prices, recap) is genuinely flat — its LLM cost doesn't move from 1 to 100 users, exactly as designed (universe growth is sub-linear, stories are synthesized once).
- The only line that scales linearly is per-user LLM, and chat is ~95% of it. BYOK converts that line to $0 house exposure, which is why the architecture treats BYOK as the multi-user unlock: at 100 users the house bill is roughly a Netflix-tier fixed cost, not a payroll-tier LLM bill.
- Step functions to expect on the fixed side: Supabase compute (Micro→Small→Medium), VPS size, Tiingo license tier, web hosting (Fly/Railway or Vercel Pro). Each is a $5–50 step, not a cliff.
- Solo today, being honest: ~$90/mo all-in at defaults with light chat — of which $30 is Tiingo, $25 Supabase, ~$20 chat. During the build phase (free tiers, yfinance, no chat yet) it's realistically ~$10–20/mo.
7. Where the money actually goes
At every scale the ranking is the same: (1) chat tokens, (2) fixed subscriptions (Tiingo + Supabase + hosting), (3) everything else. The deterministic analytics engine — the core product value — costs $0/run. The daily briefing costs about a dollar per user per month. Design effort spent on cost should go to chat context discipline and model routing, nowhere else.
8. Sensitivity and knobs
- Chat volume dominates (~15× between light and heavy at the same model). A per-user LiteLLM budget cap is the safety net; usage-ledger visibility in Settings is the behavioral one. As built: the shipped caps are $2/day chat (
user_settings, preflight-enforced) with the $10/mo virtual-key budget as the hard stop — at defaults that bounds chat to roughly the light-usage line. - Chat model choice is a 2.5–4× knob: Gemini 3.1 Pro ($2/$12) vs Opus 4.8 ($5/$25) vs Fable 5 ($10/$50) — per-job defaults with user override make this a config decision, per architecture.
- Prompt caching: chat re-sends system prompt + fact pack + history every turn — the exact shape caching rewards (cache reads ~90% off input on Anthropic, ~90% on OpenAI cached input). Realistically cuts chat input cost 40–70% at medium/heavy usage; not assumed above, so treat §4 as conservative.
- Tool-call round trips: each extra round trip re-bills the whole context. Tight tool outputs (compact fact JSON, not row dumps) keep the 9k-in/message assumption from drifting to 20k.
- Polling cadence (3×/day → 30-min): raises API request counts against Tiingo limits, but embeddings/synthesis costs barely move — dedupe and thresholds mean the same articles cost the same once. A freshness knob, not a cost knob.
- Synthesis thresholds (1/3/8): raising the first threshold to 2 cuts synthesis calls ~30–40% but delays first summaries of slow-building stories. At ~$1–3/mo total, not worth touching for cost.
- Daily agent tier: mid → best is ~$0.75 →
$1.6–2.1/user/mo. If briefing quality ever disappoints, upgrading is cheap; downgrading to mini ($0.15) is on the table for cost-floor mode. - Trading-day gating already saves ~27% on the daily agent vs running every calendar day — keep the gate.
9. Source list
Verified 2026-07-04: Supabase pricing · Supabase compute · Cloudflare R2 pricing · Vercel pricing + Hobby plan terms · Tiingo pricing · Finnhub pricing · OpenAI embeddings · OpenAI/Anthropic/Google model rate cards as linked in §2 · Hetzner cloud pricing review · Fly.io pricing teardown.