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

9.0 KiB
Raw Permalink Blame 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):

  • InfrastructureDomain
  • ServiceDomain + Infrastructure
  • TrayAppDomain (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.