diff --git a/App.xaml.cs b/App.xaml.cs
index a5754e4..23878ba 100644
--- a/App.xaml.cs
+++ b/App.xaml.cs
@@ -12,11 +12,21 @@ namespace UtopiaCanteenSystem;
///
public partial class App : Application
{
+ private static Mutex _mutex;
private System.Timers.Timer? _syncTimer;
private int _isSyncRunning;
protected override void OnStartup(StartupEventArgs e)
{
+ bool isNewInstance;
+ _mutex = new Mutex(true, "UtopiaCanteenSystemMutex", out isNewInstance);
+
+ if (!isNewInstance)
+ {
+ MessageBox.Show("Another instance of the application is already running.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
+ Current.Shutdown();
+ return;
+ }
base.OnStartup(e);
// Build services (simple composition; no DI container)
@@ -52,6 +62,8 @@ public partial class App : Application
{
DataContext = mainViewModel
};
+ // Set the window to open maximized
+ mainWindow.WindowState = WindowState.Maximized;
mainWindow.Show();
// Background sync: every 15 minutes, POST unsynced lunch_order_transactions to API
@@ -83,6 +95,7 @@ public partial class App : Application
protected override void OnExit(ExitEventArgs e)
{
+ _mutex.ReleaseMutex();
_syncTimer?.Stop();
_syncTimer?.Dispose();
base.OnExit(e);
diff --git a/Data/AppDbContext.cs b/Data/AppDbContext.cs
index 1d2d490..0b2fe5b 100644
--- a/Data/AppDbContext.cs
+++ b/Data/AppDbContext.cs
@@ -7,13 +7,12 @@ namespace UtopiaCanteenSystem.Data;
///
/// SQLite DbContext for Labour and lunch_order_transactions (scan records) tables.
-/// Database file is created in application directory on first run.
+/// Database file is stored under LocalApplicationData so it persists across app updates
+/// when deployed from a file server.
///
public class AppDbContext : DbContext
{
- private static readonly string DbPath = Path.Combine(
- AppDomain.CurrentDomain.BaseDirectory,
- "utopia_canteen.db");
+ private static string DbPath => DatabasePath.GetDbPath();
public DbSet Labour { get; set; }
public DbSet LunchOrderTransactions { get; set; }
diff --git a/Data/DatabasePath.cs b/Data/DatabasePath.cs
new file mode 100644
index 0000000..2bb96cb
--- /dev/null
+++ b/Data/DatabasePath.cs
@@ -0,0 +1,94 @@
+using System.IO;
+
+namespace UtopiaCanteenSystem.Data;
+
+///
+/// Central location for persistent paths (database and config). Uses LocalApplicationData
+/// so data survives app updates when the application is deployed from a file server.
+///
+public static class DatabasePath
+{
+ private static string? _appDataFolder;
+ private static string? _dbPath;
+
+ ///
+ /// Folder under LocalApplicationData for DB and config. Created on first use.
+ ///
+ public static string GetAppDataFolder()
+ {
+ if (_appDataFolder != null)
+ return _appDataFolder;
+
+ _appDataFolder = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+ "UtopiaCanteenSystem");
+ Directory.CreateDirectory(_appDataFolder);
+ return _appDataFolder;
+ }
+
+ ///
+ /// Full path to the SQLite database file. If a DB exists in the legacy app-directory
+ /// location, it is copied to the new location once.
+ ///
+ public static string GetDbPath()
+ {
+ if (_dbPath != null)
+ return _dbPath;
+
+ var folder = GetAppDataFolder();
+ _dbPath = Path.Combine(folder, "utopia_canteen.db");
+ MigrateLegacyDbIfNeeded(_dbPath);
+ return _dbPath;
+ }
+
+ ///
+ /// Full path to appsettings.json (remember-me credentials and other config).
+ /// Stored in the same persistent folder so it survives updates. If a config exists
+ /// in the legacy app-directory location, it is copied to the new location once.
+ ///
+ public static string GetConfigPath()
+ {
+ var folder = GetAppDataFolder();
+ var newPath = Path.Combine(folder, "appsettings.json");
+ MigrateLegacyConfigIfNeeded(newPath);
+ return newPath;
+ }
+
+ private static void MigrateLegacyDbIfNeeded(string newPath)
+ {
+ if (File.Exists(newPath))
+ return;
+
+ var legacyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "utopia_canteen.db");
+ if (!File.Exists(legacyPath))
+ return;
+
+ try
+ {
+ File.Copy(legacyPath, newPath);
+ }
+ catch
+ {
+ // If copy fails, app will start with a new DB at new path.
+ }
+ }
+
+ private static void MigrateLegacyConfigIfNeeded(string newPath)
+ {
+ if (File.Exists(newPath))
+ return;
+
+ var legacyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json");
+ if (!File.Exists(legacyPath))
+ return;
+
+ try
+ {
+ File.Copy(legacyPath, newPath);
+ }
+ catch
+ {
+ // If copy fails, app will start with a new config at new path.
+ }
+ }
+}
diff --git a/Data/DbContextFactory.cs b/Data/DbContextFactory.cs
index 2b7e811..0f74bcf 100644
--- a/Data/DbContextFactory.cs
+++ b/Data/DbContextFactory.cs
@@ -13,7 +13,7 @@ public class DbContextFactory : IDbContextFactory
static DbContextFactory()
{
var builder = new DbContextOptionsBuilder();
- var dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "utopia_canteen.db");
+ var dbPath = DatabasePath.GetDbPath();
builder.UseSqlite($"Data Source={dbPath}");
Options = builder.Options;
}
diff --git a/MainWindow.xaml b/MainWindow.xaml
index c9ba628..9cd4240 100644
--- a/MainWindow.xaml
+++ b/MainWindow.xaml
@@ -5,7 +5,8 @@
Icon="pack://siteoforigin:,,,/assets/favicon.ico"
MinHeight="400" MinWidth="480"
Width="900" Height="700"
- WindowStartupLocation="CenterScreen">
+ WindowStartupLocation="CenterScreen"
+ WindowState="Maximized">
+
+
+
+ 10
+ 1.0.0.*
+ True
+ Release
+ True
+ False
+ true
+ True
+ Unc
+ \\FileServer\Edata\Deployments-by-DotNet-Team\UtopiaCanteenSystem\
+ True
+ False
+ True
+ False
+ Any CPU
+ bin\Release\net8.0-windows\win-x86\app.publish\
+ \\FileServer\Edata\Deployments-by-DotNet-Team\UtopiaCanteenSystem\
+ ClickOnce
+ False
+ True
+ win-x86
+ True
+ (none)
+ False
+ false
+ net8.0-windows
+ True
+ Foreground
+ False
+ \\FileServer\Edata\Deployments-by-DotNet-Team\UtopiaCanteenSystem\
+ Publish.html
+ True|2026-02-12T06:22:02.6537306Z||;True|2026-02-12T10:57:16.2775876+05:00||;True|2026-02-12T10:50:58.6968682+05:00||;False|2026-02-12T10:49:27.1867616+05:00||;True|2026-02-12T10:44:55.6022990+05:00||;True|2026-02-11T17:00:04.2786466+05:00||;True|2026-02-11T16:54:37.5052808+05:00||;True|2026-02-11T16:39:26.1892892+05:00||;True|2026-02-11T16:30:57.2420414+05:00||;True|2026-02-11T16:20:44.4749529+05:00||;
+
+
\ No newline at end of file
diff --git a/Services/ConfigService.cs b/Services/ConfigService.cs
index cda21f3..1c35bb2 100644
--- a/Services/ConfigService.cs
+++ b/Services/ConfigService.cs
@@ -3,11 +3,13 @@ using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
+using UtopiaCanteenSystem.Data;
namespace UtopiaCanteenSystem.Services;
///
-/// Simple JSON-backed configuration stored alongside the app binaries.
+/// JSON-backed configuration (including remember-me credentials) stored under
+/// LocalApplicationData so it survives app updates when deployed from a file server.
///
public class ConfigService : IConfigService
{
@@ -16,7 +18,7 @@ public class ConfigService : IConfigService
public ConfigService()
{
- _configPath = Path.Combine(AppContext.BaseDirectory, "appsettings.json");
+ _configPath = DatabasePath.GetConfigPath();
_config = LoadConfig();
}