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>
53 lines
1.9 KiB
C#
53 lines
1.9 KiB
C#
using EngineeringSync.Domain.Entities;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace EngineeringSync.Infrastructure;
|
|
|
|
public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
|
|
{
|
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
|
{
|
|
if (optionsBuilder.IsConfigured) return;
|
|
// WAL-Modus für bessere Nebenläufigkeit zwischen Watcher-Writer und API-Reader
|
|
optionsBuilder.UseSqlite(o => o.CommandTimeout(30));
|
|
}
|
|
|
|
|
|
public DbSet<ProjectConfig> Projects => Set<ProjectConfig>();
|
|
public DbSet<FileRevision> FileRevisions => Set<FileRevision>();
|
|
public DbSet<PendingChange> PendingChanges => Set<PendingChange>();
|
|
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
{
|
|
modelBuilder.Entity<ProjectConfig>(e =>
|
|
{
|
|
e.HasKey(p => p.Id);
|
|
e.Property(p => p.Name).IsRequired().HasMaxLength(200);
|
|
e.Property(p => p.EngineeringPath).IsRequired();
|
|
e.Property(p => p.SimulationPath).IsRequired();
|
|
e.Property(p => p.BackupEnabled).HasDefaultValue(true);
|
|
e.Property(p => p.BackupPath).HasDefaultValue(null);
|
|
e.Property(p => p.MaxBackupsPerFile).HasDefaultValue(0);
|
|
});
|
|
|
|
modelBuilder.Entity<FileRevision>(e =>
|
|
{
|
|
e.HasKey(r => r.Id);
|
|
e.HasIndex(r => new { r.ProjectId, r.RelativePath }).IsUnique();
|
|
e.HasOne(r => r.Project)
|
|
.WithMany(p => p.FileRevisions)
|
|
.HasForeignKey(r => r.ProjectId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<PendingChange>(e =>
|
|
{
|
|
e.HasKey(c => c.Id);
|
|
e.HasOne(c => c.Project)
|
|
.WithMany(p => p.PendingChanges)
|
|
.HasForeignKey(c => c.ProjectId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
}
|
|
}
|