Phase 3 — Investments: - Multi-currency support: holdings track purchase currency, FX rates convert to base for totals - Capital gains report using UK Section 104 pool method, grouped by tax year - Capital Gains tab added to Reports page Phase 5 — Polish & Hardening: - Mobile-responsive layout: bottom nav, sidebar hidden on mobile, logo in TopBar, compact header buttons, hover-only actions now always visible on touch - Backup system: encrypted GPG backups via backup.sh, nightly scheduler job, admin API (list/trigger/download/restore), Settings UI with drag-to-restore confirmation - Docker entrypoint with gosu privilege drop to fix bind-mount ownership on fresh deployments - OWASP fixes: refresh token now bound to its session (new refresh_token_hash column + migration), CSRF secure flag tied to environment, IP-level rate limiting on login, TOTPEnableRequest Pydantic schema replaces raw dict - AES-256-GCM key rotation script (rotate_keys.py) with dry-run mode and atomic DB transaction - CLAUDE.md added for AI-assisted development context - README updated: correct reverse proxy port, accurate backup/restore commands, key rotation instructions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
134 lines
2.6 KiB
Python
134 lines
2.6 KiB
Python
from datetime import date as DateType
|
|
from decimal import Decimal
|
|
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class NetWorthPoint(BaseModel):
|
|
date: DateType
|
|
total_assets: Decimal
|
|
total_liabilities: Decimal
|
|
net_worth: Decimal
|
|
base_currency: str
|
|
|
|
|
|
class NetWorthReport(BaseModel):
|
|
points: list[NetWorthPoint]
|
|
current_net_worth: Decimal
|
|
change_30d: Decimal
|
|
change_30d_pct: Decimal
|
|
base_currency: str
|
|
|
|
|
|
class IncomeExpensePoint(BaseModel):
|
|
month: str # "2024-01"
|
|
income: Decimal
|
|
expenses: Decimal
|
|
net: Decimal
|
|
|
|
|
|
class IncomeExpenseReport(BaseModel):
|
|
points: list[IncomeExpensePoint]
|
|
total_income: Decimal
|
|
total_expenses: Decimal
|
|
avg_monthly_income: Decimal
|
|
avg_monthly_expenses: Decimal
|
|
currency: str
|
|
|
|
|
|
class CashFlowPoint(BaseModel):
|
|
date: DateType
|
|
inflow: Decimal
|
|
outflow: Decimal
|
|
net: Decimal
|
|
running_balance: Decimal
|
|
|
|
|
|
class CashFlowReport(BaseModel):
|
|
points: list[CashFlowPoint]
|
|
total_inflow: Decimal
|
|
total_outflow: Decimal
|
|
currency: str
|
|
|
|
|
|
class CategoryBreakdownItem(BaseModel):
|
|
category_id: str | None
|
|
category_name: str
|
|
amount: Decimal
|
|
percent: Decimal
|
|
transaction_count: int
|
|
|
|
|
|
class CategoryBreakdownReport(BaseModel):
|
|
items: list[CategoryBreakdownItem]
|
|
total: Decimal
|
|
currency: str
|
|
date_from: DateType
|
|
date_to: DateType
|
|
|
|
|
|
class BudgetVsActualItem(BaseModel):
|
|
budget_id: str
|
|
budget_name: str
|
|
category_name: str
|
|
budgeted: Decimal
|
|
actual: Decimal
|
|
variance: Decimal
|
|
percent_used: Decimal
|
|
|
|
|
|
class BudgetVsActualReport(BaseModel):
|
|
items: list[BudgetVsActualItem]
|
|
total_budgeted: Decimal
|
|
total_actual: Decimal
|
|
currency: str
|
|
|
|
|
|
class SpendingTrendPoint(BaseModel):
|
|
month: str
|
|
category_name: str
|
|
amount: Decimal
|
|
|
|
|
|
class SpendingTrendsReport(BaseModel):
|
|
points: list[SpendingTrendPoint]
|
|
categories: list[str]
|
|
currency: str
|
|
|
|
|
|
class SavingsRatePoint(BaseModel):
|
|
month: str
|
|
income: Decimal
|
|
expenses: Decimal
|
|
savings: Decimal
|
|
savings_rate: Decimal
|
|
|
|
|
|
class SavingsRateReport(BaseModel):
|
|
points: list[SavingsRatePoint]
|
|
avg_savings_rate: Decimal
|
|
currency: str
|
|
|
|
|
|
class BalanceSheetAccount(BaseModel):
|
|
id: str
|
|
name: str
|
|
type: str
|
|
balance: Decimal
|
|
currency: str
|
|
|
|
|
|
class BalanceSheetGroup(BaseModel):
|
|
label: str
|
|
type_keys: list[str]
|
|
accounts: list[BalanceSheetAccount]
|
|
subtotal: Decimal
|
|
|
|
|
|
class BalanceSheetReport(BaseModel):
|
|
asset_groups: list[BalanceSheetGroup]
|
|
liability_groups: list[BalanceSheetGroup]
|
|
total_assets: Decimal
|
|
total_liabilities: Decimal
|
|
net_worth: Decimal
|
|
currency: str
|