diff --git a/mobile/drift_schemas/main/drift_schema_v1.json b/mobile/drift_schemas/main/drift_schema_v1.json
index 1508394b75..65986584d9 100644
--- a/mobile/drift_schemas/main/drift_schema_v1.json
+++ b/mobile/drift_schemas/main/drift_schema_v1.json
@@ -1 +1 @@
-{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"profile_image_path","getter_name":"profileImagePath","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"quota_size_in_bytes","getter_name":"quotaSizeInBytes","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"quota_usage_in_bytes","getter_name":"quotaUsageInBytes","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"blob","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"preferences","getter_name":"preferences","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userPreferenceConverter","dart_type_name":"UserPreferences"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id"]}},{"id":2,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"blob","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"blob","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":3,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter<AssetType>(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"local_id","getter_name":"localId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["local_id"]}},{"id":4,"references":[3],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"asset_count","getter_name":"assetCount","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"thumbnail_id","getter_name":"thumbnailId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (local_id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (local_id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter<BackupSelection>(BackupSelection.values)","dart_type_name":"BackupSelection"}},{"name":"is_all","getter_name":"isAll","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_all\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_all\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":5,"references":[3,4],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (local_id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (local_id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":6,"references":[3],"type":"index","data":{"on":3,"name":"local_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}}]}
\ No newline at end of file
+{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"profile_image_path","getter_name":"profileImagePath","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"quota_size_in_bytes","getter_name":"quotaSizeInBytes","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"quota_usage_in_bytes","getter_name":"quotaUsageInBytes","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"blob","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"preferences","getter_name":"preferences","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userPreferenceConverter","dart_type_name":"UserPreferences"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id"]}},{"id":2,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"blob","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"blob","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":3,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter<AssetType>(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"local_id","getter_name":"localId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["local_id"]}},{"id":4,"references":[3],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"thumbnail_id","getter_name":"thumbnailId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (local_id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (local_id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter<BackupSelection>(BackupSelection.values)","dart_type_name":"BackupSelection"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":5,"references":[3,4],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (local_id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (local_id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":6,"references":[3],"type":"index","data":{"on":3,"name":"local_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}}]}
\ No newline at end of file
diff --git a/mobile/lib/domain/interfaces/album_media.interface.dart b/mobile/lib/domain/interfaces/album_media.interface.dart
index 6257de9f17..feb3adeb25 100644
--- a/mobile/lib/domain/interfaces/album_media.interface.dart
+++ b/mobile/lib/domain/interfaces/album_media.interface.dart
@@ -1,4 +1,4 @@
-import 'package:immich_mobile/domain/models/asset/asset.model.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
 import 'package:immich_mobile/domain/models/local_album.model.dart';
 
 abstract interface class IAlbumMediaRepository {
diff --git a/mobile/lib/domain/interfaces/local_album.interface.dart b/mobile/lib/domain/interfaces/local_album.interface.dart
index 85fff14893..611527d08a 100644
--- a/mobile/lib/domain/interfaces/local_album.interface.dart
+++ b/mobile/lib/domain/interfaces/local_album.interface.dart
@@ -1,9 +1,9 @@
 import 'package:immich_mobile/domain/interfaces/db.interface.dart';
-import 'package:immich_mobile/domain/models/asset/asset.model.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
 import 'package:immich_mobile/domain/models/local_album.model.dart';
 
 abstract interface class ILocalAlbumRepository implements IDatabaseRepository {
-  Future<void> insert(LocalAlbum localAlbum, Iterable<LocalAsset> assets);
+  Future<void> insert(LocalAlbum album, Iterable<LocalAsset> assets);
 
   Future<void> addAssets(String albumId, Iterable<LocalAsset> assets);
 
@@ -11,7 +11,7 @@ abstract interface class ILocalAlbumRepository implements IDatabaseRepository {
 
   Future<List<LocalAsset>> getAssetsForAlbum(String albumId);
 
-  Future<void> update(LocalAlbum localAlbum);
+  Future<void> update(LocalAlbum album);
 
   Future<void> delete(String albumId);
 
diff --git a/mobile/lib/domain/interfaces/local_asset.interface.dart b/mobile/lib/domain/interfaces/local_asset.interface.dart
index 7cf05a55be..2f9fbd143f 100644
--- a/mobile/lib/domain/interfaces/local_asset.interface.dart
+++ b/mobile/lib/domain/interfaces/local_asset.interface.dart
@@ -1,5 +1,5 @@
 import 'package:immich_mobile/domain/interfaces/db.interface.dart';
-import 'package:immich_mobile/domain/models/asset/asset.model.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
 
 abstract interface class ILocalAssetRepository implements IDatabaseRepository {
   Future<LocalAsset> get(String assetId);
diff --git a/mobile/lib/domain/models/asset/asset.model.dart b/mobile/lib/domain/models/asset/asset.model.dart
index e6b11c3130..211d24985f 100644
--- a/mobile/lib/domain/models/asset/asset.model.dart
+++ b/mobile/lib/domain/models/asset/asset.model.dart
@@ -1,72 +1,46 @@
-part 'local_asset.model.dart';
-part 'merged_asset.model.dart';
-part 'remote_asset.model.dart';
+part of 'base_asset.model.dart';
 
-enum AssetType {
-  // do not change this order!
-  other,
-  image,
-  video,
-  audio,
-}
-
-sealed class Asset {
-  final String name;
-  final String? checksum;
-  final AssetType type;
-  final DateTime createdAt;
-  final DateTime updatedAt;
-  final int? width;
-  final int? height;
-  final int? durationInSeconds;
+class Asset extends BaseAsset {
+  final String id;
+  final String? localId;
 
   const Asset({
-    required this.name,
-    required this.checksum,
-    required this.type,
-    required this.createdAt,
-    required this.updatedAt,
-    this.width,
-    this.height,
-    this.durationInSeconds,
+    required this.id,
+    this.localId,
+    required super.name,
+    required super.checksum,
+    required super.type,
+    required super.createdAt,
+    required super.updatedAt,
+    super.width,
+    super.height,
+    super.durationInSeconds,
+    super.isFavorite = false,
   });
 
   @override
   String toString() {
     return '''Asset {
-  name: $name,
-  type: $type,
-  createdAt: $createdAt,
-  updatedAt: $updatedAt,
-  width: ${width ?? "<NA>"},
-  height: ${height ?? "<NA>"},
-  durationInSeconds: ${durationInSeconds ?? "<NA>"}
-}''';
+   id: $id,
+   name: $name,
+   type: $type,
+   createdAt: $createdAt,
+   updatedAt: $updatedAt,
+   width: ${width ?? "<NA>"},
+   height: ${height ?? "<NA>"},
+   durationInSeconds: ${durationInSeconds ?? "<NA>"},
+   localId: ${localId ?? "<NA>"},
+   isFavorite: $isFavorite,
+ }''';
   }
 
   @override
   bool operator ==(Object other) {
+    if (other is! Asset) return false;
     if (identical(this, other)) return true;
-    if (other is Asset) {
-      return name == other.name &&
-          type == other.type &&
-          createdAt == other.createdAt &&
-          updatedAt == other.updatedAt &&
-          width == other.width &&
-          height == other.height &&
-          durationInSeconds == other.durationInSeconds;
-    }
-    return false;
+    return super == other && id == other.id && localId == other.localId;
   }
 
   @override
-  int get hashCode {
-    return name.hashCode ^
-        type.hashCode ^
-        createdAt.hashCode ^
-        updatedAt.hashCode ^
-        width.hashCode ^
-        height.hashCode ^
-        durationInSeconds.hashCode;
-  }
+  int get hashCode => super.hashCode ^ id.hashCode ^ localId.hashCode;
 }
diff --git a/mobile/lib/domain/models/asset/base_asset.model.dart b/mobile/lib/domain/models/asset/base_asset.model.dart
new file mode 100644
index 0000000000..fb95437659
--- /dev/null
+++ b/mobile/lib/domain/models/asset/base_asset.model.dart
@@ -0,0 +1,76 @@
+part 'asset.model.dart';
+part 'local_asset.model.dart';
+
+enum AssetType {
+  // do not change this order!
+  other,
+  image,
+  video,
+  audio,
+}
+
+sealed class BaseAsset {
+  final String name;
+  final String? checksum;
+  final AssetType type;
+  final DateTime createdAt;
+  final DateTime updatedAt;
+  final int? width;
+  final int? height;
+  final int? durationInSeconds;
+  final bool isFavorite;
+
+  const BaseAsset({
+    required this.name,
+    required this.checksum,
+    required this.type,
+    required this.createdAt,
+    required this.updatedAt,
+    this.width,
+    this.height,
+    this.durationInSeconds,
+    this.isFavorite = false,
+  });
+
+  @override
+  String toString() {
+    return '''BaseAsset {
+  name: $name,
+  type: $type,
+  createdAt: $createdAt,
+  updatedAt: $updatedAt,
+  width: ${width ?? "<NA>"},
+  height: ${height ?? "<NA>"},
+  durationInSeconds: ${durationInSeconds ?? "<NA>"},
+  isFavorite: $isFavorite,
+}''';
+  }
+
+  @override
+  bool operator ==(Object other) {
+    if (identical(this, other)) return true;
+    if (other is BaseAsset) {
+      return name == other.name &&
+          type == other.type &&
+          createdAt == other.createdAt &&
+          updatedAt == other.updatedAt &&
+          width == other.width &&
+          height == other.height &&
+          durationInSeconds == other.durationInSeconds &&
+          isFavorite == other.isFavorite;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return name.hashCode ^
+        type.hashCode ^
+        createdAt.hashCode ^
+        updatedAt.hashCode ^
+        width.hashCode ^
+        height.hashCode ^
+        durationInSeconds.hashCode ^
+        isFavorite.hashCode;
+  }
+}
diff --git a/mobile/lib/domain/models/asset/local_asset.model.dart b/mobile/lib/domain/models/asset/local_asset.model.dart
index afab9832b5..25e617d8ed 100644
--- a/mobile/lib/domain/models/asset/local_asset.model.dart
+++ b/mobile/lib/domain/models/asset/local_asset.model.dart
@@ -1,10 +1,12 @@
-part of 'asset.model.dart';
+part of 'base_asset.model.dart';
 
-class LocalAsset extends Asset {
-  final String localId;
+class LocalAsset extends BaseAsset {
+  final String id;
+  final String? remoteId;
 
   const LocalAsset({
-    required this.localId,
+    required this.id,
+    this.remoteId,
     required super.name,
     super.checksum,
     required super.type,
@@ -13,19 +15,22 @@ class LocalAsset extends Asset {
     super.width,
     super.height,
     super.durationInSeconds,
+    super.isFavorite = false,
   });
 
   @override
   String toString() {
     return '''LocalAsset {
-   localId: $localId,
+   id: $id,
    name: $name,
    type: $type,
    createdAt: $createdAt,
    updatedAt: $updatedAt,
    width: ${width ?? "<NA>"},
    height: ${height ?? "<NA>"},
-   durationInSeconds: ${durationInSeconds ?? "<NA>"}
+   durationInSeconds: ${durationInSeconds ?? "<NA>"},
+   remoteId: ${remoteId ?? "<NA>"}
+   isFavorite: $isFavorite,
  }''';
   }
 
@@ -33,16 +38,15 @@ class LocalAsset extends Asset {
   bool operator ==(Object other) {
     if (other is! LocalAsset) return false;
     if (identical(this, other)) return true;
-    return super == other && localId == other.localId;
+    return super == other && id == other.id && remoteId == other.remoteId;
   }
 
   @override
-  int get hashCode {
-    return super.hashCode ^ localId.hashCode;
-  }
+  int get hashCode => super.hashCode ^ id.hashCode ^ remoteId.hashCode;
 
   LocalAsset copyWith({
-    String? localId,
+    String? id,
+    String? remoteId,
     String? name,
     String? checksum,
     AssetType? type,
@@ -51,9 +55,11 @@ class LocalAsset extends Asset {
     int? width,
     int? height,
     int? durationInSeconds,
+    bool? isFavorite,
   }) {
     return LocalAsset(
-      localId: localId ?? this.localId,
+      id: id ?? this.id,
+      remoteId: remoteId ?? this.remoteId,
       name: name ?? this.name,
       checksum: checksum ?? this.checksum,
       type: type ?? this.type,
@@ -62,6 +68,7 @@ class LocalAsset extends Asset {
       width: width ?? this.width,
       height: height ?? this.height,
       durationInSeconds: durationInSeconds ?? this.durationInSeconds,
+      isFavorite: isFavorite ?? this.isFavorite,
     );
   }
 }
diff --git a/mobile/lib/domain/models/asset/merged_asset.model.dart b/mobile/lib/domain/models/asset/merged_asset.model.dart
deleted file mode 100644
index 7b0b6e16c4..0000000000
--- a/mobile/lib/domain/models/asset/merged_asset.model.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-part of 'asset.model.dart';
-
-class MergedAsset extends Asset {
-  final String remoteId;
-  final String localId;
-
-  const MergedAsset({
-    required this.remoteId,
-    required this.localId,
-    required super.name,
-    required super.checksum,
-    required super.type,
-    required super.createdAt,
-    required super.updatedAt,
-    super.width,
-    super.height,
-    super.durationInSeconds,
-  });
-
-  @override
-  String toString() {
-    return '''MergedAsset {
-   remoteId: $remoteId,
-   localId: $localId,
-   name: $name,
-   type: $type,
-   createdAt: $createdAt,
-   updatedAt: $updatedAt,
-   width: ${width ?? "<NA>"},
-   height: ${height ?? "<NA>"},
-   durationInSeconds: ${durationInSeconds ?? "<NA>"}
- }''';
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (other is! MergedAsset) return false;
-    if (identical(this, other)) return true;
-    return super == other &&
-        remoteId == other.remoteId &&
-        localId == other.localId;
-  }
-
-  @override
-  int get hashCode {
-    return super.hashCode ^ remoteId.hashCode ^ localId.hashCode;
-  }
-}
diff --git a/mobile/lib/domain/models/asset/remote_asset.model.dart b/mobile/lib/domain/models/asset/remote_asset.model.dart
deleted file mode 100644
index ae04499574..0000000000
--- a/mobile/lib/domain/models/asset/remote_asset.model.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-part of 'asset.model.dart';
-
-class RemoteAsset extends Asset {
-  final String remoteId;
-
-  const RemoteAsset({
-    required this.remoteId,
-    required super.name,
-    required super.checksum,
-    required super.type,
-    required super.createdAt,
-    required super.updatedAt,
-    super.width,
-    super.height,
-    super.durationInSeconds,
-  });
-
-  @override
-  String toString() {
-    return '''RemoteAsset {
-   remoteId: $remoteId,
-   name: $name,
-   type: $type,
-   createdAt: $createdAt,
-   updatedAt: $updatedAt,
-   width: ${width ?? "<NA>"},
-   height: ${height ?? "<NA>"},
-   durationInSeconds: ${durationInSeconds ?? "<NA>"}
- }''';
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (other is! RemoteAsset) return false;
-    if (identical(this, other)) return true;
-    return super == other && remoteId == other.remoteId;
-  }
-
-  @override
-  int get hashCode {
-    return super.hashCode ^ remoteId.hashCode;
-  }
-}
diff --git a/mobile/lib/domain/models/local_album.model.dart b/mobile/lib/domain/models/local_album.model.dart
index de7c86a64f..ea3d9989f0 100644
--- a/mobile/lib/domain/models/local_album.model.dart
+++ b/mobile/lib/domain/models/local_album.model.dart
@@ -11,8 +11,6 @@ class LocalAlbum {
   final String name;
   final DateTime updatedAt;
 
-  /// Whether the album contains all photos (i.e, the virtual "Recent" album)
-  final bool isAll;
   final int assetCount;
   final String? thumbnailId;
   final BackupSelection backupSelection;
@@ -24,7 +22,6 @@ class LocalAlbum {
     this.assetCount = 0,
     this.thumbnailId,
     this.backupSelection = BackupSelection.none,
-    this.isAll = false,
   });
 
   LocalAlbum copyWith({
@@ -34,7 +31,6 @@ class LocalAlbum {
     int? assetCount,
     NullableValue<String>? thumbnailId,
     BackupSelection? backupSelection,
-    bool? isAll,
   }) {
     return LocalAlbum(
       id: id ?? this.id,
@@ -43,7 +39,6 @@ class LocalAlbum {
       assetCount: assetCount ?? this.assetCount,
       thumbnailId: thumbnailId?.getOrDefault(this.thumbnailId),
       backupSelection: backupSelection ?? this.backupSelection,
-      isAll: isAll ?? this.isAll,
     );
   }
 
@@ -56,7 +51,6 @@ class LocalAlbum {
         other.name == name &&
         other.updatedAt == updatedAt &&
         other.assetCount == assetCount &&
-        other.isAll == isAll &&
         other.thumbnailId == thumbnailId &&
         other.backupSelection == backupSelection;
   }
@@ -67,7 +61,6 @@ class LocalAlbum {
         name.hashCode ^
         updatedAt.hashCode ^
         assetCount.hashCode ^
-        isAll.hashCode ^
         thumbnailId.hashCode ^
         backupSelection.hashCode;
   }
@@ -81,7 +74,6 @@ updatedAt: $updatedAt,
 assetCount: $assetCount,
 thumbnailId: ${thumbnailId ?? '<NA>'},
 backupSelection: $backupSelection,
-isAll: $isAll
 }''';
   }
 }
diff --git a/mobile/lib/domain/services/device_sync.service.dart b/mobile/lib/domain/services/device_sync.service.dart
index 09f71fe76e..4a7b1c7c07 100644
--- a/mobile/lib/domain/services/device_sync.service.dart
+++ b/mobile/lib/domain/services/device_sync.service.dart
@@ -5,7 +5,7 @@ import 'package:flutter/widgets.dart';
 import 'package:immich_mobile/domain/interfaces/album_media.interface.dart';
 import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
 import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
-import 'package:immich_mobile/domain/models/asset/asset.model.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
 import 'package:immich_mobile/domain/models/local_album.model.dart';
 import 'package:immich_mobile/utils/diff.dart';
 import 'package:immich_mobile/utils/nullable_value.dart';
@@ -34,6 +34,7 @@ class DeviceSyncService {
       // and not the albums.
       final deviceAlbums =
           (await _albumMediaRepository.getAll()).sortedBy((a) => a.id);
+
       final dbAlbums =
           await _localAlbumRepository.getAll(sortBy: SortLocalAlbumsBy.id);
 
@@ -64,7 +65,7 @@ class DeviceSyncService {
 
       final album = deviceAlbum.copyWith(
         // The below assumes the list is already sorted by createdDate from the filter
-        thumbnailId: NullableValue.valueOrEmpty(assets.firstOrNull?.localId),
+        thumbnailId: NullableValue.valueOrEmpty(assets.firstOrNull?.id),
       );
 
       await _localAlbumRepository.insert(album, assets);
@@ -100,7 +101,7 @@ class DeviceSyncService {
         return false;
       }
 
-      _log.fine("Device album ${dbAlbum.name} has changed. Syncing...");
+      _log.info("Device album ${dbAlbum.name} has changed. Syncing...");
 
       // Faster path - only new assets added
       if (await checkAddition(dbAlbum, deviceAlbum)) {
@@ -157,13 +158,13 @@ class DeviceSyncService {
       String? thumbnailId = dbAlbum.thumbnailId;
       if (thumbnailId == null || newAssets.isNotEmpty) {
         if (thumbnailId == null) {
-          thumbnailId = newAssets.firstOrNull?.localId;
+          thumbnailId = newAssets.firstOrNull?.id;
         } else if (newAssets.isNotEmpty) {
           // The below assumes the list is already sorted by createdDate from the filter
           final oldThumbAsset = await _localAssetRepository.get(thumbnailId);
           if (oldThumbAsset.createdAt
               .isBefore(newAssets.firstOrNull!.createdAt)) {
-            thumbnailId = newAssets.firstOrNull?.localId;
+            thumbnailId = newAssets.firstOrNull?.id;
           }
         }
       }
@@ -205,14 +206,14 @@ class DeviceSyncService {
             thumbnailId: const NullableValue.empty(),
             backupSelection: dbAlbum.backupSelection,
           ),
-          assetIdsToDelete: assetsInDb.map((a) => a.localId),
+          assetIdsToDelete: assetsInDb.map((a) => a.id),
         );
         return true;
       }
 
       // The below assumes the list is already sorted by createdDate from the filter
       String? thumbnailId = assetsInDevice.isNotEmpty
-          ? assetsInDevice.firstOrNull?.localId
+          ? assetsInDevice.firstOrNull?.id
           : dbAlbum.thumbnailId;
 
       final updatedDeviceAlbum = deviceAlbum.copyWith(
@@ -228,8 +229,8 @@ class DeviceSyncService {
         return true;
       }
 
-      assert(assetsInDb.isSortedBy((a) => a.localId));
-      assetsInDevice.sort((a, b) => a.localId.compareTo(b.localId));
+      assert(assetsInDb.isSortedBy((a) => a.id));
+      assetsInDevice.sort((a, b) => a.id.compareTo(b.id));
 
       final assetsToUpsert = <LocalAsset>[];
       final assetsToDelete = <String>[];
@@ -237,7 +238,7 @@ class DeviceSyncService {
       diffSortedListsSync(
         assetsInDb,
         assetsInDevice,
-        compare: (a, b) => a.localId.compareTo(b.localId),
+        compare: (a, b) => a.id.compareTo(b.id),
         both: (dbAsset, deviceAsset) {
           // Custom comparison to check if the asset has been modified without
           // comparing the checksum
@@ -247,7 +248,7 @@ class DeviceSyncService {
           }
           return false;
         },
-        onlyFirst: (dbAsset) => assetsToDelete.add(dbAsset.localId),
+        onlyFirst: (dbAsset) => assetsToDelete.add(dbAsset.id),
         onlySecond: (deviceAsset) => assetsToUpsert.add(deviceAsset),
       );
 
diff --git a/mobile/lib/infrastructure/entities/local_album.entity.dart b/mobile/lib/infrastructure/entities/local_album.entity.dart
index 5d5f766fd4..4eff2a1154 100644
--- a/mobile/lib/infrastructure/entities/local_album.entity.dart
+++ b/mobile/lib/infrastructure/entities/local_album.entity.dart
@@ -10,12 +10,10 @@ class LocalAlbumEntity extends Table with DriftDefaultsMixin {
   TextColumn get id => text()();
   TextColumn get name => text()();
   DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
-  IntColumn get assetCount => integer().withDefault(const Constant(0))();
   TextColumn get thumbnailId => text()
       .nullable()
       .references(LocalAssetEntity, #localId, onDelete: KeyAction.setNull)();
   IntColumn get backupSelection => intEnum<BackupSelection>()();
-  BoolColumn get isAll => boolean().withDefault(const Constant(false))();
 
   @override
   Set<Column> get primaryKey => {id};
@@ -30,7 +28,6 @@ extension LocalAlbumEntityX on LocalAlbumEntityData {
       assetCount: assetCount,
       thumbnailId: thumbnailId,
       backupSelection: backupSelection,
-      isAll: isAll,
     );
   }
 }
diff --git a/mobile/lib/infrastructure/entities/local_album.entity.drift.dart b/mobile/lib/infrastructure/entities/local_album.entity.drift.dart
index 19ada47e87..ee6c5b8c61 100644
--- a/mobile/lib/infrastructure/entities/local_album.entity.drift.dart
+++ b/mobile/lib/infrastructure/entities/local_album.entity.drift.dart
@@ -16,20 +16,16 @@ typedef $$LocalAlbumEntityTableCreateCompanionBuilder
   required String id,
   required String name,
   i0.Value<DateTime> updatedAt,
-  i0.Value<int> assetCount,
   i0.Value<String?> thumbnailId,
   required i2.BackupSelection backupSelection,
-  i0.Value<bool> isAll,
 });
 typedef $$LocalAlbumEntityTableUpdateCompanionBuilder
     = i1.LocalAlbumEntityCompanion Function({
   i0.Value<String> id,
   i0.Value<String> name,
   i0.Value<DateTime> updatedAt,
-  i0.Value<int> assetCount,
   i0.Value<String?> thumbnailId,
   i0.Value<i2.BackupSelection> backupSelection,
-  i0.Value<bool> isAll,
 });
 
 final class $$LocalAlbumEntityTableReferences extends i0.BaseReferences<
@@ -82,17 +78,11 @@ class $$LocalAlbumEntityTableFilterComposer
   i0.ColumnFilters<DateTime> get updatedAt => $composableBuilder(
       column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column));
 
-  i0.ColumnFilters<int> get assetCount => $composableBuilder(
-      column: $table.assetCount, builder: (column) => i0.ColumnFilters(column));
-
   i0.ColumnWithTypeConverterFilters<i2.BackupSelection, i2.BackupSelection, int>
       get backupSelection => $composableBuilder(
           column: $table.backupSelection,
           builder: (column) => i0.ColumnWithTypeConverterFilters(column));
 
-  i0.ColumnFilters<bool> get isAll => $composableBuilder(
-      column: $table.isAll, builder: (column) => i0.ColumnFilters(column));
-
   i5.$$LocalAssetEntityTableFilterComposer get thumbnailId {
     final i5.$$LocalAssetEntityTableFilterComposer composer = $composerBuilder(
         composer: this,
@@ -135,17 +125,10 @@ class $$LocalAlbumEntityTableOrderingComposer
       column: $table.updatedAt,
       builder: (column) => i0.ColumnOrderings(column));
 
-  i0.ColumnOrderings<int> get assetCount => $composableBuilder(
-      column: $table.assetCount,
-      builder: (column) => i0.ColumnOrderings(column));
-
   i0.ColumnOrderings<int> get backupSelection => $composableBuilder(
       column: $table.backupSelection,
       builder: (column) => i0.ColumnOrderings(column));
 
-  i0.ColumnOrderings<bool> get isAll => $composableBuilder(
-      column: $table.isAll, builder: (column) => i0.ColumnOrderings(column));
-
   i5.$$LocalAssetEntityTableOrderingComposer get thumbnailId {
     final i5.$$LocalAssetEntityTableOrderingComposer composer =
         $composerBuilder(
@@ -189,16 +172,10 @@ class $$LocalAlbumEntityTableAnnotationComposer
   i0.GeneratedColumn<DateTime> get updatedAt =>
       $composableBuilder(column: $table.updatedAt, builder: (column) => column);
 
-  i0.GeneratedColumn<int> get assetCount => $composableBuilder(
-      column: $table.assetCount, builder: (column) => column);
-
   i0.GeneratedColumnWithTypeConverter<i2.BackupSelection, int>
       get backupSelection => $composableBuilder(
           column: $table.backupSelection, builder: (column) => column);
 
-  i0.GeneratedColumn<bool> get isAll =>
-      $composableBuilder(column: $table.isAll, builder: (column) => column);
-
   i5.$$LocalAssetEntityTableAnnotationComposer get thumbnailId {
     final i5.$$LocalAssetEntityTableAnnotationComposer composer =
         $composerBuilder(
@@ -252,38 +229,30 @@ class $$LocalAlbumEntityTableTableManager extends i0.RootTableManager<
             i0.Value<String> id = const i0.Value.absent(),
             i0.Value<String> name = const i0.Value.absent(),
             i0.Value<DateTime> updatedAt = const i0.Value.absent(),
-            i0.Value<int> assetCount = const i0.Value.absent(),
             i0.Value<String?> thumbnailId = const i0.Value.absent(),
             i0.Value<i2.BackupSelection> backupSelection =
                 const i0.Value.absent(),
-            i0.Value<bool> isAll = const i0.Value.absent(),
           }) =>
               i1.LocalAlbumEntityCompanion(
             id: id,
             name: name,
             updatedAt: updatedAt,
-            assetCount: assetCount,
             thumbnailId: thumbnailId,
             backupSelection: backupSelection,
-            isAll: isAll,
           ),
           createCompanionCallback: ({
             required String id,
             required String name,
             i0.Value<DateTime> updatedAt = const i0.Value.absent(),
-            i0.Value<int> assetCount = const i0.Value.absent(),
             i0.Value<String?> thumbnailId = const i0.Value.absent(),
             required i2.BackupSelection backupSelection,
-            i0.Value<bool> isAll = const i0.Value.absent(),
           }) =>
               i1.LocalAlbumEntityCompanion.insert(
             id: id,
             name: name,
             updatedAt: updatedAt,
-            assetCount: assetCount,
             thumbnailId: thumbnailId,
             backupSelection: backupSelection,
-            isAll: isAll,
           ),
           withReferenceMapper: (p0) => p0
               .map((e) => (
@@ -368,14 +337,6 @@ class $LocalAlbumEntityTable extends i3.LocalAlbumEntity
           type: i0.DriftSqlType.dateTime,
           requiredDuringInsert: false,
           defaultValue: i4.currentDateAndTime);
-  static const i0.VerificationMeta _assetCountMeta =
-      const i0.VerificationMeta('assetCount');
-  @override
-  late final i0.GeneratedColumn<int> assetCount = i0.GeneratedColumn<int>(
-      'asset_count', aliasedName, false,
-      type: i0.DriftSqlType.int,
-      requiredDuringInsert: false,
-      defaultValue: const i4.Constant(0));
   static const i0.VerificationMeta _thumbnailIdMeta =
       const i0.VerificationMeta('thumbnailId');
   @override
@@ -392,19 +353,9 @@ class $LocalAlbumEntityTable extends i3.LocalAlbumEntity
               type: i0.DriftSqlType.int, requiredDuringInsert: true)
           .withConverter<i2.BackupSelection>(
               i1.$LocalAlbumEntityTable.$converterbackupSelection);
-  static const i0.VerificationMeta _isAllMeta =
-      const i0.VerificationMeta('isAll');
-  @override
-  late final i0.GeneratedColumn<bool> isAll = i0.GeneratedColumn<bool>(
-      'is_all', aliasedName, false,
-      type: i0.DriftSqlType.bool,
-      requiredDuringInsert: false,
-      defaultConstraints:
-          i0.GeneratedColumn.constraintIsAlways('CHECK ("is_all" IN (0, 1))'),
-      defaultValue: const i4.Constant(false));
   @override
   List<i0.GeneratedColumn> get $columns =>
-      [id, name, updatedAt, assetCount, thumbnailId, backupSelection, isAll];
+      [id, name, updatedAt, thumbnailId, backupSelection];
   @override
   String get aliasedName => _alias ?? actualTableName;
   @override
@@ -431,22 +382,12 @@ class $LocalAlbumEntityTable extends i3.LocalAlbumEntity
       context.handle(_updatedAtMeta,
           updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta));
     }
-    if (data.containsKey('asset_count')) {
-      context.handle(
-          _assetCountMeta,
-          assetCount.isAcceptableOrUnknown(
-              data['asset_count']!, _assetCountMeta));
-    }
     if (data.containsKey('thumbnail_id')) {
       context.handle(
           _thumbnailIdMeta,
           thumbnailId.isAcceptableOrUnknown(
               data['thumbnail_id']!, _thumbnailIdMeta));
     }
-    if (data.containsKey('is_all')) {
-      context.handle(
-          _isAllMeta, isAll.isAcceptableOrUnknown(data['is_all']!, _isAllMeta));
-    }
     return context;
   }
 
@@ -463,15 +404,11 @@ class $LocalAlbumEntityTable extends i3.LocalAlbumEntity
           .read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!,
       updatedAt: attachedDatabase.typeMapping.read(
           i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!,
-      assetCount: attachedDatabase.typeMapping
-          .read(i0.DriftSqlType.int, data['${effectivePrefix}asset_count'])!,
       thumbnailId: attachedDatabase.typeMapping
           .read(i0.DriftSqlType.string, data['${effectivePrefix}thumbnail_id']),
       backupSelection: i1.$LocalAlbumEntityTable.$converterbackupSelection
           .fromSql(attachedDatabase.typeMapping.read(i0.DriftSqlType.int,
               data['${effectivePrefix}backup_selection'])!),
-      isAll: attachedDatabase.typeMapping
-          .read(i0.DriftSqlType.bool, data['${effectivePrefix}is_all'])!,
     );
   }
 
@@ -495,25 +432,20 @@ class LocalAlbumEntityData extends i0.DataClass
   final String id;
   final String name;
   final DateTime updatedAt;
-  final int assetCount;
   final String? thumbnailId;
   final i2.BackupSelection backupSelection;
-  final bool isAll;
   const LocalAlbumEntityData(
       {required this.id,
       required this.name,
       required this.updatedAt,
-      required this.assetCount,
       this.thumbnailId,
-      required this.backupSelection,
-      required this.isAll});
+      required this.backupSelection});
   @override
   Map<String, i0.Expression> toColumns(bool nullToAbsent) {
     final map = <String, i0.Expression>{};
     map['id'] = i0.Variable<String>(id);
     map['name'] = i0.Variable<String>(name);
     map['updated_at'] = i0.Variable<DateTime>(updatedAt);
-    map['asset_count'] = i0.Variable<int>(assetCount);
     if (!nullToAbsent || thumbnailId != null) {
       map['thumbnail_id'] = i0.Variable<String>(thumbnailId);
     }
@@ -522,7 +454,6 @@ class LocalAlbumEntityData extends i0.DataClass
           .$LocalAlbumEntityTable.$converterbackupSelection
           .toSql(backupSelection));
     }
-    map['is_all'] = i0.Variable<bool>(isAll);
     return map;
   }
 
@@ -533,11 +464,9 @@ class LocalAlbumEntityData extends i0.DataClass
       id: serializer.fromJson<String>(json['id']),
       name: serializer.fromJson<String>(json['name']),
       updatedAt: serializer.fromJson<DateTime>(json['updatedAt']),
-      assetCount: serializer.fromJson<int>(json['assetCount']),
       thumbnailId: serializer.fromJson<String?>(json['thumbnailId']),
       backupSelection: i1.$LocalAlbumEntityTable.$converterbackupSelection
           .fromJson(serializer.fromJson<int>(json['backupSelection'])),
-      isAll: serializer.fromJson<bool>(json['isAll']),
     );
   }
   @override
@@ -547,12 +476,10 @@ class LocalAlbumEntityData extends i0.DataClass
       'id': serializer.toJson<String>(id),
       'name': serializer.toJson<String>(name),
       'updatedAt': serializer.toJson<DateTime>(updatedAt),
-      'assetCount': serializer.toJson<int>(assetCount),
       'thumbnailId': serializer.toJson<String?>(thumbnailId),
       'backupSelection': serializer.toJson<int>(i1
           .$LocalAlbumEntityTable.$converterbackupSelection
           .toJson(backupSelection)),
-      'isAll': serializer.toJson<bool>(isAll),
     };
   }
 
@@ -560,32 +487,25 @@ class LocalAlbumEntityData extends i0.DataClass
           {String? id,
           String? name,
           DateTime? updatedAt,
-          int? assetCount,
           i0.Value<String?> thumbnailId = const i0.Value.absent(),
-          i2.BackupSelection? backupSelection,
-          bool? isAll}) =>
+          i2.BackupSelection? backupSelection}) =>
       i1.LocalAlbumEntityData(
         id: id ?? this.id,
         name: name ?? this.name,
         updatedAt: updatedAt ?? this.updatedAt,
-        assetCount: assetCount ?? this.assetCount,
         thumbnailId: thumbnailId.present ? thumbnailId.value : this.thumbnailId,
         backupSelection: backupSelection ?? this.backupSelection,
-        isAll: isAll ?? this.isAll,
       );
   LocalAlbumEntityData copyWithCompanion(i1.LocalAlbumEntityCompanion data) {
     return LocalAlbumEntityData(
       id: data.id.present ? data.id.value : this.id,
       name: data.name.present ? data.name.value : this.name,
       updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt,
-      assetCount:
-          data.assetCount.present ? data.assetCount.value : this.assetCount,
       thumbnailId:
           data.thumbnailId.present ? data.thumbnailId.value : this.thumbnailId,
       backupSelection: data.backupSelection.present
           ? data.backupSelection.value
           : this.backupSelection,
-      isAll: data.isAll.present ? data.isAll.value : this.isAll,
     );
   }
 
