logo
HomeSkillsCarrieraPortfolioBlogContatti
  • Home
  • Skills
  • Carriera
  • Portfolio
  • Blog
  • Contatti

PearLift

Un tracker di allenamento local-first con sincronizzazione peer-to-peer, niente account, niente server. 🍐

ExpoSQLiteHolepunchF-Droid
post_image
Codice Sorgente
08/06/2026
0
2
Codice Sorgente

La Storia

Avevo bisogno di un tracker di allenamento che non mi infastidisse. Le app esistenti o spedivano i miei dati di allenamento nel server di qualcun altro, bloccavano funzionalità base dietro abbonamenti, o semplicemente non supportavano la struttura multi-giorno con cui mi alleno realmente. Stavo tracciando tutto in un'app di note e stava diventando ridicolo.

Il primo tentativo è stato una PWA con interfaccia in stile MUI. Semplice di proposito, costruita solo per me. Salva i dati in localStorage e poteva opzionalmente sincronizzarsi tramite GitHub Gist usando una chiave API personale. Funzionava. Ma era fragile, e non risolveva il vero problema: volevo i miei dati di allenamento sul telefono in palestra, non in un tab del browser. Volevo anche un timer di riposo che continuasse a funzionare a schermo spento, cosa che una PWA non può fare bene.

Nello stesso periodo, volevo sperimentare con lo stack PEAR/Holepunch. L'idea della sincronizzazione peer-to-peer senza server, senza account, senza che i dati finiscano sul computer di qualcun altro, mi risuonava. Un tracker di allenamento sembrava il caso d'uso perfetto: dati personali, nessun motivo per un server, e un bisogno reale di sincronizzazione multi-dispositivo.

Così ho ricostruito tutto da zero come app mobile nativa. ✨

Cosa La Rende Speciale

PearLift è un tracker di allenamento local-first che non ha un backend. Non ha account utente. I tuoi dati di allenamento vivono in un database SQLite sul tuo dispositivo e da nessun'altra parte. Se vuoi sincronizzare tra i tuoi dispositivi, l'app li connette direttamente usando Holepunch, peer-to-peer, senza server coinvolti.

Supporta programmi multi-settimana con layout giornalieri configurabili, traccia la progressione dei pesi sia in kg che in lb, e include un timer di riposo in background che sopravvive al process killer di Android. I backup sono esportabili come codici QR per il trasferimento da dispositivo a dispositivo, senza cavi o account cloud necessari.

Il nome viene dall'ecosistema PEAR che alimenta il layer di sincronizzazione, più l'ovvio riferimento al sollevamento pesi. C'è qualcosa di soddisfacente nell'avere una pera come mascotte per un'app di fitness. 🍐

Il Lato Tecnico

Funzionalità Principali

  • Programmi di allenamento multi-settimana con configurazione nidificata settimana/giorno/esercizio
  • Tracciamento pesi con commutazione tra kg e lb
  • Timer di riposo in background con servizio foreground Android e notifiche persistenti
  • Backup e ripristino locale completo, esportabile come codici QR scansionabili
  • Sincronizzazione peer-to-peer tra dispositivi via Holepunch (Hypercore + HyperSwarm + Autobase)
  • Archiviazione SQLite con repository tipizzati e migrazioni dello schema
  • Internazionalizzazione con supporto per inglese e italiano
  • Zero telemetria, zero richieste di rete oltre alla sincronizzazione peer opzionale

La Ricetta Segreta

Costruita con:

  • Expo SDK 56 e React Native per mobile cross-platform
  • SQLite via expo-sqlite per persistenza local-first
  • Zustand per stato globale prevedibile
  • Reanimated per animazioni fluide basate su gesture
  • Stack Holepunch (Hypercore, HyperSwarm, Autobase) per sincronizzazione P2P senza server
  • Bare Kit con un backend Node.js bundle eseguito on-device per l'orchestrazione della sincronizzazione
  • i18next per traduzioni runtime
  • Biome per linting e formattazione, Bun per testing, Maestro per flussi E2E

pearlift_showcase

Architettura

Il layer di sincronizzazione è dove le cose si fanno interessanti. Normalmente, un'app mobile che sincronizza dati comunica con un'API REST o un server WebSocket. PearLift non fa nessuna delle due. Ogni dispositivo esegue un backend Node.js bundle all'interno di un motore JavaScript separato via react-native-bare-kit. Quel backend gestisce la replicazione Hypercore, il merging Autobase per la risoluzione dei conflitti, e la scoperta dei peer attraverso il DHT di HyperSwarm. Il layer React Native comunica con questo backend attraverso un ponte RPC.

Questo significa che la scoperta per la sincronizzazione avviene attraverso reti locali e tabelle hash distribuite, non attraverso un server centralizzato. Due dispositivi si trovano, si autenticano usando un segreto di accoppiamento condiviso, e replicano i loro dati di allenamento direttamente. Nessun server. Nessun relay. Nessuna terza parte che legge i tuoi numeri di stacco.

