Skip to content

About

Fortuna is a personal finance system that tracks a person's whole financial life.

Resources

Contributing

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

Fortuna API

Fortuna is a personal finance system that tracks a person's whole financial life — bank accounts, credit cards, investments, expenses and earnings — in one place, and turns that history into tabular views, drillable charts and forward projections. This repository is the back end only: an HTTP API that owns the domain, the data and the integrations. The Flutter application that runs on Windows, Linux, the browser and mobile is a separate repository and a separate consumer of this API.

Status: version 1.0.0 is released, and every issue in the backlog below is closed.

What it does

  • Tracks bank accounts, credit cards and investments, each with its own currency and history.
  • Records expenses, earnings and transfers, plus installment purchases and recurring commitments.
  • Ingests from several sources — manual entry, the Pluggy open-banking API, Excel spreadsheets and supported PDF statement layouts — behind one pluggable source contract.
  • Handles multiple currencies with exact decimal arithmetic and dated, attributable exchange rates from the Banco Central do Brasil's PTAX service.
  • Serves the data as a spreadsheet-shaped table and as chart aggregations that drill down to the individual transactions behind any figure.
  • Projects the future from recurring commitments, unbilled installments and statements due.
  • Exports to CSV, Excel and PDF, and files attachments against transactions.
  • Runs offline on a desktop, or multi-user on a shared instance, with the same client-facing contracts across its native and managed cores.

What it doesn't do

  • Move money. No payments, no transfers executed at a bank, no trading. Fortuna reads and records; it never writes to a financial institution.
  • Give financial advice. A projection is arithmetic over the user's own data.
  • Tax filing or accounting compliance.
  • Store bank credentials. Open-banking access lives with Pluggy and is referenced by token.
  • Manage users. Identity belongs to the Heimdall API; the desktop offline account is the one exception, and Fortuna owns it because there is no network to reach Heimdall over.
  • Render a user interface. The API serves the numbers; the Flutter client draws them.

Specifications

The project is specified before it is built. Start with the initial/ documents for context, then the requirements/ documents for the normative detail.

Document What's in it
Brainstorm The original free-form notes this project grew from.
Project Overview What the project is, who it's for, and how success is measured.
Technology Stack The informal stack decisions.
Workflow How one use case is delivered, step by step.
Business Rules Domain entities, relationships, and the BR-01 … BR-46 rules.
Vision Document Stakeholders, positioning, and the F-01 … F-20 features.
System Requirements Document The FR-<AREA>-xx and NFR-xx requirements, data model, endpoint surface, authorization matrix and traceability.
Use Case Specification Document The application use cases, their flows, and their AF-xx alternatives.
Development Workflow Document The normative branch pattern, issue lifecycle, approval gates, and Definition of Done.
Testing Specification Document How tests are written, named, and run.
Technology Stack Document The single source of truth for every technology and version.
Operations & Infrastructure Document Layout, configuration, logging, health, UC-75, and the IR-01 … IR-20 platform requirements.

Installation

Prerequisites: the .NET 10 SDK and either a reachable PostgreSQL instance for a shared deployment or local SQLite storage for desktop offline mode. Building the in-process desktop core also requires the stable Rust toolchain. Docker is required for the container workflow — see the Technology Stack Document and the Operations & Infrastructure Document.

git clone https://git.techcraftsmen.net/artur-rios/fortuna-api.git
dotnet restore src/ArturRios.Fortuna.sln

Configuration is resolved entirely from environment variables prefixed FORTUNA_. Copy the example file for your environment from docker/ and fill it in; no secret is ever committed.

cp docker/local.env.example docker/local.env

Running

One compose file serves all four environments, differing only in the environment file supplied (docker/<environment>.env.example). example.com stands for the real domain:

Environment Where Deployed by ASPNETCORE_ENVIRONMENT Address Database
local The developer's Windows machine, Docker Desktop By hand, with the command below, or with yggdrasil's scripts/deploy.sh local fortuna-api … Development http://localhost:8083 fortuna_local, on the PostgreSQL installed on Windows
development The VPS, on demand (started only when used) Jenkins, on every push to develop Development https://fortuna-api-dev.example.com fortuna_development, on the VPS's PostgreSQL
homologation The VPS, on demand Jenkins, on every push of a release/x.y.z branch Production https://fortuna-api-hml.example.com fortuna_homologation
production The VPS, always on Jenkins, on a green release/x.y.z → main pull request Production https://fortuna-api.example.com fortuna

