mirror of
https://github.com/Such-Software/smirk-backend-core.git
synced 2026-10-17 07:21:32 +02:00
feat: fiat price feed with per-feed operator control (GET /api/v1/prices)
Cached crypto→fiat price feed, refreshed by a background task and served from an in-memory snapshot — no upstream call on the request path. Public and feature-flagged: when FEATURE_PRICES is off, /prices is 404 and no upstream is ever contacted. Per-feed control, as a public server needs: PRICES_ASSETS narrows which feeds an instance quotes (unset = all supported; an explicit list serves a subset; empty serves none), validated fail-closed against SUPPORTED_PRICE_ASSETS. Provider (PRICES_PROVIDER, coingecko) and currency (PRICES_CURRENCY, usd) are configurable; the refresh interval is clamped to a provider-friendly minimum. - infra/prices: PriceClient (feed whitelist → provider coin ids), bounded by the HTTP client timeout; non-finite/negative/missing quotes are skipped, not faked. A fetch failure keeps the last good snapshot. Drift guard: a test asserts the provider mapping covers exactly SUPPORTED_PRICE_ASSETS. - main: background refresh task only when enabled and at least one feed is set. - AppState.prices snapshot; handler 404s when disabled. - openapi (prices tag); unit tests + L1 test over both feature-flag states.
This commit is contained in:
@@ -429,6 +429,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/prices": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"prices"
|
||||
],
|
||||
"summary": "Current fiat prices for the enabled feeds.",
|
||||
"operationId": "prices",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Latest cached prices",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PricesResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Price feed disabled on this server"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/by-username/{username}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -2449,6 +2473,37 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"PricesResponse": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"currency",
|
||||
"prices"
|
||||
],
|
||||
"properties": {
|
||||
"currency": {
|
||||
"type": "string",
|
||||
"description": "Fiat currency the quotes are in (e.g. `\"usd\"`)."
|
||||
},
|
||||
"prices": {
|
||||
"type": "object",
|
||||
"description": "Asset symbol → price in `currency`. Only enabled feeds appear.",
|
||||
"additionalProperties": {
|
||||
"type": "number",
|
||||
"format": "double"
|
||||
},
|
||||
"propertyNames": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"updated_at": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"description": "RFC 3339 timestamp of the last successful refresh; `null` until the first."
|
||||
}
|
||||
}
|
||||
},
|
||||
"PublicKeysInfo": {
|
||||
"type": "object",
|
||||
"description": "A user's per-asset receiving public keys, by asset.",
|
||||
@@ -3189,6 +3244,10 @@
|
||||
"name": "system",
|
||||
"description": "Service health and metadata."
|
||||
},
|
||||
{
|
||||
"name": "prices",
|
||||
"description": "Fiat price feed (cached; per-feed configurable; feature-flagged)."
|
||||
},
|
||||
{
|
||||
"name": "auth",
|
||||
"description": "Wallet authentication: registration, restore, refresh, sessions, Nostr identity."
|
||||
|
||||
Reference in New Issue
Block a user