@@ -595,17 +515,15 @@ class LocalAlbumEntityData extends i0.DataClass
           ..write('id: $id, ')
           ..write('name: $name, ')
           ..write('updatedAt: $updatedAt, ')
-          ..write('assetCount: $assetCount, ')
           ..write('thumbnailId: $thumbnailId, ')
-          ..write('backupSelection: $backupSelection, ')
-          ..write('isAll: $isAll')
+          ..write('backupSelection: $backupSelection')
           ..write(')'))
         .toString();
   }
 
   @override
-  int get hashCode => Object.hash(
-      id, name, updatedAt, assetCount, thumbnailId, backupSelection, isAll);
+  int get hashCode =>
+      Object.hash(id, name, updatedAt, thumbnailId, backupSelection);
   @override
   bool operator ==(Object other) =>
       identical(this, other) ||
@@ -613,10 +531,8 @@ class LocalAlbumEntityData extends i0.DataClass
           other.id == this.id &&
           other.name == this.name &&
           other.updatedAt == this.updatedAt &&
-          other.assetCount == this.assetCount &&
           other.thumbnailId == this.thumbnailId &&
-          other.backupSelection == this.backupSelection &&
-          other.isAll == this.isAll);
+          other.backupSelection == this.backupSelection);
 }
 
 class LocalAlbumEntityCompanion