Locally:

docker compose --env-file docker/local.env up -d --build

Local signs in with Fortuna's own local account (FORTUNA_LOCAL_AUTH_ENABLED=true). To sign in through the local heimdall-api instead, it is http://host.docker.internal:8080/: plain HTTP is accepted because that host resolves to a private address. The API has no CORS support, so a browser build of the web UI on another local port cannot call it; the UI's README describes how to work with it locally.

The three VPS environments are deployed by yggdrasil, from a copy of the matching template at /etc/yggdrasil/<environment>/fortuna-api.env on the VPS: Traefik serves the API on its own host and under the web UI's host at /api/, so the browser reaches it on the UI's own origin. Homologation runs as Production because the API treats every other ASP.NET environment as a debugging one (Swagger UI, detailed errors). Each of them has its own secrets, its own Heimdall (FORTUNA_HEIMDALL_BASE_URL, which is HTTPS, or plain HTTP to a private address: inside yggdrasil http://heimdall-api.<environment>:8080/) whose public signing keys it reads from FORTUNA_HEIMDALL_JWKS_URL, and its own FORTUNA_LOCAL_TOKEN_SECRET for local-account tokens. Only those published keys verify a Heimdall token: the shared secret Fortuna once held for Heimdall's HS256 tokens (FORTUNA_AUTH_TOKEN_SECRET, _PREVIOUS) is no longer read since 4.0.0, and a start-up warning names it while it is still set. Under yggdrasil that warning never appears, because the compose file no longer passes either variable to the container, so check the store with ygg vars list <scope> --keys instead. The release process, and how to turn development or homologation on, are in CONTRIBUTING.md.

The API's liveness is observable at the public GET /healthcheck endpoint. Instance administrators can inspect dependency health at GET /healthcheck/detailed.

Prometheus metrics are served at GET /metrics only on the private port 9464 (FORTUNA_METRICS_PORT; 0 disables them), never through the public port 8080. The compose file does not publish that port: Prometheus scrapes the container over a private Docker network — see the Operations & Infrastructure Document.

Logs are structured JSON, written to the console and to daily files under FORTUNA_LOG_DIRECTORY/<yyyy>/<MM>/. Every API request is logged with its client IP address, which is personal data under the GDPR and the LGPD, and the address is tagged on the request's trace as client.address. Behind a reverse proxy, list the proxy in FORTUNA_FORWARDED_KNOWN_NETWORKS or FORTUNA_FORWARDED_KNOWN_PROXIES so the logs and the rate limiter see the real caller rather than the proxy — see the Operations & Infrastructure Document.

For desktop offline mode, keep the same application configuration and select the local provider:

FORTUNA_DATA_DATABASETYPE=SQLite
FORTUNA_DATA_CONNECTIONSTRING=/absolute/path/to/fortuna.db
FORTUNA_RUN_MIGRATIONS=true

PostgreSQL remains the server default. Each provider has its own EF migration history while sharing the domain model; changing providers requires no application-code change.

The desktop client can instead embed the native core without starting the HTTP host or opening a listening socket. It ships fortuna_core.dll on Windows or libfortuna_core.so on Linux together with the generated C header. It has 115 generated offline route exports. Capability discovery lists the ones the native core implements, the ones it exports but does not implement yet (file imports, data-set exports, reports, projections, transfers, installment plans, statements and a few computed views, which answer 501), and the network-dependent routes that remain HTTP-only. The native core owns its Rust domain/persistence implementation and SQLite schema; see native/README.md for the ABI, ownership and build contract.

Roadmap

Seven milestones, in dependency order. Every milestone after M-01 depends on it. Closed counts are as of the 1.0.0 release — the milestones page and the project board are the live view. The board's Status field carries the lifecycle the Development Workflow Document defines: Todo → In Progress → Testing → Done.

Milestone Delivers Depends on Issues Status
M-01 — Foundation The project scaffold, data layer, job runner and CI every use case is built on — 6 6 / 6 closed
M-02 — Access and cross-cutting mechanisms Token validation, profile provisioning, the desktop local account, currencies and exchange rates, lifecycle, account erasure and the audit trail M-01 16 16 / 16 closed
M-03 — Holdings Financial accounts, credit cards with billing cycles and statements, and investments M-02 20 20 / 20 closed
M-04 — Money movement Transactions, transfers, installment plans, recurring commitments and reconciliation M-03 12 12 / 12 closed
M-05 — Organization and planning Categories, tags, counterparties, budgets and goals M-04 11 11 / 11 closed
M-06 — Ingestion The source contract, Pluggy connections and synchronization, Excel and Nubank PDF imports, and job monitoring M-04 11 11 / 11 closed
M-07 — Insight and output Attachments, tables, chart aggregations with drill-down, net position, projections, export and the health check M-05, M-06 15 15 / 15 closed

Backlog

The backlog tracks one branch and one pull request per issue. Use cases retain the stricter invariant: one use case = one branch = one issue = one pull request.

M-01 — Foundation

Issue Work Spec
#1 ✅ Project scaffold and initial infrastructure Operations & Infrastructure
#155 ✅ Support SQLite as the persistence provider for desktop offline mode Operations & Infrastructure
#156 ✅ Expose the Fortuna core over a C ABI for in-process desktop use Operations & Infrastructure
#157 ✅ Export the offline operation surface over the C ABI Operations & Infrastructure
#162 ✅ Publish exact decimal values as JSON strings Technology Stack
#163 ✅ Publish enum member names in OpenAPI System Requirements

M-02 — Access and cross-cutting mechanisms

Issue Work Spec
#2 ✅ UC-01: Authenticate a Request with a Heimdall Token Use Case Specification
#3 ✅ UC-02: Provision a User Profile on First Access Use Case Specification
#4 ✅ UC-03: Create a Desktop Local Account Use Case Specification
#5 ✅ UC-04: Authenticate with a Local Account Use Case Specification
#6 ✅ UC-05: Recover a Local Account with a Recovery Code Use Case Specification
#7 ✅ UC-06: Regenerate Local Account Recovery Codes Use Case Specification
#8 ✅ UC-07: List Supported Currencies Use Case Specification
#9 ✅ UC-08: Synchronize Exchange Rates Use Case Specification
#10 ✅ UC-09: Record a Manual Exchange Rate Use Case Specification
#11 ✅ UC-10: View Figures in a Display Currency Use Case Specification
#53 ✅ UC-52: Delete and Restore a Record Use Case Specification
#54 ✅ UC-53: Read the Audit Trail Use Case Specification
#153 ✅ UC-76: Authenticate through the Fortuna API Use Case Specification
#154 ✅ UC-77: Manage Credentials and Two-Factor Authentication through the Fortuna API Use Case Specification
#158 ✅ UC-78: Erase a User Account Use Case Specification
#175 ✅ Resend an emailed second-factor code for an outstanding challenge Use Case Specification
#208 ✅ UC-81: Register through the Fortuna API Use Case Specification

M-03 — Holdings

Issue Work Spec
#12 ✅ UC-11: Create a Financial Account Use Case Specification
#13 ✅ UC-12: View Financial Accounts Use Case Specification
#14 ✅ UC-13: Update a Financial Account Use Case Specification
#15 ✅ UC-14: View an Account Balance Use Case Specification
#16 ✅ UC-15: Delete a Financial Account Use Case Specification
#17 ✅ UC-16: Create a Credit Card Use Case Specification
#18 ✅ UC-17: View Credit Cards and Limits Use Case Specification
#19 ✅ UC-18: Update a Credit Card Use Case Specification
#20 ✅ UC-19: Delete a Credit Card Use Case Specification
#21 ✅ UC-20: Assign a Charge to a Billing Cycle Use Case Specification
#22 ✅ UC-21: Close a Statement Use Case Specification
#23 ✅ UC-22: View a Statement Use Case Specification
#24 ✅ UC-23: Settle a Statement Use Case Specification
#25 ✅ UC-24: Create an Investment Use Case Specification
#26 ✅ UC-25: Record an Investment Movement Use Case Specification
#27 ✅ UC-26: Record an Investment Valuation Use Case Specification
#28 ✅ UC-27: View Investments and Positions Use Case Specification
#29 ✅ UC-28: Update an Investment Use Case Specification
#30 ✅ UC-29: Delete an Investment Use Case Specification
#178 ✅ Accept IncludeDeleted on the credit-card and investment list endpoints System Requirements

M-04 — Money movement

Issue Work Spec
#31 ✅ UC-30: Record a Transaction Use Case Specification
#32 ✅ UC-31: Search Transactions Use Case Specification
#33 ✅ UC-32: Update a Transaction Use Case Specification
#34 ✅ UC-33: Delete a Transaction Use Case Specification
#35 ✅ UC-34: Record a Transfer Use Case Specification
#36 ✅ UC-35: Delete a Transfer Use Case Specification
#37 ✅ UC-36: Record an Installment Purchase Use Case Specification
#38 ✅ UC-37: Define a Recurring Transaction Use Case Specification
#39 ✅ UC-38: Materialize Recurring Occurrences Use Case Specification
#40 ✅ UC-39: Update a Recurring Transaction Use Case Specification
#41 ✅ UC-40: Reconcile a Transaction Use Case Specification
#176 ✅ List a user's recurring transactions System Requirements

M-05 — Organization and planning

Issue Work Spec
#42 ✅ UC-41: Create a Category Use Case Specification
#43 ✅ UC-42: View the Category Tree Use Case Specification
#44 ✅ UC-43: Update a Category Use Case Specification
#45 ✅ UC-44: Reassign Transactions Between Categories Use Case Specification
#46 ✅ UC-45: Delete a Category Use Case Specification
#47 ✅ UC-46: Manage Tags Use Case Specification
#48 ✅ UC-47: Manage Counterparties Use Case Specification
#49 ✅ UC-48: Define a Budget Use Case Specification
#50 ✅ UC-49: Track Budget Consumption Use Case Specification
#51 ✅ UC-50: Define a Goal Use Case Specification
#52 ✅ UC-51: Track Goal Progress Use Case Specification

M-06 — Ingestion

Issue Work Spec
#55 ✅ UC-54: Discover Available Data Sources Use Case Specification
#56 ✅ UC-55: Connect an Institution through Pluggy Use Case Specification
#57 ✅ UC-56: Synchronize from a Connection Use Case Specification
#58 ✅ UC-57: Reauthenticate a Connection Use Case Specification
#59 ✅ UC-58: Revoke a Connection Use Case Specification
#60 ✅ UC-59: Import Transactions from an Excel Workbook Use Case Specification
#61 ✅ UC-60: Import a Nubank Credit Card Invoice PDF Use Case Specification
#62 ✅ UC-61: Monitor an Import Job Use Case Specification
#63 ✅ UC-62: Retry a Failed Import Job Use Case Specification
#64 ✅ UC-63: Review Imported Records Use Case Specification
#160 ✅ UC-80: Record Processing Consent Use Case Specification

M-07 — Insight and output

Issue Work Spec
#65 ✅ UC-64: Attach a Document to a Transaction Use Case Specification
#66 ✅ UC-65: Download an Attachment Use Case Specification
#67 ✅ UC-66: Delete an Attachment Use Case Specification
#68 ✅ UC-67: Query Records as a Table Use Case Specification
#69 ✅ UC-68: Aggregate Transactions for a Chart Use Case Specification
#70 ✅ UC-69: Drill Into an Aggregation Use Case Specification
#71 ✅ UC-70: View the Net Position Use Case Specification
#72 ✅ UC-71: Project Cash Flow Use Case Specification
#73 ✅ UC-72: View Committed Obligations Use Case Specification
#74 ✅ UC-73: Export a Data Set Use Case Specification
#75 ✅ UC-74: Retrieve a Completed Export Use Case Specification
#76 ✅ UC-75: Check API Health Operations & Infrastructure
#159 ✅ UC-79: Export All Personal Data Use Case Specification
#161 ✅ Report API contract version from liveness Operations & Infrastructure
#177 ✅ List a transaction's attachments System Requirements

Changelog

Notable changes in each release are recorded in CHANGELOG.md.

Contributing

Building from source, running the tests, the delivery workflow, the branching model and the release process are described in CONTRIBUTING.md.

The GitHub repository is a read-only mirror for the real, open-source code of fortuna-api. Its home is Forgejo, at https://git.techcraftsmen.net/artur-rios/fortuna-api. If you want to contribute, e-mail me at arturdev@duck.com.

Legal

This project is licensed under the Artur Rios Attribution License. It is free and open source: you may view, use, fork, modify, and extend it, provided you credit the author, Artur Rios, with a link to artur-rios.tech or github.com/artur-rios.

Copyright (c) 2026 Artur Rios.

About

Fortuna is a personal finance system that tracks a person's whole financial life.

Resources

Contributing

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages