diff --git a/UtopiaCanteen.sln b/UtopiaCanteen.sln
new file mode 100644
index 0000000..52cd725
--- /dev/null
+++ b/UtopiaCanteen.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UtopiaCanteen.Shared", "UtopiaCanteen.Shared\UtopiaCanteen.Shared.csproj", "{B1B2C3D4-E5F6-7890-ABCD-EF1234567891}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UtopiaCanteen.Backend", "UtopiaCanteen.Backend\UtopiaCanteen.Backend.csproj", "{B1B2C3D4-E5F6-7890-ABCD-EF1234567892}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UtopiaCanteen.BackendService", "UtopiaCanteen.BackendService\UtopiaCanteen.BackendService.csproj", "{B1B2C3D4-E5F6-7890-ABCD-EF1234567893}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UtopiaCanteen.Client", "UtopiaCanteen.Client\UtopiaCanteen.Client.csproj", "{B1B2C3D4-E5F6-7890-ABCD-EF1234567894}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UtopiaCanteenSystem", "UtopiaCanteenSystem.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567892}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567892}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567892}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567892}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567893}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567893}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567893}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567893}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567894}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567894}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567894}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B1B2C3D4-E5F6-7890-ABCD-EF1234567894}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/UtopiaCanteenSystem.csproj b/UtopiaCanteenSystem.csproj
index 47ec17f..56ea48e 100644
--- a/UtopiaCanteenSystem.csproj
+++ b/UtopiaCanteenSystem.csproj
@@ -2,6 +2,7 @@
WinExe
+ true
net8.0-windows
enable
enable
@@ -13,6 +14,13 @@
+
+
+
+
+
+
+
diff --git a/scripts/install-backend-service.ps1 b/scripts/install-backend-service.ps1
new file mode 100644
index 0000000..d504077
--- /dev/null
+++ b/scripts/install-backend-service.ps1
@@ -0,0 +1,83 @@
+# Install or reinstall the Utopia Canteen backend as a Windows Service (requires Administrator).
+param(
+ [string]$InstallPath = "C:\UtopiaCanteenBackend",
+ [string]$ServiceName = "UtopiaCanteenBackend",
+ [string]$DisplayName = "Utopia Canteen Backend",
+ [ValidateSet("Debug", "Release")]
+ [string]$Configuration = "Release",
+ [switch]$SkipPublish,
+ [switch]$AddUrlAcl,
+ [string]$UrlAclUser = "Everyone"
+)
+
+$ErrorActionPreference = "Stop"
+
+function Test-Administrator {
+ $current = [Security.Principal.WindowsIdentity]::GetCurrent()
+ $principal = New-Object Security.Principal.WindowsPrincipal($current)
+ return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
+}
+
+if (-not (Test-Administrator)) {
+ Write-Error "Run this script in an elevated PowerShell (Run as administrator)."
+ exit 1
+}
+
+$ScriptDir = $PSScriptRoot
+if (-not $SkipPublish) {
+ & (Join-Path $ScriptDir "publish-backend.ps1") -OutputPath $InstallPath -Configuration $Configuration
+}
+
+$ExePath = Join-Path $InstallPath "UtopiaCanteen.BackendService.exe"
+if (-not (Test-Path $ExePath)) {
+ throw "Executable not found: $ExePath. Run publish-backend.ps1 first."
+}
+
+# HttpListener on http://+:5000/ often needs a URL reservation.
+if ($AddUrlAcl) {
+ Write-Host "Adding URL ACL for http://+:5000/ (user: $UrlAclUser)"
+ netsh http add urlacl url=http://+:5000/ user=$UrlAclUser 2>$null
+ if ($LASTEXITCODE -ne 0) {
+ Write-Warning "urlacl may already exist or failed (exit $LASTEXITCODE). Continue if the service binds OK."
+ }
+}
+
+$existing = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
+if ($existing) {
+ Write-Host "Stopping and removing existing service: $ServiceName"
+ if ($existing.Status -eq "Running") {
+ Stop-Service -Name $ServiceName -Force -ErrorAction SilentlyContinue
+ Start-Sleep -Seconds 2
+ }
+ sc.exe delete $ServiceName | Out-Null
+ Start-Sleep -Seconds 2
+}
+
+$binPath = "`"$ExePath`""
+Write-Host "Creating service $ServiceName -> $ExePath"
+sc.exe create $ServiceName binPath= $binPath start= auto DisplayName= $DisplayName
+if ($LASTEXITCODE -ne 0) {
+ throw "sc create failed with exit code $LASTEXITCODE"
+}
+
+sc.exe description $ServiceName "Central canteen API, SQLite, and HRMS/UIND sync for RFID scanners."
+sc.exe failure $ServiceName reset= 86400 actions= restart/60000/restart/60000/restart/60000
+
+Write-Host "Starting service..."
+sc.exe start $ServiceName
+if ($LASTEXITCODE -ne 0) {
+ Write-Warning "sc start returned $LASTEXITCODE. Check Event Viewer and appsettings.json."
+} else {
+ Write-Host "Service started. Health check: http://localhost:5000/api/health"
+}
+
+Write-Host @"
+
+Installed:
+ Path: $InstallPath
+ Service: $ServiceName (auto-start)
+ Data: %LocalAppData%\UtopiaCanteenBackend\
+
+Firewall: allow inbound TCP 5000 on this PC for scanner clients.
+
+"@
diff --git a/scripts/publish-backend.ps1 b/scripts/publish-backend.ps1
new file mode 100644
index 0000000..8bef91a
--- /dev/null
+++ b/scripts/publish-backend.ps1
@@ -0,0 +1,28 @@
+# Publish UtopiaCanteen.BackendService to a folder (default C:\UtopiaCanteenBackend).
+param(
+ [string]$OutputPath = "C:\UtopiaCanteenBackend",
+ [ValidateSet("Debug", "Release")]
+ [string]$Configuration = "Release"
+)
+
+$ErrorActionPreference = "Stop"
+$Root = Split-Path -Parent $PSScriptRoot
+$Project = Join-Path $Root "UtopiaCanteen.BackendService\UtopiaCanteen.BackendService.csproj"
+
+if (-not (Test-Path $Project)) {
+ throw "Project not found: $Project"
+}
+
+Write-Host "Publishing backend ($Configuration) -> $OutputPath"
+dotnet publish $Project -c $Configuration -o $OutputPath --self-contained false
+
+if ($LASTEXITCODE -ne 0) {
+ throw "dotnet publish failed with exit code $LASTEXITCODE"
+}
+
+$appsettings = Join-Path $OutputPath "appsettings.json"
+if (Test-Path $appsettings) {
+ Write-Host "Edit connection strings in: $appsettings"
+}
+
+Write-Host "Done. Executable: $(Join-Path $OutputPath 'UtopiaCanteen.BackendService.exe')"
diff --git a/scripts/publish-client.ps1 b/scripts/publish-client.ps1
new file mode 100644
index 0000000..b49c334
--- /dev/null
+++ b/scripts/publish-client.ps1
@@ -0,0 +1,28 @@
+# Publish UtopiaCanteen.Client (WPF scanner) to a folder (default C:\UtopiaCanteenClient).
+param(
+ [string]$OutputPath = "C:\UtopiaCanteenClient",
+ [ValidateSet("Debug", "Release")]
+ [string]$Configuration = "Release"
+)
+
+$ErrorActionPreference = "Stop"
+$Root = Split-Path -Parent $PSScriptRoot
+$Project = Join-Path $Root "UtopiaCanteen.Client\UtopiaCanteen.Client.csproj"
+
+if (-not (Test-Path $Project)) {
+ throw "Project not found: $Project"
+}
+
+Write-Host "Publishing client ($Configuration) -> $OutputPath"
+dotnet publish $Project -c $Configuration -o $OutputPath --self-contained false
+
+if ($LASTEXITCODE -ne 0) {
+ throw "dotnet publish failed with exit code $LASTEXITCODE"
+}
+
+Write-Host @"
+Done. Run: $(Join-Path $OutputPath 'UtopiaCanteen.Client.exe')
+
+First run: open Settings and set Backend base URL (e.g. http://192.168.1.10:5000).
+Config file: %LocalAppData%\UtopiaCanteenClient\appsettings.json
+"@