Initial commit: MyMidas personal finance tracker

Full-stack self-hosted finance app with FastAPI backend and React frontend.

Features:
- Accounts, transactions, budgets, investments with GBP base currency
- CSV import with auto-detection for 10 UK bank formats
- ML predictions: spending forecast, net worth projection, Monte Carlo
- 7 selectable themes (Obsidian, Arctic, Midnight, Vault, Terminal, Synthwave, Ledger)
- Receipt/document attachments on transactions (JPEG, PNG, WebP, PDF)
- AES-256-GCM field encryption, RS256 JWT, TOTP 2FA, RLS, audit log
- Encrypted nightly backups + key rotation script
- Mobile-responsive layout with bottom nav

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
megaproxy 2026-04-21 11:56:10 +00:00
commit 61a7884ee5
127 changed files with 13323 additions and 0 deletions

View file

@ -0,0 +1,107 @@
import { api } from "./client";
export interface Account {
id: string;
name: string;
institution: string | null;
type: string;
currency: string;
current_balance: number;
credit_limit: number | null;
interest_rate: number | null;
is_active: boolean;
include_in_net_worth: boolean;
color: string;
icon: string | null;
notes: string | null;
created_at: string;
updated_at: string;
}
export interface AccountCreate {
name: string;
institution?: string;
type: string;
currency?: string;
credit_limit?: number;
interest_rate?: number;
include_in_net_worth?: boolean;
color?: string;
opening_balance?: number;
notes?: string;
}
export async function getAccounts(): Promise<Account[]> {
const res = await api.get("/accounts");
return res.data;
}
export async function createAccount(data: AccountCreate): Promise<Account> {
const res = await api.post("/accounts", data);
return res.data;
}
export async function updateAccount(id: string, data: Partial<AccountCreate>): Promise<Account> {
const res = await api.put(`/accounts/${id}`, data);
return res.data;
}
export async function deleteAccount(id: string): Promise<void> {
await api.delete(`/accounts/${id}`);
}
export interface CsvMapping {
date: string;
description: string;
amount: string | null;
debit: string | null;
credit: string | null;
balance: string | null;
reference: string | null;
}
export interface ImportPreview {
detected_format: string | null;
headers: string[];
mapping: CsvMapping;
total_rows: number;
preview: {
date_raw: string;
description_raw: string;
amount_raw: number | null;
balance_raw?: string;
}[];
}
export async function previewImport(accountId: string, file: File): Promise<ImportPreview> {
const form = new FormData();
form.append("file", file);
const res = await api.post(`/accounts/${accountId}/import/preview`, form);
return res.data;
}
export async function importCsvToAccount(
accountId: string,
file: File,
mapping: CsvMapping
): Promise<{ imported: number; skipped: number }> {
const form = new FormData();
form.append("file", file);
form.append("date_col", mapping.date);
form.append("description_col", mapping.description);
form.append("amount_col", mapping.amount ?? "");
form.append("debit_col", mapping.debit ?? "");
form.append("credit_col", mapping.credit ?? "");
const res = await api.post(`/accounts/${accountId}/import`, form);
return res.data;
}
export async function getNetWorth(): Promise<{
total_assets: number;
total_liabilities: number;
net_worth: number;
base_currency: string;
}> {
const res = await api.get("/accounts/net-worth");
return res.data;
}