Files

211 lines
9.0 KiB
Markdown
Raw Permalink Normal View History

# 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<ProjectConfig>`, `DbSet<FileRevision>`, `DbSet<PendingChange>`
- 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<FileEvent>` (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.