Files
EngineeringSync/AGENTS.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

6.3 KiB

AGENTS.md

Build, Test & Run Commands

# Build entire solution
dotnet build EngineeringSync.slnx

# Run the background service (dev mode)
dotnet run --project EngineeringSync.Service

# Run the WPF tray app
dotnet run --project EngineeringSync.TrayApp

# Run all tests
dotnet test

# Run a single test project
dotnet test EngineeringSync.Tests --filter "FullyQualifiedName~WatcherServiceTests"

# Run tests with verbose output
dotnet test --verbosity normal

# Build Release
dotnet build EngineeringSync.slnx -c Release

# Install as Windows Service (production)
sc create EngineeringSync binPath="<path>\EngineeringSync.Service.exe"

# Build installer (requires Inno Setup 6)
.\installer\build-installer.ps1

Code Style Guidelines

General Principles

  • Use C# 12+ features (file-scoped namespaces, collection expressions, primary constructors)
  • Use [ObservableProperty] and [RelayCommand] attributes from CommunityToolkit.Mvvm
  • Prefer source generators over boilerplate code

Imports

  • Sort by: System namespaces first, then Microsoft, then third-party, then project-specific
  • Use file-scoped namespaces: namespace EngineeringSync.Domain.Entities;
  • Global using statements in each project for common types

Types & Collections

  • Use collection expressions [] instead of new List<T>() where possible
  • Use IReadOnlyList<T> for parameters that should not be modified
  • Use Guid for all ID types
  • Use DateTime.UtcNow for timestamps, convert to local time in UI layer only

Naming Conventions

  • Classes/Interfaces: PascalCase (e.g., WatcherService, IApiClient)
  • Methods: PascalCase (e.g., StartWatchingAsync)
  • Private fields: camelCase (e.g., _watchers, _channel)
  • Properties: PascalCase (e.g., IsActive, EngineeringPath)
  • Parameters: camelCase (e.g., project, stoppingToken)
  • Constants: PascalCase (e.g., DefaultTimeout)

Records vs Classes

  • Use record for DTOs and API models
  • Use class for entities with mutable properties

Error Handling

  • Use try/catch with specific exception types
  • Log exceptions with context using ILogger (use structured logging: logger.LogError(ex, "Message {Param}", param))
  • In ViewModels, catch exceptions and set StatusMessage for user feedback

Async/Await

  • Always use Async suffix for async methods
  • Pass CancellationToken to all cancellable operations
  • Use await using for IDisposable resources that implement IAsyncDisposable

Entity Framework Core

  • Use IDbContextFactory<AppDbContext> for scoped DbContext in background services
  • Use await using var db = await dbFactory.CreateDbContextAsync(ct);
  • Configure SQLite with WAL mode for better concurrency

WPF / MVVM

  • ViewModels inherit from ObservableObject (CommunityToolkit.Mvvm)
  • Use [ObservableProperty] for properties that need change notification
  • Use [RelayCommand] for commands
  • Use partial class for generated properties

Dependency Injection

  • Constructor injection with primary constructors:
    public sealed class WatcherService(
        IDbContextFactory<AppDbContext> dbFactory,
        IHubContext<NotificationHub> hub,
        ILogger<WatcherService> logger) : BackgroundService
    

File Organization

EngineeringSync.Domain/       - Entities, Enums, Interfaces
EngineeringSync.Infrastructure/ - EF Core, DbContext, Migrations
EngineeringSync.Service/      - API, Hubs, Background Services
EngineeringSync.TrayApp/      - WPF Views, ViewModels, Services
EngineeringSync.Setup/        - Installer wizard

Key Patterns

FileSystemWatcher Debouncing: Events flow into a Channel<FileEvent>, consumer groups by (ProjectId, RelativePath) within 2000ms window, SHA-256 confirms actual changes.

SignalR Notifications: NotificationHub at /notifications broadcasts ReceiveChangeNotification(projectId, projectName, count) to all clients.

Backup before sync: Use timestamped naming {filename}_{yyyyMMdd_HHmmss}.bak.

Service API Endpoints

  • GET/POST/PUT/DELETE /api/projects - Project CRUD
  • GET /api/changes/{projectId} - Get pending changes
  • GET /api/changes/{projectId}/history - Get synced/ignored changes
  • POST /api/sync - Sync selected changes
  • POST /api/ignore - Ignore selected changes

Database

  • SQLite with WAL mode
  • Entities: ProjectConfig, FileRevision, PendingChange
  • ProjectConfig.FileExtensions is comma-separated (e.g., ".jt,.cojt,.xml")

Solution Structure

EngineeringSync.slnx
├── EngineeringSync.Domain/         (Class Library, net10.0) - Entities, Enums, Interfaces
├── EngineeringSync.Infrastructure/  (Class Library, net10.0) - EF Core, DbContext
├── EngineeringSync.Service/         (Worker Service, net10.0) - Kestrel on :5050, SignalR hub
├── EngineeringSync.TrayApp/         (WPF App, net10.0-windows) - System tray + UI windows
├── EngineeringSync.Setup/           (WPF App, net10.0-windows) - Setup wizard + Installer
└── installer/
    ├── setup.iss                     - Inno Setup Script
    └── build-installer.ps1           - Build + Publish + ISCC Pipeline

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 + CommunityToolkit.Mvvm
  • Database: SQLite via EF Core 10 (WAL mode)
  • File Watching: System.IO.FileSystemWatcher + System.Threading.Channels (debouncing)

Key Architecture

  • ProjectConfig in DB: Managed via TrayApp UI, stored in SQLite. User adds/edits/deletes projects with folder browser dialogs. CRUD operations go through Service API, which dynamically starts/stops watchers.
  • FileSystemWatcher Debouncing: Events (Created, Changed, Renamed, Deleted) pushed into Channel<FileEvent>. Consumer groups events by (ProjectId, RelativePath) within 2000ms sliding window. SHA-256 hashing against FileRevision confirms actual changes before writing a PendingChange.
  • SignalR Hub: NotificationHub at /notifications broadcasts ReceiveChangeNotification(projectId, projectName, count) and ProjectConfigChanged().

Notes

  • Domain project has no dependencies (pure entities/enums)
  • Infrastructure depends on Domain
  • Service depends on Domain + Infrastructure
  • TrayApp depends on Domain + Service (via HTTP client)