Conversational expense tracking with tool-calling, monthly insights, and built-in observability (traces, metrics, logs).
- Java 21
- Maven 3.9+
- Docker + Docker Compose (for the full stack)
- Ollama running locally
- Models used by default:
qwen2.5:7b-instructnomic-embed-text:latest
- Example:
ollama pull qwen2.5:7b-instructollama pull nomic-embed-text:latest
- Models used by default:
docker compose up --buildServices and ports:
- App: http://localhost:8080
- Jaeger: http://localhost:16686
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000
- Loki: http://localhost:3100
The app container expects Ollama on host.docker.internal:11434.
Start PostgreSQL locally (example with Homebrew):
brew install postgresql@16
brew services start postgresql@16
psql postgres -c "CREATE USER expenseai WITH PASSWORD 'expenseai';"
psql postgres -c "CREATE DATABASE expenseai OWNER expenseai;"mvn spring-boot:runOllama is expected at http://localhost:11434 (see src/main/resources/application.yml).
UI:
GET /— main dashboard
Chat:
POST /chat— conversational expense entry- body:
{ "message": "In July 25th, 2025, I bought a coffee, cost 6.66 euros" }
- body:
Expenses:
GET /expenses— list all expensesGET /expenses/month/{yyyy-MM}— list by monthGET /expenses/date/{yyyy-MM-dd}— list by datePOST /expenses— create expensePUT /expenses/{id}— update expense
Insights:
GET /insight?month=yyyy-MM&lang=en— monthly insight (language optional)
OpenTelemetry Collector runs via otel/collector-config.yml and exports:
- Traces → Jaeger + Azure Monitor
- Metrics → Prometheus + Azure Monitor
- Logs → Loki + Azure Monitor
- Open: http://localhost:16686
- Open: http://localhost:9090
- Check scrape targets: http://localhost:9090/targets
- Open: http://localhost:3000 (admin/admin by default)
- Add data sources:
- Prometheus:
http://prometheus:9090 - Loki:
http://loki:3100 - Jaeger (optional):
http://jaeger:16686
- Prometheus:
Set APPLICATIONINSIGHTS_CONNECTION_STRING before starting:
export APPLICATIONINSIGHTS_CONNECTION_STRING="InstrumentationKey=...;IngestionEndpoint=..."The collector will send traces/metrics/logs to Azure Monitor via the azuremonitor exporter.
- App config:
src/main/resources/application.yml - Collector config:
otel/collector-config.yml - Prometheus config:
otel/prometheus.yml - Docker compose:
docker-compose.yml
- The app uses PostgreSQL by default via Docker Compose. Data is persisted in the
pgdatavolume. - If Grafana shows no Loki labels/data, ensure the Loki data source uses
http://loki:3100(notlocalhost).