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

155 lines
6.3 KiB
Markdown

# AGENTS.md
## Build, Test & Run Commands
```bash
# 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:
```csharp
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)