Goals
The basic idea and goals of this project.
- feature-rich and simple to use App (Desktop, Mobile, Web)
- easy to use and understand API
- easy to self-host => you own your data
Features
General Features
- Budgets
- Categories
- Accounts
- Transactions
- Reports
- custom currencies
- Import/Export
- Family (or multiple users) Accounts
- scan bills and add to transaction
Other specific features
For frontend specific features see Frontend Features
For backend specific features see Backend Features
Frontend
Features that are specific to the frontend.
- (MAYBE) fully offline support without any backend
- Localization
Backend
Features that are specific to the backend.
- API
- compression (brotli, zstd, gzip => in this order!)
- handling of trailing slashes for the API
Easy Deployment
- provide docker image
- provide good installation instructions
-
reduce external dependencies
- we only need our databases PostgreSQL & redis
- integrated rate limiter -> no need for an external one
API
Stage
The stage gets wiped on every deploy!!!
For development use only!!!
Url: https://api-stage.financrr.app/swagger-ui/
API Error
We provide a custom error object that is utilized throughout the library.
Error and HTTP Codes
We employ semantic HTTP codes to signify the type of error that occurred, enabling more precise error handling.
If HTTP codes lack granularity, we offer a custom error code for more specific error handling scenarios. By default,
HTTP codes are used.
Custom Error Codes
Custom error codes come into play when HTTP codes lack granularity. For instance, if you need to handle a particular
error in a specific manner, custom error codes allow for such tailored handling.
Custom error codes always consist of at least four digits to prevent conflicts with HTTP codes.
We call these custom error codes Api Codes
.
Api Codes
Auth related
Code | Description |
---|---|
1000 | Invalid Session |
1002 | Invalid credentials provided |
1003 | Unauthorized |
1004 | No bearer token provided |
User-causes errors
Code | Description |
---|---|
1100 | Resource not found |
1101 | Serialization error |
1102 | Missing permissions |
1103 | Error while parsing to cron |
Validation errors
Code | Description |
---|---|
1200 | Validation error! |
Internal server errors
Code | Description |
---|---|
1300 | DB-Entitiy error |
1301 | Database error |
1302 | Redis error |
1303 | Cron builder error |
1304 | An internal time-error |
1305 | An internal error that occurs when a snowflake could not be generated! |
Misc errors
Code | Description |
---|---|
9000 | Actix error |
9999 | Unknown error |
Validation Codes
Validation codes are just like Api Codes
but instead of just a number, they contain String code and a message.
They are used to provide more detailed information about the validation-error that occurred.
Recurring rule
A recurring rule is a rule that defines when and how often a recurring transaction should be executed.
Structure of a recurring rule:
{
"cron_pattern": {
"day_of_month": "*",
"month": "*",
"day_of_week": "*"
}
}
This rule will execute the transaction every day.
day_of_month
: The day of the month when the transaction should be executed.*
: Every day of the month.1-31
: The day of the month.
month
: The month when the transaction should be executed.*
: Every month.1-12
: The month.
day_of_week
: The day of the week when the transaction should be executed.*
: Every day of the week.1-7
: The day of the week. (1 is Monday, ..., 6 is Saturday, 7 is Sunday)
We use croner-rust to parse the recurring rule.
Check out their repository to see what is supported.
Special rules
There are some special rules that can be used instead of the cron pattern.
The special rules are:
@yearly
: Execute the transaction every year.@annually
: Execute the transaction every year.@monthly
: Execute the transaction every month.@weekly
: Execute the transaction every week.@daily
: Execute the transaction every day.
How to use it easily
You should be able to use a cron builder to create the recurring rule.
Simply build the cron and extract the day_of_month
, month
, and day_of_week
from the cron string.
Examples
repeat every day
{
"cron_pattern": {
"day_of_month": "*",
"month": "*",
"day_of_week": "*"
}
}
repeat every 4th day
{
"cron_pattern": {
"day_of_month": "*",
"month": "*",
"day_of_week": "*/4"
}
}
repeat every 2nd week on monday and friday
{
"cron_pattern": {
"day_of_month": "*",
"month": "*",
"day_of_week": "1,5"
}
}
repeat every month
{
"special": "@monthly"
}
repeat every 3rd month on the 2nd monday
{
"cron_pattern": {
"day_of_month": "*",
"month": "*/3",
"day_of_week": "1#2"
}
}
repeat every year on january and august
{
"cron_pattern": {
"day_of_month": "*",
"month": "1,8",
"day_of_week": "*"
}
}
Database
Model
erDiagram User { int id PK string username UK string email UK "Nullable" string password UK "Hashed and salted Password" timestamp created_at bool is_admin } Currency { int id PK string name string symbol string iso_code int decimal_places User user FK "Nullable" } Currency }|--|| User: "many to one" Account { int id PK string name string description "Nullable" string iban UK "Nullable" int balance Currency currency FK timestamp created_at } UserAccount { User user PK "References User.id" Account account PK "References Account.id" } UserAccount ||--|{ User: "one to many" UserAccount ||--|{ Account: "one to many" Transaction { int id PK Account source FK "Nullable" Account destination FK "Nullable" int amount Currency currency FK string description "Nullable" Budget budget FK "Nullable" timestamp created_at timestamp executed_at } Transaction ||--|| Account: "one to one" Transaction ||--|| Budget: "one to one" Budget { int id PK User user FK int amount string name string description "Nullable" timestamp created_at } Budget ||--|| User: "one to one"
SQL
You can find the SQL script here.
Developers
This section is intended for contributors or developers.
Stage system
We provide a stage system for testing purposes.
- Backend Stage: https://backend.stage.financrr.denux.dev/api/openapi/scalar
- Frontend Stage: Still in development
Please note that this system is not intended for production use and may be reset at any time.