diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ef9dc8ada..98da1a783 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -96,7 +96,11 @@ jobs:
         if: ${{ !cancelled() }}
 
       - name: Run svelte checks
-        run: npm run check
+        run: npm run check:svelte
+        if: ${{ !cancelled() }}
+
+      - name: Run tsc
+        run: npm run check:typescript
         if: ${{ !cancelled() }}
 
       - name: Run unit tests & coverage
diff --git a/web/package.json b/web/package.json
index 90673a3a3..09df801a1 100644
--- a/web/package.json
+++ b/web/package.json
@@ -6,9 +6,10 @@
 		"build": "vite build",
 		"package": "svelte-kit package",
 		"preview": "vite preview",
-		"check": "svelte-check --no-tsconfig --fail-on-warnings --ignore \"src/api/open-api\"",
-		"check:watch": "npm run check -- --watch",
-		"check:code": "npm run format && npm run lint && npm run check",
+		"check:svelte": "svelte-check --no-tsconfig --fail-on-warnings --ignore \"src/api/open-api\"",
+		"check:typescript": "tsc --noEmit",
+		"check:watch": "npm run check:svelte -- --watch",
+		"check:code": "npm run format && npm run lint && npm run check:svelte && npm run check:typescript",
 		"check:all": "npm run check:code && npm run test:cov",
 		"lint": "eslint . --max-warnings 0",
 		"lint:fix": "npm run lint -- --fix",
diff --git a/web/src/api/utils.ts b/web/src/api/utils.ts
index c7fa62bfa..39c319901 100644
--- a/web/src/api/utils.ts
+++ b/web/src/api/utils.ts
@@ -1,6 +1,6 @@
-import { AxiosError, AxiosPromise } from 'axios';
+import type { AxiosError, AxiosPromise } from 'axios';
 import { api } from './api';
-import { UserResponseDto } from './open-api';
+import type { UserResponseDto } from './open-api';
 
 export type ApiError = AxiosError<{ message: string }>;
 
diff --git a/web/src/hooks.server.ts b/web/src/hooks.server.ts
index 959ed5e3e..8998257e7 100644
--- a/web/src/hooks.server.ts
+++ b/web/src/hooks.server.ts
@@ -1,6 +1,6 @@
-import type { Handle, HandleServerError } from '@sveltejs/kit';
-import { AxiosError, AxiosResponse } from 'axios';
 import { env } from '$env/dynamic/public';
