diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 6b7095305f..4f487990c2 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,10 +3,11 @@
   "isRoot": true,
   "tools": {
     "dotnet-ef": {
-      "version": "8.0.10",
+      "version": "9.0.0",
       "commands": [
         "dotnet-ef"
-      ]
+      ],
+      "rollForward": false
     }
   }
-}
+}
\ No newline at end of file
diff --git a/.github/workflows/fw-lite.yaml b/.github/workflows/fw-lite.yaml
index 37043dfdab..f36d825e6b 100644
--- a/.github/workflows/fw-lite.yaml
+++ b/.github/workflows/fw-lite.yaml
@@ -35,10 +35,14 @@ jobs:
           submodules: true
       - uses: actions/setup-dotnet@v4
         with:
-          dotnet-version: '8.x'
+          dotnet-version: '9.x'
       - uses: actions/setup-node@v4
         with:
           node-version-file: './frontend/package.json'
+
+      - name: Setup Maui
+        run: dotnet workload install maui-windows
+
       - name: Set Version
         id: setVersion
         shell: bash
@@ -86,7 +90,7 @@ jobs:
           path: frontend/viewer/dist
       - uses: actions/setup-dotnet@v4
         with:
-          dotnet-version: '8.x'
+          dotnet-version: '9.x'
 
       - name: Dotnet build
         working-directory: backend/FwLite/LocalWebApp
@@ -123,7 +127,7 @@ jobs:
           path: frontend/viewer/dist
       - uses: actions/setup-dotnet@v4
         with:
-          dotnet-version: '8.x'
+          dotnet-version: '9.x'
 
       - name: Dotnet build
         working-directory: backend/FwLite/LocalWebApp
@@ -156,7 +160,7 @@ jobs:
           path: frontend/viewer/dist
       - uses: actions/setup-dotnet@v4
         with:
-          dotnet-version: '8.x'
+          dotnet-version: '9.x'
 
       - name: Setup Maui
         run: dotnet workload install maui-windows
diff --git a/.github/workflows/integration-test-gha.yaml b/.github/workflows/integration-test-gha.yaml
index a604eea411..1e2315e21e 100644
--- a/.github/workflows/integration-test-gha.yaml
+++ b/.github/workflows/integration-test-gha.yaml
@@ -22,6 +22,9 @@ jobs:
       - uses: actions/checkout@v4
         with:
           submodules: true
+      - uses: actions/setup-dotnet@v4
+        with:
+          dotnet-version: '9.x'
       - name: Install Task
         uses: arduino/setup-task@v2
         with:
diff --git a/.github/workflows/integration-test.yaml b/.github/workflows/integration-test.yaml
index d353111212..e39d17716d 100644
--- a/.github/workflows/integration-test.yaml
+++ b/.github/workflows/integration-test.yaml
@@ -85,7 +85,7 @@ jobs:
         env:
           DOTNET_INSTALL_DIR: ${{ inputs.runs-on == 'self-hosted' && '/opt/hostedtoolcache/dotnet' || '' }} #poor man's conditional
         with:
-          dotnet-version: '8.x'
+          dotnet-version: '9.x'
       - uses: MatteoH2O1999/setup-python@429b7dee8a48c31eb72ce0b420ea938ff51c2f11 # v3.2.1
         id: python
         if: ${{ inputs.runs-on != 'windows-latest' && !env.act && inputs.hg-version == '3' }}
diff --git a/.github/workflows/lexbox-api.yaml b/.github/workflows/lexbox-api.yaml
index d0774bcd05..135e5ae955 100644
--- a/.github/workflows/lexbox-api.yaml
+++ b/.github/workflows/lexbox-api.yaml
@@ -49,7 +49,7 @@ jobs:
           submodules: true
       - uses: actions/setup-dotnet@v4
         with:
-          dotnet-version: '8.x'
+          dotnet-version: '9.x'
       - name: Install Task
         uses: arduino/setup-task@v2
         with:
diff --git a/Taskfile.yml b/Taskfile.yml
index 0306ea6741..ec5513e7e5 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -68,7 +68,12 @@ tasks:
     cmds:
       - tilt up
 
-      # dev
+  prod-ui-up:
+    interactive: true
+    desc: 'Starts the cluster using the production build of UI, good for automated testing'
+    cmds:
+      - tilt up -- --prod-ui-build
+    # dev
   infra-up:
     desc: 'Starts infrastructure for our ui and api, does not forward ports for api, if you want port forwarding use k8s:infra-forward'
     cmds:
diff --git a/Tiltfile b/Tiltfile
index 061bdb63d8..224a00bcf0 100644
--- a/Tiltfile
+++ b/Tiltfile
@@ -4,8 +4,10 @@
 version_settings(constraint='>=0.33.20')
 secret_settings(disable_scrub=True)
 config.define_bool("lexbox-api-local")
+config.define_bool("prod-ui-build")
 cfg = config.parse()
 forward_lexbox = not cfg.get("lexbox-api-local", False)
+prod_ui_build = cfg.get("prod-ui-build", False)
 
 docker_build(
     'local-dev-init',
@@ -33,16 +35,23 @@ docker_build(
         sync('backend', '/src/backend')
     ]
 )
