From 664b53013666352e1bf8b84fad5088fd666b0d95 Mon Sep 17 00:00:00 2001 From: megaproxy Date: Thu, 23 Apr 2026 22:47:44 +0000 Subject: [PATCH] Seed historical net worth snapshots and trigger live price sync on demo startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - seed.py: adds 30 weekly NetWorthSnapshot rows (Sep 2025 → Apr 2026) so the Net Worth chart has full history on first boot, not just today's value - main.py: fires price_sync_job and fx_sync_job in the background immediately after the scheduler starts in demo mode, so portfolio valuations are live from the moment the container becomes healthy Co-Authored-By: Claude Sonnet 4.6 --- backend/app/demo/seed.py | 55 +++++++++++++++++++++++++++++++++++++++- backend/app/main.py | 9 +++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/backend/app/demo/seed.py b/backend/app/demo/seed.py index b8c107f..0524de0 100644 --- a/backend/app/demo/seed.py +++ b/backend/app/demo/seed.py @@ -12,7 +12,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.core.security import encrypt_field, hash_password from app.db.models import ( Account, Asset, Budget, Category, InvestmentHolding, - InvestmentTransaction, ManualCGTDisposal, Payslip, + InvestmentTransaction, ManualCGTDisposal, NetWorthSnapshot, Payslip, TaxProfile, Transaction, User, ) @@ -501,3 +501,56 @@ async def seed_demo(db: AsyncSession) -> None: )) await db.flush() + + # ── Historical net worth snapshots (weekly, Oct 2025 → present) ─────── + # Plausible progression: cash + growing investment portfolio, salary in + # each month, large purchases (car insurance Oct, Christmas Dec, etc.) + nw_history = [ + # (date, total_assets, total_liabilities) + (date(2025, 9, 28), "8150.00", "0.00"), + (date(2025, 10, 5), "8320.00", "220.00"), # VWRP+AAPL bought, Amex started + (date(2025, 10, 12), "8050.00", "680.00"), # car insurance £485 hit + (date(2025, 10, 19), "8750.00", "820.00"), # salary in, investments ticked up + (date(2025, 10, 26), "9150.00", "820.00"), + (date(2025, 11, 2), "9820.00", "820.00"), # salary + BTC purchase Nov 1 + (date(2025, 11, 9), "9600.00", "820.00"), # slight market dip + (date(2025, 11, 16), "9900.00", "820.00"), + (date(2025, 11, 23), "10150.00", "820.00"), + (date(2025, 11, 30), "10380.00", "820.00"), + (date(2025, 12, 7), "10620.00", "820.00"), + (date(2025, 12, 14), "10250.00", "1250.00"), # Christmas spending on Amex + (date(2025, 12, 21), "10100.00", "1350.00"), # VWRP 2nd buy + holiday spend + (date(2025, 12, 28), "10350.00", "1350.00"), # post-Xmas, markets recovering + (date(2026, 1, 4), "10950.00", "1100.00"), # new year, paid some Amex, markets up + (date(2026, 1, 11), "11350.00", "1100.00"), + (date(2026, 1, 18), "11700.00", "1100.00"), + (date(2026, 1, 25), "11500.00", "1100.00"), # small dip + (date(2026, 2, 1), "12050.00", "1100.00"), # salary in + (date(2026, 2, 8), "12450.00", "1100.00"), + (date(2026, 2, 15), "13050.00", "1100.00"), # VWRP 3rd buy + market run + (date(2026, 2, 22), "13500.00", "1100.00"), + (date(2026, 3, 1), "14050.00", "1100.00"), # salary in + (date(2026, 3, 8), "14450.00", "1100.00"), + (date(2026, 3, 15), "15000.00", "1050.00"), + (date(2026, 3, 22), "15500.00", "1042.50"), + (date(2026, 3, 29), "15650.00", "1042.50"), + (date(2026, 4, 5), "15680.00", "1042.50"), + (date(2026, 4, 12), "15710.00", "1042.50"), + (date(2026, 4, 19), "15740.00", "1042.50"), + ] + for snap_date, assets_str, liabs_str in nw_history: + assets = Decimal(assets_str) + liabs = Decimal(liabs_str) + db.add(NetWorthSnapshot( + id=uuid.uuid4(), + user_id=uid, + date=snap_date, + total_assets=assets, + total_liabilities=liabs, + net_worth=assets - liabs, + base_currency="GBP", + breakdown={}, + created_at=now, + )) + + await db.flush() diff --git a/backend/app/main.py b/backend/app/main.py index 3f0dc7c..f3add37 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -51,6 +51,15 @@ async def lifespan(app: FastAPI): from app.workers.scheduler import start_scheduler, stop_scheduler await start_scheduler() + # Demo: sync live prices and FX rates immediately so portfolio values are fresh + if settings.is_demo: + import asyncio + from app.workers.price_sync import price_sync_job + from app.workers.fx_sync import fx_sync_job + asyncio.ensure_future(price_sync_job()) + asyncio.ensure_future(fx_sync_job()) + logger.info("demo_background_sync_queued") + logger.info("startup_complete", env=settings.environment) yield