How dipto0321/spendrift-be works
1. What this repository is
- Spendrift is a backend-only personal finance API built around multiple independent “Trackers” per user.
- A tracker is the main workspace boundary: expenses, categories, budgets, dashboards, and reports are all scoped to a specific tracker.
2. Request entrypoint and API surface
- The app is a FastAPI service with a versioned API under /api/v1.
- app/main.py is the runtime entrypoint, while app/api/v1/api.py aggregates the module routers into the public API surface.
3. Layered architecture inside each feature
- Most business areas follow the same vertical slice pattern:
- router: HTTP endpoints and request/response wiring
- service: business rules and orchestration
- repo: database access
- model: SQLModel persistence objects
- schema: Pydantic request/response shapes
- This pattern is repeated across auth, users, trackers, categories, expenses, budgets, refresh tokens, dashboard, and reports.
4. Core/shared infrastructure
- app/core/ contains shared platform concerns:
- config.py for environment-driven settings
- database.py for database session/engine setup
- security.py for password hashing and token handling
- logging_config.py for application logging
- storage/ for object storage abstraction
- app/middleware/rate_limit.py adds API throttling via middleware.
5. Authentication and session management
- Auth is based on Argon2 password hashing and JWT tokens.
- The auth module handles registration/login, while refresh_tokens persists refresh token state separately, indicating token rotation/revocation is part of the architecture.
- The README’s sample responses confirm the API issues both access_token and refresh_token on login/register.
6. Domain boundaries and data ownership
- Users manage profile data such as name, email, activity status, and avatar URL.
- Trackers represent isolated finance workspaces and are the root for all financial data.
- Categories, Expenses, and Budgets are subordinate to a tracker, which is the key multi-tenant-like boundary in the system.
- Dashboard and Reports are read-focused modules that aggregate tracker data rather than owning primary records.
7. Tracker lifecycle and seeded defaults
- Creating a tracker triggers automatic setup of default categories; the README shows 10 seeded categories.
- That implies tracker creation is not just a CRUD operation, but an orchestration step that initializes dependent data.
8. Persistence and migrations
- The primary database is PostgreSQL 18, accessed via SQLModel.
- Alembic manages schema evolution, with migrations covering tracker/category/budget/expense changes, refresh tokens, avatars, and timezone-aware timestamps.
- The repository is designed so schema changes are explicit and versioned, which is important for diagramming the persistence boundary.
9. Storage beyond the database
- app/core/storage/ includes a storage abstraction plus an S3 implementation, which is relevant for user avatars.
- The repo also contains migrations for avatar-related tables/fields, so file/object storage and DB metadata are part of the user-profile subsystem.
10. Cross-cutting runtime and deployment concerns
- Local development uses Docker and docker-compose.yml for PostgreSQL.
- The project is configured for Python 3.12+ and uses uv / pyproject.toml for dependency and tool management.
- CI is present in .github/workflows/ci.yml, and the Makefile exposes the main lifecycle commands: run, migrate, upgrade, test, and lint.
11. Testing structure
- The test suite mirrors the domain modules: auth, budgets, categories, dashboard, expenses, reports, trackers, and users.
- tests/conftest.py suggests shared fixtures for app/database setup, reinforcing that the architecture is integration-test friendly around the API and persistence layers.
12. How to draw the architecture
- A useful diagram would show:
- Client → FastAPI app → versioned routers
- routers delegating to service layer
- services using repositories/models
- repositories reading/writing PostgreSQL
- auth flowing through JWT/refresh-token storage
- avatar uploads flowing through storage abstraction / S3
- tracker-scoped business modules feeding dashboard/report aggregation
Main entry points: main.py App Main · api.py V1 API · trackers/service.py Trackers Service · dashboard/service.py Dashboard Service
Components 24
Runtime
Process entrypoint and HTTP surface
Core
Shared platform infrastructure
- Rate Limit · API throttling middleware
app/middleware/rate_limit.py - Config · Environment-driven application settings
app/core/config.py - Database · Engine and session setup for PostgreSQL
app/core/database.py - Security · Password hashing and token handling
app/core/security.py - Storage Base · Object storage interface
app/core/storage/base.py - S3 Storage · S3-backed storage implementation
app/core/storage/s3.py
Auth & Session
Login, tokens, and user identity
- Auth Router · Register and login endpoints
modules/auth/router.py - Auth Service · Authentication and token issuance logic
modules/auth/service.py - Refresh Tokens · Persisted refresh token state
modules/refresh_tokens/repo.py - Users Router · User profile endpoints
modules/users/router.py - Users Service · Profile management and avatar updates
modules/users/service.py - Users Repo · User persistence access
modules/users/repo.py
Finance Domain
Tracker-scoped business modules
- Trackers Router · Tracker workspace endpoints
modules/trackers/router.py - Trackers Service · Tracker lifecycle and default seeding
modules/trackers/service.py - Trackers Repo · Tracker persistence access
modules/trackers/repo.py - Categories Service · Tracker-scoped category rules
modules/categories/service.py - Expenses Service · Expense entry and lookup logic
modules/expenses/service.py - Budgets Service · Budget rules and enforcement
modules/budgets/service.py
Insights
Read-focused aggregation modules
- Dashboard Service · Tracker overview summaries
modules/dashboard/service.py - Reports Service · Tracker report generation
modules/reports/service.py
Persistence
Database and object storage
- PostgreSQL · Primary relational datastore
Connections 30
- API Client → App Main: HTTP · Requests enter the FastAPI app
- App Main → V1 API: mounts · Registers the versioned API surface
- App Main → Rate Limit: uses · Applies request throttling
- App Main → Config: loads · Reads runtime settings
- App Main → Database: initializes · Creates database access layer
- V1 API → Auth Router: includes · Publishes auth endpoints
- V1 API → Users Router: includes · Publishes user endpoints
- V1 API → Trackers Router: includes · Publishes tracker endpoints
- Auth Router → Auth Service: calls · Delegates auth requests
- Auth Service → Security: uses · Hashes passwords and issues tokens
- Auth Service → Refresh Tokens: stores · Persists refresh token state
- Refresh Tokens → PostgreSQL: reads/writes · Refresh tokens live in PostgreSQL
- Users Router → Users Service: calls · Delegates profile operations
- Users Service → Users Repo: uses · Loads and updates users
- Users Service → Storage Base: uploads · Abstracts avatar storage
- S3 Storage → Storage Base: implements · S3 backend for object storage
- Users Repo → PostgreSQL: reads/writes · User records are stored in PostgreSQL
- Trackers Router → Trackers Service: calls · Delegates tracker operations
- Trackers Service → Trackers Repo: uses · Stores tracker workspaces
- Trackers Service → Categories Service: seeds · Initializes default categories on create
- Trackers Repo → PostgreSQL: reads/writes · Trackers are persisted in PostgreSQL
- Categories Service → PostgreSQL: reads/writes · Categories are tracker-scoped data
- Expenses Service → PostgreSQL: reads/writes · Expense records are stored in PostgreSQL
- Budgets Service → PostgreSQL: reads/writes · Budget records are stored in PostgreSQL
- Dashboard Service → Expenses Service: aggregates · Builds summaries from expense data
- Dashboard Service → Budgets Service: aggregates · Compares spending to budgets
- Dashboard Service → Categories Service: aggregates · Groups tracker data by category
- Reports Service → Expenses Service: analyzes · Produces reporting views from expenses
- Reports Service → Trackers Service: scopes · Reports are tracker-bound
- Database → PostgreSQL: connects · Database engine targets PostgreSQL