TRAUTOK STATION: la dashboard personale che gira su Python stdlib e SQLite
C'è una schermata che tengo aperta più di ogni altra. Non è un prodotto, non ha utenti, non deve piacere a nessuno tranne che a me. È il cruscotto da cui guardo la mia giornata — e come ogni strumento che uso davvero, l'ho costruito perché resistesse: due file, nessuna dipendenza che non possa perdere senza affondare. Il costrutto la chiama stazione. Io la chiamo il posto da cui capisco a che punto sono.
Cos'è un "command deck" personale
La TRAUTOK STATION è una dashboard personale: un'unica pagina dove convergono le cose che altrimenti finiscono sparse tra dieci app diverse — una citazione per iniziare, le cose da fare, la situazione economica, la settimana, il diario, la mappa delle persone che contano. Non l'ho costruita per venderla: l'ho costruita perché avevo bisogno di un solo posto da guardare, e perché volevo che quel posto fosse mio nel senso più letterale — codice che capisco, dati che stanno su un file che posso aprire con le mani.
È un progetto di Zona 1 nella sua forma più onesta: uno strumento nato da un problema reale, il mio per primo. Questo è il build log di com'è fatta dentro.
Come è costruita: due file e nient'altro
Tutta la dashboard sta in due pezzi, e la separazione è netta:
- UN FILE UI —
trautok-dashboard.html: la struttura, tutto il CSS e tutto il JavaScript stanno inline in quel singolo file. L'unica risorsa esterna sono i font di Google (Orbitron, Share Tech Mono, Special Elite). Nessun bundler, nessun framework, nessuna pipeline di build da mandare a memoria. - UN SERVER STDLIB —
launcher.py: un server HTTP scritto con la sola libreria standard di Python[1] (http.server+sqlite3). Serve la pagina e espone una piccola API REST appoggiata a un database SQLite locale indata/trautok.db. Si avvia conpython3 launcher.pysulocalhost:8765e crea il DB al primo giro se non esiste. - UNA SOLA ECCEZIONE, OPZIONALE — l'integrazione con Google Calendar. Le librerie Google vengono importate lazy, solo se si tocca un endpoint del calendario: se non sono installate, il server parte lo stesso e ogni altro pannello funziona. La dipendenza pesante è confinata dove serve, e si può amputare senza uccidere il resto.
- NIENTE BUILD, NIENTE TEST SUITE, NIENTE LINTER — si modificano i due file e basta. È una scelta, non una pigrizia: meno strati ci sono tra me e il programma, più a lungo il programma sopravvive a me che lo dimentico per sei mesi.
I sette pannelli
L'interfaccia è una griglia CSS di sette pannelli, ognuno autonomo:
- MOTIVAZIONE — una citazione "del momento" da un array statico, battuta a schermo con effetto macchina da scrivere. Parte subito, non aspetta il server.
- TASK — cose da fare con scadenza e priorità, spuntabili.
- ECONOMIA — non uno snapshot fisso, ma una lista di obiettivi (progetto, famiglia, risparmio, tasse) con le proprie voci di entrata e uscita. In cima, tre indicatori a semicerchio disegnati in SVG — autonomia, quota business, margine — e un mini-grafico di proiezione del netto sui prossimi sei mesi.
- PIANIFICAZIONE SETTIMANALE — la griglia della settimana corrente, con oggi evidenziato, sopra cui si sovrappongono gli eventi di Google Calendar.
- DIARIO — note datate, indipendenti, con salvataggio automatico.
- FAMIGLIA — la mappa delle relazioni, di cui parlo tra un attimo.
- CALENDARIO — l'agenda dei prossimi impegni, separata dalla settimana, con aggiunta ed eliminazione eventi.
La mappa delle relazioni
Il pannello di cui vado più orgoglioso è la Famiglia, ed è una vera mappa a nodi. Al centro c'è il nodo IO; le persone stanno su un cerchio intorno, collegate da linee. Le linee non sono decorazione: lo stile della linea codifica il tipo di legame — continua per il sangue, tratteggiata per gli affini, punteggiata per tutto il resto. A questi si aggiungono legami liberi tra persona e persona, con un loro stile.
- ARCHI SVG CLICCABILI — ogni collegamento è una linea SVG con sopra una traccia trasparente più larga che fa da bersaglio al click. Cliccare un arco apre la checklist delle attività con quella persona; ogni attività può essere spedita come evento su Google Calendar (
"<attività> · con <persona>"). - ZOOM E FOCUS — doppio click su un nodo e la vista ci si centra sopra con una
transformCSS; i non-vicini sbiadiscono. C'è anche un filtro "solo chi è connesso a X" per sfoltire quando i nodi crescono. - NOTE PER NODO — ogni persona (e il nodo IO) ha le proprie note in testo libero, con un piccolo badge quando non sono vuote.
Il flusso dati (offline-first)
Qui sta la parte che conta davvero. La fonte di verità è SQLite[2], non il browser. Il JavaScript della pagina non scrive mai direttamente nel localStorage: c'è un unico punto di scrittura, persist(store, valore), che prima salva un backup locale a perdita zero e poi, se il server è online, spedisce un PUT /api/<store>. Ogni funzione di salvataggio passa di lì.
Al caricamento, un GET /api/all riempie in un colpo tutti gli store (task, budget, diario, famiglia). Se quella chiamata fallisce — per esempio ho aperto il file via file://, senza server — la dashboard scivola in modalità offline: mostra un banner, accende il badge DB offline e legge dal backup locale. Il localStorage non è l'archivio: è la scialuppa. E se il DB è vuoto ma un backup esiste, la pagina lo re-importa da sola una volta.
> ui: 1 file html (css + js inline) · unica dip. esterna: google fonts
> server: python http.server + sqlite3 (stdlib) · localhost:8765
> verità: sqlite → data/trautok.db · localStorage = solo backup offline
> api: GET /api/all · PUT /api/<store> (rimpiazzo atomico)
> calendar: google, import lazy · assente → il resto vive
Perché stdlib e niente framework
La domanda ovvia è: perché farsi male con http.server quando esistono framework che ti danno tutto in tre righe? La risposta è la stessa che percorre tutto ciò che pubblico qui. Uno strumento personale che uso ogni giorno deve superare un test preciso: se il servizio di terzi sparisse, il progetto vive? Con due file di sola libreria standard e un file SQLite, la risposta è sì. Google Calendar può staccarsi domani e perdo un pannello, non la stazione.
È il principio del ritorno al self-hosting applicato in piccolo, e lo stesso patto che mi sono imposto quando ho iniziato a scrivere codice con un agente: usare gli strumenti del presente, ma restare capace di sopravvivere alla loro assenza. Una dashboard che dipende da mezza Internet non è un cruscotto, è un'altra cosa che può rompersi.
Domande frequenti
Che stack usa questa dashboard?
Due file: un trautok-dashboard.html con CSS e JavaScript inline (unica dipendenza esterna i font di Google) e un launcher.py che è un server HTTP di sola libreria standard Python (http.server + sqlite3). Nessun framework, nessun bundler, nessun passo di build.
Dove sono salvati i dati?
In un database SQLite locale, il file data/trautok.db. Il localStorage del browser è usato solo come backup d'emergenza quando il server non è raggiungibile, non come archivio principale.
Funziona senza connessione?
Sì, in due sensi. Gira tutto in locale, quindi non serve Internet per usarla. E se apro la pagina senza il server attivo, entra in modalità offline: banner di avviso, badge "DB offline" e lettura dal backup locale. L'unico pezzo che richiede la rete è l'integrazione opzionale con Google Calendar.
Chiudo il portatile e la stazione resta lì, sul suo file da qualche megabyte. Nessuna nuvola da ringraziare, nessun abbonamento che scade. Che il tuo cruscotto sopravviva all'apocalisse — e soprattutto a te che te ne dimentichi.
Note
- stdlib (libreria standard) — l'insieme dei moduli che arrivano con Python senza installare nulla. Qui i due pilastri sono
http.server(server HTTP di base) esqlite3(interfaccia al database SQLite). Meno dipendenze esterne = meno cose che si rompono nel tempo. ↑ torna al testo - SQLite — un database relazionale che vive in un unico file sul disco, senza un server separato. Il server apre una connessione per richiesta in modalità WAL, compatibile con il server multi-thread. ↑ torna al testo
SURVIVAL APPS