@@ -624,27 +540,21 @@ class LocalAlbumEntityCompanion
   final i0.Value<String> id;
   final i0.Value<String> name;
   final i0.Value<DateTime> updatedAt;
-  final i0.Value<int> assetCount;
   final i0.Value<String?> thumbnailId;
   final i0.Value<i2.BackupSelection> backupSelection;
-  final i0.Value<bool> isAll;
   const LocalAlbumEntityCompanion({
     this.id = const i0.Value.absent(),
     this.name = const i0.Value.absent(),
     this.updatedAt = const i0.Value.absent(),
-    this.assetCount = const i0.Value.absent(),
     this.thumbnailId = const i0.Value.absent(),
     this.backupSelection = const i0.Value.absent(),
-    this.isAll = const i0.Value.absent(),
   });
   LocalAlbumEntityCompanion.insert({
     required String id,
     required String name,
     this.updatedAt = const i0.Value.absent(),
-    this.assetCount = const i0.Value.absent(),
     this.thumbnailId = const i0.Value.absent(),
     required i2.BackupSelection backupSelection,
-    this.isAll = const i0.Value.absent(),
   })  : id = i0.Value(id),
         name = i0.Value(name),
         backupSelection = i0.Value(backupSelection);
@@ -652,19 +562,15 @@ class LocalAlbumEntityCompanion
     i0.Expression<String>? id,
     i0.Expression<String>? name,
     i0.Expression<DateTime>? updatedAt,
