Search

PythonReactSEOPDF
GitHub Skill

multi-currency

Exchange rate management, currency conversion, and Frankfurter API integration. Use when working with USD/EUR/ILS conversions, exchange rates, or multi-currency dashboard displays.

avifenesh☆ 0 Repository stars0 Repository forks

Installation

Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.

View source ↗Guides

Skill instructions

Multi-Currency Domain Knowledge

Supported Currencies

enum Currency {
  USD  // US Dollar
  EUR  // Euro
  ILS  // Israeli Shekel
}

Exchange Rate Storage

model ExchangeRate {
  id             String   @id @default(cuid())
  baseCurrency   Currency
  targetCurrency Currency
  rate           Decimal  @db.Decimal(12, 6)  // 6 decimal precision
  date           DateTime
  fetchedAt      DateTime @default(now())

  @@unique([baseCurrency, targetCurrency, date])
}

Frankfurter API Integration

Location: src/lib/currency.ts

Base URL: https://api.frankfurter.dev/v1

fetchExchangeRates
export async function fetchExchangeRates(baseCurrency: Currency): Promise<FrankfurterResponse>

Features:

  • Request deduplication via inFlightRequests Map
  • Concurrent requests for same base currency return same Promise
  • Automatic cleanup after request completes
getExchangeRate
export async function getExchangeRate(from: Currency, to: Currency, date?: Date): Promise<number>

Strategy:

  1. Same currency returns 1 (no conversion needed)
  2. Check cache (ExchangeRate table) for today's rate
  3. Fetch from API if not cached
  4. Upsert to cache
  5. Fallback to most recent cached rate if API fails
convertAmount
export async function convertAmount(
  amount: number,
  from: Currency,
  to: Currency,
  date?: Date
): Promise<number>
  • Returns amount unchanged if same currency
  • Rounds to 2 decimal places: Math.round(converted * 100) / 100

Batch Loading Pattern (N+1 Prevention)

For dashboard aggregations, use batch loading:

batchLoadExchangeRates
export async function batchLoadExchangeRates(date?: Date): Promise<RateCache>
// Returns Map<string, number> for O(1) lookups
convertAmountWithCache
export function convertAmountWithCache(
  amount: number,
  from: Currency,
  to: Currency,
  cache: RateCache
): number
  • No database calls (uses preloaded cache)
  • Logs warning if rate missing, returns original amount
  • Use in loops/aggregations to avoid N+1 queries

Cache Key Format

function rateCacheKey(from: Currency, to: Currency): string {
  return `${from}:${to}`  // e.g., "USD:EUR"
}

Refresh Workflow

export async function refreshExchangeRates(): Promise<
  { success: true; updatedAt: Date } | { error: { general: string[] }; updatedAt: Date }
>
  • Fetches rates for ALL base currencies
  • Upserts all currency pairs for today
  • Called via refreshExchangeRatesAction from dashboard UI

User Preference

model User {
  preferredCurrency Currency @default(USD)
}

Dashboard displays amounts in user's preferred currency via conversion.

Key Files

  • src/lib/currency.ts - All currency functions
  • src/app/actions/misc.ts - refreshExchangeRatesAction
  • src/lib/dashboard-ux.ts - Uses batchLoadExchangeRates for aggregation

Examples

Read the usage examples in the source repository.

View source ↗

Source history

Indexed on
2026-01-20
Index updated
2026-01-26
Branch
main

Index and sync dates describe this directory. View the source repository for code history.

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!