# Project Context: Engineering-to-Simulation Sync Tool ("EngineeringSync") You are an expert C# / .NET 10 developer. Build a middleware tool that bridges mechanical engineering (CAD) and simulation (Process Simulate). **Problem:** Engineers save files to a shared folder. Immediate overwrites in the simulation folder cause data corruption for the simulator. This tool watches the engineering folder, records changes, and notifies the simulation engineer via a WPF System Tray App. The simulation engineer reviews changes, selects what to sync, and triggers a controlled copy. --- ## Tech Stack - **Framework:** .NET 10 - **Service:** Worker Service (Windows Service) + ASP.NET Core Minimal API + SignalR - **Client:** WPF (.NET 10-Windows) with `H.NotifyIcon.Wpf` - **Database:** SQLite via EF Core 10 (WAL mode for concurrency) - **File Watching:** `System.IO.FileSystemWatcher` + `System.Threading.Channels` (debouncing) - **UI Pattern:** MVVM with `CommunityToolkit.Mvvm` --- ## Phase 1: Solution Initialization Create solution structure via .NET CLI: ``` EngineeringSync.sln ├── EngineeringSync.Domain (Class Library, net10.0) – Entities, Enums, Interfaces ├── EngineeringSync.Infrastructure (Class Library, net10.0) – EF Core, AppDbContext, Migrations ├── EngineeringSync.Service (Worker Service, net10.0) – Kestrel :5050, SignalR, Watcher └── EngineeringSync.TrayApp (WPF App, net10.0-windows) – System tray + all UI windows ``` **Dependency direction (strict one-way):** - `Infrastructure` → `Domain` - `Service` → `Domain` + `Infrastructure` - `TrayApp` → `Domain` (for shared DTOs/Enums only) **NuGet Packages:** | Project | Packages | |---|---| | Domain | *(none – pure POCOs)* | | Infrastructure | `Microsoft.EntityFrameworkCore.Sqlite`, `Microsoft.EntityFrameworkCore.Design` | | Service | `Microsoft.Extensions.Hosting.WindowsServices`, `Microsoft.AspNetCore.SignalR` | | TrayApp | `H.NotifyIcon.Wpf`, `Microsoft.AspNetCore.SignalR.Client`, `CommunityToolkit.Mvvm` | --- ## Phase 2: Domain & Database Modeling ### Domain Entities (`EngineeringSync.Domain`) **`ProjectConfig`** – A watched project (persisted in DB, managed via UI): - `Id` (Guid, PK) - `Name` (string) – Display name, e.g. "Hauptprojekt Karosserie" - `EngineeringPath` (string) – Source folder the watcher monitors - `SimulationPath` (string) – Target folder for controlled sync - `FileExtensions` (string) – Comma-separated, e.g. ".jt,.cojt,.xml" - `IsActive` (bool) – Enable/disable watching without deleting - `CreatedAt` (DateTime) **`FileRevision`** – Tracks known file state for change detection: - `Id` (Guid, PK) - `ProjectId` (Guid, FK → ProjectConfig) - `RelativePath` (string) - `FileHash` (string) – SHA-256 - `Size` (long) - `LastModified` (DateTime) **`PendingChange`** – A detected change awaiting user action: - `Id` (Guid, PK) - `ProjectId` (Guid, FK → ProjectConfig) - `RelativePath` (string) - `ChangeType` (Enum: Created, Modified, Renamed, Deleted) - `OldRelativePath` (string?) – Only for Renamed - `Status` (Enum: Pending, Synced, Ignored) - `CreatedAt` (DateTime) - `SyncedAt` (DateTime?) ### Infrastructure (`EngineeringSync.Infrastructure`) - `AppDbContext` with `DbSet`, `DbSet`, `DbSet` - SQLite connection string with `Mode=ReadWriteCreate` and WAL pragma - Auto-migration at service startup via `context.Database.Migrate()` - Unique index on `(ProjectId, RelativePath)` for `FileRevision` --- ## Phase 3: The Windows Service (Core Logic) ### 3.1 Project Management API (CRUD) New endpoints for managing projects from the TrayApp UI: - `GET /api/projects` – List all ProjectConfig - `POST /api/projects` – Create new ProjectConfig (validates paths exist) - `PUT /api/projects/{id}` – Update ProjectConfig (restarts watcher for that project) - `DELETE /api/projects/{id}` – Delete ProjectConfig + associated changes When a ProjectConfig is created or updated with `IsActive = true`, the WatcherService must dynamically start/stop the corresponding `FileSystemWatcher`. ### 3.2 FileSystemWatcher & Debouncing (`WatcherService`) - `BackgroundService` that manages one `FileSystemWatcher` per active `ProjectConfig` - Listen to: `Created`, `Changed`, `Renamed`, `Deleted` - Filter by `ProjectConfig.FileExtensions` - **Debouncing pipeline:** 1. Push raw `FileSystemEventArgs` into a `Channel` (unbounded) 2. Consumer reads from channel, groups events by `(ProjectId, RelativePath)` within a 2000ms sliding window 3. After window closes, compute SHA-256 hash of file 4. Compare hash against latest `FileRevision` for that path 5. If hash differs (or file is new): write `FileRevision` + `PendingChange` to DB 6. Broadcast via SignalR - **Renamed:** Record old + new path, update `FileRevision.RelativePath` - **Deleted:** Record as `ChangeType.Deleted`, remove `FileRevision` ### 3.3 Minimal API & SignalR Hub Host Kestrel on `http://localhost:5050`: | Method | Endpoint | Description | |---|---|---| | GET | `/api/projects` | List all projects | | POST | `/api/projects` | Create project | | PUT | `/api/projects/{id}` | Update project | | DELETE | `/api/projects/{id}` | Delete project | | GET | `/api/changes/{projectId}` | Pending changes for project | | GET | `/api/changes/{projectId}/history` | Synced/ignored changes (last 100) | | POST | `/api/sync` | Sync selected PendingChange IDs | | POST | `/api/ignore` | Ignore selected PendingChange IDs | **SignalR Hub** (`NotificationHub` at `/notifications`): - `ReceiveChangeNotification(projectId, projectName, count)` – Fired when new PendingChanges are persisted - `ProjectConfigChanged()` – Fired when a project is created/updated/deleted ### 3.4 Sync Logic (`SyncManager`) When `POST /api/sync` is called with a list of PendingChange IDs: 1. Load PendingChange + ProjectConfig from DB 2. Verify source file exists at `EngineeringPath / RelativePath` 3. If target already exists in `SimulationPath`: - Rename to `{filename}_{timestamp:yyyyMMdd_HHmmss}.bak` (timestamped to prevent overwriting previous backups) 4. Copy source → target (create subdirectories as needed) 5. Mark PendingChange as `Status = Synced`, set `SyncedAt` 6. For `ChangeType.Deleted`: Delete target file (after backup), mark Synced 7. Return result summary (success count, errors) --- ## Phase 4: The WPF Tray App ### 4.1 System Tray Setup - `H.NotifyIcon.Wpf`: headless startup (no main window) - Tray icon context menu: - **"Änderungen anzeigen"** → Opens PendingChangesWindow - **"Projekte verwalten"** → Opens ProjectManagementWindow - **"Beenden"** → Graceful shutdown ### 4.2 SignalR Client - Connect to `http://localhost:5050/notifications` on startup - Auto-reconnect with exponential backoff - On `ReceiveChangeNotification`: Show balloon tip "Neue Engineering-Daten für Projekt [Name] verfügbar. Klicken zum Überprüfen." - On `ProjectConfigChanged`: Refresh project list in any open window ### 4.3 Project Management Window (NEW) A WPF Window (MVVM) for managing watched projects: - **ListView** showing all ProjectConfig entries (Name, EngineeringPath, SimulationPath, Active-Status) - **"Neues Projekt"** button → Opens inline form or dialog: - Name (TextBox) - Engineering-Pfad (TextBox + FolderBrowserDialog via Button) - Simulations-Pfad (TextBox + FolderBrowserDialog via Button) - Dateiendungen (TextBox, comma-separated, default: ".jt,.cojt,.xml") - Aktiv (CheckBox) - **"Bearbeiten"** / **"Löschen"** buttons per row - All CRUD calls go to `POST/PUT/DELETE /api/projects` - Path validation: Check that folders exist before saving ### 4.4 Pending Changes Window - MVVM with `DataGrid` - **Project selector** (ComboBox) at top → fetches from `GET /api/projects` - Columns: Datei, Änderungstyp, Zeitstempel, Auswahl (CheckBox) - **"Ausgewählte synchronisieren"** → `POST /api/sync` - **"Ausgewählte ignorieren"** → `POST /api/ignore` - **"Alle synchronisieren"** / **"Alle ignorieren"** convenience buttons - Auto-refresh when SignalR notification arrives for the selected project --- ## Phase 5: Build Order & Execution Build step-by-step, verify each phase compiles before proceeding: 1. **Phase 1** – Solution scaffolding via `dotnet` CLI. Verify `dotnet build` succeeds. 2. **Phase 2** – Domain entities + EF Core DbContext + initial migration. Verify migration applies. 3. **Phase 3.1** – Project CRUD API endpoints. Test with manual HTTP requests. 4. **Phase 3.2** – WatcherService with Channel debouncing. Test with file drops. 5. **Phase 3.3** – SignalR hub + remaining API endpoints. 6. **Phase 3.4** – SyncManager copy logic. 7. **Phase 4.1+4.2** – TrayApp shell with SignalR client. 8. **Phase 4.3** – Project Management Window (path configuration UI). 9. **Phase 4.4** – Pending Changes Window. Use `CommunityToolkit.Mvvm` for `[ObservableProperty]`, `[RelayCommand]` source generators in all ViewModels. Ensure all code compiles under .NET 10. Use clean architecture and dependency injection throughout.