Building ResumoFII

This project started as a way to learn more about Rust – and to explore how Clean Architecture principles can help avoid getting trapped in a tangled backend mess.
I chose Rust because I wanted to deepen my understanding of the language, and building a small project is my preferred way of learning. I'm also curious to see how this setup compares to the JVM ecosystems I'm more familiar with.
Since I'm paying out of pocket to host and run the app on a VPS, I also wanted something lean and efficient. Most production workloads I've seen are built on stacks where even the baseline feels expensive. Here, my goal was simple: build a focused backend that's fast, cheap, and easy to evolve.
Clean Architecture
So yeah – we're not just hacking things together.
The goal was to assemble the right pieces with the right abstractions so the system can stay flexible as requirements shift. I don't want the database or email provider or even the AI service to be baked into the core logic. The setup should allow for easily swapping those parts out.

A Tour Through the Layers
Domain
The Domain layer is the heart of the system. It defines the fundamental entities (FII, User, etc.) and the business rules they must follow. This layer has zero awareness of databases or HTTP servers, or email APIs – just pure Rust structs and logic.
It doesn't depend on anything else. Everything else depends on it.
Application
The Application layer is where use cases live. This is the layer that actually does things: listing FIIs, requesting magic logic links, summarizing a fund's monthly report.
It wires up logic using the Domain layer and defines interfaces (Rust traits) for things like repositories, email services and JWT authentication – without caring about how they're implemented.
Infrastructure
This is where the mess lives.
The Infrastructure layer contains the adapters that connect the outside world to the rest of the system: SQLx queries, Axum HTTP handlers, Resend email API calls. It implements the traits from the Application layer and translates HTTP requests into use case calls (and responses back out).
Why Bother?
I could just hack everything together and mix database queries with HTTP handlers, random structs and get a working prototype faster. But then the following issues would arise:
- Changing anything becomes a pain
- Testing core business rules is difficult
- Integrating new things becomes risky or time-consuming
ResumoFII is partly a learning exercise, partly a useful product for myself, it should be able to naturally evolve with changing requirements and be the place where these patterns can be applied in practice.