# 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 ```bash # 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 class - `lib/data/local/models/item.dart` - Item data model - `test/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 class - `lib/data/immich/models/immich_asset.dart` - Asset model - `lib/data/immich/models/upload_response.dart` - Upload response model - `test/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 class - `lib/data/nostr/models/nostr_keypair.dart` - Keypair model - `lib/data/nostr/models/nostr_event.dart` - Event model - `lib/data/nostr/models/nostr_relay.dart` - Relay model - `test/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`: ```bash # 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 URL - `prod` - Production: Logging disabled, production API URL ## Running the App ### Android Emulator **Important:** Wait for emulator to fully boot (30-60 seconds on cold boot). 1. Start emulator from Android Studio AVD Manager 2. Wait for boot animation to complete and home screen appears 3. Run: `flutter run` ### iOS Simulator (macOS) ```bash open -a Simulator flutter run ``` ## Running Tests ```bash # 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 ```