Il timer di riposo usa un modulo nativo Kotlin di servizio foreground. Android uccide i processi in background in modo aggressivo, specialmente sulle versioni più recenti del sistema operativo. Un servizio foreground con una notifica persistente è l'unico modo affidabile per mantenere vivo un timer quando l'utente cambia app o blocca lo schermo. Lo stato del timer è replicato su SQLite per sopravvivere a riavvii completi dell'app.

Sfide e Soluzioni

Il Labirinto della Sincronizzazione P2P

  • Sfida: Scoperta dei peer, risoluzione dei conflitti, ed esecuzione di un backend Node.js su un dispositivo mobile. Le librerie Holepunch sono minimali per design, espongono le primitive ma non c'è un layer di astrazione. La documentazione è scarsa, e quasi nessuno l'aveva fatto su React Native prima
  • Soluzione: Confrontato casi d'uso con la documentazione ufficiale pezzo per pezzo, ragionando sulla logica con l'aiuto dell'IA per colmare i vuoti dove la documentazione finiva. Ripetuti test per tentativi ed errori tra emulatore e dispositivo reale via adb e flussi E2E Maestro
  • Risultato: Due dispositivi possono scoprirsi, autenticarsi con un segreto di accoppiamento, e replicare dati di allenamento peer-to-peer. Nessun server richiesto. Ancora non pretendo di capire completamente gli interni di ogni libreria Holepunch, ma la sincronizzazione funziona

Il Servizio Foreground Android

  • Sfida: Android 14 ha cambiato significativamente le regole dei servizi foreground. Un timer di riposo deve continuare a contare quando l'utente apre Instagram o blocca il telefono, e deve lanciare una notifica al momento giusto
  • Soluzione: Costruito un modulo nativo Kotlin di servizio foreground con canali di notifica persistenti. Lo stato del timer è scritto su SQLite così sopravvive alla terminazione del processo. La notifica mostra il tempo rimanente e offre azioni di stop
  • Risultato: La musica suona, lo schermo si spegne, il timer continua a contare, la notifica si attiva in orario

Dietro Le Quinte

Questo progetto è nato come PWA che si sincronizzava via GitHub Gists. Era brutta, era semplice, ed era mia. Quando ho deciso di trasformarla in un'app completa, avevo due obiettivi: costruire qualcosa che avrei usato davvero in palestra ogni giorno, e testare se lo stack PEAR/Holepunch fosse praticabile per applicazioni mobile reali.

L'ho costruita da solo con l'assistenza dell'IA, concentrandomi su architettura e testing fin dal primo giorno. Il setup di test E2E è una piccola storia di ingegneria a sé: un emulatore, un dispositivo reale collegato via adb, Maestro che orchestra i flussi, e l'agente IA che esegue diagnostiche di sincronizzazione parsando l'output JSON dai log di test. Un altro livello di follia ma funziona.

La maggior parte dello sviluppo è avvenuta nel giro di settimane. L'IA ha accelerato significativamente la codifica. Ma le decisioni architetturali, il modello dati, la strategia di sincronizzazione, quelle sono state scelte deliberate informate dall'uso reale dell'app tra una serie e l'altra in palestra. Ogni volta che la notifica del timer non partiva o la progressione dei pesi calcolava male, la sistemavo sul momento perché mi serviva funzionante per la serie successiva.

L'app è costruita intorno al mio vero programma di allenamento multi-giorno. I programmi, gli esercizi, le durate di riposo, vengono dal mio allenamento reale. È per questo che le funzionalità sembrano coerenti. Non stavo indovinando cosa potesse volere un frequentatore di palestra. Ho semplicemente costruito ciò di cui avevo bisogno e poi l'ho rifinito abbastanza perché anche altri potessero usarlo.

Un amico ha aiutato a testare la sincronizzazione occasionalmente, collegandosi da un dispositivo diverso per verificare che scoperta e replicazione funzionassero attraverso le reti. Oltre a quello, è stato un progetto individuale dalla prima linea della PWA fino alla submission F-Droid in sospeso.

Prossimi Passi

  • Il rilascio su F-Droid è la priorità immediata, bloccato da modifiche alle librerie upstream
  • L'affidabilità della sincronizzazione ha ancora bisogno di essere rafforzata, casi limite su modifiche simultanee e interruzioni di rete
  • Ottimizzazioni delle performance, specialmente sui cali di frame delle animazioni su dispositivi più vecchi
  • Supporto iOS, l'app è costruita su Expo quindi dovrebbe funzionare, ma il servizio foreground è solo Android e richiede un approccio diverso

PearLift non è il tracker di allenamento più rifinito nello store. Ma è uno dei pochissimi che non invia i tuoi dati da nessuna parte, si sincronizza senza un server, e ti dà il pieno controllo sulla tua cronologia di allenamento. Per me, questo compromesso ne vale la pena.

Creato con ❤️ da Okazakee | Codice Sorgente
CMS|Informativa sulla Privacy