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:
commit
61a7884ee5
127 changed files with 13323 additions and 0 deletions
107
frontend/src/api/accounts.ts
Normal file
107
frontend/src/api/accounts.ts
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue