# PRD: Supabase Auto-Shutdown Prevention System ## 1. Executive Summary Questo progetto definisce un servizio Python dockerizzato con il solo scopo di mantenere attivo un database Supabase in free tier, prevenendo la sospensione automatica dovuta a lunghi periodi di inattivita'. La soluzione prevista e' un processo long-running eseguito in un container Docker che: - carica la configurazione da file `.env`; - si connette al database Supabase/PostgreSQL; - esegue periodicamente una query leggera di keep-alive; - registra esito e tempi di esecuzione; - salva i campioni di latenza/esito in un database RRD locale con finestra storica di 48 ore; - espone una webapp con vista storica in stile SmokePing tramite backend FastAPI servito da Uvicorn; - espone API HTTP documentate automaticamente con Swagger/OpenAPI; - continua a funzionare finche' il container non viene fermato. ## 2. Problema Nel piano gratuito di Supabase, un progetto puo' essere sospeso o parcheggiato dopo un periodo prolungato di inattivita'. Quando questo avviene: - il database puo' diventare temporaneamente non raggiungibile; - l'applicazione che lo usa puo' apparire guasta o lenta al primo accesso; - l'esperienza di sviluppo, demo o staging peggiora sensibilmente. Il problema da risolvere non e' l'alta disponibilita' in senso enterprise, ma la continuita' operativa minima per ambienti personali, prototipi, demo e staging leggeri. ## 3. Obiettivo di Prodotto Garantire che Supabase rilevi attivita' reale sul database almeno una volta entro ogni finestra di 7 giorni, con un margine di sicurezza sufficiente a evitare la sospensione automatica nella pratica. ## 4. Obiettivi Specifici - Eseguire automaticamente attivita' valida sul database senza intervento umano. - Mantenere il processo attivo in modo continuativo tramite container Docker. - Consentire configurazione interamente tramite `.env`. - Rendere il comportamento osservabile con log chiari di successo e fallimento. - Rendere osservabile lo storico delle misure tramite una webapp con grafico temporale in stile SmokePing. - Mantenere la soluzione minimale, portabile e facile da eseguire su qualsiasi host con Docker. ## 5. Non-Obiettivi - Non e' un sistema di backup, replica o disaster recovery. - Non e' un sistema di monitoraggio completo del database. - Non deve gestire provisioning, creazione schema o migrazioni Supabase. - Non deve introdurre traffico aggressivo o pattern assimilabili ad abuso del free tier. - Non deve dipendere obbligatoriamente da GitHub Actions, servizi cron esterni o infrastrutture cloud aggiuntive. - Non e' un sistema di osservabilita' multi-tenant o con retention storica di lungo periodo oltre 48 ore in V1. ## 6. Pubblico di Riferimento - Sviluppatori individuali che usano Supabase free tier per prototipi. - Team piccoli che usano Supabase come ambiente di staging leggero. - Progetti personali o dimostrativi che devono restare pronti all'uso senza accessi frequenti. ## 7. User Stories - Come sviluppatore, voglio che il mio database Supabase resti raggiungibile anche se non uso l'app per giorni. - Come maintainer, voglio configurare il servizio con un semplice file `.env` senza modificare il codice. - Come operatore, voglio eseguire il servizio in Docker e lasciarlo attivo finche' non decido di fermarlo. - Come utente tecnico, voglio vedere nei log se il keep-alive sta funzionando oppure no. ## 8. Scope della Soluzione La soluzione target per questo repository e': - applicazione Python; - esecuzione in container Docker; - loop applicativo continuo; - connessione diretta a PostgreSQL/Supabase; - query di keep-alive configurabile; - persistenza campioni in database RRD locale con retention fissa a 48 ore; - webapp per visualizzazione dello storico con UI ispirata a SmokePing; - configurazione tramite file `.env` e `.env.example`. Stack applicativo vincolata per la componente web: - FastAPI per endpoint API e documentazione OpenAPI; - Uvicorn come server ASGI runtime; - Swagger UI (endpoint `/docs`) e schema OpenAPI (endpoint `/openapi.json`). Alternative come GitHub Actions, `pg_cron` o cron esterni restano opzioni comparabili, ma non rappresentano la soluzione primaria di questo repository. ## 9. Assunzioni di Prodotto - Supabase considera una query SQL valida come attivita' sufficiente a evitare la sospensione per inattivita'. - Un'attivita' 2 o 3 volte a settimana offre margine adeguato rispetto alla finestra di 7 giorni. - L'host che esegue Docker resta normalmente acceso o comunque ripristina il container tramite restart policy. - L'utente dispone delle credenziali di accesso al database Supabase. ## 10. Requisiti Funzionali ### RF1. Caricamento configurazione da `.env` Il sistema deve caricare tutti i parametri necessari da file `.env`. Parametri minimi richiesti: - `SUPABASE_DB_HOST` - `SUPABASE_DB_PORT` - `SUPABASE_DB_NAME` - `SUPABASE_DB_USER` - `SUPABASE_DB_PASSWORD` - `PING_INTERVAL_MINUTES` - `PING_QUERY` - `TZ` ### RF2. Presenza di `.env.example` Il repository deve includere un file `.env.example` che documenti tutte le variabili necessarie senza contenere segreti reali. ### RF3. Connessione al database Supabase Il sistema deve aprire una connessione verso il database PostgreSQL di Supabase usando le credenziali fornite. ### RF4. Esecuzione di attivita' reale Il sistema deve eseguire un'operazione SQL reale che venga contabilizzata come attivita' dal database. Comportamento previsto: - default consigliato: query leggera come `SELECT 1;`; - opzione futura: query custom o update su tabella tecnica di log; - l'operazione deve essere configurabile tramite environment variable. ### RF5. Esecuzione periodica automatizzata Il processo deve essere automatico e ciclico, senza intervento umano manuale dopo l'avvio del container. Vincoli di frequenza: - il sistema deve supportare un intervallo configurabile; - l'intervallo operativo raccomandato deve garantire almeno 2 esecuzioni a settimana; - il default di prodotto consigliato e' tra 72 e 96 ore; - non devono essere usati intervalli inutilmente aggressivi come default. ### RF6. Processo long-running Il processo Python non deve terminare dopo un singolo ping riuscito o fallito. Deve restare attivo e continuare a schedulare i cicli successivi finche' il container non viene fermato. ### RF7. Logging di esecuzione Il sistema deve emettere log almeno per: - avvio del servizio; - lettura configurazione valida; - tentativo di connessione; - esecuzione query; - successo dell'operazione; - errore dell'operazione; - attesa del prossimo ciclo. ### RF8. Gestione errori resiliente In caso di fallimento di connessione o query, il processo non deve terminare immediatamente. Deve: - loggare l'errore; - chiudere in sicurezza eventuali risorse aperte; - attendere il prossimo intervallo o un retry definito; - riprovare automaticamente. ### RF9. Arresto controllato Il processo deve supportare lo stop del container in modo ordinato, chiudendo connessioni e terminando il loop senza lasciare risorse sporche. ### RF10. Modalita' di esecuzione containerizzata Il sistema deve essere eseguibile tramite Docker con restart policy adatta a mantenerlo operativo finche' non viene fermato esplicitamente. Policy target: - `unless-stopped` come impostazione raccomandata. ### RF11. Notifica di errore opzionale La notifica all'utente in caso di fallimento e' opzionale in prima versione. Per la V1, il requisito minimo e' il logging locale/STDOUT. In versioni successive, potranno essere introdotte integrazioni opzionali come email, webhook o Telegram. ### RF12. Persistenza storica su database RRD (48 ore) Il sistema deve salvare a ogni ciclo un campione di connettivita' in un database RRD locale. Vincoli obbligatori: - retention dimensionata per una finestra storica continua di 48 ore; - granularita' coerente con l'intervallo di misura configurato; - dati minimi per campione: timestamp, esito (ok/errore) e tempo di risposta; - comportamento a buffer pieno di tipo circolare tipico RRD (sovrascrittura dei campioni piu' vecchi). ### RF13. Webapp storica in stile SmokePing Il sistema deve esporre una webapp locale che mostri lo storico della connessione con visualizzazione ispirata a SmokePing. Capacita' minime richieste: - pagina di overview con stato corrente e trend delle ultime 48 ore; - grafico temporale con evidenza di latenza e fallimenti; - aggiornamento periodico automatico della vista senza riavvio del servizio; - accesso via porta HTTP configurabile. - implementazione obbligatoria con FastAPI + Uvicorn. ### RF14. API di lettura dello storico La webapp deve leggere i dati dal RRD tramite un endpoint applicativo di sola lettura. Vincoli: - nessuna operazione di scrittura esposta lato web; - filtri minimi per finestra temporale entro il limite delle 48 ore; - risposta con formato stabile e documentato per supportare eventuali evoluzioni UI. ### RF15. Documentazione API via Swagger/OpenAPI Le API devono essere auto-documentate tramite le funzionalita' native FastAPI. Capacita' minime richieste: - endpoint Swagger UI disponibile in `/docs`; - schema OpenAPI disponibile in `/openapi.json`; - descrizione chiara di parametri, risposta e codici errore degli endpoint principali; - coerenza tra comportamento effettivo e documentazione generata. ### RF16. Continuita' operativa tra collector e UI Il collector di ping e la webapp devono convivere nello stesso servizio/container senza bloccare il loop di keep-alive. In caso di errore della UI, la raccolta dati non deve interrompersi. In caso di errore temporaneo del collector, la UI deve continuare a mostrare l'ultimo storico disponibile. ## 11. Requisiti Non Funzionali ### RNF1. Semplicita' La soluzione deve restare piccola, leggibile e con poche dipendenze. ### RNF2. Portabilita' Il servizio deve poter girare su qualsiasi ambiente che supporti Docker: VPS, mini PC, NAS, server domestico o macchina di sviluppo. ### RNF3. Sicurezza - Nessun segreto hardcoded nel codice. - Nessun segreto committato nel repository. - Tutti i segreti devono essere passati tramite `.env` o strumenti equivalenti. ### RNF4. Osservabilita' minima I log devono essere sufficienti a diagnosticare se il job di keep-alive ha funzionato senza richiedere debugging interattivo. ### RNF5. Basso impatto Il sistema deve usare query leggere e frequenza moderata per minimizzare costo computazionale e rischio di comportamento eccessivo verso il free tier. ### RNF6. Retention e storage prevedibile Lo storage storico deve restare bounded: il database RRD deve mantenere esclusivamente 48 ore di dati, con uso disco stabile nel tempo. ### RNF7. Usabilita' operativa della dashboard La webapp deve essere leggibile su desktop e mobile, con tempi di caricamento adeguati all'uso operativo (target iniziale: visualizzazione disponibile in pochi secondi su rete locale). ### RNF8. Contratto API documentato La documentazione OpenAPI/Swagger deve essere sempre disponibile in ambiente runtime V1.1+ e deve riflettere fedelmente gli endpoint esposti. ## 12. Configurazione di Prodotto ### Variabili richieste ```env SUPABASE_DB_HOST= SUPABASE_DB_PORT=5432 SUPABASE_DB_NAME= SUPABASE_DB_USER= SUPABASE_DB_PASSWORD= PING_INTERVAL_MINUTES=4320 PING_QUERY=SELECT 1; TZ=Europe/Rome ``` ### Note sulla configurazione - `PING_INTERVAL_MINUTES=4320` equivale a 72 ore. - Il valore effettivo puo' essere modificato, ma il default raccomandato deve restare prudente rispetto ai termini d'uso e al limite dei 7 giorni. - Il file `.env.example` deve contenere le stesse chiavi, ma senza valori sensibili. ## 13. Flusso Operativo Atteso 1. L'utente crea il file `.env` partendo da `.env.example`. 2. L'utente avvia il container con `--env-file .env`. 3. Il processo Python parte e valida la configurazione. 4. Il servizio apre una connessione al database Supabase. 5. Il servizio esegue la query di keep-alive. 6. Il servizio registra esito e timestamp. 7. Il servizio attende fino al ciclo successivo. 8. Il loop continua finche' il container non viene fermato. ## 14. Architettura Logica Componenti logici previsti: - loader configurazione: valida e carica le variabili ambiente; - scheduler loop: gestisce l'attesa fra i cicli; - database client: apre connessione ed esegue la query; - collector metriche: misura latenza/esito e normalizza i campioni; - storage RRD: persiste i campioni con retention circolare 48 ore; - API storico FastAPI: espone i dati aggregati alla webapp in sola lettura; - server Uvicorn: esegue l'app ASGI e pubblica endpoint API e docs Swagger; - web frontend: renderizza vista storica in stile SmokePing; - logger: stampa esiti ed errori su STDOUT/STDERR; - runtime Docker: mantiene il processo eseguito come container persistente. ## 15. Soluzioni Tecniche Valutate | Soluzione | Descrizione | Pro | Contro | Esito | | --- | --- | --- | --- | --- | | Python + Docker long-running | Processo residente che esegue query periodiche via connessione DB diretta. | Indipendente da servizi terzi, semplice da portare ovunque, coerente con il repository. | Richiede un host sempre acceso. | Scelta primaria | | GitHub Actions | Workflow schedulato con chiamata HTTP o query indiretta. | Facile da configurare, economico. | Dipende da GitHub e da scheduling esterno. | Alternativa | | pg_cron | Job schedulati internamente al database. | Soluzione interna a Postgres. | Affidabilita' e disponibilita' non sempre ideali su free tier. | Non primaria | | External Cron | Servizi terzi che attivano un endpoint o una function. | Molto affidabile. | Dipendenza esterna aggiuntiva. | Alternativa | ## 16. Vincoli e Rischi ### Vincoli - Uso del piano gratuito Supabase. - Necessita' di rispettare termini e limiti del servizio. - Presenza di un host Docker sempre disponibile o quasi sempre disponibile. ### Rischi - Una frequenza troppo alta potrebbe essere interpretata come utilizzo artificiale o eccessivo. - Una frequenza troppo bassa potrebbe non prevenire il parking. - Credenziali esposte in repository o log rappresentano rischio di sicurezza. - Cambiamenti futuri nelle policy Supabase potrebbero ridurre l'efficacia della soluzione. - Corruzione o inizializzazione errata del file RRD puo' rendere incompleta la visualizzazione storica. ### Mitigazioni - Default conservativo a poche esecuzioni settimanali. - Query molto leggere. - Segreti solo in `.env`. - Logging senza stampa delle credenziali. - Validazione all'avvio della struttura RRD e ricreazione controllata in caso di inconsistenza. ## 17. Requisiti di Sicurezza - Il sistema non deve stampare password o DSN completi nei log. - Il file `.env` deve essere escluso dal versionamento. - Il file `.env.example` deve essere versionato come riferimento. - Eventuali errori devono essere sanitizzati per evitare leak accidentali di segreti. ## 18. Requisiti di Deployment - Il progetto deve essere buildabile tramite `docker build`. - Il progetto deve poter essere eseguito con `docker run --env-file .env`. - Deve essere compatibile anche con `docker compose`. - La restart policy raccomandata deve essere `unless-stopped`. ## 19. Metriche di Successo - Il database Supabase non entra in stato paused durante normali periodi di mancato utilizzo dell'applicazione. - Ogni esecuzione pianificata produce un log di successo oppure un log di errore esplicito. - Il container resta in esecuzione senza terminare dopo il primo ciclo. - La configurazione puo' essere modificata senza cambiare il codice applicativo. - La webapp mostra sempre uno storico disponibile delle ultime 48 ore, compatibilmente con il tempo trascorso dal primo avvio. ## 20. Acceptance Criteria ### AC1. Configurazione - Esiste un file `.env.example` completo con tutte le variabili richieste. - Il servizio fallisce in modo chiaro se manca una variabile obbligatoria. ### AC2. Keep-alive riuscito - A container avviato, il servizio esegue con successo almeno una query di keep-alive verso Supabase. - I log mostrano chiaramente l'avvenuta esecuzione con timestamp. ### AC3. Continuita' del processo - Dopo una query riuscita, il processo non termina. - Il container rimane in stato attivo fino a stop manuale o errore esterno del runtime. ### AC4. Tolleranza ai fallimenti - Se una query fallisce, il processo logga l'errore e continua a riprovare nei cicli successivi. ### AC5. Sicurezza di configurazione - Nessuna credenziale reale compare nel repository tracciato. - Le istruzioni d'uso spiegano chiaramente la differenza tra `.env` e `.env.example`. ### AC6. Coerenza con il free tier - Il sistema consente una schedulazione moderata, raccomandata su 2-3 esecuzioni a settimana. ### AC7. Persistenza RRD 48 ore - A servizio avviato, i campioni di connessione vengono scritti su RRD a ogni ciclo. - Dopo oltre 48 ore di funzionamento continuo, lo storico visualizzato copre solo la finestra mobile piu' recente di 48 ore. ### AC8. Dashboard stile SmokePing - Esiste una webapp accessibile via HTTP che mostra andamento temporale di latenza ed errori. - La dashboard si aggiorna automaticamente e riflette i nuovi campioni senza riavvio. ### AC9. API e Swagger operativi - Gli endpoint API principali sono serviti da FastAPI tramite Uvicorn. - L'endpoint `/docs` e' accessibile e mostra la documentazione Swagger UI. - L'endpoint `/openapi.json` e' accessibile e coerente con le API realmente disponibili. ### AC10. Degrado controllato - Se il modulo UI fallisce temporaneamente, il collector continua a registrare campioni su RRD. - Se una misura fallisce, la dashboard mantiene lo storico precedente e rende visibile il fallimento del nuovo campione. ## 21. Roadmap Evolutiva ### V1 - Connessione diretta al database. - Query di keep-alive configurabile. - Loop continuo. - Logging base. - Container Docker con restart policy consigliata. - Persistenza storico su RRD locale (48 ore). - Webapp di visualizzazione storica in stile SmokePing. ### V1.1 - Implementazione backend web con FastAPI servito da Uvicorn. - API read-only per storico RRD. - Documentazione API Swagger/OpenAPI esposta in runtime. ### V1.1 - Retry con backoff configurabile. - Miglioramento dei messaggi di health e startup. - Distinzione chiara tra errori di configurazione e di rete. ### V2 - Notifiche opzionali su webhook o email. - Healthcheck Docker dedicato. - Modalita' dry-run o startup check. - Supporto a metriche esportabili. ## 22. Decisione di Prodotto La soluzione da implementare in questo repository e' un servizio Python sempre attivo, eseguito in Docker, configurato via `.env`, con query di keep-alive leggera e frequenza moderata. Questa scelta massimizza semplicita', portabilita' e controllo operativo, riducendo dipendenze esterne rispetto alle alternative basate su scheduler di terze parti.