-
-docker_build(
-    'ghcr.io/sillsdev/lexbox-ui',
-    context='frontend',
-    dockerfile='./frontend/dev.Dockerfile',
-    only=['.'],
-    live_update=[
-        sync('frontend', '/app'),
-    ]
-)
+if prod_ui_build:
+    docker_build(
+        'ghcr.io/sillsdev/lexbox-ui',
+        context='frontend',
+        dockerfile='./frontend/Dockerfile',
+        only=['.']
+    )
+else:
+    docker_build(
+        'ghcr.io/sillsdev/lexbox-ui',
+        context='frontend',
+        dockerfile='./frontend/dev.Dockerfile',
+        only=['.'],
+        live_update=[
+            sync('frontend', '/app'),
+        ]
+    )
 
 docker_build(
     'ghcr.io/sillsdev/lexbox-hgweb',
diff --git a/backend/Directory.Build.props b/backend/Directory.Build.props
index e703205863..574e961efe 100644
--- a/backend/Directory.Build.props
+++ b/backend/Directory.Build.props
@@ -9,7 +9,10 @@
         <BaseOutputPath>$(MSBuildProjectDirectory)/bin/container/</BaseOutputPath>
     </PropertyGroup>
     <PropertyGroup>
+        <InformationalVersion>dev</InformationalVersion>
+        <TargetFramework>net9.0</TargetFramework>
         <EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
+        <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
         <WarningsAsErrors>Nullable</WarningsAsErrors>
     </PropertyGroup>
diff --git a/backend/Dockerfile b/backend/Dockerfile
index 4c4630a7fd..3a43c094f1 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -1,10 +1,10 @@
 # syntax=docker/dockerfile:1
-FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
+FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
 WORKDIR /app
 EXPOSE 80
 EXPOSE 443
 
-FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
 
 COPY . .
 # WORKDIR /src
diff --git a/backend/FixFwData/FixFwData.csproj b/backend/FixFwData/FixFwData.csproj
index 7c217f1732..e96561fcad 100644
--- a/backend/FixFwData/FixFwData.csproj
+++ b/backend/FixFwData/FixFwData.csproj
@@ -2,14 +2,17 @@
 
   <PropertyGroup>
     <OutputType>WinExe</OutputType>
-    <TargetFramework>net8.0</TargetFramework>
-    <ImplicitUsings>enable</ImplicitUsings>
-    <Nullable>enable</Nullable>
+    <RootNamespace>FixFwData</RootNamespace>
+    <Description>FixFwData</Description>
+    <Company>SIL Global</Company>
+    <Authors>SIL Global</Authors>
+    <Product>LexBoxApi Testing</Product>
+    <Copyright>Copyright © 2024 SIL Global</Copyright>
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
-    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
+    <PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
     <PackageReference Include="SIL.LCModel.FixData" Version="11.0.0-beta0109" />
   </ItemGroup>
 </Project>
diff --git a/backend/FwHeadless/FwHeadless.csproj b/backend/FwHeadless/FwHeadless.csproj
index 82dcf05216..a106c1fa54 100644
--- a/backend/FwHeadless/FwHeadless.csproj
+++ b/backend/FwHeadless/FwHeadless.csproj
@@ -1,17 +1,15 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
-    <TargetFramework>net9.0</TargetFramework>
-    <Nullable>enable</Nullable>
-    <ImplicitUsings>enable</ImplicitUsings>
     <Mercurial4ChorusDestDir>$(MSBuildProjectDirectory)</Mercurial4ChorusDestDir>
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0-rc.1.24452.1" />
+    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
     <PackageReference Include="Scalar.AspNetCore" Version="1.2.22" />
     <PackageReference Include="SIL.ChorusPlugin.LfMergeBridge" Version="4.2.0-beta0027" />
     <PackageReference Include="SIL.Chorus.Mercurial" Version="6.5.1.*" />
+    <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.0" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/backend/FwHeadless/dev.Dockerfile b/backend/FwHeadless/dev.Dockerfile
index db60a422c2..38a83bf9de 100644
--- a/backend/FwHeadless/dev.Dockerfile
+++ b/backend/FwHeadless/dev.Dockerfile
@@ -11,13 +11,13 @@ WORKDIR /src/backend
 # Uncomment line below if second COPY fails
 # RUN mkdir -p FwLite && chown www-data:www-data FwLite
 # Copy the main source project files
-COPY --chown=www-data:www-data *.sln FwHeadless/FwHeadless.csproj FixFwData/FixFwData.csproj LexCore/LexCore.csproj LexData/LexData.csproj ./
+COPY --chown=www-data:www-data *.sln FwHeadless/FwHeadless.csproj FixFwData/FixFwData.csproj LexCore/LexCore.csproj LexData/LexData.csproj Directory.Build.props ./
 # move them into the proper sub folders, based on the name of the project
 RUN for file in $(ls *.csproj); do dir=${file%.*}; mkdir -p ${dir}/ && mv -v $file ${dir}/; done
 # Do the same for csproj files in slightly different hierarchies
 COPY --chown=www-data:www-data harmony/src/*/*.csproj ./
 RUN for file in $(ls *.csproj); do dir=${file%.*}; mkdir -p harmony/src/${dir}/ && mv -v $file harmony/src/${dir}/; done
-COPY --chown=www-data:www-data harmony/src/Directory.Build.props ./harmony/src/
+COPY --chown=www-data:www-data harmony/src/Directory.Build.props harmony/Directory.Packages.props ./harmony/src/
 COPY --chown=www-data:www-data FwLite/FwDataMiniLcmBridge/FwDataMiniLcmBridge.csproj FwLite/LcmCrdt/LcmCrdt.csproj FwLite/MiniLcm/MiniLcm.csproj FwLite/FwLiteProjectSync/FwLiteProjectSync.csproj ./
 RUN for file in $(ls *.csproj); do dir=${file%.*}; mkdir -p FwLite/${dir}/ && mv -v $file FwLite/${dir}/; done
 
diff --git a/backend/FwLite/FwDataMiniLcmBridge.Tests/Fixtures/MockFwProjectList.cs b/backend/FwLite/FwDataMiniLcmBridge.Tests/Fixtures/MockFwProjectList.cs
index 43e3a65b80..6463670c1a 100644
--- a/backend/FwLite/FwDataMiniLcmBridge.Tests/Fixtures/MockFwProjectList.cs
+++ b/backend/FwLite/FwDataMiniLcmBridge.Tests/Fixtures/MockFwProjectList.cs
@@ -7,7 +7,7 @@ public class MockFwProjectList(IOptions<FwDataBridgeConfig> config, MockFwProjec
 {
     public override IEnumerable<IProjectIdentifier> EnumerateProjects()
     {
-        return loader.Projects.Keys.Select(k => new FwDataProject(k, config.Value.ProjectsFolder));
+        return loader.Projects.Keys.Select(k => new FwDataProject(k, _config.Value.ProjectsFolder));
     }
 
     public override FwDataProject? GetProject(string name)
diff --git a/backend/FwLite/FwDataMiniLcmBridge.Tests/FwDataMiniLcmBridge.Tests.csproj b/backend/FwLite/FwDataMiniLcmBridge.Tests/FwDataMiniLcmBridge.Tests.csproj
index f2ff05e5d6..c7f4be0c09 100644
--- a/backend/FwLite/FwDataMiniLcmBridge.Tests/FwDataMiniLcmBridge.Tests.csproj
+++ b/backend/FwLite/FwDataMiniLcmBridge.Tests/FwDataMiniLcmBridge.Tests.csproj
@@ -1,9 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
 
         <IsPackable>false</IsPackable>
         <IsTestProject>true</IsTestProject>
@@ -18,16 +15,16 @@
           <PrivateAssets>all</PrivateAssets>
           <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
         </PackageReference>
-        <PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
-        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
-        <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1"/>
+        <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
+        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
+        <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0" />
         <PackageReference Include="FluentAssertions" Version="7.0.0-alpha.5"/>
-        <PackageReference Include="xunit" Version="2.9.0" />
+        <PackageReference Include="xunit" Version="2.9.2" />
         <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
-          <PrivateAssets>all</PrivateAssets>
-          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+            <PrivateAssets>all</PrivateAssets>
+            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
         </PackageReference>
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
     </ItemGroup>
 
     <ItemGroup>
diff --git a/backend/FwLite/FwDataMiniLcmBridge/FieldWorksProjectList.cs b/backend/FwLite/FwDataMiniLcmBridge/FieldWorksProjectList.cs
index 47cb91b575..f77bf944c8 100644
--- a/backend/FwLite/FwDataMiniLcmBridge/FieldWorksProjectList.cs
+++ b/backend/FwLite/FwDataMiniLcmBridge/FieldWorksProjectList.cs
@@ -6,15 +6,17 @@ namespace FwDataMiniLcmBridge;
 
 public class FieldWorksProjectList(IOptions<FwDataBridgeConfig> config)
 {
+    protected readonly IOptions<FwDataBridgeConfig> _config = config;
+
     public virtual IEnumerable<IProjectIdentifier> EnumerateProjects()
     {
-        if (!Directory.Exists(config.Value.ProjectsFolder)) Directory.CreateDirectory(config.Value.ProjectsFolder);
-        foreach (var directory in Directory.EnumerateDirectories(config.Value.ProjectsFolder))
+        if (!Directory.Exists(_config.Value.ProjectsFolder)) Directory.CreateDirectory(_config.Value.ProjectsFolder);
+        foreach (var directory in Directory.EnumerateDirectories(_config.Value.ProjectsFolder))
         {
             var projectName = Path.GetFileName(directory);
             if (string.IsNullOrEmpty(projectName)) continue;
             if (!File.Exists(Path.Combine(directory, projectName + ".fwdata"))) continue;
-            yield return new FwDataProject(projectName, config.Value.ProjectsFolder);
+            yield return new FwDataProject(projectName, _config.Value.ProjectsFolder);
         }
     }
 
diff --git a/backend/FwLite/FwDataMiniLcmBridge/FwDataMiniLcmBridge.csproj b/backend/FwLite/FwDataMiniLcmBridge/FwDataMiniLcmBridge.csproj
index 5ab11b140b..dd6ae37436 100644
--- a/backend/FwLite/FwDataMiniLcmBridge/FwDataMiniLcmBridge.csproj
+++ b/backend/FwLite/FwDataMiniLcmBridge/FwDataMiniLcmBridge.csproj
@@ -1,25 +1,22 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
         <InformationalVersion>$(ApplicationDisplayVersion)</InformationalVersion>
         <FileVersion>$(ApplicationDisplayVersion)</FileVersion>
     </PropertyGroup>
     <ItemGroup>
-        <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
-        <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
-        <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
-        <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
-        <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
+        <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.0" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
+        <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0" />
+        <PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
+        <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0" />
         <PackageReference Include="SIL.Core" Version="14.2.0-beta0022" />
         <PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="72.1.0.3" Condition="$([MSBuild]::IsOsPlatform('Windows'))" />
         <PackageReference Include="SIL.LCModel" Version="11.0.0-beta0111" />
         <PackageReference Include="structuremap.patched" Version="4.7.3" />
         <PackageReference Include="System.Linq.Async" Version="6.0.1" />
         <PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
+        <PackageReference Include="System.Private.Uri" Version="4.3.2" />
         <PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />
     </ItemGroup>
 
diff --git a/backend/FwLite/FwLiteDesktop/FwLiteDesktop.csproj b/backend/FwLite/FwLiteDesktop/FwLiteDesktop.csproj
index 043dacd5d9..71ce7fca5e 100644
--- a/backend/FwLite/FwLiteDesktop/FwLiteDesktop.csproj
+++ b/backend/FwLite/FwLiteDesktop/FwLiteDesktop.csproj
@@ -2,7 +2,7 @@
 
 	<PropertyGroup>
 <!--        for now we only target windows-->
-        <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
+        <TargetFramework>net9.0-windows10.0.19041.0</TargetFramework>
 <!--		<TargetFrameworks Condition="!$([MSBuild]::IsOSPlatform('windows'))">net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>-->
 <!--		<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>-->
 		<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
@@ -80,7 +80,7 @@
 	<ItemGroup>
 		<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
 		<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
-		<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
+		<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0" />
         <PackageReference Include="NReco.Logging.File" Version="1.2.1" />
 	</ItemGroup>
 
diff --git a/backend/FwLite/FwLiteProjectSync.Tests/FwLiteProjectSync.Tests.csproj b/backend/FwLite/FwLiteProjectSync.Tests/FwLiteProjectSync.Tests.csproj
index 0858009d0f..abe85567f5 100644
--- a/backend/FwLite/FwLiteProjectSync.Tests/FwLiteProjectSync.Tests.csproj
+++ b/backend/FwLite/FwLiteProjectSync.Tests/FwLiteProjectSync.Tests.csproj
@@ -1,10 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
-
         <IsPackable>false</IsPackable>
         <IsTestProject>true</IsTestProject>
         <Mercurial4ChorusDestDir>$(MSBuildProjectDirectory)</Mercurial4ChorusDestDir>
@@ -19,16 +15,16 @@
           <PrivateAssets>all</PrivateAssets>
           <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
         </PackageReference>
-        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
-        <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1"/>
+        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
+        <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0"/>
         <PackageReference Include="FluentAssertions" Version="7.0.0-alpha.5"/>
         <PackageReference Include="Soenneker.Utils.AutoBogus" Version="3.0.410" />
-        <PackageReference Include="xunit" Version="2.9.0" />
+        <PackageReference Include="xunit" Version="2.9.2" />
         <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
-          <PrivateAssets>all</PrivateAssets>
-          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+            <PrivateAssets>all</PrivateAssets>
+            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
         </PackageReference>
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1"/>
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0"/>
         <PackageReference Include="SIL.ChorusPlugin.LfMergeBridge" Version="4.2.0-beta0028" />
         <PackageReference Include="SIL.Chorus.Mercurial" Version="6.5.1.*" />
     </ItemGroup>
diff --git a/backend/FwLite/FwLiteProjectSync/FwLiteProjectSync.csproj b/backend/FwLite/FwLiteProjectSync/FwLiteProjectSync.csproj
index 2d0c452f06..8cbde01b83 100644
--- a/backend/FwLite/FwLiteProjectSync/FwLiteProjectSync.csproj
+++ b/backend/FwLite/FwLiteProjectSync/FwLiteProjectSync.csproj
@@ -1,9 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
         <InformationalVersion>$(ApplicationDisplayVersion)</InformationalVersion>
         <FileVersion>$(ApplicationDisplayVersion)</FileVersion>
     </PropertyGroup>
@@ -14,8 +11,8 @@
     </ItemGroup>
 
     <ItemGroup>
-      <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
-      <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
+      <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
+      <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0" />
       <PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
     </ItemGroup>
 
diff --git a/backend/FwLite/LcmCrdt.Tests/DataModelSnapshotTests.VerifyDbModel.verified.txt b/backend/FwLite/LcmCrdt.Tests/DataModelSnapshotTests.VerifyDbModel.verified.txt
index 129ee865c9..5e1e13fe72 100644
--- a/backend/FwLite/LcmCrdt.Tests/DataModelSnapshotTests.VerifyDbModel.verified.txt
+++ b/backend/FwLite/LcmCrdt.Tests/DataModelSnapshotTests.VerifyDbModel.verified.txt
@@ -335,4 +335,4 @@
       Relational:ViewName: 
       Relational:ViewSchema: 
 Annotations: 
-  ProductVersion: 8.0.4
\ No newline at end of file
+  ProductVersion: 8.0.11
\ No newline at end of file
diff --git a/backend/FwLite/LcmCrdt.Tests/LcmCrdt.Tests.csproj b/backend/FwLite/LcmCrdt.Tests/LcmCrdt.Tests.csproj
index 9f03df7437..82a3eb3d85 100644
--- a/backend/FwLite/LcmCrdt.Tests/LcmCrdt.Tests.csproj
+++ b/backend/FwLite/LcmCrdt.Tests/LcmCrdt.Tests.csproj
@@ -1,9 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
 
         <IsPackable>false</IsPackable>
         <IsTestProject>true</IsTestProject>
@@ -15,14 +12,14 @@
           <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
         </PackageReference>
         <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
-        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
+        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
         <PackageReference Include="FluentAssertions" Version="7.0.0-alpha.5"/>
         <PackageReference Include="Soenneker.Utils.AutoBogus" Version="3.0.410" />
-        <PackageReference Include="Verify.Xunit" Version="27.0.1" />
+        <PackageReference Include="Verify.Xunit" Version="28.2.1" />
         <PackageReference Include="xunit" Version="2.9.2" />
         <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
-          <PrivateAssets>all</PrivateAssets>
-          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+            <PrivateAssets>all</PrivateAssets>
+            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
         </PackageReference>
         <PackageReference Include="GitHubActionsTestLogger" Version="2.4.1">
             <PrivateAssets>all</PrivateAssets>
diff --git a/backend/FwLite/LcmCrdt.Tests/OpenProjectTests.cs b/backend/FwLite/LcmCrdt.Tests/OpenProjectTests.cs
index cdaa72ab05..702431f668 100644
--- a/backend/FwLite/LcmCrdt.Tests/OpenProjectTests.cs
+++ b/backend/FwLite/LcmCrdt.Tests/OpenProjectTests.cs
@@ -10,6 +10,7 @@ public class OpenProjectTests
     public async Task OpeningAProjectWorks()
     {
         var sqliteConnectionString = "OpeningAProjectWorks.sqlite";
+        if (File.Exists(sqliteConnectionString)) File.Delete(sqliteConnectionString);
         var builder = Host.CreateEmptyApplicationBuilder(null);
         builder.Services.AddLcmCrdtClient();
         using var host = builder.Build();
diff --git a/backend/FwLite/LcmCrdt/LcmCrdt.csproj b/backend/FwLite/LcmCrdt/LcmCrdt.csproj
index c2382ec8ab..ce06a235f5 100644
--- a/backend/FwLite/LcmCrdt/LcmCrdt.csproj
+++ b/backend/FwLite/LcmCrdt/LcmCrdt.csproj
@@ -1,9 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
         <InformationalVersion>$(ApplicationDisplayVersion)</InformationalVersion>
         <FileVersion>$(ApplicationDisplayVersion)</FileVersion>
     </PropertyGroup>
@@ -14,12 +11,12 @@
 
     <ItemGroup>
         <PackageReference Include="linq2db.AspNet" Version="5.4.1"/>
-        <PackageReference Include="linq2db.EntityFrameworkCore" Version="8.1.0"/>
+        <PackageReference Include="linq2db.EntityFrameworkCore" Version="8.1.0" />
         <PackageReference Include="linq2db.SQLite" Version="5.4.1" />
         <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0"/>
-        <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
-        <PackageReference Include="Refit" Version="7.1.2"/>
-        <PackageReference Include="Refit.HttpClientFactory" Version="7.1.2"/>
+        <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0" />
+        <PackageReference Include="Refit" Version="8.0.0"/>
+        <PackageReference Include="Refit.HttpClientFactory" Version="8.0.0"/>
     </ItemGroup>
 
     <ItemGroup>
diff --git a/backend/FwLite/LcmCrdt/LcmCrdtDbContext.cs b/backend/FwLite/LcmCrdt/LcmCrdtDbContext.cs
index 525d1d8e69..3a303f6436 100644
--- a/backend/FwLite/LcmCrdt/LcmCrdtDbContext.cs
+++ b/backend/FwLite/LcmCrdt/LcmCrdtDbContext.cs
@@ -10,7 +10,6 @@ namespace LcmCrdt;
 public class LcmCrdtDbContext(DbContextOptions<LcmCrdtDbContext> dbContextOptions, IOptions<CrdtConfig> options): DbContext(dbContextOptions), ICrdtDbContext
 {
     public DbSet<ProjectData> ProjectData => Set<ProjectData>();
-    public IQueryable<ObjectSnapshot> Snapshots => ((ICrdtDbContext)this).Snapshots;
 
     protected override void OnModelCreating(ModelBuilder modelBuilder)
     {
diff --git a/backend/FwLite/LocalWebApp/LocalWebApp.csproj b/backend/FwLite/LocalWebApp/LocalWebApp.csproj
index 6d03a3e542..301cc5491d 100644
--- a/backend/FwLite/LocalWebApp/LocalWebApp.csproj
+++ b/backend/FwLite/LocalWebApp/LocalWebApp.csproj
@@ -1,9 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <Nullable>enable</Nullable>
-        <ImplicitUsings>enable</ImplicitUsings>
         <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
         <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
         <ServerGarbageCollection>false</ServerGarbageCollection>
@@ -20,9 +17,9 @@
     <ItemGroup>
         <PackageReference Include="Humanizer.Core" Version="2.14.1" />
         <PackageReference Include="icu.net" Version="3.0.0-beta.297" GeneratePathProperty="true" />
-        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
-        <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.10" />
-        <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.10" />
+        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
+        <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.0" />
+        <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="9.0.0" />
         <PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.64.0" />
         <PackageReference Include="NReco.Logging.File" Version="1.2.1" />
         <PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
diff --git a/backend/FwLite/LocalWebApp/Routes/HistoryRoutes.cs b/backend/FwLite/LocalWebApp/Routes/HistoryRoutes.cs
index 4ea3870618..354d0e9ff7 100644
--- a/backend/FwLite/LocalWebApp/Routes/HistoryRoutes.cs
+++ b/backend/FwLite/LocalWebApp/Routes/HistoryRoutes.cs
@@ -7,6 +7,7 @@
 using LinqToDB.EntityFrameworkCore;
 using LocalWebApp.Hubs;
 using Microsoft.OpenApi.Models;
+using MiniLcm.Models;
 
 namespace LocalWebApp.Routes;
 
@@ -32,7 +33,7 @@ public static IEndpointConventionBuilder MapHistoryRoutes(this WebApplication ap
             {
                 //todo requires the timestamp to be exact, otherwise the change made on that timestamp will not be included
                 //consider using a commitId and looking up the timestamp, but then we should be exact to the commit which we aren't right now.
-                return await dataModel.GetAtTime<IObjectBase>(new DateTimeOffset(timestamp), entityId);
+                return await dataModel.GetAtTime<IObjectWithId>(new DateTimeOffset(timestamp), entityId);
             });
         group.MapGet("/{entityId}",
             (Guid entityId, ICrdtDbContext dbcontext) =>
diff --git a/backend/FwLite/MiniLcm.Tests/MiniLcm.Tests.csproj b/backend/FwLite/MiniLcm.Tests/MiniLcm.Tests.csproj
index be07e4f4e4..1e5de3a289 100644
--- a/backend/FwLite/MiniLcm.Tests/MiniLcm.Tests.csproj
+++ b/backend/FwLite/MiniLcm.Tests/MiniLcm.Tests.csproj
@@ -1,10 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
-
         <IsPackable>false</IsPackable>
         <IsTestProject>true</IsTestProject>
     </PropertyGroup>
@@ -12,9 +8,12 @@
     <ItemGroup>
         <PackageReference Include="coverlet.collector" Version="6.0.0"/>
         <PackageReference Include="Meziantou.Extensions.Logging.Xunit" Version="1.0.7" />
-        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0"/>
-        <PackageReference Include="xunit" Version="2.9.0"/>
-        <PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
+        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
+        <PackageReference Include="xunit" Version="2.9.2" />
+        <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
+            <PrivateAssets>all</PrivateAssets>
+            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+        </PackageReference>
         <PackageReference Include="GitHubActionsTestLogger" Version="2.4.1">
             <PrivateAssets>all</PrivateAssets>
             <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/backend/FwLite/MiniLcm/MiniLcm.csproj b/backend/FwLite/MiniLcm/MiniLcm.csproj
index 8f4dc0c48f..7635880b15 100644
--- a/backend/FwLite/MiniLcm/MiniLcm.csproj
+++ b/backend/FwLite/MiniLcm/MiniLcm.csproj
@@ -1,16 +1,13 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
         <InformationalVersion>$(ApplicationDisplayVersion)</InformationalVersion>
         <FileVersion>$(ApplicationDisplayVersion)</FileVersion>
     </PropertyGroup>
 
     <ItemGroup>
       <PackageReference Include="SIL.WritingSystems" Version="14.2.0-beta*" />
-      <PackageReference Include="System.Text.Json" Version="8.0.5" />
+      <PackageReference Include="System.Text.Json" Version="9.0.0" />
       <PackageReference Include="SystemTextJsonPatch" Version="3.2.1" />
     </ItemGroup>
 
diff --git a/backend/LexBoxApi/LexBoxApi.csproj b/backend/LexBoxApi/LexBoxApi.csproj
index 238fc7e578..638ba148e2 100644
--- a/backend/LexBoxApi/LexBoxApi.csproj
+++ b/backend/LexBoxApi/LexBoxApi.csproj
@@ -1,12 +1,8 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <Nullable>enable</Nullable>
-        <ImplicitUsings>enable</ImplicitUsings>
         <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
         <IncludeOpenAPIAnalyzers>true</IncludeOpenAPIAnalyzers>
-        <InformationalVersion>dev</InformationalVersion>
         <UserSecretsId>7392cddf-9b3b-441c-9316-203bb5c4a6bc</UserSecretsId>
         <GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode>
     </PropertyGroup>
@@ -27,22 +23,23 @@
         <PackageReference Include="Humanizer.Core" Version="2.14.1" />
         <PackageReference Include="MailKit" Version="4.7.1.1" />
         <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="8.0.10" />
-        <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
-        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
-        <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
+        <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.0" />
+        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
+        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
+        <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11">
           <PrivateAssets>all</PrivateAssets>
           <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
         </PackageReference>
         <PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="9.0.0" />
-        <PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.0.2" />
+        <PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.2.0" />
         <PackageReference Include="Nito.AsyncEx.Coordination" Version="5.1.2" />
-        <PackageReference Include="Npgsql.OpenTelemetry" Version="8.0.3" />
+        <PackageReference Include="Npgsql.OpenTelemetry" Version="8.0.6" />
         <PackageReference Include="OpenIddict.AspNetCore" Version="5.8.0" />
         <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="5.8.0" />
         <PackageReference Include="OpenIddict.Quartz" Version="5.8.0" />
-        <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.9.0" />
-        <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
-        <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
+        <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.10.0" />
+        <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" />
+        <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" />
         <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
         <PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.0.0-beta.8" />
         <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
@@ -54,6 +51,7 @@
         <PackageReference Include="Quartz.AspNetCore" Version="3.13.0" />
         <PackageReference Include="Quartz.Serialization.SystemTextJson" Version="3.13.0" />
         <PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
+        <PackageReference Include="System.Text.Encodings.Web" Version="9.0.0" />
         <PackageReference Include="tusdotnet" Version="2.8.0" />
         <PackageReference Include="zxcvbn-core" Version="7.0.92" />
     </ItemGroup>
diff --git a/backend/LexBoxApi/dev.Dockerfile b/backend/LexBoxApi/dev.Dockerfile
index bbedcbe097..77d9b6d5da 100644
--- a/backend/LexBoxApi/dev.Dockerfile
+++ b/backend/LexBoxApi/dev.Dockerfile
@@ -1,5 +1,5 @@
 # syntax=docker/dockerfile:1
-FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
 EXPOSE 80
 EXPOSE 443
 RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
@@ -9,13 +9,13 @@ RUN mkdir -p /var/www && chown -R www-data:www-data /var/www
 USER www-data:www-data
 WORKDIR /src/backend
 # Copy the main source project files
-COPY */*.csproj *.sln ./
+COPY */*.csproj *.sln Directory.Build.props ./
 # move them into the proper sub folders, based on the name of the project
 RUN for file in $(ls *.csproj); do dir=${file%.*}; mkdir -p ${dir}/ && mv -v $file ${dir}/; done
 # Do the same for csproj files in slightly different hierarchies
 COPY harmony/src/*/*.csproj ./
 RUN for file in $(ls *.csproj); do dir=${file%.*}; mkdir -p harmony/src/${dir}/ && mv -v $file harmony/src/${dir}/; done
-COPY harmony/src/Directory.Build.props ./harmony/src/
+COPY harmony/src/Directory.Build.props harmony/Directory.Packages.props ./harmony/src/
 COPY FwLite/*/*.csproj ./
 RUN for file in $(ls *.csproj); do dir=${file%.*}; mkdir -p FwLite/${dir}/ && mv -v $file FwLite/${dir}/; done
 
diff --git a/backend/LexCore/LexCore.csproj b/backend/LexCore/LexCore.csproj
index 276363f1a3..db0930955e 100644
--- a/backend/LexCore/LexCore.csproj
+++ b/backend/LexCore/LexCore.csproj
@@ -1,14 +1,10 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
-        <InformationalVersion>dev</InformationalVersion>
     </PropertyGroup>
 
     <ItemGroup>
-      <PackageReference Include="EntityFrameworkCore.Projectables.Abstractions" Version="3.0.4" />
+      <PackageReference Include="EntityFrameworkCore.Projectables.Abstractions" Version="4.0.0-preview.4" />
     </ItemGroup>
 
 </Project>
diff --git a/backend/LexData/DataKernel.cs b/backend/LexData/DataKernel.cs
index e12fc003c4..25dc734ca5 100644
--- a/backend/LexData/DataKernel.cs
+++ b/backend/LexData/DataKernel.cs
@@ -1,5 +1,6 @@
 using LexData.Configuration;
 using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Options;
 
@@ -18,6 +19,9 @@ public static void AddLexData(this IServiceCollection services,
             options.EnableDetailedErrors();
             options.UseNpgsql(serviceProvider.GetRequiredService<IOptions<DbConfig>>().Value.LexBoxConnectionString);
             options.UseProjectables();
+            //todo remove this once this bug is fixed: https://github.com/dotnet/efcore/issues/35110
+            //we ended up not upgrading to EF Core 9, so this was disabled for now, may or may not be needed in the future
+            // options.ConfigureWarnings(builder => builder.Ignore(RelationalEventId.PendingModelChangesWarning));
             if (useOpenIddict) options.UseOpenIddict();
 #if DEBUG
             options.EnableSensitiveDataLogging();
diff --git a/backend/LexData/LexData.csproj b/backend/LexData/LexData.csproj
index 1ad6d57d95..65ede2fc7c 100644
--- a/backend/LexData/LexData.csproj
+++ b/backend/LexData/LexData.csproj
@@ -1,28 +1,22 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
-        <InformationalVersion>dev</InformationalVersion>
     </PropertyGroup>
 
     <ItemGroup>
       <PackageReference Include="EntityFrameworkCore.Projectables" Version="3.0.4" />
       <PackageReference Include="Humanizer.Core" Version="2.14.1" />
-      <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
+      <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11">
         <PrivateAssets>all</PrivateAssets>
         <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       </PackageReference>
-      <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
-      <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.10" />
-      <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
-      <PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
-      <PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="8.0.0" />
-      <PackageReference Include="Npgsql" Version="8.0.3" />
-      <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
+      <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.11" />
+      <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
+      <PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="9.0.0" />
+      <PackageReference Include="Npgsql" Version="8.0.6" />
+      <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.11" />
       <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="5.8.0" />
-</ItemGroup>
+    </ItemGroup>
 
     <ItemGroup>
       <ProjectReference Include="..\harmony\src\SIL.Harmony.Core\SIL.Harmony.Core.csproj" />
diff --git a/backend/LfClassicData/LfClassicData.csproj b/backend/LfClassicData/LfClassicData.csproj
index cbe4974fa7..2a35852ac4 100644
--- a/backend/LfClassicData/LfClassicData.csproj
+++ b/backend/LfClassicData/LfClassicData.csproj
@@ -1,15 +1,12 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
     </PropertyGroup>
 
     <ItemGroup>
         <FrameworkReference Include="Microsoft.AspNetCore.App"/>
-        <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
-        <PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2"/>
+        <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.0" />
+        <PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
         <PackageReference Include="MongoDB.Analyzer" Version="1.5.0" />
         <PackageReference Include="MongoDB.Driver" Version="2.28.0" />
         <PackageReference Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="1.5.0" />
diff --git a/backend/LfNext/LcmDebugger/LcmDebugger.csproj b/backend/LfNext/LcmDebugger/LcmDebugger.csproj
index e47e15988e..92e8860a64 100644
--- a/backend/LfNext/LcmDebugger/LcmDebugger.csproj
+++ b/backend/LfNext/LcmDebugger/LcmDebugger.csproj
@@ -2,9 +2,6 @@
 
     <PropertyGroup>
         <OutputType>Exe</OutputType>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
     </PropertyGroup>
 
     <ItemGroup>
diff --git a/backend/SyncReverseProxy/Dockerfile b/backend/SyncReverseProxy/Dockerfile
deleted file mode 100644
index 8c431359b4..0000000000
--- a/backend/SyncReverseProxy/Dockerfile
+++ /dev/null
@@ -1,20 +0,0 @@
-FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
-WORKDIR /app
-EXPOSE 80
-EXPOSE 443
-
-FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
-WORKDIR /src
-COPY ["SyncReverseProxy/SyncReverseProxy.csproj", "SyncReverseProxy/"]
-RUN dotnet restore "SyncReverseProxy/SyncReverseProxy.csproj"
-COPY . .
-WORKDIR "/src/SyncReverseProxy"
-RUN dotnet build "SyncReverseProxy.csproj" -c Release -o /app/build
-
-FROM build AS publish
-RUN dotnet publish "SyncReverseProxy.csproj" -c Release -o /app/publish
-
-FROM base AS final
-WORKDIR /app
-COPY --from=publish /app/publish .
-ENTRYPOINT ["dotnet", "SyncReverseProxy.dll"]
diff --git a/backend/SyncReverseProxy/SyncReverseProxy.csproj b/backend/SyncReverseProxy/SyncReverseProxy.csproj
index 0a58ba985c..fe72988bf0 100644
--- a/backend/SyncReverseProxy/SyncReverseProxy.csproj
+++ b/backend/SyncReverseProxy/SyncReverseProxy.csproj
@@ -1,27 +1,23 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <Nullable>enable</Nullable>
-        <ImplicitUsings>enable</ImplicitUsings>
         <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
         <RootNamespace>LexSyncReverseProxy</RootNamespace>
-        <InformationalVersion>dev</InformationalVersion>
     </PropertyGroup>
 
     <ItemGroup>
-        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
-        <PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
+        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
+        <PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
         <PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
-        <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.2" />
-        <PackageReference Include="Yarp.ReverseProxy" Version="2.1.0" />
+        <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.2.0" />
+        <PackageReference Include="Yarp.ReverseProxy" Version="2.2.0" />
 
-        <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.9.0" />
-        <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
-        <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
+        <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.10.0" />
+        <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" />
+        <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" />
         <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
         <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
-        <PackageReference Include="Yarp.Telemetry.Consumption" Version="2.1.0" />
+        <PackageReference Include="Yarp.Telemetry.Consumption" Version="2.2.0" />
 
     </ItemGroup>
 
diff --git a/backend/Testing/Testing.csproj b/backend/Testing/Testing.csproj
index 3ccb8771e0..a473fcdaa8 100644
--- a/backend/Testing/Testing.csproj
+++ b/backend/Testing/Testing.csproj
@@ -1,10 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
-
         <IsPackable>false</IsPackable>
         <Mercurial4ChorusDestDir>$(MSBuildProjectDirectory)</Mercurial4ChorusDestDir>
         <!-- To switch Mercurial versions, do dotnet build /p:MercurialVersion=3 followed by dotnet test -->
@@ -16,7 +12,7 @@
         <When Condition=" '$(MercurialVersion)' == '6' ">
             <ItemGroup>
                 <PackageReference Include="SIL.Chorus.LibChorus" Version="6.0.0-beta0049" />
-                <PackageReference Include="SIL.Chorus.Mercurial" Version="6.5.1.36" />
+                <PackageReference Include="SIL.Chorus.Mercurial" Version="6.5.1.43" />
             </ItemGroup>
         </When>
         <Otherwise>
@@ -27,22 +23,22 @@
         </Otherwise>
     </Choose>
     <ItemGroup>
-        <PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.8.0" />
-        <PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" Version="8.9.1" />
+        <PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.0.0" />
+        <PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" Version="9.0.0" />
         <PackageReference Include="Squidex.Assets.TusClient" Version="6.6.4" />
-        <PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
-        <PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
-        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
+        <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
+        <PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
+        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
         <PackageReference Include="Moq" Version="4.20.70" />
         <PackageReference Include="Moq.Contrib.HttpClient" Version="1.4.0" />
         <PackageReference Include="FluentAssertions" Version="7.0.0-alpha.5"/>
         <PackageReference Include="SIL.ChorusPlugin.LfMergeBridge" Version="4.1.0" />
         <PackageReference Include="SIL.Core" Version="14.2.0-*" />
-        <PackageReference Include="xunit" Version="2.9.0" />
+        <PackageReference Include="xunit" Version="2.9.2" />
         <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
-            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
             <PrivateAssets>all</PrivateAssets>
+            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
         </PackageReference>
         <PackageReference Include="coverlet.collector" Version="6.0.2">
             <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/backend/harmony b/backend/harmony
index 33b1aba763..c13987d13f 160000
--- a/backend/harmony
+++ b/backend/harmony
@@ -1 +1 @@
-Subproject commit 33b1aba763633e8fc63f97b1d02332d1e1739c5a
+Subproject commit c13987d13f7fa4c37e0ebdd28b04e42a31df7e4c
diff --git a/frontend/tests/pages/userDashboardPage.ts b/frontend/tests/pages/userDashboardPage.ts
index e5d284699a..a99fa0d669 100644
--- a/frontend/tests/pages/userDashboardPage.ts
+++ b/frontend/tests/pages/userDashboardPage.ts
@@ -9,12 +9,17 @@ export class UserDashboardPage extends AuthenticatedBasePage {
   }
 
   async openProject(projectName: string, projectCode: string): Promise<ProjectPage> {
+    await this.selectGridView();
     const projectHeader = this.page.getByRole('heading', {name: projectName});
     const projectCard = this.page.locator('.card', {has: projectHeader});
     await projectCard.click();
     return new ProjectPage(this.page, projectName, projectCode).waitFor();
   }
 
+  async selectGridView(): Promise<void> {
+    await this.page.click('.i-mdi-grid');
+  }
+
   async clickCreateProject(): Promise<CreateProjectPage> {
     await this.page.getByRole('link', {name: /(Create|Request) Project/, exact: true}).click();
     return new CreateProjectPage(this.page).waitFor();