Skip to content

Multi-currency display: FX port + per-user display currency - #13

Merged
jckail merged 1 commit into
masterfrom
feature/multi-currency
Jul 9, 2026
Merged

Multi-currency display: FX port + per-user display currency#13
jckail merged 1 commit into
masterfrom
feature/multi-currency

Conversation

@jckail

@jckail jckail commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

Roadmap item: "Multi-currency valuations — FX port + display currency preference; cents-per-point stays USD-denominated internally." Users pick a display currency; the portfolio summary carries a converted total. No stored data changes with the exchange rate — conversion happens only at the display edge.

  • DomainFxRateSource port, supported currencies (USD/EUR/GBP/CAD/AUD/JPY), pure convertUsdCents (2dp; 0dp for JPY), InvalidDisplayCurrencyError; UserSettings entity + repository port (one row per user, designed to grow column-by-column — notification prefs are the natural next tenant).
  • DBuser_setting table + migration 0007 (additive only) + Drizzle repo (validates the currency on read so a bad row degrades loudly, not silently).
  • FX adaptersHttpFxRateSource (frankfurter-style GET /latest?base=USD&symbols=…, injectable fetch, 1-hour in-process cache) and StaticFxRateSource (pinned dev rates).
  • ApplicationGetUserSettings (defaults USD) / SetDisplayCurrency / BuildDisplayValue. Conversion is best-effort: USD or an FX outage yields null, never a broken summary.
  • WebGET/PUT /api/v1/settings; the summary response gains an optional display: { currency, amount, ratePerUsd }; FX_API_URL env (static fallback when unset).
  • Contracts + OpenAPI + api-client + docs updated; summary DTO change is backward-compatible (optional field).

Verification

  • 141 tests pass (110 core incl. 7 new + 20 bot + 11 extension) — conversion rounding (incl. JPY), defaulting, validation, FX failure degradation, HTTP adapter caching/error paths.
  • typecheck + eslint clean.

⚠️ Migration note

Adds migration 0007 (new table only, additive). Applies on deploy via the worker migrate task once deploys are enabled (AWS_DEPLOY_ROLE_ARN).

🤖 Generated with Claude Code

Roadmap item ("Multi-currency valuations — FX port + display currency
preference; cents-per-point stays USD-denominated internally").

- domain: FxRateSource port + supported display currencies (USD/EUR/GBP/CAD/
  AUD/JPY) + convertUsdCents (2dp; 0dp JPY) + InvalidDisplayCurrencyError;
  UserSettings entity + repository port (one row per user, extended
  column-by-column as preferences accrue).
- db: user_setting table + migration 0007 (additive only) + Drizzle repo
  (validates currency on read so a bad row degrades loudly).
- infra adapters: HttpFxRateSource (frankfurter-style GET /latest?base=USD,
  injectable fetch, 1h in-process cache) + StaticFxRateSource pinned dev rates.
- application: GetUserSettings (defaults USD) / SetDisplayCurrency /
  BuildDisplayValue — conversion is best-effort: FX failure or USD returns
  null and never breaks the response.
- web: GET/PUT /api/v1/settings; summary response gains an optional `display`
  {currency, amount, ratePerUsd}; FX_API_URL env (static fallback otherwise).
- contracts + OpenAPI + api-client (getUserSettings/updateUserSettings) +
  docs (api.md) + .env-example.

Verification: 141 tests pass (110 core incl. 7 new + 20 bot + 11 extension);
typecheck + lint clean; migration generated offline (additive).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cursor

cursor Bot commented Jul 9, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@jckail
jckail merged commit 4ebba1f into master Jul 9, 2026
2 checks passed
@jckail
jckail deleted the feature/multi-currency branch July 9, 2026 23:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant