mirror of
https://github.com/Zproger/Aurum.git
synced 2026-10-14 03:26:40 +07:00
feat: add a Crypto tab with live CoinGecko prices synced into Net Worth
Track individual coins (identity + quantity) in a dedicated tab, backed by CoinGecko's Demo API (AURUM_COINGECKO_API_KEY). A holding is just another Asset under the hood (asset_class=crypto) with its value written as a regular AssetValuation — the existing Net Worth aggregation needs zero changes to pick it up. Prices never refresh in the background (no scheduler in this stack, same reasoning as recurring transactions): a "Refresh prices" button forces a sync, and GET /crypto/holdings lazily re-syncs at most once every 24h. CoinGecko outages leave existing values untouched (error_key: "unreachable") instead of failing the request. Backup/restore now carries CryptoHolding rows too, so a restore doesn't silently strip a holding's coin identity. Backend: 75/75 tests passing (9 new), including a real identity-map staleness bug the tests caught in the raw-Core-upsert + ORM re-read pattern, fixed via populate_existing=True. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01855PiW5Wd8n4aRW4n9kByY
This commit is contained in:
@@ -95,6 +95,19 @@ class AssetValuationBackup(BaseModel):
|
||||
as_of_date: date_
|
||||
|
||||
|
||||
class CryptoHoldingBackup(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
# asset_id doubles as this row's own primary key (see
|
||||
# models/crypto.py's CryptoHolding) — there's no separate `id`.
|
||||
asset_id: int
|
||||
coingecko_id: str
|
||||
symbol: str
|
||||
name: str
|
||||
thumb_url: str | None
|
||||
quantity: Decimal
|
||||
|
||||
|
||||
class BudgetBackup(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
@@ -173,6 +186,9 @@ class BackupPayload(BaseModel):
|
||||
transactions: list[TransactionBackup]
|
||||
assets: list[AssetBackup]
|
||||
asset_valuations: list[AssetValuationBackup]
|
||||
# Defaulted so a backup exported before crypto holdings existed still
|
||||
# imports cleanly under the same format version.
|
||||
crypto_holdings: list[CryptoHoldingBackup] = Field(default_factory=list)
|
||||
# Defaulted so a backup exported before budgets existed still imports
|
||||
# cleanly under the same format version.
|
||||
budgets: list[BudgetBackup] = Field(default_factory=list)
|
||||
|
||||
Reference in New Issue
Block a user