Refactor: solo SQLite, limiti auto, UI statistiche nuova

Rimosso completamente il supporto a PostgreSQL: ora tutte le statistiche e i dati persistenti usano solo SQLite, con percorso configurabile tramite DATA_PATH per Docker/volumi. Aggiunta gestione avanzata delle statistiche per prodotto, limiti consigliati calcolati automaticamente e applicabili dalla UI. Rinnovata la pagina Statistiche con tabelle aste recenti e prodotti, rimosso il supporto a grafici legacy e a "Puntate Gratuite". Migliorata la ricerca e la gestione delle aste nel browser, aggiunta diagnostica avanzata e logging dettagliato per il database. Aggiornati Dockerfile e docker-compose: l'app è ora self-contained e pronta per l'uso senza database esterni.
This commit is contained in:
2026-01-23 16:56:03 +01:00
parent 21a1d57cab
commit a0ec72f6c0
19 changed files with 2311 additions and 968 deletions

View File

@@ -37,8 +37,14 @@ namespace AutoBidder.Models
public double MaxPrice { get; set; } = 0;
public int MinResets { get; set; } = 0; // Numero minimo reset prima di puntare
public int MaxResets { get; set; } = 0; // Numero massimo reset (0 = illimitati)
/// <summary>
/// [OBSOLETO] Numero massimo di puntate consentite - Non più utilizzato nell'UI
/// Mantenuto per retrocompatibilità con salvataggi JSON esistenti
/// </summary>
[Obsolete("MaxClicks non è più utilizzato. Usa invece la logica di limiti per prodotto.")]
[JsonPropertyName("MaxClicks")]
public int MaxClicks { get; set; } = 0; // Numero massimo di puntate consentite (0 = illimitato)
public int MaxClicks { get; set; } = 0;
// Stato asta
public bool IsActive { get; set; } = true;

View File

@@ -0,0 +1,120 @@
namespace AutoBidder.Models
{
/// <summary>
/// Record per le statistiche aggregate di un prodotto nel database
/// </summary>
public class ProductStatisticsRecord
{
public string ProductKey { get; set; } = string.Empty;
public string ProductName { get; set; } = string.Empty;
// Contatori
public int TotalAuctions { get; set; }
public int WonAuctions { get; set; }
public int LostAuctions { get; set; }
// Statistiche prezzo
public double AvgFinalPrice { get; set; }
public double? MinFinalPrice { get; set; }
public double? MaxFinalPrice { get; set; }
// Statistiche puntate
public double AvgBidsToWin { get; set; }
public int? MinBidsToWin { get; set; }
public int? MaxBidsToWin { get; set; }
// Statistiche reset
public double AvgResets { get; set; }
public int? MinResets { get; set; }
public int? MaxResets { get; set; }
// Limiti consigliati (calcolati dall'algoritmo)
public double? RecommendedMinPrice { get; set; }
public double? RecommendedMaxPrice { get; set; }
public int? RecommendedMinResets { get; set; }
public int? RecommendedMaxResets { get; set; }
public int? RecommendedMaxBids { get; set; }
// JSON con statistiche per fascia oraria
public string? HourlyStatsJson { get; set; }
// Metadata
public string? LastUpdated { get; set; }
/// <summary>
/// Calcola il win rate come percentuale
/// </summary>
public double WinRate => TotalAuctions > 0 ? (double)WonAuctions / TotalAuctions * 100 : 0;
}
/// <summary>
/// Risultato asta esteso con tutti i campi per analytics
/// </summary>
public class AuctionResultExtended
{
public int Id { get; set; }
public string AuctionId { get; set; } = "";
public string AuctionName { get; set; } = "";
public double FinalPrice { get; set; }
public int BidsUsed { get; set; }
public bool Won { get; set; }
public string Timestamp { get; set; } = "";
public double? BuyNowPrice { get; set; }
public double? ShippingCost { get; set; }
public double? TotalCost { get; set; }
public double? Savings { get; set; }
// Campi estesi per analytics
public string? WinnerUsername { get; set; }
public int? ClosedAtHour { get; set; }
public string? ProductKey { get; set; }
public int? TotalResets { get; set; }
public int? WinnerBidsUsed { get; set; }
}
/// <summary>
/// Limiti consigliati per un'asta basati sulle statistiche storiche
/// </summary>
public class RecommendedLimits
{
public double MinPrice { get; set; }
public double MaxPrice { get; set; }
public int MinResets { get; set; }
public int MaxResets { get; set; }
public int MaxBids { get; set; }
/// <summary>
/// Confidence score (0-100) - quanto sono affidabili questi limiti
/// </summary>
public int ConfidenceScore { get; set; }
/// <summary>
/// Numero di aste usate per calcolare i limiti
/// </summary>
public int SampleSize { get; set; }
/// <summary>
/// Fascia oraria migliore per vincere (0-23)
/// </summary>
public int? BestHourToPlay { get; set; }
/// <summary>
/// Win rate medio per questo prodotto
/// </summary>
public double? AverageWinRate { get; set; }
}
/// <summary>
/// Statistiche per fascia oraria
/// </summary>
public class HourlyStats
{
public int Hour { get; set; }
public int TotalAuctions { get; set; }
public int WonAuctions { get; set; }
public double AvgFinalPrice { get; set; }
public double AvgBidsUsed { get; set; }
public double WinRate => TotalAuctions > 0 ? (double)WonAuctions / TotalAuctions * 100 : 0;
}
}