Files
EngineeringSync/plan.md
EngineeringSync 04ae8a0aae Initial commit: EngineeringSync v1.0.0
Vollständige Implementierung des EngineeringSync-Middleware-Tools:
- Windows Service (Kestrel :5050) mit FileSystemWatcher + SignalR
- WPF Tray-App mit PendingChanges- und Projektverwaltungs-Fenster
- Setup-Wizard (8-Schritte-Installer)
- SQLite/EF Core Datenschicht (WAL-Modus)
- SHA-256-basiertes Debouncing (2s Fenster)
- Backup-System mit konfigurierbarer Aufbewahrung

Bugfixes & Verbesserungen:
- BUG-1: AppDbContext OnConfiguring invertierte Bedingung behoben
- BUG-2: Event-Handler-Leak in TrayApp (Fenster-Singleton-Pattern)
- BUG-3: ProjectConfigChanged SignalR-Signal in allen CRUD-Endpoints
- BUG-5: Rename-Sync löscht alte Datei im Simulations-Ordner
- BUG-6: Doppeltes Dispose von SignalR verhindert
- BUG-7: Registry-Deinstallation nur EngineeringSync-Eintrag entfernt
- S1: Path-Traversal-Schutz via SafeCombine() im SyncManager
- E1: FSW Buffer 64KB + automatischer Re-Scan bei Overflow
- E2: Retry-Logik (3x) für gesperrte Dateien mit exponentiellem Backoff
- E4: Channel.Writer.TryComplete() beim Shutdown
- C2: HubMethodNames-Konstanten statt Magic Strings
- E3: Pagination in Changes-API (page/pageSize Query-Parameter)
- A1: Fire-and-Forget mit try/catch + Logging

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 21:52:26 +01:00

211 lines
9.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.