App di gestione budget personale multi-portafoglio: portafogli con budget mensile, categorie di spesa, transazioni e un "salvadanaio" che traccia i risparmi mese per mese.
Questo repository contiene il backend Strapi 5 ed è anche la guida d'installazione dell'intero progetto (backend + web + app Android).
- 💼 Multi-portafoglio — più portafogli indipendenti (es. Casa, Affitto, Spese Personali), ognuno con il proprio budget mensile e selezione rapida.
- 📊 Dashboard mensile — per ogni categoria vedi Budget / Speso / Rimanente con barra di avanzamento; navighi tra i mesi; i valori sforati diventano rossi; espandi una categoria per vederne le transazioni.
- 🏷️ Categorie con budget e icone — ogni categoria ha budget mensile, icona e ricorrenza.
- ➕ Transazioni rapide — importo, categoria, data, descrizione opzionale e toggle ricorrente (si ripete ogni mese).
- 🐷 Salvadanaio — traccia i risparmi mese per mese (
budget − speso) con totale storico; snapshot mensile automatico via cron Strapi. - 🤖 Analisi estratto conto — carichi il PDF (o CSV) della banca e viene confrontato con le transazioni registrate: sforamenti, movimenti mancanti e un giudizio sintetico. I movimenti si leggono con un parser esatto quando il formato è riconosciuto, altrimenti ci pensa un LLM. Vedi Estratti conto e banche.
- 🔔 Notifiche — promemoria degli addebiti ricorrenti a un orario configurabile.
- ⚙️ Impostazioni — gestisci portafogli (nome, budget) e categorie (crea, modifica, elimina anche in multi-selezione).
- 📤 Export CSV dei dati.
- 🔐 Autenticazione JWT — login sicuro, multi-dispositivo.
- 🌙 UI dark, stile banking moderno.
| Dashboard | Salvadanaio | Nuova transazione |
|---|---|---|
![]() |
![]() |
![]() |
| Analisi estratto conto (AI) | Impostazioni |
|---|---|
![]() |
![]() |
Il progetto è diviso in tre repository:
| Repo | Cosa | Stack |
|---|---|---|
| budget-api (questo) | Backend / API REST | Strapi 5 + MySQL |
| budget-app | Frontend web | Vue 3 + Vite + PrimeVue |
| budget-flutter | App Android nativa | Flutter |
Web e mobile consumano le stesse API REST esposte da questo backend.
- Wallet → più Categories (one-to-many)
- Category → più Transactions (one-to-many)
- Salvadanaio → snapshot mensili per wallet (
risparmio = budget_allocato − speso, se positivo)
- Node.js
>= 20 <= 24(nvm consigliato) - MySQL
8.x(o MariaDB 11.x) in ascolto e raggiungibile - npm
>= 6 - (Opzionale) Docker + Docker Compose per il deploy
- (Opzionale) Ollama in locale per la feature "analisi estratto conto" via LLM
# 1. Clona il repo
git clone https://github.com/v3zz0/budget-api.git
cd budget-api
# 2. Installa le dipendenze
npm install
# 3. Crea il file di ambiente dai placeholder
cp .env.example .env
# 4. Genera segreti REALI e compilali nel .env (vedi sotto)
openssl rand -base64 16 # ripeti per ogni segreto
# 5. Prepara il database MySQL (una tantum)
# mysql -u root -p -e "CREATE DATABASE budget CHARACTER SET utf8mb4;"
# 6. Avvia in sviluppo (hot reload + admin panel)
npm run developAdmin panel: http://localhost:1337/admin (al primo avvio crei l'utente amministratore). API REST: http://localhost:1337/api
Strapi crea le tabelle da solo al primo avvio, ma tiene tutte le API chiuse.
Finché non abiliti i permessi, l'app risponde 403 Forbidden a ogni chiamata,
senza spiegare il motivo. È il primo scoglio di chiunque clona il progetto.
Nel pannello admin: Settings → Users & Permissions plugin → Roles → Authenticated, poi spunta queste voci e premi Save:
| Sezione | Voci da abilitare |
|---|---|
| Wallet | find, findOne, create, update, delete |
| Categorie | find, findOne, create, update, delete |
| Transazioni | find, findOne, create, update, delete |
| Salvadanaio | find, findOne, create, update, delete |
| Analisi | analizza, testAi |
| Consiglio | find, findOne, applica, segna |
| Users-permissions → User | me, update |
Il ruolo Public non serve: tutte le rotte richiedono un utente autenticato.
I controller filtrano comunque per utente: ognuno vede solo i wallet propri e ciò che vi appartiene. Abilitare i permessi non espone i dati altrui.
L'utente dell'admin panel non è un utente dell'app. Registra il tuo dalla schermata di login dell'app, oppure via API:
curl -X POST http://localhost:1337/api/auth/local/register \
-H 'Content-Type: application/json' \
-d '{"username":"mario","email":"mario@esempio.it","password":"unaPasswordSolida"}'Copiate da .env.example. Nessun valore va committato (.env è in .gitignore).
| Variabile | Descrizione |
|---|---|
HOST / PORT |
Bind del server (default 0.0.0.0:1337) |
APP_KEYS |
Chiavi di sessione (lista separata da virgole) |
API_TOKEN_SALT, TRANSFER_TOKEN_SALT |
Salt per i token |
JWT_SECRET, ADMIN_JWT_SECRET |
Firma dei JWT (API e admin) |
ENCRYPTION_KEY |
Cifratura dei dati Strapi |
DATABASE_* |
Client, host, porta, nome, utente, password del DB |
OLLAMA_URL, OLLAMA_MODEL |
(Opzionale) endpoint e modello per l'analisi estratto conto |
AI_TIMEOUT_MS |
(Opzionale) quanto aspettare una risposta del modello, default 60000 |
AI_MAX_BLOCCHI |
(Opzionale) blocchi di testo per documento senza parser dedicato, default 6 |
⚠️ Genera segreti nuovi e casuali (es.openssl rand -base64 16). Non riusare mai valori d'esempio o presi da altri deploy.
Un 504 Gateway Time-out non arriva da Strapi ma dal reverse proxy davanti
(nginx/openresty), che chiude la connessione prima che l'analisi finisca.
L'analisi è sincrona e con un modello lento può durare minuti.
Tre leve, in ordine di efficacia:
-
Usa un modello non "reasoning". Quelli che ragionano prima di rispondere (
qwen3,deepseek-r1,o1…) impiegano molto più tempo e il ragionamento noi lo buttiamo via. Per questo compito vanno benissimo modelli normali tipoqwen2.5-7b-instructollama-3.1-8b-instruct. -
Alza il timeout del reverse proxy. Il default di nginx è 60s:
location /api/analisi- { proxy_pass http://strapi:1337; proxy_read_timeout 300s; proxy_send_timeout 300s; }
-
Scrivi un parser per la tua banca. È la soluzione vera: l'estrazione diventa istantanea e il modello serve solo per le rifiniture. Vedi Scrivere il parser della tua banca.
Il server comunque non resta più appeso: superato AI_TIMEOUT_MS la chiamata
viene abortita, e i passi opzionali (categorie suggerite e giudizio) vengono
saltati con un avviso nel report invece di far fallire tutta l'analisi.
Il repo include Dockerfile e docker-compose.yml. I segreti NON sono nell'immagine:
vengono iniettati a runtime dal file .env (che resta fuori dal versionamento).
# Assicurati di aver compilato .env (vedi sopra)
docker compose up -d --build- Il container legge tutte le variabili da
.env(env_filenel compose). - Gli upload vengono persistiti in
./data/uploads. - Per usare un registry tuo, modifica
image:nel compose e lo scriptpushDocker.sh(l'hostregistry.example.comè un placeholder da sostituire).
🖥️ Frontend web — budget-app
git clone https://github.com/v3zz0/budget-app.git
cd budget-app
npm install
cp .env.example .env # imposta VITE_API_URL sull'URL del backend
npm run dev # http://localhost:5173Dettagli nel README di budget-app.
📱 App Android — budget-flutter
git clone https://github.com/v3zz0/budget-flutter.git
cd budget-flutter
flutter pub get
flutter build apk --release --split-per-abiL'indirizzo del backend si inserisce nell'app, nel campo Server della schermata di login: non serve ricompilare per puntare al proprio Strapi. Resta salvato sul telefono e si può cambiare quando si vuole.
In sviluppo puoi comunque precompilarlo:
flutter run --dart-define=API_BASE_URL=http://10.0.2.2:1337 # emulatore AndroidPer distribuire un APK serve una chiave di firma tua: vedi
android/key.properties.example nel repo dell'app. Senza, la release viene
firmata con la chiave di debug (va bene per provare, non per distribuire).
Guida build APK completa nel README di budget-flutter.
L'analisi legge i movimenti in due modi, nell'ordine:
- Parser esatto. Se il documento ha un formato riconosciuto, i movimenti si
estraggono con una regex: istantaneo, ripetibile, nessun rischio che una riga
venga saltata o inventata. Oggi c'è
sella-parser.jsper Banca Sella (PDF ed export CSV). - LLM di riserva. Se nessun parser riconosce il documento, il testo va al modello configurato (Ollama o un servizio compatibile OpenAI, es. OpenRouter). Funziona con qualsiasi banca, ma è lento e può sbagliare: verifica sempre i risultati.
Nel report il campo fonte dice quale strada è stata usata
(sella-parser, llm, o entrambe se hai caricato più documenti).
Il modo migliore per contribuire. Serve un file che esponga parse(testo) e
restituisca un array di { data: 'YYYY-MM-DD', importo, descrizione } con i soli
addebiti (importo positivo). sella-parser.js è il modello da copiare: 70 righe.
Due accorgimenti che fanno la differenza:
- Pretendi i due decimali nell'importo (
,dd): scarta da solo numeri di conto, date e conteggi che altrimenti verrebbero letti come cifre. - Verifica il totale. Se l'estratto stampa un totale, controlla che la somma dei movimenti estratti coincida: è la prova che non ne hai persi.
Il motore AI si sceglie dall'app in Impostazioni → Analisi AI (indirizzo,
modello e chiave API); i valori in .env restano il default.
.env,*.sqle i dump dati non vanno mai committati (già in.gitignore).- Se cloni per deploy, genera segreti tuoi e usa una password DB forte.
- CORS: per far dialogare web/mobile col backend, configura le origini consentite
in
config/middlewares.js(strapi::cors→origin).
Progetto personale. Usa/adatta liberamente.




