Welcome to CoderLegion 22s

Leader posted 3 min read

Building finance tools people actually trust: a practical playbook (from the Pocket Portfolio trenches)

I’m 22s, one of the folks behind Pocket Portfolio — an open-source, no-paywall investing dashboard where you can import a CSV -> get clean live P/L, and model trades in a Mock-Trade & Scenario Lab without touching real totals.

I’ve shipped and broken my fair share of features. This post is the short list of things that made a night-and-day difference for us — equal parts tech, product, and what’s next.

Use anything here in your own project. If you want to kick the tires, the app + repo are at the end.


1) Technical: design for “no 0.00s” (fallbacks that fail gracefully)

Finance UI dies when prices flicker to 0.00. Our rule: client -> edge fallbacks with light telemetry and circuit-breakers.

// edge/fallbackQuote.ts (pseudo)
const providers = [
  { name: 'p1', url: env.P1_URL, timeoutMs: 1400 },
  { name: 'p2', url: env.P2_URL, timeoutMs: 1400 },
  { name: 'p3', url: env.P3_URL, timeoutMs: 1600 },
];

export async function getQuote(sym: string) {
  const errors: string[] = [];
  for (const p of providers) {
    try {
      const ctl = new AbortController();
      const t = setTimeout(() => ctl.abort(), p.timeoutMs);
      const r = await fetch(`${p.url}/q?symbol=${sym}`, { signal: ctl.signal, cf: { cacheTtl: 10 }});
      clearTimeout(t);
      if (!r.ok) throw new Error(`${p.name}:${r.status}`);
      const { price } = await r.json();
      if (!isFinite(price)) throw new Error(`${p.name}:NaN`);
      return { price, src: p.name };
    } catch (e: any) {
      errors.push(String(e.message));
      // soft failover: keep trying; never return 0
    }
  }
  // last resort: return "stale but not zero"
  const cached = await KV.get(`q:${sym}`); // store last good
  return { price: cached?.price ?? null, stale: true, errors };
}
````

Why it works

* Fast happy path from provider 1 with short TTL.
* Soft failover and never-zero fallback (last known good).
* Errors are counted, not logged to death.

---

## 2) Technical: CSV imports that don’t make people rage-quit

You will never have every broker format. Make it survivable:

```ts
type ImportRow = {
  raw: Record<string, string>;  // source columns intact
  norm?: { sym: string; qty: number; price: number; ts: string };
  err?: { code: 'PARSE'|'SCHEMA'|'MISSING'; hint: string };
};

UX rules that helped immediately

  • Always show a sample file (eToro/Coinbase/Generic) and a Download error CSV when something fails.
  • Ask users to paste one redacted row in an issue; ship the mapping the same day.
  • Keep the import stateless — users can re-run safely.

3) Product: ship the “Are we sure?” layer

If you build tools that move money, people need a rehearsal. Our answer: a Mock-Trade & Scenario Lab that is:

  • Instant: Add TSLA +2 @ 260 with zero setup.
  • Isolated: Mock totals never touch real P/L.
  • Obvious: A big "mock trades active" chip, and a reset.

This one feature cut buyer’s remorse reports to near zero. Whatever you’re building, ask: What’s the one safe preview my user needs before a hard commit?


4) Business: one metric that punches above its weight

Time-to-first-insight (TTFI)
From first page load -> the moment a user sees something true about their portfolio. We track it like performance.

Things that reduce TTFI:

  • Sample CSVs in the modal
  • Default scenario ("add 1 share") with undo
  • Fallback quotes (the “no 0.00s” rule)

If your TTFI is < 60 seconds, activation will feel different.


5) Next frontier (where we’re headed)

  • Keyboard-first dashboards: a11y that doubles as speed. Arrow/Home/End for the grid; M opens Mock-Trade; ? shows shortcuts.
  • Explainers, not black boxes: when totals change, show why ("+2 TSLA @ 260 changed delta P/L +$48"). Debuggable numbers build trust.
  • Local-first where it matters: scenarios and recent quotes cached on device; sensitive bits never have to round-trip.

If you’re exploring the same things, I’d love to swap notes.


What we’re building (and where to try it)

Pocket Portfolio is open-source and free to use:

Good first issues right now

  • CSV mapping for a new broker format (drop one redacted row)
  • Playwright test for the error-CSV -> fix -> success loop
  • Light UI polish on the Mock-Trade modal

If you have thoughts on price fallbacks, import UX, or keyboard nav, hit me. I’ll review your project back — README, a11y, or a small PR.

— 22s
Founder, Pocket Portfolio

If you read this far, tweet to the author to show them you care. Tweet a Thanks

This breakdown of building trustworthy finance tools feels very practical, especially the focus on graceful failures and quick insights. Do you think prioritising transparency in calculations could become a key trust factor for all modern fintech apps?

Hey Andrew — great question. Short answer: yes. Making the math legible is a cheat-code for trust and growth. Here’s how I think about it:

1) Trust (the human layer)

  • Show the “why,” not just the number.
    If P/L jumps, reveal the ingredients: +2 TSLA @ 260 → +$48.
  • Label uncertainty.
    If a quote is stale, say so (Last update 28s • p2 fallback). “Known-stale” beats silent wrong.
  • Let users rehearse decisions.
    A Mock-Trade layer lets you model changes without touching real totals. That safety net builds confidence.

In Pocket Portfolio we treat explainability as a feature: hover explains source & deltas, stale chips are explicit, and imports return an error CSV with a fix path.

2) Business value (it quietly improves your funnel)

  • Lower support costs: fewer “why is this number wrong?” tickets.
  • Faster activation: users reach first insight sooner when the app explains itself.
  • Higher retention: when numbers are predictable + debuggable, people stick around (and recommend you).

We track TTFI (Time-to-First-Insight). Making calculations transparent consistently moves this metric down.

3) Product innovation (it unlocks better features)

  • Composable math → new views. If you expose the formula parts (qty, price, FX, fees), you can mix them into scenarios, sensitivity sliders, and alerts.
  • Safer automation. Clear inputs/outputs make it easier to add rules, backtests, and “what-if” tools without spooky behavior.
  • A11y as speed. When states are explicit, they’re easier to announce to screen readers and to map to keyboard shortcuts.

Simple rule of thumb:

If a number can’t explain itself in one click/hover, it’s not ready to ship.

If you’re game, I’d love to swap examples from your world: which number in your app causes the most “wait, how?” moments? I can share the tiny “why-this-changed” component we use.

More Posts

[DISCUSS] The “Never 0.00” Challenge — design a resilient price pipeline (client → edge) together

Pocket Portfolio - Sep 29

From Simplicity to Complexity: My Love-Hate Journey with Next.js

Sibasish Mohanty - Sep 9

How To Build A Dynamic Modal In Next.js

chukwuemeka Emmanuel - Apr 5

Hello World! Welcome to the React Dev Group!

James Dayal - Sep 25

Learn how to integrate Firebase AI Logic into your iOS app.

Francesco - Jun 8
chevron_left