Webapp per gestire gli abbonamenti team condivisi ai servizi LLM (Claude, ChatGPT, estendibile ad altri), in sostituzione dell'attuale Google Sheet. Calcola automaticamente quote, scadenze e stato dei pagamenti, e conserva lo storico completo.
Contesto e scope: PROJECT.md · Convenzioni di lavoro: AGENT.md
- Frontend + API: Next.js 16 (App Router) + React 19 + Tailwind CSS 4 + TypeScript
- Database: MongoDB (Atlas piano free) via Mongoose
- Script utility: Python 3 + pymongo
- Hosting: Vercel + MongoDB Atlas
subsmate/
├── frontend/ # App Next.js (UI + API routes)
│ ├── app/
│ │ ├── api/ # Route handler REST, avvolti in withAdmin()
│ │ ├── (protected)/ # route group con guardia admin
│ │ │ ├── abbonamenti/ # elenco con filtri + scheda con storico
│ │ │ ├── persone/ servizi/ pagamenti/
│ │ │ ├── layout.tsx # header/footer navy, font Manrope + Inter
│ │ │ └── page.tsx # dashboard
│ │ ├── login/ # pagina di login, fuori dal gruppo protetto
│ │ └── layout.tsx # root layout (nessun header/footer qui)
│ ├── middleware.ts # Edge: verifica solo la firma del cookie di sessione
│ ├── lib/
│ │ ├── mongodb.ts # connessione con cache globale
│ │ ├── billing.ts # motore di calcolo (quote, scadenze, stato)
│ │ ├── queries.ts # letture condivise API/pagine
│ │ ├── validation.ts # schemi Zod di input
│ │ ├── api.ts # risposte e gestione errori uniformi
│ │ ├── auth.ts # verifyPassword() con bcryptjs (solo Node)
│ │ ├── session-token.ts # firma/verifica JWT con jose (Edge + Node)
│ │ └── requireAdmin.ts # controllo autorevole su DB (Node): requireAdmin()/withAdmin()
│ ├── components/ # primitive UI (card, tabella, badge di stato)
│ └── models/ # schemi Mongoose (incluso AdminUser)
├── directives/ # SOP in Markdown (livello 1)
├── execution/ # script Python deterministici (livello 3)
├── .tmp/ # file intermedi, mai committati
└── .env.example
| Collezione | Contenuto |
|---|---|
services |
Servizio LLM: nome, tariffa mensile, giorno di addebito |
people |
Persone del team (email univoca) |
subscriptions |
Istanza persona × servizio: periodicità, supplemento donazione, stato onboarding, lastPaymentDate |
payments |
Storico incassi: importo, quota donazione, data, metodo, periodo coperto |
adminusers |
Admin dell'app (email + password hashata) |
Principio chiave: quota, totale dovuto, prossima scadenza e stato pagamento non
sono salvati. Sono derivati a ogni lettura da lib/billing.ts a partire da
lastPaymentDate + periodicità, così non possono andare fuori sincrono.
Stati calcolati: in_regola · in_scadenza (entro 15 giorni) · in_ritardo · da_attivare.
La UI segue brand-guidelines.md: navy #161b2d confinato a header,
footer e bottoni primari; pagine di dati su sfondo chiaro; bordi sottili al posto delle ombre;
Manrope per titoli e numeri, Inter per tabelle e dati; i quattro colori di stato non sono
riusati per nient'altro. I token vivono in frontend/app/globals.css.
| Metodo | Endpoint | Descrizione |
|---|---|---|
| GET / POST | /api/services |
Elenco e creazione servizi |
| GET / PATCH / DELETE | /api/services/:id |
Dettaglio servizio |
| GET / POST | /api/people |
Elenco (con ?q=) e creazione persone |
| GET / PATCH / DELETE | /api/people/:id |
Scheda persona con abbonamenti e totale dovuto |
| GET / POST | /api/subscriptions |
Elenco con calcoli (?status=, ?person=, ?service=) |
| GET / PATCH / DELETE | /api/subscriptions/:id |
Dettaglio con storico pagamenti |
| GET / POST | /api/subscriptions/:id/payments |
Storico e registrazione pagamento |
| GET | /api/payments |
Storico globale (?person=, ?from=, ?to=) |
| GET | /api/dashboard |
Totali, contatori di stato, abbonamenti da seguire |
cp .env.example frontend/.env.local # valorizza MONGODB_URI
cd frontend && npm install && npm run devpip install -r execution/requirements.txt
python execution/check_db_connection.py # diagnosi: DNS / TCP / TLS / autenticazione
python execution/seed_services.py # crea Claude e ChatGPT
python execution/seed_demo_data.py # dati di prova per verificare la UICreare il primo admin (genera anche AUTH_SECRET):
python execution/seed_admin.py --email "tua@email.it" --name "Nome Cognome"Nota rete: la porta 27017 è bloccata in uscita sulla rete ICPN, quindi MongoDB Atlas non è raggiungibile dalle postazioni interne. Lo sviluppo avviene su MongoDB Community locale;
frontend/.env.localcontiene entrambe le URI, con quella Atlas commentata. Dettagli in directives/setup_ambiente.md.
Procedura completa in directives/setup_ambiente.md.
- Modelli dati e motore di calcolo
- API REST complete (servizi, persone, abbonamenti, pagamenti, dashboard)
- Direttive e script di import
- UI — dashboard, abbonamenti (con filtri), scheda abbonamento con registrazione pagamento, persone, servizi, pagamenti
- Verifica end-to-end su MongoDB locale: registrazione pagamento, ricalcolo di scadenza e stato
- Autenticazione admin (login email + password, sessione 7 giorni, blocco dopo 5 tentativi)
- Import reale dal Google Sheet
- Connessione ad Atlas (bloccata dalla rete, non dal codice)