Category Management
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/java/io/github/mojri/hesabyar/domain/usecase/ManageCategoryUseCase.kt
- app/src/main/java/io/github/mojri/hesabyar/ui/CategoryViewModel.kt
- app/src/main/java/io/github/mojri/hesabyar/data/Entities.kt
- app/src/main/java/io/github/mojri/hesabyar/ui/screens/CategoryManagementScreen.kt
- app/src/test/java/io/github/mojri/hesabyar/CategoryTest.kt
- rust/hesabyar-core/src/ai_validation.rs
Introduction
Category Management is a core module in Hesabyar responsible for organizing financial activities into logical groups such as Income, Expenses, and Loans. It provides the structural foundation for the Analytic Dashboard and transaction tracking by allowing users to classify every Rial spent or earned. The system supports both a set of hardcoded default categories and user-defined custom categories, each characterized by specific icons, colors, and transaction types.
The module follows an offline-first architecture where data persists in a Room database and flows through a clean architecture stack consisting of UI (Compose), ViewModels, Use Cases, and Repositories. Additionally, a Rust-based core handles advanced logic like category normalization for AI-driven transaction parsing.
Sources: README.md, app/src/main/java/io/github/mojri/hesabyar/data/Entities.kt:7-66, AGENTS.md
Data Model and Schema
The Category entity is defined as a Room database table. Each category is uniquely identified and carries metadata used for UI rendering and financial logic.
Entity Attributes
| Field | Type | Description |
|---|---|---|
id | Long | Primary key (auto-generated). |
name | String | Display name in Persian. |
key | String | English unique identifier used for logic/AI mapping. |
icon | String | String identifier for Vector icons (e.g., "Restaurant"). |
color | Long | ARGB color value for UI elements. |
type | CategoryType | Enum: EXPENSE, INCOME, BOTH, or UNKNOWN. |
isDefault | Boolean | Flag indicating if the category is built-in (non-deletable). |
Sources: app/src/main/java/io/github/mojri/hesabyar/data/Entities.kt:7-16, app/src/main/java/io/github/mojri/hesabyar/ui/screens/CategoryManagementScreen.kt:39-70
Default Categories
The system initializes with eight default categories to ensure immediate usability:
- Income (درآمد): Type
INCOME. - Food (خوراک): Type
EXPENSE. - Transportation (حمل و نقل): Type
EXPENSE. - Shopping (خرید): Type
EXPENSE. - Bills (قبوض): Type
EXPENSE. - Installments (اقساط): Type
EXPENSE. - Loans (وام و قرض): Type
BOTH. - Other (سایر): Type
BOTH.
Sources: app/src/main/java/io/github/mojri/hesabyar/data/Entities.kt:18-65, app/src/test/java/io/github/mojri/hesabyar/CategoryTest.kt:14-17
Architecture and Data Flow
Category Management utilizes a standard MVVM pattern mediated by Use Cases to separate business logic from the UI.
Component Relationship
The flow begins at the CategoryManagementScreen, which interacts with the CategoryViewModel. The ViewModel triggers operations through ManageCategoryUseCase, which interacts with the repository to perform CRUD operations on the underlying Room database.
Sources: app/src/main/java/io/github/mojri/hesabyar/domain/usecase/ManageCategoryUseCase.kt:9-11, app/src/main/java/io/github/mojri/hesabyar/ui/CategoryViewModel.kt:15-18
Management Operations
The ManageCategoryUseCase exposes several key functions for state management:
allCategories: AFlow<List<Category>>providing real-time updates.addCategory(...): Inserts a new category into the repository.updateCategory(category): Modifies an existing record.deleteCategory(category): Removes a category (typically restricted for non-default ones).
Sources: app/src/main/java/io/github/mojri/hesabyar/domain/usecase/ManageCategoryUseCase.kt:12-32
UI and Interaction
The user interface is built with Jetpack Compose, featuring a split view between default and custom categories.
UI Components
- CategoryItem: A card-based component displaying the icon, name, key, and type. It includes conditional action buttons (Edit/Delete).
- CategoryDialog: A modal used for both creating and editing categories. It features a Persian name input, an optional English key input, a color picker grid, and an icon selector grid.
- Type Selector: An
ExposedDropdownMenuBoxallowing users to set the category as Expense, Income, or Both.
Sources: app/src/main/java/io/github/mojri/hesabyar/ui/screens/CategoryManagementScreen.kt:142-205, app/src/main/java/io/github/mojri/hesabyar/ui/screens/CategoryManagementScreen.kt:294-460
Logic Sequence for Adding a Category
AI Category Normalization
The system includes a Rust-based core (hesabyar-core) that provides category normalization logic. This is primarily used when parsing transactions generated by AI (e.g., Gemini) to ensure that external classification labels match the app's internal 8 core categories.
Normalization Logic
The Rust function normalize_category maps extended or fine-grained categories to core categories. Any unknown or empty categories are automatically coerced to "Other".
| Extended Category | Core Mapping |
|---|---|
| Personal Care | Shopping |
| Education | Other |
| Rent & Utilities | Bills |
| Loans & Debt | Loans |
| Events & Gifts | Other |
| Investment | Other |
Sources: rust/hesabyar-core/src/ai_validation.rs:59-86
fn normalize_category(cat: &str) -> String {
let trimmed = cat.trim();
if trimmed.is_empty() {
return "Other".to_string();
}
for &(from, to) in CATEGORY_MAP {
if trimmed.eq_ignore_ascii_case(from) {
return to.to_string();
}
}
"Other".to_string()
}
Sources: rust/hesabyar-core/src/ai_validation.rs:90-101
Conclusion
Category Management provides a robust, extensible framework for financial data classification in Hesabyar. By combining a strict set of defaults with user-defined custom categories, the system balances ease of use with flexibility. The integration between Kotlin-based UI and Rust-based AI validation ensures that category assignments remain consistent across manual entry and automated AI parsing.