An offline-first mobile application for tracking long-term meditation practices, built with React Native, TypeScript, Expo, SQLite, and Supabase.
I designed and developed 108 Again end-to-end, including its application architecture, mobile UI, local persistence, optional cloud synchronization, statistics, calendar-based tracking, backup and restore, account management, and production release.
React Native · TypeScript · Expo · Expo Router · SQLite · Supabase
The application is designed around a local-first architecture: users can continue recording and reviewing their practice data without a network connection, while authenticated users can optionally synchronize their data across devices.
Dashboard, practice tracking, and historical statistics
Calendar tracking, practice management, and application settings
- Offline-first data model backed by SQLite
- Optional Supabase authentication and cloud synchronization
- Repository-based persistence layer separating application logic from storage
- Write queue for reliable synchronization
- Mutex-protected database writes
- Soft-delete synchronization
- Responsive React Native UI for phones and tablets
- Practice-history analytics and chart visualization
- Calendar-based session tracking and editing
- JSON backup, import, validation, and versioning
- Account and data-management functionality
- Automated application and synchronization tests
- Continuous integration through GitHub Actions
Users can:
- Track multiple meditation practices
- Add, edit, remove, and restore practices
- Record repetitions using default or custom session amounts
- Reorder practices
- Track cumulative progress toward long-term targets
- Set daily targets
- Estimate completion dates
- Navigate between individual practice views
108 Again provides:
- Overall progress visualization
- Daily goal tracking
- Target-date calculation
- Practice streak tracking
- Practice history
- Historical statistics
- Session-size analytics
- Calendar-based activity visualization
- Celebration feedback when targets are reached
Practice sessions can be reviewed through an interactive calendar that supports:
- Monthly navigation
- Daily repetition totals
- Session review and editing
- Current-date navigation
- Target-date visualization
Users can inspect their practice history over different periods and review statistics such as:
- Average session size
- Largest session
- Current streak
- Longest streak
- Daily activity over time
Practice data can be exported and restored using JSON backups.
The backup system includes:
- Export
- Import
- Validation
- Backup-version handling
- Error handling
Cloud functionality is optional.
Authenticated users can synchronize practice data with Supabase while the application continues to use SQLite as its local data store.
Account-related functionality includes:
- Authentication
- Synchronization
- Account information
- Logout
- Privacy and data controls
- Account deletion
The application also includes:
- Responsive layouts for phones and tablets
- Touch-friendly controls
- Light/dark theme support
- Language preferences
- Modal-based secondary workflows
- Practice imagery
- Header and gesture-based navigation
108 Again separates UI, application behavior, persistence, and synchronization responsibilities.
flowchart LR
UI[React Native UI]
APP[Application Services]
REPO[Repository Layer]
SQLITE[(SQLite)]
SYNC[Sync / Write Queue]
SUPABASE[(Supabase)]
UI --> APP
APP --> REPO
REPO --> SQLITE
REPO --> SYNC
SYNC --> SUPABASE
SQLite is the primary local persistence mechanism.
Core functionality remains available locally rather than requiring every user action to depend on a remote API.
Cloud synchronization is an additional capability rather than a prerequisite for using the application.
Persistence responsibilities are separated into repositories for different parts of the application's data model, including:
- Practices
- Sessions
- User profile
- Deleted records
- Application metadata
- Dashboard queries
This keeps database operations separated from presentation components and higher-level application behavior.
The SQLite database includes data for:
practicessessionsdeleted_recordsprofileapp_meta
Supabase stores synchronized user data including:
- Practices
- Sessions
- User profiles
Synchronization was designed around the application's offline-first requirements.
The implementation includes:
- A write queue
- Mutex-protected writes
- Soft-delete synchronization
- Remote synchronization through Supabase
- Cleanup of synchronized deleted records
This allows local changes to be recorded independently of immediate network availability and synchronized when cloud functionality is available.
The repository contains separate automated tests for application behavior and synchronization behavior.
Run application tests:
npm run test:appRun synchronization integration tests:
npm run test:syncRun the complete test suite:
npm run test:ciLint the project:
npm run lintThe repository also includes a GitHub Actions workflow for automated synchronization testing.
The codebase is organized around distinct application responsibilities:
108-Again/
├── app/ # Expo Router screens and routes
├── components/ # Reusable React Native UI components
├── constants/ # Application constants
├── database/ # SQLite database infrastructure
├── hooks/ # React hooks
├── i18n/ # Internationalization
├── lib/ # Shared infrastructure
├── models/ # Application models
├── repositories/ # Persistence abstraction
├── services/ # Application and synchronization services
├── styles/ # Shared styling
├── supabase/ # Supabase-related functionality
├── tests/
│ ├── app/ # Application behavior tests
│ └── sync/ # Synchronization tests
├── types/ # TypeScript types
└── utils/ # Shared utilities
- Node.js
- npm
- Expo development environment
- Android Studio and/or Xcode when running native builds
npm installnpx expo startor:
npm startnpx expo run:androidnpx expo run:iosnpx expo start -c108 Again was created for practitioners performing Ngöndro and other repetition-based meditation practices, where progress can involve tens or hundreds of thousands of repetitions over extended periods.
The application is intended to make that long-term process easier to manage without making connectivity or cloud accounts mandatory.
This required solving product and engineering problems around:
- Fast session entry
- Long-lived local data
- Offline operation
- Progress calculations
- Historical tracking
- Data portability
- Optional cross-device synchronization
- Mobile usability
- Reliable state transitions between local and remote data
Gian Piero Bandieramonte
Senior Software Engineer