-    i0.Expression<int>? assetCount,
     i0.Expression<String>? thumbnailId,
     i0.Expression<int>? backupSelection,
-    i0.Expression<bool>? isAll,
   }) {
     return i0.RawValuesInsertable({
       if (id != null) 'id': id,
       if (name != null) 'name': name,
       if (updatedAt != null) 'updated_at': updatedAt,
-      if (assetCount != null) 'asset_count': assetCount,
       if (thumbnailId != null) 'thumbnail_id': thumbnailId,
       if (backupSelection != null) 'backup_selection': backupSelection,
-      if (isAll != null) 'is_all': isAll,
     });
   }
 
@@ -672,18 +578,14 @@ class LocalAlbumEntityCompanion
       {i0.Value<String>? id,
       i0.Value<String>? name,
       i0.Value<DateTime>? updatedAt,
-      i0.Value<int>? assetCount,
       i0.Value<String?>? thumbnailId,
-      i0.Value<i2.BackupSelection>? backupSelection,
-      i0.Value<bool>? isAll}) {
+      i0.Value<i2.BackupSelection>? backupSelection}) {
     return i1.LocalAlbumEntityCompanion(
       id: id ?? this.id,
       name: name ?? this.name,
       updatedAt: updatedAt ?? this.updatedAt,
-      assetCount: assetCount ?? this.assetCount,
       thumbnailId: thumbnailId ?? this.thumbnailId,
       backupSelection: backupSelection ?? this.backupSelection,
-      isAll: isAll ?? this.isAll,
     );
   }
 
@@ -699,9 +601,6 @@ class LocalAlbumEntityCompanion
     if (updatedAt.present) {
       map['updated_at'] = i0.Variable<DateTime>(updatedAt.value);
     }
-    if (assetCount.present) {
-      map['asset_count'] = i0.Variable<int>(assetCount.value);
-    }
     if (thumbnailId.present) {
       map['thumbnail_id'] = i0.Variable<String>(thumbnailId.value);
     }
@@ -710,9 +609,6 @@ class LocalAlbumEntityCompanion
           .$LocalAlbumEntityTable.$converterbackupSelection
           .toSql(backupSelection.value));
     }
-    if (isAll.present) {
-      map['is_all'] = i0.Variable<bool>(isAll.value);
-    }
     return map;
   }
 
@@ -722,10 +618,8 @@ class LocalAlbumEntityCompanion
           ..write('id: $id, ')
           ..write('name: $name, ')
           ..write('updatedAt: $updatedAt, ')
-          ..write('assetCount: $assetCount, ')
           ..write('thumbnailId: $thumbnailId, ')
-          ..write('backupSelection: $backupSelection, ')
-          ..write('isAll: $isAll')
+          ..write('backupSelection: $backupSelection')
           ..write(')'))
         .toString();
   }
diff --git a/mobile/lib/infrastructure/entities/local_asset.entity.dart b/mobile/lib/infrastructure/entities/local_asset.entity.dart
index 1620e703f4..0f3dd25936 100644
--- a/mobile/lib/infrastructure/entities/local_asset.entity.dart
+++ b/mobile/lib/infrastructure/entities/local_asset.entity.dart
@@ -1,5 +1,5 @@
 import 'package:drift/drift.dart';
-import 'package:immich_mobile/domain/models/asset/asset.model.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
 import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
 import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart';
 import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
@@ -12,6 +12,9 @@ class LocalAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin {
 
   TextColumn get checksum => text().nullable()();
 
+  // Only used during backup to mirror the favorite status of the asset in the server
+  BoolColumn get isFavorite => boolean().withDefault(const Constant(false))();
+
   @override
   Set<Column> get primaryKey => {localId};
 }
@@ -19,7 +22,7 @@ class LocalAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin {
 extension LocalAssetEntityX on LocalAssetEntityData {
   LocalAsset toDto() {
     return LocalAsset(
-      localId: localId,
+      id: localId,
       name: name,
       checksum: checksum,
       type: type,
@@ -28,6 +31,7 @@ extension LocalAssetEntityX on LocalAssetEntityData {
       width: width,
       height: height,
       durationInSeconds: durationInSeconds,
+      isFavorite: isFavorite,
     );
   }
 }
diff --git a/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart b/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart
index e9ab09e8cf..2cec2d329c 100644
--- a/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart
+++ b/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart
@@ -3,7 +3,7 @@
 import 'package:drift/drift.dart' as i0;
 import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
     as i1;
-import 'package:immich_mobile/domain/models/asset/asset.model.dart' as i2;
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart' as i2;
 import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart'
     as i3;
 import 'package:drift/src/runtime/query_builder/query_builder.dart' as i4;
@@ -19,6 +19,7 @@ typedef $$LocalAssetEntityTableCreateCompanionBuilder
   i0.Value<int?> durationInSeconds,
   required String localId,
   i0.Value<String?> checksum,
+  i0.Value<bool> isFavorite,
 });
 typedef $$LocalAssetEntityTableUpdateCompanionBuilder
     = i1.LocalAssetEntityCompanion Function({
@@ -31,6 +32,7 @@ typedef $$LocalAssetEntityTableUpdateCompanionBuilder
   i0.Value<int?> durationInSeconds,
   i0.Value<String> localId,
   i0.Value<String?> checksum,
+  i0.Value<bool> isFavorite,
 });
 
 class $$LocalAssetEntityTableFilterComposer
@@ -71,6 +73,9 @@ class $$LocalAssetEntityTableFilterComposer
 
   i0.ColumnFilters<String> get checksum => $composableBuilder(
       column: $table.checksum, builder: (column) => i0.ColumnFilters(column));
+
+  i0.ColumnFilters<bool> get isFavorite => $composableBuilder(
+      column: $table.isFavorite, builder: (column) => i0.ColumnFilters(column));
 }
 
 class $$LocalAssetEntityTableOrderingComposer
