Files
2026-04-24 13:50:58 +02:00

18 KiB

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

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.