Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
n/a
0 / 0
n/a
0 / 0
CRAP
n/a
0 / 0
1<?php
2
3declare(strict_types=1);
4
5namespace App\Currency\Application;
6
7use App\Shared\Domain\ValueObject\Currency;
8use DateTimeImmutable;
9
10/**
11 * Port: the exchange rate between two currencies as of a given date. Conversion
12 * stays a view-time concern (never stored on an Expense), but it is anchored to
13 * the expense's spend date — not "today" — so a past expense always shows the
14 * rate of the day it was spent and never drifts with the market. Past rates are
15 * immutable, so the result is stable and safe to cache for a long time. The
16 * Reporting context reuses this port.
17 *
18 * DECISION (2026-06-22) — view-time historical lookup (B), NOT a persisted rate
19 * snapshot (A). The drift the user flagged comes from using *today's* rate, not
20 * from a lack of persistence; looking the rate up by the spend date fixes it with
21 * zero schema/aggregate/write-path change, and survives a user changing their
22 * preferred currency (it re-converts to the *current* preferred at the historical
23 * rate). A snapshot was rejected because recording a back-dated expense would
24 * still need a history-capable provider at write time, so it would NOT remove the
25 * provider-history dependency — it would only freeze already-recorded rows.
26 *
27 * FUTURE — switch to persistence (or a dedicated daily rate-history store) ONLY
28 * when one of these becomes real:
29 *   1. we leave a provider that serves historical dates (Frankfurter `/v1/{date}`)
30 *      for one that serves only "latest" → then own the rates (snapshot at write +
31 *      back-fill, or an `exchange_rates(date, base, quote, rate)` table);
32 *   2. we need an immutable audit trail frozen at write time, independent of any
33 *      provider.
34 * A per-user "change preferred currency" feature alone does NOT force this. Full
35 * rationale + the rejected option in docs/PROGRESS.md.
36 */
37interface ExchangeRateProvider
38{
39    /**
40     * Multiplier to take an amount from $from into $to as of $on (e.g. EUR→USD ≈ 1.08).
41     */
42    public function rate(Currency $from, Currency $to, DateTimeImmutable $on): float;
43}