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
79
backend/app/api/v1/budgets.py
Normal file
79
backend/app/api/v1/budgets.py
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import uuid
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.dependencies import get_current_user, get_db
|
||||
from app.db.models.user import User
|
||||
from app.schemas.budget import BudgetCreate, BudgetResponse, BudgetSummaryItem, BudgetUpdate
|
||||
from app.services import budget_service
|
||||
|
||||
router = APIRouter(prefix="/budgets", tags=["budgets"])
|
||||
|
||||
|
||||
@router.get("", response_model=list[BudgetResponse])
|
||||
async def list_budgets(
|
||||
active_only: bool = True,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
return await budget_service.list_budgets(db, current_user.id, active_only)
|
||||
|
||||
|
||||
@router.post("", response_model=BudgetResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_budget(
|
||||
data: BudgetCreate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
budget = await budget_service.create_budget(db, current_user.id, data)
|
||||
await db.commit()
|
||||
return budget
|
||||
|
||||
|
||||
@router.get("/summary", response_model=list[BudgetSummaryItem])
|
||||
async def get_budget_summary(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
return await budget_service.get_budget_summary(db, current_user.id)
|
||||
|
||||
|
||||
@router.get("/{budget_id}", response_model=BudgetResponse)
|
||||
async def get_budget(
|
||||
budget_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
budget = await budget_service.get_budget(db, current_user.id, budget_id)
|
||||
if not budget:
|
||||
raise HTTPException(status_code=404, detail="Budget not found")
|
||||
return budget
|
||||
|
||||
|
||||
@router.put("/{budget_id}", response_model=BudgetResponse)
|
||||
async def update_budget(
|
||||
budget_id: uuid.UUID,
|
||||
data: BudgetUpdate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
budget = await budget_service.get_budget(db, current_user.id, budget_id)
|
||||
if not budget:
|
||||
raise HTTPException(status_code=404, detail="Budget not found")
|
||||
budget = await budget_service.update_budget(db, budget, data)
|
||||
await db.commit()
|
||||
return budget
|
||||
|
||||
|
||||
@router.delete("/{budget_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_budget(
|
||||
budget_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
budget = await budget_service.get_budget(db, current_user.id, budget_id)
|
||||
if not budget:
|
||||
raise HTTPException(status_code=404, detail="Budget not found")
|
||||
await budget_service.delete_budget(db, budget)
|
||||
await db.commit()
|
||||
Loading…
Add table
Add a link
Reference in a new issue