diff --git a/code/backend/Cleanuparr.Persistence/Migrations/Data/20260310181205_RemoveProcessMissingId.Designer.cs b/code/backend/Cleanuparr.Persistence/Migrations/Data/20260310181205_RemoveProcessMissingId.Designer.cs
new file mode 100644
index 00000000..d5c474bc
--- /dev/null
+++ b/code/backend/Cleanuparr.Persistence/Migrations/Data/20260310181205_RemoveProcessMissingId.Designer.cs
@@ -0,0 +1,1300 @@
+//
+using System;
+using System.Collections.Generic;
+using Cleanuparr.Persistence;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Cleanuparr.Persistence.Migrations.Data
+{
+ [DbContext(typeof(DataContext))]
+ [Migration("20260310181205_RemoveProcessMissingId")]
+ partial class RemoveProcessMissingId
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "10.0.1");
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Arr.ArrConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("FailedImportMaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_max_strikes");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type");
+
+ b.HasKey("Id")
+ .HasName("pk_arr_configs");
+
+ b.ToTable("arr_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Arr.ArrInstance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("ApiKey")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("api_key");
+
+ b.Property("ArrConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("arr_config_id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("ExternalUrl")
+ .HasColumnType("TEXT")
+ .HasColumnName("external_url");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("Url")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("url");
+
+ b.Property("Version")
+ .HasColumnType("REAL")
+ .HasColumnName("version");
+
+ b.HasKey("Id")
+ .HasName("pk_arr_instances");
+
+ b.HasIndex("ArrConfigId")
+ .HasDatabaseName("ix_arr_instances_arr_config_id");
+
+ b.ToTable("arr_instances", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.BlacklistSync.BlacklistSyncConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("BlacklistPath")
+ .HasColumnType("TEXT")
+ .HasColumnName("blacklist_path");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("cron_expression");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.HasKey("Id")
+ .HasName("pk_blacklist_sync_configs");
+
+ b.ToTable("blacklist_sync_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.DownloadCleaner.DownloadCleanerConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("cron_expression");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.PrimitiveCollection("IgnoredDownloads")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("ignored_downloads");
+
+ b.PrimitiveCollection("UnlinkedCategories")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_categories");
+
+ b.Property("UnlinkedEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("unlinked_enabled");
+
+ b.PrimitiveCollection("UnlinkedIgnoredRootDirs")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_ignored_root_dirs");
+
+ b.Property("UnlinkedTargetCategory")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_target_category");
+
+ b.Property("UnlinkedUseTag")
+ .HasColumnType("INTEGER")
+ .HasColumnName("unlinked_use_tag");
+
+ b.Property("UseAdvancedScheduling")
+ .HasColumnType("INTEGER")
+ .HasColumnName("use_advanced_scheduling");
+
+ b.HasKey("Id")
+ .HasName("pk_download_cleaner_configs");
+
+ b.ToTable("download_cleaner_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.DownloadCleaner.SeedingRule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("DeleteSourceFiles")
+ .HasColumnType("INTEGER")
+ .HasColumnName("delete_source_files");
+
+ b.Property("DownloadCleanerConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("download_cleaner_config_id");
+
+ b.Property("MaxRatio")
+ .HasColumnType("REAL")
+ .HasColumnName("max_ratio");
+
+ b.Property("MaxSeedTime")
+ .HasColumnType("REAL")
+ .HasColumnName("max_seed_time");
+
+ b.Property("MinSeedTime")
+ .HasColumnType("REAL")
+ .HasColumnName("min_seed_time");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("PrivacyType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("privacy_type");
+
+ b.HasKey("Id")
+ .HasName("pk_seeding_rules");
+
+ b.HasIndex("DownloadCleanerConfigId")
+ .HasDatabaseName("ix_seeding_rules_download_cleaner_config_id");
+
+ b.ToTable("seeding_rules", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.DownloadClientConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("ExternalUrl")
+ .HasColumnType("TEXT")
+ .HasColumnName("external_url");
+
+ b.Property("Host")
+ .HasColumnType("TEXT")
+ .HasColumnName("host");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("Password")
+ .HasColumnType("TEXT")
+ .HasColumnName("password");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type");
+
+ b.Property("TypeName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type_name");
+
+ b.Property("UrlBase")
+ .HasColumnType("TEXT")
+ .HasColumnName("url_base");
+
+ b.Property("Username")
+ .HasColumnType("TEXT")
+ .HasColumnName("username");
+
+ b.HasKey("Id")
+ .HasName("pk_download_clients");
+
+ b.ToTable("download_clients", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.General.GeneralConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("DisplaySupportBanner")
+ .HasColumnType("INTEGER")
+ .HasColumnName("display_support_banner");
+
+ b.Property("DryRun")
+ .HasColumnType("INTEGER")
+ .HasColumnName("dry_run");
+
+ b.Property("EncryptionKey")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("encryption_key");
+
+ b.Property("HttpCertificateValidation")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("http_certificate_validation");
+
+ b.Property("HttpMaxRetries")
+ .HasColumnType("INTEGER")
+ .HasColumnName("http_max_retries");
+
+ b.Property("HttpTimeout")
+ .HasColumnType("INTEGER")
+ .HasColumnName("http_timeout");
+
+ b.PrimitiveCollection("IgnoredDownloads")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("ignored_downloads");
+
+ b.Property("SearchDelay")
+ .HasColumnType("INTEGER")
+ .HasColumnName("search_delay");
+
+ b.Property("SearchEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("search_enabled");
+
+ b.Property("StatusCheckEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("status_check_enabled");
+
+ b.Property("StrikeInactivityWindowHours")
+ .HasColumnType("INTEGER")
+ .HasColumnName("strike_inactivity_window_hours");
+
+ b.ComplexProperty(typeof(Dictionary), "Auth", "Cleanuparr.Persistence.Models.Configuration.General.GeneralConfig.Auth#AuthConfig", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("DisableAuthForLocalAddresses")
+ .HasColumnType("INTEGER")
+ .HasColumnName("auth_disable_auth_for_local_addresses");
+
+ b1.Property("TrustForwardedHeaders")
+ .HasColumnType("INTEGER")
+ .HasColumnName("auth_trust_forwarded_headers");
+
+ b1.Property("TrustedNetworks")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("auth_trusted_networks");
+ });
+
+ b.ComplexProperty(typeof(Dictionary), "Log", "Cleanuparr.Persistence.Models.Configuration.General.GeneralConfig.Log#LoggingConfig", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("ArchiveEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("log_archive_enabled");
+
+ b1.Property("ArchiveRetainedCount")
+ .HasColumnType("INTEGER")
+ .HasColumnName("log_archive_retained_count");
+
+ b1.Property("ArchiveTimeLimitHours")
+ .HasColumnType("INTEGER")
+ .HasColumnName("log_archive_time_limit_hours");
+
+ b1.Property("Level")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("log_level");
+
+ b1.Property("RetainedFileCount")
+ .HasColumnType("INTEGER")
+ .HasColumnName("log_retained_file_count");
+
+ b1.Property("RollingSizeMB")
+ .HasColumnType("INTEGER")
+ .HasColumnName("log_rolling_size_mb");
+
+ b1.Property("TimeLimitHours")
+ .HasColumnType("INTEGER")
+ .HasColumnName("log_time_limit_hours");
+ });
+
+ b.HasKey("Id")
+ .HasName("pk_general_configs");
+
+ b.ToTable("general_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.MalwareBlocker.ContentBlockerConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("cron_expression");
+
+ b.Property("DeletePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("delete_private");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("IgnorePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("ignore_private");
+
+ b.PrimitiveCollection("IgnoredDownloads")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("ignored_downloads");
+
+ b.Property("UseAdvancedScheduling")
+ .HasColumnType("INTEGER")
+ .HasColumnName("use_advanced_scheduling");
+
+ b.ComplexProperty(typeof(Dictionary), "Lidarr", "Cleanuparr.Persistence.Models.Configuration.MalwareBlocker.ContentBlockerConfig.Lidarr#BlocklistSettings", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("BlocklistPath")
+ .HasColumnType("TEXT")
+ .HasColumnName("lidarr_blocklist_path");
+
+ b1.Property("BlocklistType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("lidarr_blocklist_type");
+
+ b1.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("lidarr_enabled");
+ });
+
+ b.ComplexProperty(typeof(Dictionary), "Radarr", "Cleanuparr.Persistence.Models.Configuration.MalwareBlocker.ContentBlockerConfig.Radarr#BlocklistSettings", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("BlocklistPath")
+ .HasColumnType("TEXT")
+ .HasColumnName("radarr_blocklist_path");
+
+ b1.Property("BlocklistType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("radarr_blocklist_type");
+
+ b1.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("radarr_enabled");
+ });
+
+ b.ComplexProperty(typeof(Dictionary), "Readarr", "Cleanuparr.Persistence.Models.Configuration.MalwareBlocker.ContentBlockerConfig.Readarr#BlocklistSettings", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("BlocklistPath")
+ .HasColumnType("TEXT")
+ .HasColumnName("readarr_blocklist_path");
+
+ b1.Property("BlocklistType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("readarr_blocklist_type");
+
+ b1.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("readarr_enabled");
+ });
+
+ b.ComplexProperty(typeof(Dictionary), "Sonarr", "Cleanuparr.Persistence.Models.Configuration.MalwareBlocker.ContentBlockerConfig.Sonarr#BlocklistSettings", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("BlocklistPath")
+ .HasColumnType("TEXT")
+ .HasColumnName("sonarr_blocklist_path");
+
+ b1.Property("BlocklistType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("sonarr_blocklist_type");
+
+ b1.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("sonarr_enabled");
+ });
+
+ b.ComplexProperty(typeof(Dictionary), "Whisparr", "Cleanuparr.Persistence.Models.Configuration.MalwareBlocker.ContentBlockerConfig.Whisparr#BlocklistSettings", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("BlocklistPath")
+ .HasColumnType("TEXT")
+ .HasColumnName("whisparr_blocklist_path");
+
+ b1.Property("BlocklistType")
+ .HasColumnType("INTEGER")
+ .HasColumnName("whisparr_blocklist_type");
+
+ b1.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("whisparr_enabled");
+ });
+
+ b.HasKey("Id")
+ .HasName("pk_content_blocker_configs");
+
+ b.ToTable("content_blocker_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.AppriseConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Key")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("TEXT")
+ .HasColumnName("key");
+
+ b.Property("Mode")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("mode");
+
+ b.Property("NotificationConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("notification_config_id");
+
+ b.Property("ServiceUrls")
+ .HasMaxLength(4000)
+ .HasColumnType("TEXT")
+ .HasColumnName("service_urls");
+
+ b.Property("Tags")
+ .HasMaxLength(255)
+ .HasColumnType("TEXT")
+ .HasColumnName("tags");
+
+ b.Property("Url")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("TEXT")
+ .HasColumnName("url");
+
+ b.HasKey("Id")
+ .HasName("pk_apprise_configs");
+
+ b.HasIndex("NotificationConfigId")
+ .IsUnique()
+ .HasDatabaseName("ix_apprise_configs_notification_config_id");
+
+ b.ToTable("apprise_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.DiscordConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("AvatarUrl")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("TEXT")
+ .HasColumnName("avatar_url");
+
+ b.Property("NotificationConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("notification_config_id");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasMaxLength(80)
+ .HasColumnType("TEXT")
+ .HasColumnName("username");
+
+ b.Property("WebhookUrl")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("TEXT")
+ .HasColumnName("webhook_url");
+
+ b.HasKey("Id")
+ .HasName("pk_discord_configs");
+
+ b.HasIndex("NotificationConfigId")
+ .IsUnique()
+ .HasDatabaseName("ix_discord_configs_notification_config_id");
+
+ b.ToTable("discord_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.GotifyConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("ApplicationToken")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("TEXT")
+ .HasColumnName("application_token");
+
+ b.Property("NotificationConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("notification_config_id");
+
+ b.Property("Priority")
+ .HasColumnType("INTEGER")
+ .HasColumnName("priority");
+
+ b.Property("ServerUrl")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("TEXT")
+ .HasColumnName("server_url");
+
+ b.HasKey("Id")
+ .HasName("pk_gotify_configs");
+
+ b.HasIndex("NotificationConfigId")
+ .IsUnique()
+ .HasDatabaseName("ix_gotify_configs_notification_config_id");
+
+ b.ToTable("gotify_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.NotifiarrConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("ApiKey")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("TEXT")
+ .HasColumnName("api_key");
+
+ b.Property("ChannelId")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("TEXT")
+ .HasColumnName("channel_id");
+
+ b.Property("NotificationConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("notification_config_id");
+
+ b.HasKey("Id")
+ .HasName("pk_notifiarr_configs");
+
+ b.HasIndex("NotificationConfigId")
+ .IsUnique()
+ .HasDatabaseName("ix_notifiarr_configs_notification_config_id");
+
+ b.ToTable("notifiarr_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.NotificationConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("created_at");
+
+ b.Property("IsEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("is_enabled");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("OnCategoryChanged")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_category_changed");
+
+ b.Property("OnDownloadCleaned")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_download_cleaned");
+
+ b.Property("OnFailedImportStrike")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_failed_import_strike");
+
+ b.Property("OnQueueItemDeleted")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_queue_item_deleted");
+
+ b.Property("OnSlowStrike")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_slow_strike");
+
+ b.Property("OnStalledStrike")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_stalled_strike");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("updated_at");
+
+ b.HasKey("Id")
+ .HasName("pk_notification_configs");
+
+ b.HasIndex("Name")
+ .IsUnique()
+ .HasDatabaseName("ix_notification_configs_name");
+
+ b.ToTable("notification_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.NtfyConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("AccessToken")
+ .HasMaxLength(500)
+ .HasColumnType("TEXT")
+ .HasColumnName("access_token");
+
+ b.Property("AuthenticationType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("authentication_type");
+
+ b.Property("NotificationConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("notification_config_id");
+
+ b.Property("Password")
+ .HasMaxLength(255)
+ .HasColumnType("TEXT")
+ .HasColumnName("password");
+
+ b.Property("Priority")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("priority");
+
+ b.Property("ServerUrl")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("TEXT")
+ .HasColumnName("server_url");
+
+ b.PrimitiveCollection("Tags")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("tags");
+
+ b.PrimitiveCollection("Topics")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("topics");
+
+ b.Property("Username")
+ .HasMaxLength(255)
+ .HasColumnType("TEXT")
+ .HasColumnName("username");
+
+ b.HasKey("Id")
+ .HasName("pk_ntfy_configs");
+
+ b.HasIndex("NotificationConfigId")
+ .IsUnique()
+ .HasDatabaseName("ix_ntfy_configs_notification_config_id");
+
+ b.ToTable("ntfy_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.PushoverConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("ApiToken")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("TEXT")
+ .HasColumnName("api_token");
+
+ b.Property("Devices")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("devices");
+
+ b.Property("Expire")
+ .HasColumnType("INTEGER")
+ .HasColumnName("expire");
+
+ b.Property("NotificationConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("notification_config_id");
+
+ b.Property("Priority")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("priority");
+
+ b.Property("Retry")
+ .HasColumnType("INTEGER")
+ .HasColumnName("retry");
+
+ b.Property("Sound")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT")
+ .HasColumnName("sound");
+
+ b.Property("Tags")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("tags");
+
+ b.Property("UserKey")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("TEXT")
+ .HasColumnName("user_key");
+
+ b.HasKey("Id")
+ .HasName("pk_pushover_configs");
+
+ b.HasIndex("NotificationConfigId")
+ .IsUnique()
+ .HasDatabaseName("ix_pushover_configs_notification_config_id");
+
+ b.ToTable("pushover_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.TelegramConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("BotToken")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("TEXT")
+ .HasColumnName("bot_token");
+
+ b.Property("ChatId")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("TEXT")
+ .HasColumnName("chat_id");
+
+ b.Property("NotificationConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("notification_config_id");
+
+ b.Property("SendSilently")
+ .HasColumnType("INTEGER")
+ .HasColumnName("send_silently");
+
+ b.Property("TopicId")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT")
+ .HasColumnName("topic_id");
+
+ b.HasKey("Id")
+ .HasName("pk_telegram_configs");
+
+ b.HasIndex("NotificationConfigId")
+ .IsUnique()
+ .HasDatabaseName("ix_telegram_configs_notification_config_id");
+
+ b.ToTable("telegram_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.QueueCleaner.QueueCleanerConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("cron_expression");
+
+ b.Property("DownloadingMetadataMaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("downloading_metadata_max_strikes");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.PrimitiveCollection("IgnoredDownloads")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("ignored_downloads");
+
+ b.Property("UseAdvancedScheduling")
+ .HasColumnType("INTEGER")
+ .HasColumnName("use_advanced_scheduling");
+
+ b.ComplexProperty(typeof(Dictionary), "FailedImport", "Cleanuparr.Persistence.Models.Configuration.QueueCleaner.QueueCleanerConfig.FailedImport#FailedImportConfig", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("DeletePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_delete_private");
+
+ b1.Property("IgnorePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_ignore_private");
+
+ b1.Property("MaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_max_strikes");
+
+ b1.Property("PatternMode")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("failed_import_pattern_mode");
+
+ b1.PrimitiveCollection("Patterns")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("failed_import_patterns");
+
+ b1.Property("SkipIfNotFoundInClient")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_skip_if_not_found_in_client");
+ });
+
+ b.HasKey("Id")
+ .HasName("pk_queue_cleaner_configs");
+
+ b.ToTable("queue_cleaner_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.QueueCleaner.SlowRule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("DeletePrivateTorrentsFromClient")
+ .HasColumnType("INTEGER")
+ .HasColumnName("delete_private_torrents_from_client");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("IgnoreAboveSize")
+ .HasColumnType("TEXT")
+ .HasColumnName("ignore_above_size");
+
+ b.Property("MaxCompletionPercentage")
+ .HasColumnType("INTEGER")
+ .HasColumnName("max_completion_percentage");
+
+ b.Property("MaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("max_strikes");
+
+ b.Property("MaxTimeHours")
+ .HasColumnType("REAL")
+ .HasColumnName("max_time_hours");
+
+ b.Property("MinCompletionPercentage")
+ .HasColumnType("INTEGER")
+ .HasColumnName("min_completion_percentage");
+
+ b.Property("MinSpeed")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("min_speed");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("PrivacyType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("privacy_type");
+
+ b.Property("QueueCleanerConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("queue_cleaner_config_id");
+
+ b.Property("ResetStrikesOnProgress")
+ .HasColumnType("INTEGER")
+ .HasColumnName("reset_strikes_on_progress");
+
+ b.HasKey("Id")
+ .HasName("pk_slow_rules");
+
+ b.HasIndex("QueueCleanerConfigId")
+ .HasDatabaseName("ix_slow_rules_queue_cleaner_config_id");
+
+ b.ToTable("slow_rules", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.QueueCleaner.StallRule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("DeletePrivateTorrentsFromClient")
+ .HasColumnType("INTEGER")
+ .HasColumnName("delete_private_torrents_from_client");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("MaxCompletionPercentage")
+ .HasColumnType("INTEGER")
+ .HasColumnName("max_completion_percentage");
+
+ b.Property("MaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("max_strikes");
+
+ b.Property("MinCompletionPercentage")
+ .HasColumnType("INTEGER")
+ .HasColumnName("min_completion_percentage");
+
+ b.Property("MinimumProgress")
+ .HasColumnType("TEXT")
+ .HasColumnName("minimum_progress");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("PrivacyType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("privacy_type");
+
+ b.Property("QueueCleanerConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("queue_cleaner_config_id");
+
+ b.Property("ResetStrikesOnProgress")
+ .HasColumnType("INTEGER")
+ .HasColumnName("reset_strikes_on_progress");
+
+ b.HasKey("Id")
+ .HasName("pk_stall_rules");
+
+ b.HasIndex("QueueCleanerConfigId")
+ .HasDatabaseName("ix_stall_rules_queue_cleaner_config_id");
+
+ b.ToTable("stall_rules", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.State.BlacklistSyncHistory", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("DownloadClientId")
+ .HasColumnType("TEXT")
+ .HasColumnName("download_client_id");
+
+ b.Property("Hash")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("hash");
+
+ b.HasKey("Id")
+ .HasName("pk_blacklist_sync_history");
+
+ b.HasIndex("DownloadClientId")
+ .HasDatabaseName("ix_blacklist_sync_history_download_client_id");
+
+ b.HasIndex("Hash")
+ .HasDatabaseName("ix_blacklist_sync_history_hash");
+
+ b.HasIndex("Hash", "DownloadClientId")
+ .IsUnique()
+ .HasDatabaseName("ix_blacklist_sync_history_hash_download_client_id");
+
+ b.ToTable("blacklist_sync_history", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Arr.ArrInstance", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.Arr.ArrConfig", "ArrConfig")
+ .WithMany("Instances")
+ .HasForeignKey("ArrConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_arr_instances_arr_configs_arr_config_id");
+
+ b.Navigation("ArrConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.DownloadCleaner.SeedingRule", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.DownloadCleaner.DownloadCleanerConfig", "DownloadCleanerConfig")
+ .WithMany("Categories")
+ .HasForeignKey("DownloadCleanerConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_seeding_rules_download_cleaner_configs_download_cleaner_config_id");
+
+ b.Navigation("DownloadCleanerConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.AppriseConfig", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.Notification.NotificationConfig", "NotificationConfig")
+ .WithOne("AppriseConfiguration")
+ .HasForeignKey("Cleanuparr.Persistence.Models.Configuration.Notification.AppriseConfig", "NotificationConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_apprise_configs_notification_configs_notification_config_id");
+
+ b.Navigation("NotificationConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.DiscordConfig", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.Notification.NotificationConfig", "NotificationConfig")
+ .WithOne("DiscordConfiguration")
+ .HasForeignKey("Cleanuparr.Persistence.Models.Configuration.Notification.DiscordConfig", "NotificationConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_discord_configs_notification_configs_notification_config_id");
+
+ b.Navigation("NotificationConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.GotifyConfig", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.Notification.NotificationConfig", "NotificationConfig")
+ .WithOne("GotifyConfiguration")
+ .HasForeignKey("Cleanuparr.Persistence.Models.Configuration.Notification.GotifyConfig", "NotificationConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_gotify_configs_notification_configs_notification_config_id");
+
+ b.Navigation("NotificationConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.NotifiarrConfig", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.Notification.NotificationConfig", "NotificationConfig")
+ .WithOne("NotifiarrConfiguration")
+ .HasForeignKey("Cleanuparr.Persistence.Models.Configuration.Notification.NotifiarrConfig", "NotificationConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_notifiarr_configs_notification_configs_notification_config_id");
+
+ b.Navigation("NotificationConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.NtfyConfig", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.Notification.NotificationConfig", "NotificationConfig")
+ .WithOne("NtfyConfiguration")
+ .HasForeignKey("Cleanuparr.Persistence.Models.Configuration.Notification.NtfyConfig", "NotificationConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_ntfy_configs_notification_configs_notification_config_id");
+
+ b.Navigation("NotificationConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.PushoverConfig", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.Notification.NotificationConfig", "NotificationConfig")
+ .WithOne("PushoverConfiguration")
+ .HasForeignKey("Cleanuparr.Persistence.Models.Configuration.Notification.PushoverConfig", "NotificationConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_pushover_configs_notification_configs_notification_config_id");
+
+ b.Navigation("NotificationConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.TelegramConfig", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.Notification.NotificationConfig", "NotificationConfig")
+ .WithOne("TelegramConfiguration")
+ .HasForeignKey("Cleanuparr.Persistence.Models.Configuration.Notification.TelegramConfig", "NotificationConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_telegram_configs_notification_configs_notification_config_id");
+
+ b.Navigation("NotificationConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.QueueCleaner.SlowRule", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.QueueCleaner.QueueCleanerConfig", "QueueCleanerConfig")
+ .WithMany("SlowRules")
+ .HasForeignKey("QueueCleanerConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_slow_rules_queue_cleaner_configs_queue_cleaner_config_id");
+
+ b.Navigation("QueueCleanerConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.QueueCleaner.StallRule", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.QueueCleaner.QueueCleanerConfig", "QueueCleanerConfig")
+ .WithMany("StallRules")
+ .HasForeignKey("QueueCleanerConfigId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_stall_rules_queue_cleaner_configs_queue_cleaner_config_id");
+
+ b.Navigation("QueueCleanerConfig");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.State.BlacklistSyncHistory", b =>
+ {
+ b.HasOne("Cleanuparr.Persistence.Models.Configuration.DownloadClientConfig", "DownloadClient")
+ .WithMany()
+ .HasForeignKey("DownloadClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_blacklist_sync_history_download_clients_download_client_id");
+
+ b.Navigation("DownloadClient");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Arr.ArrConfig", b =>
+ {
+ b.Navigation("Instances");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.DownloadCleaner.DownloadCleanerConfig", b =>
+ {
+ b.Navigation("Categories");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Notification.NotificationConfig", b =>
+ {
+ b.Navigation("AppriseConfiguration");
+
+ b.Navigation("DiscordConfiguration");
+
+ b.Navigation("GotifyConfiguration");
+
+ b.Navigation("NotifiarrConfiguration");
+
+ b.Navigation("NtfyConfiguration");
+
+ b.Navigation("PushoverConfiguration");
+
+ b.Navigation("TelegramConfiguration");
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.QueueCleaner.QueueCleanerConfig", b =>
+ {
+ b.Navigation("SlowRules");
+
+ b.Navigation("StallRules");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/code/backend/Cleanuparr.Persistence/Migrations/Data/20260310181205_RemoveProcessMissingId.cs b/code/backend/Cleanuparr.Persistence/Migrations/Data/20260310181205_RemoveProcessMissingId.cs
new file mode 100644
index 00000000..3c9bb13d
--- /dev/null
+++ b/code/backend/Cleanuparr.Persistence/Migrations/Data/20260310181205_RemoveProcessMissingId.cs
@@ -0,0 +1,40 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Cleanuparr.Persistence.Migrations.Data
+{
+ ///
+ public partial class RemoveProcessMissingId : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "process_no_content_id",
+ table: "queue_cleaner_configs");
+
+ migrationBuilder.DropColumn(
+ name: "process_no_content_id",
+ table: "content_blocker_configs");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "process_no_content_id",
+ table: "queue_cleaner_configs",
+ type: "INTEGER",
+ nullable: false,
+ defaultValue: false);
+
+ migrationBuilder.AddColumn(
+ name: "process_no_content_id",
+ table: "content_blocker_configs",
+ type: "INTEGER",
+ nullable: false,
+ defaultValue: false);
+ }
+ }
+}
diff --git a/code/backend/Cleanuparr.Persistence/Migrations/Data/20260310181320_AddProcessMissingId.Designer.cs b/code/backend/Cleanuparr.Persistence/Migrations/Data/20260310181320_AddProcessMissingId.Designer.cs
new file mode 100644
index 00000000..146609c7
--- /dev/null
+++ b/code/backend/Cleanuparr.Persistence/Migrations/Data/20260310181320_AddProcessMissingId.Designer.cs
@@ -0,0 +1,1308 @@
+//
+using System;
+using System.Collections.Generic;
+using Cleanuparr.Persistence;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Cleanuparr.Persistence.Migrations.Data
+{
+ [DbContext(typeof(DataContext))]
+ [Migration("20260310181320_AddProcessMissingId")]
+ partial class AddProcessMissingId
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "10.0.1");
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Arr.ArrConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("FailedImportMaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_max_strikes");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type");
+
+ b.HasKey("Id")
+ .HasName("pk_arr_configs");
+
+ b.ToTable("arr_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.Arr.ArrInstance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("ApiKey")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("api_key");
+
+ b.Property("ArrConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("arr_config_id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("ExternalUrl")
+ .HasColumnType("TEXT")
+ .HasColumnName("external_url");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("Url")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("url");
+
+ b.Property("Version")
+ .HasColumnType("REAL")
+ .HasColumnName("version");
+
+ b.HasKey("Id")
+ .HasName("pk_arr_instances");
+
+ b.HasIndex("ArrConfigId")
+ .HasDatabaseName("ix_arr_instances_arr_config_id");
+
+ b.ToTable("arr_instances", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.BlacklistSync.BlacklistSyncConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("BlacklistPath")
+ .HasColumnType("TEXT")
+ .HasColumnName("blacklist_path");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("cron_expression");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.HasKey("Id")
+ .HasName("pk_blacklist_sync_configs");
+
+ b.ToTable("blacklist_sync_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.DownloadCleaner.DownloadCleanerConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("cron_expression");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.PrimitiveCollection("IgnoredDownloads")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("ignored_downloads");
+
+ b.PrimitiveCollection("UnlinkedCategories")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_categories");
+
+ b.Property("UnlinkedEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("unlinked_enabled");
+
+ b.PrimitiveCollection("UnlinkedIgnoredRootDirs")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_ignored_root_dirs");
+
+ b.Property("UnlinkedTargetCategory")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_target_category");
+
+ b.Property("UnlinkedUseTag")
+ .HasColumnType("INTEGER")
+ .HasColumnName("unlinked_use_tag");
+
+ b.Property("UseAdvancedScheduling")
+ .HasColumnType("INTEGER")
+ .HasColumnName("use_advanced_scheduling");
+
+ b.HasKey("Id")
+ .HasName("pk_download_cleaner_configs");
+
+ b.ToTable("download_cleaner_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.DownloadCleaner.SeedingRule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("DeleteSourceFiles")
+ .HasColumnType("INTEGER")
+ .HasColumnName("delete_source_files");
+
+ b.Property("DownloadCleanerConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("download_cleaner_config_id");
+
+ b.Property("MaxRatio")
+ .HasColumnType("REAL")
+ .HasColumnName("max_ratio");
+
+ b.Property("MaxSeedTime")
+ .HasColumnType("REAL")
+ .HasColumnName("max_seed_time");
+
+ b.Property("MinSeedTime")
+ .HasColumnType("REAL")
+ .HasColumnName("min_seed_time");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("PrivacyType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("privacy_type");
+
+ b.HasKey("Id")
+ .HasName("pk_seeding_rules");
+
+ b.HasIndex("DownloadCleanerConfigId")
+ .HasDatabaseName("ix_seeding_rules_download_cleaner_config_id");
+
+ b.ToTable("seeding_rules", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.DownloadClientConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("ExternalUrl")
+ .HasColumnType("TEXT")
+ .HasColumnName("external_url");
+
+ b.Property("Host")
+ .HasColumnType("TEXT")
+ .HasColumnName("host");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("Password")
+ .HasColumnType("TEXT")
+ .HasColumnName("password");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type");
+
+ b.Property("TypeName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type_name");
+
+ b.Property("UrlBase")
+ .HasColumnType("TEXT")
+ .HasColumnName("url_base");
+
+ b.Property("Username")
+ .HasColumnType("TEXT")
+ .HasColumnName("username");
+
+ b.HasKey("Id")
+ .HasName("pk_download_clients");
+
+ b.ToTable("download_clients", (string)null);
+ });
+
+ modelBuilder.Entity("Cleanuparr.Persistence.Models.Configuration.General.GeneralConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("DisplaySupportBanner")
+ .HasColumnType("INTEGER")
+ .HasColumnName("display_support_banner");
+
+ b.Property("DryRun")
+ .HasColumnType("INTEGER")
+ .HasColumnName("dry_run");
+
+ b.Property("EncryptionKey")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("encryption_key");
+
+ b.Property("HttpCertificateValidation")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("http_certificate_validation");
+
+ b.Property("HttpMaxRetries")
+ .HasColumnType("INTEGER")
+ .HasColumnName("http_max_retries");
+
+ b.Property("HttpTimeout")
+ .HasColumnType("INTEGER")
+ .HasColumnName("http_timeout");
+
+ b.PrimitiveCollection("IgnoredDownloads")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("ignored_downloads");
+
+ b.Property("SearchDelay")
+ .HasColumnType("INTEGER")
+ .HasColumnName("search_delay");
+
+ b.Property("SearchEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("search_enabled");
+
+ b.Property("StatusCheckEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("status_check_enabled");
+
+ b.Property("StrikeInactivityWindowHours")
+ .HasColumnType("INTEGER")
+ .HasColumnName("strike_inactivity_window_hours");
+
+ b.ComplexProperty(typeof(Dictionary), "Auth", "Cleanuparr.Persistence.Models.Configuration.General.GeneralConfig.Auth#AuthConfig", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("DisableAuthForLocalAddresses")
+ .HasColumnType("INTEGER")
+ .HasColumnName("auth_disable_auth_for_local_addresses");
+
+ b1.Property("TrustForwardedHeaders")
+ .HasColumnType("INTEGER")
+ .HasColumnName("auth_trust_forwarded_headers");
+
+ b1.Property("TrustedNetworks")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("auth_trusted_networks");
+ });
+
+ b.ComplexProperty(typeof(Dictionary