How phupa26/personal-expense-management works
1. Overall shape
This repository is a single-process Python CLI application for personal finance tracking. The architecture is layered: core data structures and domain models at the bottom, persistence and indexing in the middle, business services above that, and a CLI entrypoint in main.py on top.
2. Entry point and interaction loop
main.py is the orchestration layer. It drives the terminal menu, collects user input, invokes service methods, and displays summaries/reports. The CLI is also the natural boundary where user actions become domain operations such as add/update/delete transaction, category maintenance, budget setting, and report generation.
3. Domain model layer
core/models.py contains the main business entities: Transaction, Category, and monthly state objects such as CategoryState, IncomeState, ExpenseState, plus MonthData. This layer holds the system’s financial meaning: transaction amount, date, category, type, notes, category activation status, and monthly budget/expense accumulation.
4. Custom data structures
core/data_structure.py implements a custom HashMap/HashNode rather than using Python dict as the primary storage abstraction. This is an important architectural choice because other modules depend on it for fast lookups, collision handling, and month/category indexing. The repo also claims binary search support for date-based lookup, so search performance is explicitly part of the design, not incidental.
5. Persistence boundary
data/file_io.py is the persistence layer. It serializes and restores the application state to the custom text file in storage/data.txt, so the app does not depend on an external database. This layer is also where the system likely centralizes reading/writing of the full object graph: categories, monthly state, and transactions.
6. Indexing and lookup services
data/index_services.py provides the internal indices that make the CLI responsive: MonthIndex, TransactionIndex, TransactionMap, and CategoryIndex. These are not just storage helpers; they are the mechanism that ties transaction IDs to months, categories to monthly states, and date/category queries to the right subset of data.
7. Business services
The services/ package contains the application logic:
- category_manager.py handles category CRUD-like behavior and filtering by name/type/ID.
- transaction_manager.py manages transaction creation, update, deletion, budget checks, and category suggestions based on note history.
- report_manager.py assembles daily, monthly, yearly, and rolling K-month reports.
These services sit between CLI input and the underlying indexed data structures.
8. Data flow for transaction writes
A new transaction typically flows from main.py into transaction_manager.py, which validates the input, resolves the category, updates the relevant monthly state in MonthIndex, and records the transaction in the transaction index/map. If budgets are exceeded, the service layer is responsible for detecting and surfacing that condition. The state then persists through file_io.py.
9. Data flow for reads and reports
Reporting reads from the same monthly indices rather than recomputing everything from scratch. report_manager.py pulls the relevant MonthData and aggregates by time window: day, month, year, or last K months. The report layer also renders ASCII-style visual output, so it transforms internal financial state into human-readable terminal output.
10. Category and budget model
Categories are soft-deleted rather than removed outright, preserving historical transaction integrity. Budgeting is month-scoped: category limits are represented through per-month CategoryState objects, not only on the base Category record. This separation is a key architectural boundary because it keeps current configuration distinct from historical financial state.
11. Import and external file inputs
import.csv is an ingest path for bulk transaction loading. The system uses Python’s built-in csv module, so imported data enters the same transaction pipeline as manually entered records. That means CSV import is not a separate subsystem; it is an alternate input source feeding the same domain services.
12. Storage and operational artifacts
storage/data.txt is the main persistent state file, while storage/inputoutput.txt is an execution log of prompts and user actions. Those two files reflect the app’s operating model: one file captures durable financial state, and the other captures interaction history for debugging/auditing.
13. Important architectural boundary
There are no external databases, web services, or third-party frameworks. The repo’s architecture is intentionally self-contained: standard Python only, custom data structures, custom serialization, and CLI rendering. For an architecture diagram, the main arrows should be from CLI → services → indices/models → file I/O, with core underpinning everything and storage serving as the persistence boundary.
Main entry points: transaction_manager.py Transactions · index_services.py Indices · main.py Main CLI · file_io.py File IO
Components 15
CLI
Terminal entrypoint and user interaction loop
- Main CLI · Drives menus, input, and top-level orchestration
main.py
Core
Domain models and custom data structures
- Models · Transactions, categories, and monthly financial state
core/models.py - Hash Map · Custom hashmap/node storage for fast lookup and indexing
core/data_structure.py - Month Data · Per-month aggregation of income, expense, budgets, and category state
core/models.py - Category State · Month-scoped category budget and activity status
core/models.py - Transaction · Single expense or income entry with date, amount, category, and notes
core/models.py - Category · Named financial bucket with type and active status
core/models.py
Data
Persistence and indexing boundary
Services
Business logic and reporting
- Transactions · Creates, updates, deletes, and validates transactions
services/transaction_manager.py - Categories · Category CRUD and category-based filtering
services/category_manager.py - Reports · Builds daily, monthly, yearly, and rolling reports
services/report_manager.py
Storage
Durable files and operational artifacts
- CSV Import · External CSV ingest path feeding the same transaction pipeline
import.csv - State File · Primary saved financial data file
storage/data.txt - Action Log · Recorded prompts and user actions
storage/inputoutput.txt
Connections 21
- Main CLI → Transactions: manage · Menu actions for add, update, delete, and validation
- Main CLI → Categories: maintain · Category management actions
- Main CLI → Reports: report · Requests summaries and reports
- Main CLI → File IO: load/save · Loads persisted state and writes updates
- Transactions → Indices: update · Maintains transaction and month lookup structures
- Transactions → Models: uses · Operates on transactions and monthly state
- Transactions → Category State: budget check · Checks and updates month-scoped category budgets
- Transactions → Category: resolve · Finds or assigns categories for transactions
- Categories → Category: manage · Creates, filters, and soft-deletes categories
- Reports → Indices: read · Reads month and transaction indices for aggregation
- Reports → Month Data: aggregate · Summarizes monthly financial state into reports
- Indices → Hash Map: backed by · Uses custom hashmap-based storage for lookup
- Indices → Transaction: map · Tracks transaction IDs and related lookup keys
- Indices → Month Data: organize · Groups transactions and state by month
- Month Data → Category State: contains · Holds per-category monthly budget state
- Month Data → Transaction: contains · Tracks transactions contributing to the month
- File IO → State File: persist · Reads and writes durable application state
- File IO → Models: serialize · Stores and restores domain objects
- File IO → Indices: restore · Rebuilds index structures from saved state
- CSV Import → Transactions: feed · Bulk imported records enter the transaction pipeline
- Main CLI → Action Log: record · Captures interaction history and prompts