@@ -111,6 +116,10 @@ class $$LocalAssetEntityTableOrderingComposer
 
   i0.ColumnOrderings<String> get checksum => $composableBuilder(
       column: $table.checksum, builder: (column) => i0.ColumnOrderings(column));
+
+  i0.ColumnOrderings<bool> get isFavorite => $composableBuilder(
+      column: $table.isFavorite,
+      builder: (column) => i0.ColumnOrderings(column));
 }
 
 class $$LocalAssetEntityTableAnnotationComposer
@@ -148,6 +157,9 @@ class $$LocalAssetEntityTableAnnotationComposer
 
   i0.GeneratedColumn<String> get checksum =>
       $composableBuilder(column: $table.checksum, builder: (column) => column);
+
+  i0.GeneratedColumn<bool> get isFavorite => $composableBuilder(
+      column: $table.isFavorite, builder: (column) => column);
 }
 
 class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
@@ -188,6 +200,7 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
             i0.Value<int?> durationInSeconds = const i0.Value.absent(),
             i0.Value<String> localId = const i0.Value.absent(),
             i0.Value<String?> checksum = const i0.Value.absent(),
+            i0.Value<bool> isFavorite = const i0.Value.absent(),
           }) =>
               i1.LocalAssetEntityCompanion(
             name: name,
@@ -199,6 +212,7 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
             durationInSeconds: durationInSeconds,
             localId: localId,
             checksum: checksum,
+            isFavorite: isFavorite,
           ),
           createCompanionCallback: ({
             required String name,
@@ -210,6 +224,7 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
             i0.Value<int?> durationInSeconds = const i0.Value.absent(),
             required String localId,
             i0.Value<String?> checksum = const i0.Value.absent(),
+            i0.Value<bool> isFavorite = const i0.Value.absent(),
           }) =>
               i1.LocalAssetEntityCompanion.insert(
             name: name,
@@ -221,6 +236,7 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
             durationInSeconds: durationInSeconds,
             localId: localId,
             checksum: checksum,
+            isFavorite: isFavorite,
           ),
           withReferenceMapper: (p0) => p0
               .map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
@@ -312,6 +328,16 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
   late final i0.GeneratedColumn<String> checksum = i0.GeneratedColumn<String>(
       'checksum', aliasedName, true,
       type: i0.DriftSqlType.string, requiredDuringInsert: false);
+  static const i0.VerificationMeta _isFavoriteMeta =
+      const i0.VerificationMeta('isFavorite');
+  @override
+  late final i0.GeneratedColumn<bool> isFavorite = i0.GeneratedColumn<bool>(
+      'is_favorite', aliasedName, false,
+      type: i0.DriftSqlType.bool,
+      requiredDuringInsert: false,
+      defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
+          'CHECK ("is_favorite" IN (0, 1))'),
+      defaultValue: const i4.Constant(false));
   @override
   List<i0.GeneratedColumn> get $columns => [
         name,
@@ -322,7 +348,8 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
         height,
         durationInSeconds,
         localId,
-        checksum
+        checksum,
+        isFavorite
       ];
   @override
   String get aliasedName => _alias ?? actualTableName;
@@ -373,6 +400,12 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
       context.handle(_checksumMeta,
           checksum.isAcceptableOrUnknown(data['checksum']!, _checksumMeta));
     }
+    if (data.containsKey('is_favorite')) {
+      context.handle(
+          _isFavoriteMeta,
+          isFavorite.isAcceptableOrUnknown(
+              data['is_favorite']!, _isFavoriteMeta));
+    }
     return context;
   }
 
@@ -402,6 +435,8 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
           .read(i0.DriftSqlType.string, data['${effectivePrefix}local_id'])!,
       checksum: attachedDatabase.typeMapping
           .read(i0.DriftSqlType.string, data['${effectivePrefix}checksum']),
+      isFavorite: attachedDatabase.typeMapping
+          .read(i0.DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!,
     );
   }
 
@@ -429,6 +464,7 @@ class LocalAssetEntityData extends i0.DataClass
   final int? durationInSeconds;
   final String localId;
   final String? checksum;
+  final bool isFavorite;
   const LocalAssetEntityData(
       {required this.name,
       required this.type,
@@ -438,7 +474,8 @@ class LocalAssetEntityData extends i0.DataClass
       this.height,
       this.durationInSeconds,
       required this.localId,
-      this.checksum});
+      this.checksum,
+      required this.isFavorite});
   @override
   Map<String, i0.Expression> toColumns(bool nullToAbsent) {
     final map = <String, i0.Expression>{};
@@ -462,6 +499,7 @@ class LocalAssetEntityData extends i0.DataClass
     if (!nullToAbsent || checksum != null) {
       map['checksum'] = i0.Variable<String>(checksum);
     }
+    map['is_favorite'] = i0.Variable<bool>(isFavorite);
     return map;
   }
 
@@ -479,6 +517,7 @@ class LocalAssetEntityData extends i0.DataClass
       durationInSeconds: serializer.fromJson<int?>(json['durationInSeconds']),
       localId: serializer.fromJson<String>(json['localId']),
       checksum: serializer.fromJson<String?>(json['checksum']),
+      isFavorite: serializer.fromJson<bool>(json['isFavorite']),
     );
   }
   @override
@@ -495,6 +534,7 @@ class LocalAssetEntityData extends i0.DataClass
       'durationInSeconds': serializer.toJson<int?>(durationInSeconds),
       'localId': serializer.toJson<String>(localId),
       'checksum': serializer.toJson<String?>(checksum),
+      'isFavorite': serializer.toJson<bool>(isFavorite),
     };
   }
 
@@ -507,7 +547,8 @@ class LocalAssetEntityData extends i0.DataClass
           i0.Value<int?> height = const i0.Value.absent(),
           i0.Value<int?> durationInSeconds = const i0.Value.absent(),
           String? localId,
-          i0.Value<String?> checksum = const i0.Value.absent()}) =>
+          i0.Value<String?> checksum = const i0.Value.absent(),
+          bool? isFavorite}) =>
       i1.LocalAssetEntityData(
         name: name ?? this.name,
         type: type ?? this.type,
@@ -520,6 +561,7 @@ class LocalAssetEntityData extends i0.DataClass
             : this.durationInSeconds,
         localId: localId ?? this.localId,
         checksum: checksum.present ? checksum.value : this.checksum,
+        isFavorite: isFavorite ?? this.isFavorite,
       );
   LocalAssetEntityData copyWithCompanion(i1.LocalAssetEntityCompanion data) {
     return LocalAssetEntityData(
@@ -534,6 +576,8 @@ class LocalAssetEntityData extends i0.DataClass
           : this.durationInSeconds,
       localId: data.localId.present ? data.localId.value : this.localId,
       checksum: data.checksum.present ? data.checksum.value : this.checksum,
+      isFavorite:
+          data.isFavorite.present ? data.isFavorite.value : this.isFavorite,
     );
   }
 
@@ -548,14 +592,15 @@ class LocalAssetEntityData extends i0.DataClass
           ..write('height: $height, ')
           ..write('durationInSeconds: $durationInSeconds, ')
           ..write('localId: $localId, ')
-          ..write('checksum: $checksum')
+          ..write('checksum: $checksum, ')
+          ..write('isFavorite: $isFavorite')
           ..write(')'))
         .toString();
   }
 
   @override
   int get hashCode => Object.hash(name, type, createdAt, updatedAt, width,
-      height, durationInSeconds, localId, checksum);
+      height, durationInSeconds, localId, checksum, isFavorite);
   @override
   bool operator ==(Object other) =>
       identical(this, other) ||
@@ -568,7 +613,8 @@ class LocalAssetEntityData extends i0.DataClass
           other.height == this.height &&
           other.durationInSeconds == this.durationInSeconds &&
           other.localId == this.localId &&
-          other.checksum == this.checksum);
+          other.checksum == this.checksum &&
+          other.isFavorite == this.isFavorite);
 }
 
 class LocalAssetEntityCompanion
@@ -582,6 +628,7 @@ class LocalAssetEntityCompanion
   final i0.Value<int?> durationInSeconds;
   final i0.Value<String> localId;
   final i0.Value<String?> checksum;
+  final i0.Value<bool> isFavorite;
   const LocalAssetEntityCompanion({
     this.name = const i0.Value.absent(),
     this.type = const i0.Value.absent(),
@@ -592,6 +639,7 @@ class LocalAssetEntityCompanion
     this.durationInSeconds = const i0.Value.absent(),
     this.localId = const i0.Value.absent(),
     this.checksum = const i0.Value.absent(),
+    this.isFavorite = const i0.Value.absent(),
   });
   LocalAssetEntityCompanion.insert({
     required String name,
@@ -603,6 +651,7 @@ class LocalAssetEntityCompanion
     this.durationInSeconds = const i0.Value.absent(),
     required String localId,
     this.checksum = const i0.Value.absent(),
+    this.isFavorite = const i0.Value.absent(),
   })  : name = i0.Value(name),
         type = i0.Value(type),
         localId = i0.Value(localId);
