feat: Implementazione completa sistema schedulazione con intervalli personalizzati

- Aggiunto supporto schedulazione con intervalli flessibili (secondi/minuti/ore/giorni/settimane/mesi)
- Esteso modello ProfileSchedule con campi IntervalValue e IntervalUnit
- Ottimizzato ScheduledJobService per controlli ogni 30s con esecuzione parallela
- Implementata interfaccia UI completa con anteprima real-time in italiano
- Aggiunta migrazione database AddIntervalSchedulingFields
- Implementati metodi calcolo NextExecutionTime per intervalli
- Aggiunta gestione tracking anti-duplicati e cleanup automatico
- Creata documentazione completa (6 file, 2500+ righe)

Modifiche tecniche:
- ProfileSchedule.cs: Nuovi campi e metodi CalculateNextInterval/GetScheduleDescription
- ScheduledJobService.cs: Ridotto check interval a 30s, aggiunto parallel processing
- ProfileScheduleService.cs: Supporto calcolo intervalli in UpdateNextExecutionTimeAsync
- Scheduling.razor: Aggiunta sezione UI per configurazione intervalli
- Scheduling.razor.cs: Implementato GetIntervalPreview() e gestione stato campi
This commit is contained in:
2025-10-02 01:12:39 +02:00
parent b76a6760fb
commit d042863a56
71 changed files with 17860 additions and 144 deletions
@@ -320,6 +320,190 @@ namespace CredentialManager.Migrations
b.ToTable("KeyAssociations", (string)null);
});
modelBuilder.Entity("CredentialManager.Models.ProfileSchedule", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("CreatedBy")
.HasMaxLength(100)
.HasColumnType("TEXT");
b.Property<string>("DailyTime")
.HasMaxLength(10)
.HasColumnType("TEXT");
b.Property<int?>("DayOfMonth")
.HasColumnType("INTEGER");
b.Property<int?>("DayOfWeek")
.HasColumnType("INTEGER");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("TEXT");
b.Property<string>("DestinationDatabaseOverride")
.HasMaxLength(100)
.HasColumnType("TEXT");
b.Property<int>("ExecutionCount")
.HasColumnType("INTEGER");
b.Property<string>("IntervalUnit")
.HasMaxLength(20)
.HasColumnType("TEXT");
b.Property<int?>("IntervalValue")
.HasColumnType("INTEGER");
b.Property<bool>("IsActive")
.HasColumnType("INTEGER");
b.Property<bool>("IsEnabled")
.HasColumnType("INTEGER");
b.Property<string>("LastExecutionMessage")
.HasMaxLength(1000)
.HasColumnType("TEXT");
b.Property<int?>("LastExecutionRecordCount")
.HasColumnType("INTEGER");
b.Property<string>("LastExecutionStatus")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("TEXT");
b.Property<DateTime?>("LastExecutionTime")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("TEXT");
b.Property<DateTime?>("NextExecutionTime")
.HasColumnType("TEXT");
b.Property<int>("ProfileId")
.HasColumnType("INTEGER");
b.Property<string>("ScheduleType")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("TEXT");
b.Property<DateTime?>("ScheduledDateTime")
.HasColumnType("TEXT");
b.Property<string>("SourceDatabaseOverride")
.HasMaxLength(100)
.HasColumnType("TEXT");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("ProfileId");
b.ToTable("ProfileSchedules");
});
modelBuilder.Entity("CredentialManager.Models.ScheduleExecutionHistory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AdditionalInfo")
.HasMaxLength(2000)
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("DestinationInfo")
.HasMaxLength(500)
.HasColumnType("TEXT");
b.Property<string>("DestinationType")
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<DateTime?>("EndTime")
.HasColumnType("TEXT");
b.Property<string>("ErrorDetails")
.HasMaxLength(5000)
.HasColumnType("TEXT");
b.Property<string>("Message")
.HasMaxLength(2000)
.HasColumnType("TEXT");
b.Property<int>("ProfileId")
.HasColumnType("INTEGER");
b.Property<string>("ProfileName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("TEXT");
b.Property<int>("RecordsProcessed")
.HasColumnType("INTEGER");
b.Property<int?>("RecordsWithErrors")
.HasColumnType("INTEGER");
b.Property<int>("ScheduleId")
.HasColumnType("INTEGER");
b.Property<string>("SourceInfo")
.HasMaxLength(500)
.HasColumnType("TEXT");
b.Property<string>("SourceType")
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<DateTime>("StartTime")
.HasColumnType("TEXT");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("TEXT");
b.Property<string>("TriggerType")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("TEXT");
b.Property<string>("TriggeredBy")
.HasMaxLength(100)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("ProfileId");
b.HasIndex("ScheduleId");
b.HasIndex("StartTime");
b.HasIndex("Status");
b.HasIndex("TriggerType");
b.ToTable("ScheduleExecutionHistories", (string)null);
});
modelBuilder.Entity("CredentialManager.Models.DataCouplerProfile", b =>
{
b.HasOne("CredentialManager.Models.CredentialEntity", "DestinationCredential")
@@ -336,6 +520,28 @@ namespace CredentialManager.Migrations
b.Navigation("SourceCredential");
});
modelBuilder.Entity("CredentialManager.Models.ProfileSchedule", b =>
{
b.HasOne("CredentialManager.Models.DataCouplerProfile", "Profile")
.WithMany()
.HasForeignKey("ProfileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Profile");
});
modelBuilder.Entity("CredentialManager.Models.ScheduleExecutionHistory", b =>
{
b.HasOne("CredentialManager.Models.ProfileSchedule", "Schedule")
.WithMany()
.HasForeignKey("ScheduleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Schedule");
});
#pragma warning restore 612, 618
}
}