+import type { Handle, HandleServerError } from '@sveltejs/kit';
+import type { AxiosError, AxiosResponse } from 'axios';
 import { ImmichApi } from './api/api';
 
 export const handle = (async ({ event, resolve }) => {
diff --git a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte
index 06a3d05a5..5930cfa41 100644
--- a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte
+++ b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte
@@ -3,10 +3,11 @@
 		notificationController,
 		NotificationType
 	} from '$lib/components/shared-components/notification/notification';
+	import { AppRoute } from '$lib/constants';
 	import { handleError } from '$lib/utils/handle-error';
 	import { AllJobStatusResponseDto, api, JobCommand, JobCommandDto, JobName } from '@api';
 	import type { ComponentType } from 'svelte';
-	import Icon from 'svelte-material-icons/DotsVertical.svelte';
+	import type Icon from 'svelte-material-icons/DotsVertical.svelte';
 	import FaceRecognition from 'svelte-material-icons/FaceRecognition.svelte';
 	import FileJpgBox from 'svelte-material-icons/FileJpgBox.svelte';
 	import FileXmlBox from 'svelte-material-icons/FileXmlBox.svelte';
@@ -19,7 +20,6 @@
 	import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
 	import JobTile from './job-tile.svelte';
 	import StorageMigrationDescription from './storage-migration-description.svelte';
-	import { AppRoute } from '$lib/constants';
 
 	export let jobs: AllJobStatusResponseDto;
 
diff --git a/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte b/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte
index c1b73f9a4..c1d26f115 100644
--- a/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte
+++ b/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte
@@ -1,11 +1,11 @@
 <script lang="ts">
-	import { ServerStatsResponseDto } from '@api';
-	import CameraIris from 'svelte-material-icons/CameraIris.svelte';
-	import PlayCircle from 'svelte-material-icons/PlayCircle.svelte';
-	import Memory from 'svelte-material-icons/Memory.svelte';
-	import StatsCard from './stats-card.svelte';
-	import { asByteUnitString, getBytesWithUnit } from '../../../utils/byte-units';
 	import { locale } from '$lib/stores/preferences.store';
+	import type { ServerStatsResponseDto } from '@api';
+	import CameraIris from 'svelte-material-icons/CameraIris.svelte';
+	import Memory from 'svelte-material-icons/Memory.svelte';
+	import PlayCircle from 'svelte-material-icons/PlayCircle.svelte';
+	import { asByteUnitString, getBytesWithUnit } from '../../../utils/byte-units';
+	import StatsCard from './stats-card.svelte';
 
 	export let stats: ServerStatsResponseDto = {
 		photos: 0,
diff --git a/web/src/lib/components/admin-page/settings/storage-template/supported-datetime-panel.svelte b/web/src/lib/components/admin-page/settings/storage-template/supported-datetime-panel.svelte
index 14c817b1e..d30798fb1 100644
--- a/web/src/lib/components/admin-page/settings/storage-template/supported-datetime-panel.svelte
+++ b/web/src/lib/components/admin-page/settings/storage-template/supported-datetime-panel.svelte
@@ -1,5 +1,5 @@
 <script lang="ts">
-	import { SystemConfigTemplateStorageOptionDto } from '@api';
+	import type { SystemConfigTemplateStorageOptionDto } from '@api';
 	import * as luxon from 'luxon';
 
 	export let options: SystemConfigTemplateStorageOptionDto;
diff --git a/web/src/lib/components/album-page/__tests__/album-card.spec.ts b/web/src/lib/components/album-page/__tests__/album-card.spec.ts
index 1270e2f1b..ba7b194c5 100644
--- a/web/src/lib/components/album-page/__tests__/album-card.spec.ts
+++ b/web/src/lib/components/album-page/__tests__/album-card.spec.ts
@@ -37,7 +37,7 @@ describe('AlbumCard component', () => {
 	])(
 		'shows album data without thumbnail with count $count - shared: $shared',
 		async ({ album, count, shared }) => {
-			sut = render(AlbumCard, { album });
+			sut = render(AlbumCard, { album, user: album.owner });
 
 			const albumImgElement = sut.getByTestId('album-image');
 			const albumNameElement = sut.getByTestId('album-name');
@@ -58,10 +58,10 @@ describe('AlbumCard component', () => {
 	);
 
 	it('shows album data and and loads the thumbnail image when available', async () => {
-		const thumbnailBlob = new Blob();
+		const thumbnailFile = new File([new Blob()], 'fileThumbnail');
 		const thumbnailUrl = 'blob:thumbnailUrlOne';
 		apiMock.assetApi.getAssetThumbnail.mockResolvedValue({
-			data: thumbnailBlob,
+			data: thumbnailFile,
 			config: {},
 			headers: {},
 			status: 200,
@@ -74,7 +74,7 @@ describe('AlbumCard component', () => {
 			shared: false,
 			albumName: 'some album name'
 		});
-		sut = render(AlbumCard, { album });
+		sut = render(AlbumCard, { album, user: album.owner });
 
 		const albumImgElement = sut.getByTestId('album-image');
 		const albumNameElement = sut.getByTestId('album-name');
@@ -92,7 +92,7 @@ describe('AlbumCard component', () => {
 			},
 			{ responseType: 'blob' }
 		);
-		expect(createObjectURLMock).toHaveBeenCalledWith(thumbnailBlob);
+		expect(createObjectURLMock).toHaveBeenCalledWith(thumbnailFile);
 
 		expect(albumNameElement).toHaveTextContent('some album name');
 		expect(albumDetailsElement).toHaveTextContent('0 items');
@@ -102,7 +102,7 @@ describe('AlbumCard component', () => {
 		const album = Object.freeze(albumFactory.build({ albumThumbnailAssetId: null }));
 
 		beforeEach(async () => {
-			sut = render(AlbumCard, { album });
+			sut = render(AlbumCard, { album, user: album.owner });
 
 			const albumImgElement = sut.getByTestId('album-image');
 			await waitFor(() => expect(albumImgElement).toHaveAttribute('src'));
diff --git a/web/src/lib/components/album-page/album-card.svelte b/web/src/lib/components/album-page/album-card.svelte
index 8249810ca..5900abb03 100644
--- a/web/src/lib/components/album-page/album-card.svelte
+++ b/web/src/lib/components/album-page/album-card.svelte
@@ -1,23 +1,11 @@
-<script lang="ts" context="module">
-	type OnShowContextMenu = {
-		showalbumcontextmenu: OnShowContextMenuDetail;
-	};
-
-	type OnClick = {
-		click: OnClickDetail;
-	};
-
-	export type OnShowContextMenuDetail = { x: number; y: number };
-	export type OnClickDetail = AlbumResponseDto;
-</script>
-
 <script lang="ts">
+	import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
+	import { locale } from '$lib/stores/preferences.store';
 	import { AlbumResponseDto, api, ThumbnailFormat, UserResponseDto } from '@api';
 	import { createEventDispatcher, onMount } from 'svelte';
 	import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
-	import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
-	import { locale } from '$lib/stores/preferences.store';
 	import IconButton from '../elements/buttons/icon-button.svelte';
+	import type { OnClick, OnShowContextMenu } from './album-card';
 
 	export let album: AlbumResponseDto;
 	export let isSharingView = false;
diff --git a/web/src/lib/components/album-page/album-card.ts b/web/src/lib/components/album-page/album-card.ts
new file mode 100644
index 000000000..c69b7e6c3
--- /dev/null
+++ b/web/src/lib/components/album-page/album-card.ts
@@ -0,0 +1,12 @@
+import type { AlbumResponseDto } from '@api';
+
+export type OnShowContextMenu = {
+	showalbumcontextmenu: OnShowContextMenuDetail;
+};
+
+export type OnClick = {
+	click: OnClickDetail;
+};
+
+export type OnShowContextMenuDetail = { x: number; y: number };
+export type OnClickDetail = AlbumResponseDto;
diff --git a/web/src/lib/components/album-page/asset-selection.svelte b/web/src/lib/components/album-page/asset-selection.svelte
index 82a9d3d94..6282da2c3 100644
--- a/web/src/lib/components/album-page/asset-selection.svelte
+++ b/web/src/lib/components/album-page/asset-selection.svelte
@@ -1,18 +1,18 @@
 <script lang="ts">
-	import { createEventDispatcher, onMount } from 'svelte';
-	import { quintOut } from 'svelte/easing';
-	import { fly } from 'svelte/transition';
-	import { AssetResponseDto } from '@api';
-	import { openFileUploadDialog } from '$lib/utils/file-uploader';
-	import ControlAppBar from '../shared-components/control-app-bar.svelte';
-	import AssetGrid from '../photos-page/asset-grid.svelte';
 	import {
 		assetInteractionStore,
 		assetsInAlbumStoreState,
 		selectedAssets
 	} from '$lib/stores/asset-interaction.store';
 	import { locale } from '$lib/stores/preferences.store';
+	import { openFileUploadDialog } from '$lib/utils/file-uploader';
+	import type { AssetResponseDto } from '@api';
+	import { createEventDispatcher, onMount } from 'svelte';
+	import { quintOut } from 'svelte/easing';
+	import { fly } from 'svelte/transition';
 	import Button from '../elements/buttons/button.svelte';
+	import AssetGrid from '../photos-page/asset-grid.svelte';
+	import ControlAppBar from '../shared-components/control-app-bar.svelte';
 
 	const dispatch = createEventDispatcher();
 
diff --git a/web/src/lib/components/album-page/thumbnail-selection.svelte b/web/src/lib/components/album-page/thumbnail-selection.svelte
index c2923002d..6486ad60e 100644
--- a/web/src/lib/components/album-page/thumbnail-selection.svelte
+++ b/web/src/lib/components/album-page/thumbnail-selection.svelte
@@ -1,11 +1,11 @@
 <script lang="ts">
-	import { AlbumResponseDto, AssetResponseDto } from '@api';
+	import type { AlbumResponseDto, AssetResponseDto } from '@api';
 	import { createEventDispatcher } from 'svelte';
 	import { quintOut } from 'svelte/easing';
 	import { fly } from 'svelte/transition';
 	import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
-	import ControlAppBar from '../shared-components/control-app-bar.svelte';
 	import Button from '../elements/buttons/button.svelte';
+	import ControlAppBar from '../shared-components/control-app-bar.svelte';
 
 	export let album: AlbumResponseDto;
 
diff --git a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte
index daaea852b..302e6e361 100644
--- a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte
+++ b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte
@@ -1,23 +1,21 @@
 <script lang="ts">
-	import { createEventDispatcher } from 'svelte';
-
+	import { page } from '$app/stores';
 	import { clickOutside } from '$lib/utils/click-outside';
+	import type { AssetResponseDto } from '@api';
+	import { createEventDispatcher } from 'svelte';
 	import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
 	import CloudDownloadOutline from 'svelte-material-icons/CloudDownloadOutline.svelte';
-	import InformationOutline from 'svelte-material-icons/InformationOutline.svelte';
-	import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
+	import ContentCopy from 'svelte-material-icons/ContentCopy.svelte';
 	import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
+	import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
+	import Heart from 'svelte-material-icons/Heart.svelte';
+	import HeartOutline from 'svelte-material-icons/HeartOutline.svelte';
+	import InformationOutline from 'svelte-material-icons/InformationOutline.svelte';
+	import MotionPauseOutline from 'svelte-material-icons/MotionPauseOutline.svelte';
+	import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte';
 	import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
 	import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
 	import MenuOption from '../shared-components/context-menu/menu-option.svelte';
-	import Heart from 'svelte-material-icons/Heart.svelte';
-	import HeartOutline from 'svelte-material-icons/HeartOutline.svelte';
-	import ContentCopy from 'svelte-material-icons/ContentCopy.svelte';
-	import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte';
-	import MotionPauseOutline from 'svelte-material-icons/MotionPauseOutline.svelte';
-
-	import { page } from '$app/stores';
-	import { AssetResponseDto } from '../../../api';
 
 	export let asset: AssetResponseDto;
 	export let showCopyButton: boolean;
diff --git a/web/src/lib/components/forms/api-key-form.svelte b/web/src/lib/components/forms/api-key-form.svelte
index a11317bed..dad32d61b 100644
--- a/web/src/lib/components/forms/api-key-form.svelte
+++ b/web/src/lib/components/forms/api-key-form.svelte
@@ -1,9 +1,9 @@
 <script lang="ts">
-	import { APIKeyResponseDto } from '@api';
+	import type { APIKeyResponseDto } from '@api';
 	import { createEventDispatcher } from 'svelte';
 	import KeyVariant from 'svelte-material-icons/KeyVariant.svelte';
-	import FullScreenModal from '../shared-components/full-screen-modal.svelte';
 	import Button from '../elements/buttons/button.svelte';
+	import FullScreenModal from '../shared-components/full-screen-modal.svelte';
 
 	export let apiKey: Partial<APIKeyResponseDto>;
 	export let title = 'API Key';
diff --git a/web/src/lib/components/map-page/map-settings-modal.svelte b/web/src/lib/components/map-page/map-settings-modal.svelte
index 823536fc7..3d5fe5656 100644
--- a/web/src/lib/components/map-page/map-settings-modal.svelte
+++ b/web/src/lib/components/map-page/map-settings-modal.svelte
@@ -1,15 +1,6 @@
-<script lang="ts" context="module">
-	export interface MapSettings {
-		allowDarkMode: boolean;
-		onlyFavorites: boolean;
-		relativeDate: string;
-		dateAfter: string;
-		dateBefore: string;
-	}
-</script>
-
 <script lang="ts">
 	import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
+	import type { MapSettings } from '$lib/stores/preferences.store';
 	import { Duration } from 'luxon';
 	import { createEventDispatcher } from 'svelte';
 	import { fly } from 'svelte/transition';
diff --git a/web/src/lib/components/photos-page/asset-date-group.svelte b/web/src/lib/components/photos-page/asset-date-group.svelte
index 3b000d6a2..a9e704ab1 100644
--- a/web/src/lib/components/photos-page/asset-date-group.svelte
+++ b/web/src/lib/components/photos-page/asset-date-group.svelte
@@ -1,10 +1,4 @@
 <script lang="ts">
-	import { assetStore } from '$lib/stores/assets.store';
-	import CheckCircle from 'svelte-material-icons/CheckCircle.svelte';
-	import CircleOutline from 'svelte-material-icons/CircleOutline.svelte';
-	import { fly } from 'svelte/transition';
-	import { AssetResponseDto } from '@api';
-	import lodash from 'lodash-es';
 	import {
 		assetInteractionStore,
 		assetsInAlbumStoreState,
@@ -12,9 +6,15 @@
 		selectedAssets,
 		selectedGroup
 	} from '$lib/stores/asset-interaction.store';
+	import { assetStore } from '$lib/stores/assets.store';
 	import { locale } from '$lib/stores/preferences.store';
-	import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
+	import type { AssetResponseDto } from '@api';
+	import lodash from 'lodash-es';
+	import CheckCircle from 'svelte-material-icons/CheckCircle.svelte';
+	import CircleOutline from 'svelte-material-icons/CircleOutline.svelte';
 	import { flip } from 'svelte/animate';
+	import { fly } from 'svelte/transition';
+	import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
 
 	export let assets: AssetResponseDto[];
 	export let bucketDate: string;
diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte
index dc2eac76c..0adbe217a 100644
--- a/web/src/lib/components/photos-page/asset-grid.svelte
+++ b/web/src/lib/components/photos-page/asset-grid.svelte
@@ -1,22 +1,21 @@
 <script lang="ts">
-	import { onDestroy, onMount } from 'svelte';
-
-	import { UserResponseDto } from '@api';
-	import IntersectionObserver from '../asset-viewer/intersection-observer.svelte';
-	import { assetGridState, assetStore, loadingBucketState } from '$lib/stores/assets.store';
-	import { api, AssetCountByTimeBucketResponseDto, AssetResponseDto, TimeGroupEnum } from '@api';
-	import AssetDateGroup from './asset-date-group.svelte';
-	import Portal from '../shared-components/portal/portal.svelte';
-	import AssetViewer from '../asset-viewer/asset-viewer.svelte';
 	import {
 		assetInteractionStore,
 		isViewingAssetStoreState,
 		viewingAssetStoreState
 	} from '$lib/stores/asset-interaction.store';
+	import { assetGridState, assetStore, loadingBucketState } from '$lib/stores/assets.store';
+	import type { UserResponseDto } from '@api';
+	import { AssetCountByTimeBucketResponseDto, AssetResponseDto, TimeGroupEnum, api } from '@api';
+	import { onDestroy, onMount } from 'svelte';
+	import AssetViewer from '../asset-viewer/asset-viewer.svelte';
+	import IntersectionObserver from '../asset-viewer/intersection-observer.svelte';
+	import Portal from '../shared-components/portal/portal.svelte';
 	import Scrollbar, {
 		OnScrollbarClickDetail,
 		OnScrollbarDragDetail
 	} from '../shared-components/scrollbar/scrollbar.svelte';
+	import AssetDateGroup from './asset-date-group.svelte';
 
 	export let user: UserResponseDto | undefined = undefined;
 	export let isAlbumSelectionMode = false;
diff --git a/web/src/lib/components/photos-page/asset-select-control-bar.svelte b/web/src/lib/components/photos-page/asset-select-control-bar.svelte
index ceb6c6aab..3e0f4bcca 100644
--- a/web/src/lib/components/photos-page/asset-select-control-bar.svelte
+++ b/web/src/lib/components/photos-page/asset-select-control-bar.svelte
@@ -17,7 +17,7 @@
 
 <script lang="ts">
 	import { locale } from '$lib/stores/preferences.store';
-	import { AssetResponseDto } from '@api';
+	import type { AssetResponseDto } from '@api';
 	import Close from 'svelte-material-icons/Close.svelte';
 	import ControlAppBar from '../shared-components/control-app-bar.svelte';
 
diff --git a/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte b/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte
index 8391467b6..32fb22d08 100644
--- a/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte
+++ b/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte
@@ -1,23 +1,23 @@
 <script lang="ts">
-	import { createEventDispatcher, onMount } from 'svelte';
-	import BaseModal from '../base-modal.svelte';
-	import Link from 'svelte-material-icons/Link.svelte';
-	import {
-		AlbumResponseDto,
-		api,
-		AssetResponseDto,
-		SharedLinkResponseDto,
-		SharedLinkType
-	} from '@api';
-	import { notificationController, NotificationType } from '../notification/notification';
-	import { ImmichDropDownOption } from '../dropdown-button.svelte';
-	import SettingSwitch from '$lib/components/admin-page/settings/setting-switch.svelte';
-	import DropdownButton from '../dropdown-button.svelte';
 	import SettingInputField, {
 		SettingInputFieldType
 	} from '$lib/components/admin-page/settings/setting-input-field.svelte';
-	import { handleError } from '$lib/utils/handle-error';
+	import SettingSwitch from '$lib/components/admin-page/settings/setting-switch.svelte';
 	import Button from '$lib/components/elements/buttons/button.svelte';
+	import { handleError } from '$lib/utils/handle-error';
+	import {
+		AlbumResponseDto,
+		AssetResponseDto,
+		SharedLinkResponseDto,
+		SharedLinkType,
+		api
+	} from '@api';
+	import { createEventDispatcher, onMount } from 'svelte';
+	import Link from 'svelte-material-icons/Link.svelte';
+	import BaseModal from '../base-modal.svelte';
+	import type { ImmichDropDownOption } from '../dropdown-button.svelte';
+	import DropdownButton from '../dropdown-button.svelte';
+	import { NotificationType, notificationController } from '../notification/notification';
 
 	export let shareType: SharedLinkType;
 	export let sharedAssets: AssetResponseDto[] = [];
diff --git a/web/src/lib/components/shared-components/leaflet/marker-cluster/asset-marker-cluster.svelte b/web/src/lib/components/shared-components/leaflet/marker-cluster/asset-marker-cluster.svelte
index dcd5ddece..15288b2a1 100644
--- a/web/src/lib/components/shared-components/leaflet/marker-cluster/asset-marker-cluster.svelte
+++ b/web/src/lib/components/shared-components/leaflet/marker-cluster/asset-marker-cluster.svelte
@@ -10,7 +10,7 @@
 </script>
 
 <script lang="ts">
-	import { MapMarkerResponseDto } from '@api';
+	import type { MapMarkerResponseDto } from '@api';
 	import { DivIcon, LeafletEvent, LeafletMouseEvent, MarkerCluster, Point } from 'leaflet';
 	import 'leaflet.markercluster';
 	import { createEventDispatcher, onDestroy, onMount } from 'svelte';
diff --git a/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte b/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte
index 719ed42de..c9efdeffa 100644
--- a/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte
+++ b/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte
@@ -1,12 +1,12 @@
 <script lang="ts">
-	import { UserResponseDto } from '@api';
+	import Button from '$lib/components/elements/buttons/button.svelte';
+	import { AppRoute } from '$lib/constants';
+	import type { UserResponseDto } from '@api';
 	import { createEventDispatcher } from 'svelte';
-	import { fade } from 'svelte/transition';
 	import Cog from 'svelte-material-icons/Cog.svelte';
 	import Logout from 'svelte-material-icons/Logout.svelte';
-	import Button from '$lib/components/elements/buttons/button.svelte';
+	import { fade } from 'svelte/transition';
 	import UserAvatar from '../user-avatar.svelte';
-	import { AppRoute } from '$lib/constants';
 
 	export let user: UserResponseDto;
 
diff --git a/web/src/lib/components/shared-components/upload-asset-preview.svelte b/web/src/lib/components/shared-components/upload-asset-preview.svelte
index bccb1f79f..b417b85d6 100644
--- a/web/src/lib/components/shared-components/upload-asset-preview.svelte
+++ b/web/src/lib/components/shared-components/upload-asset-preview.svelte
@@ -1,9 +1,9 @@
 <script lang="ts">
-	import { fade } from 'svelte/transition';
-	import { asByteUnitString } from '$lib/utils/byte-units';
-	import { UploadAsset } from '$lib/models/upload-asset';
-	import ImmichLogo from './immich-logo.svelte';
+	import type { UploadAsset } from '$lib/models/upload-asset';
 	import { locale } from '$lib/stores/preferences.store';
+	import { asByteUnitString } from '$lib/utils/byte-units';
+	import { fade } from 'svelte/transition';
+	import ImmichLogo from './immich-logo.svelte';
 
 	export let uploadAsset: UploadAsset;
 
diff --git a/web/src/lib/components/user-settings-page/device-card.svelte b/web/src/lib/components/user-settings-page/device-card.svelte
index 2b9003207..b55d54f7e 100644
--- a/web/src/lib/components/user-settings-page/device-card.svelte
+++ b/web/src/lib/components/user-settings-page/device-card.svelte
@@ -1,6 +1,6 @@
 <script lang="ts">
 	import { locale } from '$lib/stores/preferences.store';
-	import { AuthDeviceResponseDto } from '@api';
+	import type { AuthDeviceResponseDto } from '@api';
 	import { DateTime, ToRelativeCalendarOptions } from 'luxon';
 	import { createEventDispatcher } from 'svelte';
 	import Android from 'svelte-material-icons/Android.svelte';
diff --git a/web/src/lib/models/asset-grid-state.ts b/web/src/lib/models/asset-grid-state.ts
index 23e015edb..464fb5519 100644
--- a/web/src/lib/models/asset-grid-state.ts
+++ b/web/src/lib/models/asset-grid-state.ts
@@ -1,4 +1,4 @@
-import { AssetResponseDto } from '@api';
+import type { AssetResponseDto } from '@api';
 
 export class AssetBucket {
 	/**
diff --git a/web/src/lib/stores/archived-asset.store.ts b/web/src/lib/stores/archived-asset.store.ts
index 6168d29e9..4e478580d 100644
--- a/web/src/lib/stores/archived-asset.store.ts
+++ b/web/src/lib/stores/archived-asset.store.ts
@@ -1,4 +1,4 @@
-import { AssetResponseDto } from '@api';
+import type { AssetResponseDto } from '@api';
 import { writable } from 'svelte/store';
 
 export const archivedAsset = writable<AssetResponseDto[]>([]);
diff --git a/web/src/lib/stores/preferences.store.ts b/web/src/lib/stores/preferences.store.ts
index e5c6a154f..b0f491a3a 100644
--- a/web/src/lib/stores/preferences.store.ts
+++ b/web/src/lib/stores/preferences.store.ts
@@ -1,5 +1,4 @@
 import { browser } from '$app/environment';
-import { MapSettings } from '$lib/components/map-page/map-settings-modal.svelte';
 import { persisted } from 'svelte-local-storage-store';
 
 const initialTheme =
@@ -21,6 +20,14 @@ export const locale = persisted<string | undefined>('locale', undefined, {
 	}
 });
 
+export interface MapSettings {
+	allowDarkMode: boolean;
+	onlyFavorites: boolean;
+	relativeDate: string;
+	dateAfter: string;
+	dateBefore: string;
+}
+
 export const mapSettings = persisted<MapSettings>('map-settings', {
 	allowDarkMode: true,
 	onlyFavorites: false,
diff --git a/web/src/lib/utils/file-uploader.ts b/web/src/lib/utils/file-uploader.ts
index e825d0eb7..9f91ff047 100644
--- a/web/src/lib/utils/file-uploader.ts
+++ b/web/src/lib/utils/file-uploader.ts
@@ -1,13 +1,13 @@
+import { uploadAssetsStore } from '$lib/stores/upload';
+import { addAssetsToAlbum, getFileMimeType, getFilenameExtension } from '$lib/utils/asset-utils';
+import type { AssetFileUploadResponseDto } from '@api';
+import axios from 'axios';
+import { combineLatestAll, filter, firstValueFrom, from, mergeMap, of } from 'rxjs';
+import type { UploadAsset } from '../models/upload-asset';
 import {
 	notificationController,
 	NotificationType
 } from './../components/shared-components/notification/notification';
-import { uploadAssetsStore } from '$lib/stores/upload';
-import type { UploadAsset } from '../models/upload-asset';
-import { AssetFileUploadResponseDto } from '@api';
-import { addAssetsToAlbum, getFileMimeType, getFilenameExtension } from '$lib/utils/asset-utils';
-import { mergeMap, filter, firstValueFrom, from, of, combineLatestAll } from 'rxjs';
-import axios from 'axios';
 
 export const openFileUploadDialog = async (
 	albumId: string | undefined = undefined,
diff --git a/web/src/lib/utils/handle-error.ts b/web/src/lib/utils/handle-error.ts
index 5751ef909..853b88758 100644
--- a/web/src/lib/utils/handle-error.ts
+++ b/web/src/lib/utils/handle-error.ts
@@ -1,4 +1,4 @@
-import { ApiError } from '../../api';
+import type { ApiError } from '@api';
 import {
 	notificationController,
 	NotificationType
diff --git a/web/src/routes/(user)/albums/albums.bloc.ts b/web/src/routes/(user)/albums/albums.bloc.ts
index ceca7db14..537ce33f1 100644
--- a/web/src/routes/(user)/albums/albums.bloc.ts
+++ b/web/src/routes/(user)/albums/albums.bloc.ts
@@ -1,10 +1,10 @@
+import type { OnShowContextMenuDetail } from '$lib/components/album-page/album-card';
 import {
 	notificationController,
 	NotificationType
 } from '$lib/components/shared-components/notification/notification';
 import { AlbumResponseDto, api } from '@api';
-import { OnShowContextMenuDetail } from '$lib/components/album-page/album-card.svelte';
-import { writable, derived, get } from 'svelte/store';
+import { derived, get, writable } from 'svelte/store';
 
 type AlbumsProps = { albums: AlbumResponseDto[] };
 
diff --git a/web/src/routes/(user)/search/+page.svelte b/web/src/routes/(user)/search/+page.svelte
index 1c215834f..f4230b8c0 100644
--- a/web/src/routes/(user)/search/+page.svelte
+++ b/web/src/routes/(user)/search/+page.svelte
@@ -12,7 +12,7 @@
 	import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
 	import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
 	import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
-	import { AssetResponseDto } from '@api';
+	import type { AssetResponseDto } from '@api';
 	import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
 	import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
 	import ImageOffOutline from 'svelte-material-icons/ImageOffOutline.svelte';
diff --git a/web/src/test-data/factories/album-factory.ts b/web/src/test-data/factories/album-factory.ts
index 2b01054d9..fc0861d21 100644
--- a/web/src/test-data/factories/album-factory.ts
+++ b/web/src/test-data/factories/album-factory.ts
@@ -1,6 +1,7 @@
-import { AlbumResponseDto } from '@api';
-import { Sync } from 'factory.ts';
+import type { AlbumResponseDto } from '@api';
 import { faker } from '@faker-js/faker';
+import { Sync } from 'factory.ts';
+import { userFactory } from './user-factory';
 
 export const albumFactory = Sync.makeFactory<AlbumResponseDto>({
 	albumName: Sync.each(() => faker.commerce.product()),
@@ -8,8 +9,10 @@ export const albumFactory = Sync.makeFactory<AlbumResponseDto>({
 	assetCount: Sync.each((i) => i % 5),
 	assets: [],
 	createdAt: Sync.each(() => faker.date.past().toISOString()),
+	updatedAt: Sync.each(() => faker.date.past().toISOString()),
 	id: Sync.each(() => faker.datatype.uuid()),
 	ownerId: Sync.each(() => faker.datatype.uuid()),
+	owner: userFactory.build(),
 	shared: false,
 	sharedUsers: []
 });
diff --git a/web/src/test-data/factories/user-factory.ts b/web/src/test-data/factories/user-factory.ts
new file mode 100644
index 000000000..f4e5b21eb
--- /dev/null
+++ b/web/src/test-data/factories/user-factory.ts
@@ -0,0 +1,18 @@
+import type { UserResponseDto } from '@api';
+import { faker } from '@faker-js/faker';
+import { Sync } from 'factory.ts';
+
+export const userFactory = Sync.makeFactory<UserResponseDto>({
+	id: Sync.each(() => faker.datatype.uuid()),
+	email: Sync.each(() => faker.internet.email()),
+	firstName: Sync.each(() => faker.name.firstName()),
+	lastName: Sync.each(() => faker.name.lastName()),
+	storageLabel: Sync.each(() => faker.random.alphaNumeric()),
+	profileImagePath: '',
+	shouldChangePassword: Sync.each(() => faker.datatype.boolean()),
+	isAdmin: true,
+	createdAt: Sync.each(() => faker.date.past().toISOString()),
+	deletedAt: null,
+	updatedAt: Sync.each(() => faker.date.past().toISOString()),
+	oauthId: ''
+});
diff --git a/web/tsconfig.json b/web/tsconfig.json
index c9b1460dc..a118602cd 100644
--- a/web/tsconfig.json
+++ b/web/tsconfig.json
@@ -16,7 +16,6 @@
     "sourceMap": true,
     "strict": true,
     "target": "es2020",
-    "importsNotUsedAsValues": "preserve",
     "preserveValueImports": false,
     "paths": {
       "$lib": [