@@ -616,6 +665,7 @@ class LocalAssetEntityCompanion
     i0.Expression<int>? durationInSeconds,
     i0.Expression<String>? localId,
     i0.Expression<String>? checksum,
+    i0.Expression<bool>? isFavorite,
   }) {
     return i0.RawValuesInsertable({
       if (name != null) 'name': name,
@@ -627,6 +677,7 @@ class LocalAssetEntityCompanion
       if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds,
       if (localId != null) 'local_id': localId,
       if (checksum != null) 'checksum': checksum,
+      if (isFavorite != null) 'is_favorite': isFavorite,
     });
   }
 
@@ -639,7 +690,8 @@ class LocalAssetEntityCompanion
       i0.Value<int?>? height,
       i0.Value<int?>? durationInSeconds,
       i0.Value<String>? localId,
-      i0.Value<String?>? checksum}) {
+      i0.Value<String?>? checksum,
+      i0.Value<bool>? isFavorite}) {
     return i1.LocalAssetEntityCompanion(
       name: name ?? this.name,
       type: type ?? this.type,
@@ -650,6 +702,7 @@ class LocalAssetEntityCompanion
       durationInSeconds: durationInSeconds ?? this.durationInSeconds,
       localId: localId ?? this.localId,
       checksum: checksum ?? this.checksum,
+      isFavorite: isFavorite ?? this.isFavorite,
     );
   }
 
@@ -684,6 +737,9 @@ class LocalAssetEntityCompanion
     if (checksum.present) {
       map['checksum'] = i0.Variable<String>(checksum.value);
     }
+    if (isFavorite.present) {
+      map['is_favorite'] = i0.Variable<bool>(isFavorite.value);
+    }
     return map;
   }
 
@@ -698,7 +754,8 @@ class LocalAssetEntityCompanion
           ..write('height: $height, ')
           ..write('durationInSeconds: $durationInSeconds, ')
           ..write('localId: $localId, ')
-          ..write('checksum: $checksum')
+          ..write('checksum: $checksum, ')
+          ..write('isFavorite: $isFavorite')
           ..write(')'))
         .toString();
   }
diff --git a/mobile/lib/infrastructure/repositories/album_media.repository.dart b/mobile/lib/infrastructure/repositories/album_media.repository.dart
index c834169852..0a2da332fc 100644
--- a/mobile/lib/infrastructure/repositories/album_media.repository.dart
+++ b/mobile/lib/infrastructure/repositories/album_media.repository.dart
@@ -1,11 +1,15 @@
 import 'package:immich_mobile/constants/constants.dart';
 import 'package:immich_mobile/domain/interfaces/album_media.interface.dart';
-import 'package:immich_mobile/domain/models/asset/asset.model.dart' as asset;
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'
+    as asset;
 import 'package:immich_mobile/domain/models/local_album.model.dart';
 import 'package:photo_manager/photo_manager.dart';
