5.3 KiB
App Boilerplate
A modular, offline-first Flutter boilerplate for apps that store, sync, and share media and metadata across centralized (Immich, Firebase) and decentralized (Nostr) systems.
Phase 3 - Nostr Integration
- Nostr protocol service for decentralized metadata synchronization
- Keypair generation and event publishing
- Multi-relay support for metadata syncing
- Comprehensive unit tests
Phase 2 - Immich Integration
- Immich API service for uploading and fetching images
- Automatic metadata storage in local database
- Offline-first behavior with local caching
- Comprehensive unit tests
Phase 1 - Local Storage & Caching
- Local storage service with SQLite database
- CRUD operations for items
- Image caching functionality
- Comprehensive unit tests
Quick Start
# Install dependencies
flutter pub get
# Run tests
flutter test
# Run app
flutter run
Local Storage & Caching
Service for local storage and caching operations. Provides CRUD operations for items stored in SQLite, image caching with automatic download/storage, and cache hit/miss handling. Modular design with no UI dependencies.
Files:
lib/data/local/local_storage_service.dart- Main service classlib/data/local/models/item.dart- Item data modeltest/data/local/local_storage_service_test.dart- Unit tests
Key Methods: initialize(), insertItem(), getItem(), getAllItems(), updateItem(), deleteItem(), getCachedImage(), clearImageCache(), close()
Immich Integration
Service for interacting with Immich API. Uploads images, fetches asset lists, and automatically stores metadata in local database. Offline-first design allows access to cached metadata without network.
Configuration: Edit lib/config/config_loader.dart to set immichBaseUrl and immichApiKey for dev/prod environments (lines 40-41 for dev, lines 47-48 for prod).
Files:
lib/data/immich/immich_service.dart- Main service classlib/data/immich/models/immich_asset.dart- Asset modellib/data/immich/models/upload_response.dart- Upload response modeltest/data/immich/immich_service_test.dart- Unit tests
Key Methods: uploadImage(), fetchAssets(), getCachedAsset(), getCachedAssets()
Nostr Integration
Service for decentralized metadata synchronization using Nostr protocol. Generates keypairs, publishes events, and syncs metadata across multiple relays. Modular design allows testing without real relay connections.
Files:
lib/data/nostr/nostr_service.dart- Main service classlib/data/nostr/models/nostr_keypair.dart- Keypair modellib/data/nostr/models/nostr_event.dart- Event modellib/data/nostr/models/nostr_relay.dart- Relay modeltest/data/nostr/nostr_service_test.dart- Unit tests
Key Methods: generateKeyPair(), addRelay(), connectRelay(), publishEvent(), syncMetadata(), dispose()
Configuration
All configuration is in: lib/config/config_loader.dart
Edit this file to change API URLs, Immich server URL and API key, logging settings, and other environment-specific values. Replace placeholder values ('your-dev-api-key-here', 'your-prod-api-key-here') with your actual API keys.
Nostr Relays: Configure relay URLs in lib/config/config_loader.dart in the nostrRelays list (lines 43-46 for dev, lines 52-54 for prod). Add or remove relay URLs as needed.
Environment Variables
Currently, the app uses compile-time environment variables via --dart-define:
# Set environment at runtime
flutter run --dart-define=ENV=prod
Future: .env file support can be added in later phases. When implemented, .env files would go in the project root and be loaded at runtime.
Available Environments
dev- Development (default): Logging enabled, dev API URLprod- Production: Logging disabled, production API URL
Running the App
Android Emulator
Important: Wait for emulator to fully boot (30-60 seconds on cold boot).
- Start emulator from Android Studio AVD Manager
- Wait for boot animation to complete and home screen appears
- Run:
flutter run
iOS Simulator (macOS)
open -a Simulator
flutter run
Running Tests
# Run all tests
flutter test
# Run with coverage
flutter test --coverage
Important: Tests must be run separately - flutter run does not execute tests.
Project Structure
lib/
├── config/
│ ├── app_config.dart
│ └── config_loader.dart
├── data/
│ ├── local/
│ │ ├── local_storage_service.dart
│ │ └── models/
│ │ └── item.dart
│ ├── immich/
│ │ ├── immich_service.dart
│ │ └── models/
│ │ ├── immich_asset.dart
│ │ └── upload_response.dart
│ └── nostr/
│ ├── nostr_service.dart
│ └── models/
│ ├── nostr_keypair.dart
│ ├── nostr_event.dart
│ └── nostr_relay.dart
└── main.dart
test/
├── config/
│ └── config_loader_test.dart
└── data/
├── local/
│ └── local_storage_service_test.dart
├── immich/
│ └── immich_service_test.dart
└── nostr/
└── nostr_service_test.dart