Add accounts expansion, analytics, exchange rates, API tokens, PWA support, and UI overhaul
All checks were successful
Deploy to VPS / deploy (push) Successful in 45s

- Expand Account model with account_type (pension, savings, liability, crypto), new banks/currencies (BTC, XMR, FCL, ROP, VOL, MEMP, MPAT, MORTGAGE), and next_payment field
- Add exchange rate endpoint (BCCR integration), analytics endpoint, paste-import for transactions, and API token management
- Add PWA manifest, service worker, and app icons
- Redesign dashboard, transactions, transfers, and login pages with theme support
- Add billing cycle selector, confirm dialog, and paste import modal components
- One-time DB reset in deploy workflow for schema migration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Carlos Escalante
2026-03-21 18:23:47 -06:00
parent 1257b0dd61
commit 0a8e00e227
39 changed files with 2247 additions and 220 deletions

View File

@@ -19,12 +19,28 @@ class TransactionSource(str, enum.Enum):
class Currency(str, enum.Enum):
CRC = "CRC"
USD = "USD"
BTC = "BTC"
XMR = "XMR"
class Bank(str, enum.Enum):
BAC = "BAC"
BCR = "BCR"
DAVIVIENDA = "DAVIVIENDA"
FCL = "FCL"
ROP = "ROP"
VOL = "VOL"
MEMP = "MEMP"
MPAT = "MPAT"
MORTGAGE = "MORTGAGE"
class AccountType(str, enum.Enum):
BANK = "BANK"
PENSION = "PENSION"
CRYPTO = "CRYPTO"
SAVINGS = "SAVINGS"
LIABILITY = "LIABILITY"
# --- Category ---
@@ -64,8 +80,10 @@ class CategoryUpdate(SQLModel):
class AccountBase(SQLModel):
bank: Bank
currency: Currency
label: str = Field(description="e.g. 'BAC Colones', 'BAC Dólares'")
label: str
balance: float = 0.0
account_type: AccountType = AccountType.BANK
next_payment: Optional[float] = None
class Account(AccountBase, table=True):
@@ -85,6 +103,7 @@ class AccountRead(AccountBase):
class AccountUpdate(SQLModel):
balance: Optional[float] = None
label: Optional[str] = None
next_payment: Optional[float] = None
# --- Transaction ---
@@ -99,7 +118,7 @@ class TransactionBase(SQLModel):
card_type: Optional[str] = None
card_last4: Optional[str] = None
authorization_code: Optional[str] = None
reference: Optional[str] = None
reference: Optional[str] = Field(default=None, index=True)
transaction_type: TransactionType = TransactionType.COMPRA
source: TransactionSource = TransactionSource.CREDIT_CARD
bank: Bank = Bank.BAC
@@ -133,3 +152,46 @@ class TransactionUpdate(SQLModel):
source: Optional[TransactionSource] = None
notes: Optional[str] = None
category_id: Optional[int] = None
# --- Exchange Rate ---
class ExchangeRate(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
date: datetime
buy_rate: float
sell_rate: float
fetched_at: datetime = Field(default_factory=datetime.utcnow)
class ExchangeRateRead(SQLModel):
buy_rate: float
sell_rate: float
date: datetime
fetched_at: datetime
# --- API Token ---
class APIToken(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
token_hash: str = Field(index=True)
created_at: datetime = Field(default_factory=datetime.utcnow)
expires_at: Optional[datetime] = None
is_active: bool = True
class APITokenCreate(SQLModel):
name: str
expires_days: Optional[int] = None
class APITokenRead(SQLModel):
id: int
name: str
created_at: datetime
expires_at: Optional[datetime]
is_active: bool