+import 'package:platform/platform.dart';
 
 class AlbumMediaRepository implements IAlbumMediaRepository {
-  const AlbumMediaRepository();
+  final Platform _platform;
+  const AlbumMediaRepository({Platform platform = const LocalPlatform()})
+      : _platform = platform;
 
   PMFilter _getAlbumFilter({
     withAssetTitle = false,
@@ -42,7 +46,12 @@ class AlbumMediaRepository implements IAlbumMediaRepository {
     );
 
     return PhotoManager.getAssetPathList(hasAll: true, filterOption: filter)
-        .then((e) => e.toDtoList());
+        .then((e) {
+      if (_platform.isAndroid) {
+        e.removeWhere((a) => a.isAll);
+      }
+      return e.toDtoList();
+    });
   }
 
   @override
@@ -85,7 +94,7 @@ class AlbumMediaRepository implements IAlbumMediaRepository {
 
 extension on AssetEntity {
   Future<asset.LocalAsset> toDto() async => asset.LocalAsset(
-        localId: id,
+        id: id,
         name: title ?? await titleAsync,
         type: switch (type) {
           AssetType.other => asset.AssetType.other,
@@ -114,7 +123,6 @@ extension on AssetPathEntity {
         // the assetCountAsync call is expensive for larger albums with several thousand assets
         assetCount: withAssetCount ? await assetCountAsync : 0,
         backupSelection: BackupSelection.none,
-        isAll: isAll,
       );
 }
 
diff --git a/mobile/lib/infrastructure/repositories/local_album.repository.dart b/mobile/lib/infrastructure/repositories/local_album.repository.dart
index 557c264409..da85380c20 100644
--- a/mobile/lib/infrastructure/repositories/local_album.repository.dart
+++ b/mobile/lib/infrastructure/repositories/local_album.repository.dart
@@ -1,6 +1,6 @@
 import 'package:drift/drift.dart';
 import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
-import 'package:immich_mobile/domain/models/asset/asset.model.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
 import 'package:immich_mobile/domain/models/local_album.model.dart';
 import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
 import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
@@ -137,10 +137,8 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository
       id: localAlbum.id,
       name: localAlbum.name,
       updatedAt: Value(localAlbum.updatedAt),
-      assetCount: Value(localAlbum.assetCount),
       thumbnailId: Value.absentIfNull(localAlbum.thumbnailId),
       backupSelection: localAlbum.backupSelection,
-      isAll: Value(localAlbum.isAll),
     );
 
     return _db.localAlbumEntity
@@ -160,7 +158,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository
         _db.localAlbumAssetEntity,
         assets.map(
           (a) => LocalAlbumAssetEntityCompanion.insert(
-            assetId: a.localId,
+            assetId: a.id,
             albumId: albumId,
           ),
         ),
@@ -223,7 +221,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository
             width: Value.absentIfNull(a.width),
             height: Value.absentIfNull(a.height),
             durationInSeconds: Value.absentIfNull(a.durationInSeconds),
-            localId: a.localId,
+            localId: a.id,
             checksum: Value.absentIfNull(a.checksum),
           ),
         ),
diff --git a/mobile/lib/infrastructure/repositories/local_asset.repository.dart b/mobile/lib/infrastructure/repositories/local_asset.repository.dart
index c77e997d23..cb9119b653 100644
--- a/mobile/lib/infrastructure/repositories/local_asset.repository.dart
+++ b/mobile/lib/infrastructure/repositories/local_asset.repository.dart
@@ -1,5 +1,5 @@
 import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
-import 'package:immich_mobile/domain/models/asset/asset.model.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
 import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
 import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
 
diff --git a/mobile/lib/infrastructure/utils/asset.mixin.dart b/mobile/lib/infrastructure/utils/asset.mixin.dart
index e632b0a49d..4e14a2919f 100644
--- a/mobile/lib/infrastructure/utils/asset.mixin.dart
+++ b/mobile/lib/infrastructure/utils/asset.mixin.dart
@@ -1,5 +1,5 @@
 import 'package:drift/drift.dart';
-import 'package:immich_mobile/domain/models/asset/asset.model.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
 
 mixin AssetEntityMixin on Table {
   TextColumn get name => text()();
diff --git a/mobile/test/domain/services/device_sync_service_test.dart b/mobile/test/domain/services/device_sync_service_test.dart
index 49ccb81117..389872626b 100644
--- a/mobile/test/domain/services/device_sync_service_test.dart
+++ b/mobile/test/domain/services/device_sync_service_test.dart
@@ -3,7 +3,7 @@ import 'package:flutter_test/flutter_test.dart';
 import 'package:immich_mobile/domain/interfaces/album_media.interface.dart';
 import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
 import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
-import 'package:immich_mobile/domain/models/asset/asset.model.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
 import 'package:immich_mobile/domain/models/local_album.model.dart';
 import 'package:immich_mobile/domain/services/device_sync.service.dart';
 import 'package:immich_mobile/utils/nullable_value.dart';
@@ -257,9 +257,9 @@ void main() {
             newAlbum.copyWith(updatedAt: DateTime(2024), assetCount: 2);
         final assets = [
           LocalAssetStub.image1
-              .copyWith(localId: "asset1", createdAt: DateTime(2024, 1, 1)),
+              .copyWith(id: "asset1", createdAt: DateTime(2024, 1, 1)),
           LocalAssetStub.image2.copyWith(
-            localId: "asset2",
+            id: "asset2",
             createdAt: DateTime(2024, 1, 2),
           ),
         ];
@@ -284,7 +284,7 @@ void main() {
         expect(capturedAlbum.id, newAlbum.id);
         expect(capturedAlbum.assetCount, refreshedAlbum.assetCount);
         expect(capturedAlbum.updatedAt, refreshedAlbum.updatedAt);
-        expect(capturedAlbum.thumbnailId, assets.first.localId);
+        expect(capturedAlbum.thumbnailId, assets.first.id);
         expect(listEquals(capturedAssets, assets), isTrue);
       },
     );
@@ -354,7 +354,7 @@ void main() {
       when(() => mockAlbumMediaRepo.refresh(dbAlbum.id))
           .thenAnswer((_) async => refreshedAlbum);
 
-      final newAsset = LocalAssetStub.image2.copyWith(localId: "new_asset");
+      final newAsset = LocalAssetStub.image2.copyWith(id: "new_asset");
       when(
         () => mockAlbumMediaRepo.getAssetsForAlbum(
           dbAlbum.id,
@@ -387,7 +387,7 @@ void main() {
               (a) =>
                   a.id == dbAlbum.id &&
                   a.assetCount == 2 &&
-                  a.thumbnailId == newAsset.localId,
+                  a.thumbnailId == newAsset.id,
             ),
           ),
         ),
@@ -446,7 +446,7 @@ void main() {
         ).called(1);
         verify(
           () => mockLocalAlbumRepo
-              .removeAssets(dbAlbum.id, [LocalAssetStub.image1.localId]),
+              .removeAssets(dbAlbum.id, [LocalAssetStub.image1.id]),
         ).called(1);
       },
     );
@@ -519,7 +519,7 @@ void main() {
 
     test('returns true and updates assets/metadata on success', () async {
       final newAsset = LocalAssetStub.image2.copyWith(
-        localId: "asset2",
+        id: "asset2",
         createdAt: DateTime(2024, 1, 1, 10, 30, 0),
       );
       when(
@@ -531,7 +531,7 @@ void main() {
 
       when(() => mockLocalAssetRepo.get("thumb1")).thenAnswer(
         (_) async => LocalAssetStub.image1.copyWith(
-          localId: "thumb1",
+          id: "thumb1",
           createdAt: DateTime(2024, 1, 1, 9, 0, 0),
         ),
       );
@@ -556,7 +556,7 @@ void main() {
                   a.id == dbAlbum.id &&
                   a.assetCount == 2 &&
                   a.updatedAt == refreshedAlbum.updatedAt &&
-                  a.thumbnailId == newAsset.localId,
+                  a.thumbnailId == newAsset.id,
             ),
           ),
         ),
@@ -567,7 +567,7 @@ void main() {
 
     test('returns true and keeps old thumbnail if newer', () async {
       final newAsset = LocalAssetStub.image2.copyWith(
-        localId: "asset2",
+        id: "asset2",
         createdAt: DateTime(2024, 1, 1, 8, 0, 0),
       );
       when(
@@ -579,7 +579,7 @@ void main() {
 
       when(() => mockLocalAssetRepo.get("thumb1")).thenAnswer(
         (_) async => LocalAssetStub.image1.copyWith(
-          localId: "thumb1",
+          id: "thumb1",
           createdAt: DateTime(2024, 1, 1, 9, 0, 0),
         ),
       );
@@ -614,7 +614,7 @@ void main() {
     test('returns true and sets new thumbnail if db thumb is null', () async {
       final dbAlbumNoThumb = dbAlbum.copyWith(thumbnailId: null);
       final newAsset = LocalAssetStub.image2.copyWith(
-        localId: "asset2",
+        id: "asset2",
         createdAt: DateTime(2024, 1, 1, 10, 30, 0),
       );
       when(
@@ -644,7 +644,7 @@ void main() {
                   a.id == dbAlbum.id &&
                   a.assetCount == 2 &&
                   a.updatedAt == refreshedAlbum.updatedAt &&
-                  a.thumbnailId == newAsset.localId,
+                  a.thumbnailId == newAsset.id,
             ),
           ),
         ),
@@ -731,22 +731,22 @@ void main() {
     );
 
     final dbAsset1 = LocalAssetStub.image1.copyWith(
-      localId: "asset1",
+      id: "asset1",
       createdAt: DateTime(2024),
       updatedAt: DateTime(2024),
     );
     final dbAsset2 = LocalAssetStub.image2.copyWith(
-      localId: "asset2",
+      id: "asset2",
       createdAt: DateTime(2024),
       updatedAt: DateTime(2024),
     ); // To be deleted
     final deviceAsset1 = LocalAssetStub.image1.copyWith(
-      localId: "asset1",
+      id: "asset1",
       createdAt: DateTime(2024),
       updatedAt: DateTime(2025),
     ); // Updated
     final deviceAsset3 = LocalAssetStub.video1.copyWith(
-      localId: "asset3",
+      id: "asset3",
       createdAt: DateTime(2024),
       updatedAt: DateTime(2024),
     ); // Added
@@ -819,7 +819,7 @@ void main() {
                   a.id == emptyDbAlbum.id &&
                   a.assetCount == deviceAssets.length &&
                   a.updatedAt == refreshedWithAssets.updatedAt &&
-                  a.thumbnailId == deviceAssets.first.localId,
+                  a.thumbnailId == deviceAssets.first.id,
             ),
           ),
         ),
@@ -833,7 +833,7 @@ void main() {
       final deviceAssets = [deviceAsset1, deviceAsset3];
       deviceAssets.sort((a, b) => a.createdAt.compareTo(b.createdAt));
       final dbAssets = [dbAsset1, dbAsset2];
-      dbAssets.sort((a, b) => a.localId.compareTo(b.localId));
+      dbAssets.sort((a, b) => a.id.compareTo(b.id));
 
       when(() => mockAlbumMediaRepo.getAssetsForAlbum(dbAlbum.id)).thenAnswer(
         (_) async => deviceAssets,
@@ -857,10 +857,10 @@ void main() {
               return list.length == 2 &&
                   list.any(
                     (a) =>
-                        a.localId == "asset1" &&
+                        a.id == "asset1" &&
                         a.updatedAt == deviceAsset1.updatedAt,
                   ) &&
-                  list.any((a) => a.localId == "asset3");
+                  list.any((a) => a.id == "asset3");
             }),
           ),
         ),
@@ -874,7 +874,7 @@ void main() {
                   a.id == dbAlbum.id &&
                   a.assetCount == 2 &&
                   a.updatedAt == currentRefreshedAlbum.updatedAt &&
-                  a.thumbnailId == deviceAssets.first.localId,
+                  a.thumbnailId == deviceAssets.first.id,
             ),
           ),
         ),
@@ -892,7 +892,7 @@ void main() {
       final dbAssets = [dbAsset1, dbAsset2];
       final deviceAssets = [dbAsset1, dbAsset2];
       deviceAssets.sort((a, b) => a.createdAt.compareTo(b.createdAt));
-      dbAssets.sort((a, b) => a.localId.compareTo(b.localId));
+      dbAssets.sort((a, b) => a.id.compareTo(b.id));
 
       when(() => mockAlbumMediaRepo.getAssetsForAlbum(dbAlbum.id))
           .thenAnswer((_) async => deviceAssets);
@@ -915,7 +915,7 @@ void main() {
                   a.id == dbAlbum.id &&
                   a.assetCount == 2 &&
                   a.updatedAt == currentRefreshedAlbum.updatedAt &&
-                  a.thumbnailId == deviceAssets.first.localId,
+                  a.thumbnailId == deviceAssets.first.id,
             ),
           ),
         ),
diff --git a/mobile/test/fixtures/local_album.stub.dart b/mobile/test/fixtures/local_album.stub.dart
index 32d25ce254..517bdd5189 100644
--- a/mobile/test/fixtures/local_album.stub.dart
+++ b/mobile/test/fixtures/local_album.stub.dart
@@ -10,7 +10,6 @@ abstract final class LocalAlbumStub {
         assetCount: 1,
         thumbnailId: null,
         backupSelection: BackupSelection.none,
-        isAll: false,
       );
 
   static LocalAlbum get album2 => LocalAlbum(
@@ -20,7 +19,6 @@ abstract final class LocalAlbumStub {
         assetCount: 2,
         thumbnailId: null,
         backupSelection: BackupSelection.selected,
-        isAll: true,
       );
 
   static LocalAlbum get album3 => LocalAlbum(
@@ -30,6 +28,5 @@ abstract final class LocalAlbumStub {
         assetCount: 20,
         thumbnailId: "123",
         backupSelection: BackupSelection.excluded,
-        isAll: false,
       );
 }
diff --git a/mobile/test/fixtures/local_asset.stub.dart b/mobile/test/fixtures/local_asset.stub.dart
index a399dfdc22..1d47e7abe5 100644
--- a/mobile/test/fixtures/local_asset.stub.dart
+++ b/mobile/test/fixtures/local_asset.stub.dart
@@ -1,10 +1,10 @@
-import 'package:immich_mobile/domain/models/asset/asset.model.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
 
 abstract final class LocalAssetStub {
   const LocalAssetStub();
 
   static LocalAsset get image1 => LocalAsset(
-        localId: "image1",
+        id: "image1",
         name: "image1.jpg",
         checksum: "image1-checksum",
         type: AssetType.image,
@@ -16,7 +16,7 @@ abstract final class LocalAssetStub {
       );
 
   static LocalAsset get image2 => LocalAsset(
-        localId: "image2",
+        id: "image2",
         name: "image2.jpg",
         checksum: "image2-checksum",
         type: AssetType.image,
@@ -28,7 +28,7 @@ abstract final class LocalAssetStub {
       );
 
   static LocalAsset get video1 => LocalAsset(
-        localId: "video1",
+        id: "video1",
         name: "video1.mov",
         checksum: "video1-checksum",
         type: AssetType.video,