Role-based finance tracking on Spring Boot, with LLM-generated insights from a separate FastAPI + Groq service.
- Highlights
- Why This Design
- Architecture
- Tech Stack
- Role Permissions
- Quick Start
- API Endpoints
- Request Examples
- Project Structure
- Configuration
- License
| AI insights | Financial data goes to a FastAPI + Groq service that returns structured insights and dynamic budget alerts |
| 4 granular roles | Viewer, Analyst, Admin, Organizer, modeled on real team structures |
| Stateless JWT auth | Horizontally scalable, no sticky sessions |
| Multi-field filtering | Filter by date, category, and amount, with paginated responses |
| Net position | Income-vs-expense aggregation at a glance |
| PDF export | Finance-ready reports as a first-class feature |
| 15+ REST endpoints | Fully documented with Swagger / OpenAPI 3 and token-authenticated testing |
| Serverless database | Neon PostgreSQL, with the schema auto-provisioned by Hibernate on first run |
** Deterministic core, AI on the edge.** Money logic (balances, filtering, permissions) lives in Spring Boot, where it is predictable and testable. The LLM never touches the source of truth. It only receives data and returns advice.
** Two services, one responsibility each.** Spring Boot handles business rules; FastAPI handles prompt construction and LLM calls. Either can be scaled, deployed, or replaced independently.
** Role-based access.** Four roles map to real team structures, not arbitrary permission flags.
** Reports by default.** Finance teams work with reports, so export is built in rather than bolted on.
flowchart LR
Client([ Client / Swagger UI]) -->|JWT| SB[Spring Boot API<br/>Auth, RBAC, Transactions, PDF]
SB <-->|JPA| DB[(PostgreSQL<br/>Neon)]
SB -->|Financial data<br/>REST, synchronous| FA[FastAPI Insights Service<br/>Prompt builder]
FA -->|Contextual prompt| LLM[[Groq LLM API]]
LLM -->|Completion| FA
FA -->|Structured insights| SB
How an AI insight is produced:
- An authenticated user requests insights from the Spring Boot API.
- Spring Boot verifies the JWT and role, then aggregates the relevant transactions.
- The data is sent to the FastAPI service, which builds a contextual prompt and calls the Groq API in real time.
- FastAPI returns structured insights synchronously, and Spring Boot passes them back to the client.
| Layer | Technology |
|---|---|
| Core language | Java 21 |
| Core framework | Spring Boot 3.x |
| Security | Spring Security + JWT |
| Database | PostgreSQL (Neon, serverless) |
| ORM | Spring Data JPA / Hibernate |
| AI microservice | Python, FastAPI |
| LLM provider | Groq API |
| Documentation | Swagger / OpenAPI 3 |
| Build tool | Maven |
| Action | Viewer | Analyst | Admin | Organizer |
|---|---|---|---|---|
| View and filter transactions | X | X | X | X |
| View net position | X | X | X | X |
| View AI insights and budget alerts | X | X | X | X |
| Export PDF reports | X | X | X | |
| Create, edit, delete records | X | X | ||
| Manage workspace users | X | X |
Adjust the AI insights row to match the access rules you actually enforce.
- Java 21+
- Maven 3.8+
- A PostgreSQL database (local or Neon)
git clone https://github.com/Aakashch-code/zairo-api
cd zairo-apiNote: The FastAPI + Groq insights service lives in a separate repository, which I haven't published yet. I'll release it in the future, and its setup and configuration (including the Groq API key) will be documented there, not here. This project only needs the hosted service URL below.
Update src/main/resources/application.properties:
spring.datasource.url=jdbc:postgresql://<your-db-host>/neondb
spring.datasource.username=<your-db-username>
spring.datasource.password=<your-db-password>
application.security.jwt.secret-key=<your-secret-key-at-least-32-chars>
application.security.jwt.expiration=86400000
# AI insights service (FastAPI + Groq, hosted separately)
zai.api.url=https://zairo-ai.onrender.com/api/ai/generate-with-context
server.port=8085mvn spring-boot:runThe API runs on http://localhost:8085. Hibernate auto-creates the schema on first run.
Open Swagger UI at http://localhost:8085/swagger-ui/index.html, log in, and include your token in subsequent requests:
Authorization: Bearer <your-token>
Authentication
POST /api/auth/register Register a new user
POST /api/auth/login Login and receive JWT token
Transactions
GET /api/transactions List transactions (paginated, all roles)
GET /api/transactions/net Net income vs expenses (all roles)
POST /api/transactions/filter Filter by date, category, amount (all roles)
GET /api/transactions/pdf Export financial report (analyst+)
POST /api/transactions Create transaction (admin/organizer)
PUT /api/transactions/{id} Update transaction (admin/organizer)
DELETE /api/transactions/{id} Delete transaction (admin/organizer)
AI Insights
GET /api/transactions/insights AI-generated financial insights
GET /api/transactions/alerts LLM-powered budget alerts
Replace these two routes with your real ones.
User Management
GET /api/auth/workspace/users List workspace members (admin/organizer)
PUT /api/auth/{userId} Update user credentials (admin/organizer)
DELETE /api/auth/{userId} Remove user (admin/organizer)
FastAPI Insights Service (internal)
POST /api/ai/generate-with-context Receives financial data, returns structured insights
Called by Spring Boot, not by clients directly. Its source will be published in a separate repository.
Login
POST /api/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "yourpassword"
}Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Create a transaction
POST /api/transactions
Authorization: Bearer <your-token>
Content-Type: application/json
{
"description": "Office rent",
"amount": 1500.00,
"type": "EXPENSE",
"categoryId": 3,
"date": "2025-04-01"
}Get AI insights
GET /api/transactions/insights
Authorization: Bearer <your-token>Response (example shape, replace with your actual output):
{
"summary": "Expenses are up 18% versus last month, driven mostly by Rent and Software.",
"alerts": [
{ "category": "Software", "message": "Spending has exceeded the typical monthly range." }
],
"suggestions": [
"Review recurring software subscriptions for overlap."
]
}src/
└── main/
├── java/org/example/zairo/
│ ├── authentication/
│ │ ├── api/ # Auth controllers
│ │ ├── application/ # DTOs, services
│ │ └── domain/ # User entity
│ └── transaction/
│ ├── api/ # Transaction controllers
│ ├── application/ # DTOs, services, filtering, AI client
│ └── infrastructure/ # PDF export
└── resources/
└── application.properties
| Key | Purpose |
|---|---|
spring.datasource.url |
PostgreSQL connection string |
application.security.jwt.secret-key |
JWT signing key (minimum 32 characters) |
application.security.jwt.expiration |
Token expiration in milliseconds |
zai.api.url |
Endpoint of the hosted AI insights service |
server.port |
Server port (default 8085) |
The AI service's own configuration (such as its Groq API key) will live in its separate repository once published.
Zairo is a personal project, open for learning and portfolio use.
Built by Aakash Chauhan
If you find this useful, consider giving the repo a star!