You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
354 lines
14 KiB
354 lines
14 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 8 - Navigation & UI Scaffold
|
|
|
|
- Complete navigation structure connecting all main modules
|
|
- Bottom navigation bar with 5 main screens: Home, Immich, Nostr Events, Session, Settings
|
|
- Route guards requiring authentication for protected screens
|
|
- Placeholder screens for all modules ready for custom UI implementation
|
|
- Modular navigation architecture with testable components
|
|
- Comprehensive UI tests for navigation and route guards
|
|
|
|
## Phase 7 - Firebase Layer
|
|
|
|
- Optional Firebase integration for cloud sync, storage, auth, push notifications, and analytics
|
|
- Modular design - can be enabled or disabled without affecting other modules
|
|
- Offline-first behavior maintained when Firebase is disabled
|
|
- Integration with session management and local storage
|
|
- Comprehensive unit tests
|
|
|
|
## Phase 6 - User Session Management
|
|
|
|
- User login, logout, and session switching
|
|
- Per-user data isolation with separate storage paths
|
|
- Cache clearing on logout
|
|
- Integration with local storage and sync engine
|
|
- Comprehensive unit tests
|
|
|
|
## Phase 5 - Relay Management UI
|
|
|
|
- User interface for managing Nostr relays
|
|
- View, add, remove, and monitor relay health
|
|
- Manual sync trigger integration
|
|
- Modular controller-based architecture
|
|
- Comprehensive UI tests
|
|
|
|
## Phase 4 - Sync Engine
|
|
|
|
- Coordinates data synchronization between local storage, Immich, and Nostr
|
|
- Conflict resolution strategies (useLocal, useRemote, useLatest, merge)
|
|
- Offline queue with automatic retry
|
|
- Priority-based operation processing
|
|
- Comprehensive unit and integration tests
|
|
|
|
## 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()`
|
|
|
|
## Sync Engine
|
|
|
|
Engine for coordinating data synchronization between local storage, Immich, and Nostr. Handles conflict resolution, offline queuing, and automatic retries. Processes operations by priority with configurable conflict resolution strategies.
|
|
|
|
**Files:**
|
|
- `lib/data/sync/sync_engine.dart` - Main sync engine class
|
|
- `lib/data/sync/models/sync_status.dart` - Status and priority enums
|
|
- `lib/data/sync/models/sync_operation.dart` - Operation model
|
|
- `test/data/sync/sync_engine_test.dart` - Unit and integration tests
|
|
|
|
**Key Methods:** `syncToImmich()`, `syncFromImmich()`, `syncToNostr()`, `syncAll()`, `queueOperation()`, `resolveConflict()`, `getPendingOperations()`
|
|
|
|
**Conflict Resolution:** `useLocal`, `useRemote`, `useLatest`, `merge` - set via `setConflictResolution()`
|
|
|
|
## Relay Management UI
|
|
|
|
User interface for managing Nostr relays. View configured relays, add/remove relays, monitor connection health, and trigger manual syncs. Modular design with controller-based state management for testability.
|
|
|
|
**Files:**
|
|
- `lib/ui/relay_management/relay_management_screen.dart` - Main UI screen
|
|
- `lib/ui/relay_management/relay_management_controller.dart` - State management controller
|
|
- `test/ui/relay_management/relay_management_screen_test.dart` - UI tests
|
|
- `test/ui/relay_management/relay_management_controller_test.dart` - Controller tests
|
|
|
|
**Key Features:** Add/remove relays, connect/disconnect, health monitoring, manual sync trigger, error handling
|
|
|
|
**Usage:** Navigate to "Manage Relays" from the main screen after initialization.
|
|
|
|
## User Session Management
|
|
|
|
Service for managing user sessions, login, logout, and session isolation. Provides per-user data isolation with separate storage paths and cache directories. Clears cached data on logout and integrates with local storage and sync engine.
|
|
|
|
**Files:**
|
|
- `lib/data/session/session_service.dart` - Main session management service
|
|
- `lib/data/session/models/user.dart` - User model
|
|
- `test/data/session/session_service_test.dart` - Unit tests
|
|
|
|
**Key Methods:** `login()`, `logout()`, `switchSession()`, `getCurrentUserDbPath()`, `getCurrentUserCacheDir()`
|
|
|
|
**Features:** Per-user storage isolation, cache clearing on logout, session switching with data preservation, integration with local storage
|
|
|
|
**Usage:** Initialize `SessionService` with `LocalStorageService` and optional `SyncEngine`. Call `login()` to start a session, `logout()` to end it, and `switchSession()` to change users.
|
|
|
|
## Firebase Layer
|
|
|
|
Optional Firebase integration providing cloud sync, storage, authentication, push notifications, and analytics. Fully modular - can be enabled or disabled without affecting offline-first functionality. Integrates with local storage and session management to maintain offline-first behavior.
|
|
|
|
**Files:**
|
|
- `lib/data/firebase/firebase_service.dart` - Main Firebase service
|
|
- `lib/data/firebase/models/firebase_config.dart` - Firebase configuration model
|
|
- `test/data/firebase/firebase_service_test.dart` - Unit tests
|
|
|
|
**Key Methods:** `initialize()`, `loginWithEmailPassword()`, `logout()`, `syncItemsToFirestore()`, `syncItemsFromFirestore()`, `uploadFile()`, `getFcmToken()`, `logEvent()`
|
|
|
|
**Features:** Firestore cloud sync, Firebase Storage for media, Firebase Auth for authentication, Firebase Cloud Messaging for push notifications, Firebase Analytics for analytics, all optional and modular
|
|
|
|
**Usage:** Create `FirebaseService` with `FirebaseConfig` (disabled by default). Pass to `SessionService` for automatic sync on login/logout. Initialize Firebase with `initialize()` before use. All services gracefully handle being disabled.
|
|
|
|
**Note:** Firebase requires actual Firebase project setup with `google-services.json` (Android) and `GoogleService-Info.plist` (iOS) configuration files. The service handles missing configuration gracefully and maintains offline-first behavior.
|
|
|
|
## Navigation & UI Scaffold
|
|
|
|
Complete navigation structure connecting all main modules with bottom navigation bar. Includes route guards for protected screens and placeholder screens ready for custom UI implementation.
|
|
|
|
**Files:**
|
|
- `lib/ui/navigation/main_navigation_scaffold.dart` - Main navigation scaffold with bottom nav
|
|
- `lib/ui/navigation/app_router.dart` - Router with route guards and route generation
|
|
- `lib/ui/home/home_screen.dart` - Home screen (local storage items)
|
|
- `lib/ui/immich/immich_screen.dart` - Immich media screen (placeholder)
|
|
- `lib/ui/nostr_events/nostr_events_screen.dart` - Nostr events screen (placeholder)
|
|
- `lib/ui/session/session_screen.dart` - Session management (login/logout)
|
|
- `lib/ui/settings/settings_screen.dart` - Settings screen
|
|
- `test/ui/navigation/main_navigation_scaffold_test.dart` - Navigation tests
|
|
|
|
**Navigation Structure:**
|
|
- **Home** - Local storage and cached content (no auth required)
|
|
- **Immich** - Immich media integration (requires login)
|
|
- **Nostr Events** - Nostr events display (requires login)
|
|
- **Session** - User login/logout (no auth required)
|
|
- **Settings** - App settings and Relay Management access (no auth required)
|
|
|
|
**Route Guards:** Immich and Nostr Events screens require authentication. Unauthenticated users see a login prompt with option to navigate to Session screen.
|
|
|
|
**Usage:** The app automatically uses `MainNavigationScaffold` after initialization. All services are passed to the scaffold for dependency injection. Customize placeholder screens by editing the respective screen files in `lib/ui/`.
|
|
|
|
**Running UI Tests:**
|
|
```bash
|
|
flutter test test/ui/navigation/main_navigation_scaffold_test.dart
|
|
```
|
|
|
|
## Configuration
|
|
|
|
**Configuration uses `.env` files for sensitive values (API keys, URLs) with fallback defaults in `lib/config/config_loader.dart`.**
|
|
|
|
### Setup .env File
|
|
|
|
1. Copy `.env.example` to `.env` in the project root:
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
2. Edit `.env` and fill in your actual values:
|
|
- `IMMICH_BASE_URL` - Your Immich server URL
|
|
- `IMMICH_API_KEY_DEV` - Your development Immich API key
|
|
- `IMMICH_API_KEY_PROD` - Your production Immich API key
|
|
- `NOSTR_RELAYS_DEV` - Comma-separated Nostr relay URLs for dev
|
|
- `NOSTR_RELAYS_PROD` - Comma-separated Nostr relay URLs for prod
|
|
- Other configuration values as needed
|
|
|
|
**Important:** The `.env` file is in `.gitignore` and should never be committed to version control. Only commit `.env.example` as a template.
|
|
|
|
### Environment Variables
|
|
|
|
The app uses:
|
|
- **`.env` file** (recommended) - Loaded at runtime, falls back to defaults if not found
|
|
- **`--dart-define`** - For environment selection:
|
|
|
|
```bash
|
|
# Set environment at runtime
|
|
flutter run --dart-define=ENV=prod
|
|
```
|
|
|
|
If `.env` file is not found or variables are missing, the app uses default values from `lib/config/config_loader.dart`.
|
|
|
|
### 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
|
|
│ ├── session/
|
|
│ │ ├── session_service.dart
|
|
│ │ └── models/
|
|
│ │ └── user.dart
|
|
│ ├── firebase/
|
|
│ │ ├── firebase_service.dart
|
|
│ │ └── models/
|
|
│ │ └── firebase_config.dart
|
|
│ └── sync/
|
|
│ ├── sync_engine.dart
|
|
│ └── models/
|
|
│ ├── sync_status.dart
|
|
│ └── sync_operation.dart
|
|
├── ui/
|
|
│ ├── navigation/
|
|
│ │ ├── main_navigation_scaffold.dart
|
|
│ │ └── app_router.dart
|
|
│ ├── home/
|
|
│ │ └── home_screen.dart
|
|
│ ├── immich/
|
|
│ │ └── immich_screen.dart
|
|
│ ├── nostr_events/
|
|
│ │ └── nostr_events_screen.dart
|
|
│ ├── session/
|
|
│ │ └── session_screen.dart
|
|
│ ├── settings/
|
|
│ │ └── settings_screen.dart
|
|
│ └── relay_management/
|
|
│ ├── relay_management_screen.dart
|
|
│ └── relay_management_controller.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
|
|
├── session/
|
|
│ └── session_service_test.dart
|
|
├── firebase/
|
|
│ └── firebase_service_test.dart
|
|
├── sync/
|
|
│ └── sync_engine_test.dart
|
|
└── ui/
|
|
├── navigation/
|
|
│ └── main_navigation_scaffold_test.dart
|
|
└── relay_management/
|
|
├── relay_management_screen_test.dart
|
|
└── relay_management_controller_test.dart
|
|
```
|