Skip to content
Ritesh FirodiyaGet in touch

Work / Chitragupt / Wiki / Decisions

2026-07-02-dashboard-history-callables

Decisioncanonicalverified 2026-07-02

DECISION.2026-07-02.DASHBOARD-HISTORY-CALLABLES

Decision

Three new callables + one reference collection power the dashboard chart row:

  1. getTaxHistorySeries(from_ay, to_ay) — returns { ay, income_paise, tax_paise, position_kind, position_paise }[] for the caller's users/{uid}/tax_reviews/{ay} subcollection. AYs without a stored review are omitted.
  2. getPortfolioHistorySeries(from_fy, to_fy) — returns { fy, invested_paise, realised_paise, value_paise }[] from users/{uid}/portfolio_reviews/{ay} (portfolio-reviews are keyed by AY == FY for this range). Missing FYs omitted; realised_paise = short-term + long-term sum.
  3. getNiftyBenchmark(from_fy, to_fy) — reads nifty_benchmarks/{fy} (public read, admin write) and returns end-of-FY Nifty 50 closes for the range.

All three follow the existing onZodCall pattern. Frontend hooks in apps/website/src/store/tax-history.ts and apps/website/src/store/portfolio-history.ts wrap useCallableQuery and expose discriminated-union state consistent with useMarketplaceCas.

The nifty_benchmarks/{fy} collection is seeded via apps/functions/scripts/seed-prod.mjs alongside ay_registry and admin_kpis. Initial seed covers FY 2020-21 through FY 2024-25 with published historical closing values on the last trading day of each FY.

Why

The wireframes for dashboard-populated.md show three charts (Tax journey · Cashflow · Portfolio vs Nifty) that need historical data:

  • Tax journey wants five AYs of income + tax paid.
  • Portfolio vs Nifty wants per-FY invested / realised / value plus a broad-market benchmark to compare against.

Neither exists at the store level. useTaxReview(ay) and usePortfolioReview(ay) each subscribe to a single AY, and Nifty prices weren't stored anywhere.

Three options considered:

  1. Ship the charts with placeholder/empty state and defer the callables.
  2. Ship the callables now; seed Nifty manually.
  3. Skip the two AY-history charts on the dashboard and keep only the KPI row + cashflow.

We picked (2) — ship the callables now with a manually seeded Nifty table. The alternative left the wireframe's most visible dashboard surface stranded and the chart shells never fill; option (3) is a regression against the wireframe.

The Nifty table is manually maintained until a scheduled Cloud Function ships to refresh it from a market-data feed. Follow-up ticket: automate the refresh.

Impact

  • New callables live under apps/functions/src/tax/history.ts, apps/functions/src/portfolio/history.ts, apps/functions/src/benchmarks/nifty.ts.
  • Contracts in packages/shared/src/contracts/{tax,portfolio,benchmarks}.ts.
  • Schema in packages/shared/src/schemas/nifty-benchmark.ts.
  • Rules: nifty_benchmarks/{fy} public-read, server-write. Update in firebase/firestore.rules.
  • seed-prod.mjs seeds the Nifty rows idempotently.
  • Every dashboard chart accepts a discriminated-union state and renders placeholder / skeleton / error / chart per the frontend three-states rule.

Related surfaces:

Related concepts:

  • concept-three-states

Status

Active.

Sources

  • .context/designs/web/home/home.html (chart section reference)
  • apps/functions/src/tax/history.ts
  • apps/functions/src/portfolio/history.ts
  • apps/functions/src/benchmarks/nifty.ts
  • apps/functions/scripts/seed-prod.mjs

Every project of mine is written down like this.

Read the résumé