mirror of
https://github.com/immich-app/immich.git
synced 2026-05-21 15:16:31 -04:00
653c4db355
Adds a "Review remote deletions" mode for trash-sync: when the server marks a remote asset as deleted, the local copy is queued for user review before being moved to the device trash. The existing auto-sync mode (Android-only, requires MANAGE_MEDIA) keeps the silent-mirror behavior. iOS gets the review surface only — auto-sync is hidden because PhotoKit prompts on every batch, defeating the silent intent. State lives on a single trash_sync_entity table keyed by local_asset_id with three decisions (pendingReview / kept / appTrashed) and two trigger sources (remoteSync / localUser). Both review-mode decisions and auto-mode transitions are single-row column updates on the same table, so the cross-repo atomicity bug from the original draft cannot recur structurally. Other shape choices: - UI subscribes to watchPendingReviewCount() to surface a review-badge notification — no event-stream needed. - recheckRemoteTrashCandidates() closes the durability gap from acked assetDeleteV1 events arriving before the local was hashed. - Auto-restore is gated on TrashSyncMode.autoSync; review mode never fires OS-level trash or restore on its own. - Predicates query backup-album selection dynamically via existsQuery, so assets in multiple selected albums aren't dropped during dedup. - getAppTrashedRemotelyRestored joins trashed_local_asset_entity for album reconciliation (the asset leaves local_album_asset_entity after auto-trash but stays in the OS-trash mirror). - Bucket queries use SQL GROUP BY date instead of Dart-side reduce; shared predicate subquery between bucket and asset paths. Co-authored-by: Peter Ombodi <peter.ombodi@gmail.com>
Domain Layer
This directory contains the domain layer of Immich. The domain layer is responsible for the business logic of the app. It includes interfaces for repositories, models, services and utilities. This layer should never depend on anything from the presentation layer or from the infrastructure layer.
Structure
- Interfaces: These are the interfaces that define the contract for data operations.
- Models: These are the core data classes that represent the business models.
- Services: These are the classes that contain the business logic and interact with the repositories.
- Utils: These are utility classes and functions that provide common functionalities used across the domain layer.
domain/
├── interfaces/
│ └── user.interface.dart
├── models/
│ └── user.model.dart
├── services/
│ └── user.service.dart
└── utils/
└── date_utils.dart
Usage
The domain layer provides services that implement the business logic by consuming repositories through dependency injection. Services are exposed through Riverpod providers in the root providers directory.
// In presentation layer
final userService = ref.watch(userServiceProvider);
final user = await userService.getUser(userId);
The presentation layer should never directly use repositories, but instead interact with the domain layer through services.