Add viewer-range categories, nomination tracking, dynamic showact form, session timeout, share URLs, and workflow-per-season
Features: - Category viewer ranges + subcategory templates (admin group modal, tree workspace) - Nomination enrichment via TwitchTracker API (NominationEnrichmentService, TwitchTrackerViewerStatsProvider) with admin tracking rules editor - Nomination group tracker: CategoryGroupName as primary identifier, CategoryId stays as nullable legacy field; StreamerIdentity table - Dynamic showact application form builder (AdminShowactFormBuilder, ShowactApplicationSchedule) - Session idle timeout setting (AdminSessionTimeoutCard) - Share URLs for X and Discord (SiteSettings, public extras) - Workflow rules now stored per season (falls back to global SiteSettings) - New admin routes: settings/access, settings/workflows, tracking-rules - New admin review workspace with subcategory tabs - AdminCategoriesView rebuilt with group/subcategory modals Migrations (all additive): - AddShareUrls, AddShowactDynamicForm, AddCategoryViewerRanges, AddSessionIdleTimeoutSettings, AddSeasonSubcategoryTemplates, AddNominationGroupTrackerIdentity, AddShowactApplicationSchedule, AddSeasonWorkflowRulesJson Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -55,11 +55,27 @@ public sealed record AdminAuditEntriesResponse(
|
||||
|
||||
public sealed record AdminNominationReviewItemDto(
|
||||
int Id,
|
||||
int CategoryId,
|
||||
int? CategoryId,
|
||||
string CategoryGroupName,
|
||||
string CategoryName,
|
||||
string SubmittedByTwitchId,
|
||||
string CandidateText,
|
||||
string? StreamUrl,
|
||||
string? ResolvedChannel,
|
||||
string? ResolvedPlatform,
|
||||
int? AvgViewers,
|
||||
int? SuggestedCategoryId,
|
||||
string? SuggestedCategoryName,
|
||||
int? StreamerIdentityId,
|
||||
string TrackerStatus,
|
||||
DateTimeOffset? TrackerCheckedAt,
|
||||
string TrackingReviewStatus,
|
||||
bool RequiresManualReview,
|
||||
AdminTrackingFlagHitDto[] TrackingFlags,
|
||||
AdminTrackingMetricStateDto[] TrackingMetrics,
|
||||
string? TrackingReviewNote,
|
||||
string? TrackingReviewedByTwitchId,
|
||||
DateTimeOffset? TrackingReviewedAt,
|
||||
string Status,
|
||||
DateTimeOffset CreatedAt,
|
||||
int? CandidateId,
|
||||
@@ -68,6 +84,32 @@ public sealed record AdminNominationReviewItemDto(
|
||||
string? ReviewedByTwitchId,
|
||||
DateTimeOffset? ReviewedAt);
|
||||
|
||||
public sealed record AdminNominationReviewGroupDto(
|
||||
int Id,
|
||||
int[] NominationIds,
|
||||
string CategoryGroupName,
|
||||
string DisplayName,
|
||||
string? StreamUrl,
|
||||
string? ResolvedChannel,
|
||||
string? ResolvedPlatform,
|
||||
int? AvgViewers,
|
||||
int? SuggestedCategoryId,
|
||||
string? SuggestedCategoryName,
|
||||
int? StreamerIdentityId,
|
||||
string TrackerStatus,
|
||||
DateTimeOffset? TrackerCheckedAt,
|
||||
string TrackingReviewStatus,
|
||||
bool RequiresManualReview,
|
||||
AdminTrackingFlagHitDto[] TrackingFlags,
|
||||
AdminTrackingMetricStateDto[] TrackingMetrics,
|
||||
string? TrackingReviewNote,
|
||||
string? TrackingReviewedByTwitchId,
|
||||
DateTimeOffset? TrackingReviewedAt,
|
||||
int NominationTally,
|
||||
int UniqueSubmitterCount,
|
||||
DateTimeOffset FirstSubmittedAt,
|
||||
DateTimeOffset LastSubmittedAt);
|
||||
|
||||
public sealed record AdminClipSubmissionItemDto(
|
||||
int Id,
|
||||
int? CategoryId,
|
||||
@@ -87,10 +129,17 @@ public sealed record ApproveNominationRequest(
|
||||
string? DisplayName,
|
||||
string? ChannelSlug,
|
||||
string? Platform,
|
||||
int? CategoryId,
|
||||
string? ReviewNote);
|
||||
|
||||
public sealed record RejectNominationRequest(string? ReviewNote);
|
||||
|
||||
public sealed record ReopenRejectedNominationRequest(string? ReviewNote);
|
||||
|
||||
public sealed record UpdateNominationTrackingReviewRequest(
|
||||
string Status,
|
||||
string? ReviewNote);
|
||||
|
||||
public sealed record AdminNominationLinkBlacklistEntryDto(string Url);
|
||||
|
||||
public sealed record AdminNominationLinkBlacklistResponse(AdminNominationLinkBlacklistEntryDto[] Entries);
|
||||
@@ -136,3 +185,24 @@ public sealed record AdminWorkflowRuleDto(
|
||||
public sealed record AdminWorkflowRulesResponse(AdminWorkflowRuleDto[] Rules);
|
||||
|
||||
public sealed record UpdateWorkflowRulesRequest(AdminWorkflowRuleDto[] Rules);
|
||||
|
||||
public sealed record AdminTrackingFlagHitDto(
|
||||
string Key,
|
||||
string Label,
|
||||
string Severity,
|
||||
string Description,
|
||||
bool RequiresManualReview,
|
||||
bool BlocksApproval,
|
||||
bool AdminNoteRequiredOnOverride);
|
||||
|
||||
public sealed record AdminTrackingMetricStateDto(
|
||||
string Key,
|
||||
string Label,
|
||||
bool Required,
|
||||
string SourceSupport,
|
||||
bool Present,
|
||||
string Value,
|
||||
string Description,
|
||||
string WindowKey,
|
||||
string WindowLabel,
|
||||
bool AutoWindowSupported);
|
||||
|
||||
@@ -16,14 +16,25 @@ public sealed record AdminCategoryItemDto(
|
||||
string Description,
|
||||
int SortOrder,
|
||||
int MaxNomineesPerUser,
|
||||
int? ViewerRangeMin,
|
||||
int? ViewerRangeMax,
|
||||
int CandidateCount);
|
||||
|
||||
public sealed record AdminSubcategoryTemplateDto(
|
||||
string Name,
|
||||
string Slug,
|
||||
int SortOrder,
|
||||
int? ViewerRangeMin,
|
||||
int? ViewerRangeMax);
|
||||
|
||||
public sealed record AdminCandidateItemDto(
|
||||
int Id,
|
||||
int CategoryId,
|
||||
int? StreamerIdentityId,
|
||||
string DisplayName,
|
||||
string ChannelSlug,
|
||||
string Platform,
|
||||
int NominationTally,
|
||||
string AcceptanceStatus,
|
||||
string? AcceptanceNote,
|
||||
string? ClipCompilationUrl,
|
||||
@@ -36,6 +47,7 @@ public sealed record AdminAwardResultItemDto(
|
||||
int CategoryId,
|
||||
string CategoryName,
|
||||
int CandidateId,
|
||||
int? StreamerIdentityId,
|
||||
string CandidateDisplayName,
|
||||
string CandidateChannelSlug,
|
||||
string CandidatePlatform);
|
||||
@@ -56,10 +68,14 @@ public sealed record AdminSeasonDetailResponse(
|
||||
DateOnly ReviewEndsAt,
|
||||
DateOnly ShowDate,
|
||||
TimeOnly ShowStartsAt,
|
||||
IEnumerable<AdminSubcategoryTemplateDto> SubcategoryTemplates,
|
||||
IEnumerable<AdminCategoryItemDto> Categories,
|
||||
IEnumerable<AdminCandidateItemDto> Candidates,
|
||||
IEnumerable<AdminNominationReviewItemDto> PendingNominations,
|
||||
IEnumerable<AdminNominationReviewGroupDto> PendingNominationGroups,
|
||||
IEnumerable<AdminNominationReviewItemDto> ReviewedNominations,
|
||||
string TrackingReviewNotes,
|
||||
bool ShowTrackingReviewNotes,
|
||||
IEnumerable<AdminAwardResultItemDto> Results,
|
||||
IEnumerable<AdminClipSubmissionItemDto> ClipSubmissions);
|
||||
|
||||
@@ -102,6 +118,17 @@ public sealed record UpsertCategoryRequest(
|
||||
string Slug,
|
||||
string Description,
|
||||
int SortOrder,
|
||||
int MaxNomineesPerUser,
|
||||
int? ViewerRangeMin,
|
||||
int? ViewerRangeMax);
|
||||
|
||||
public sealed record UpdateSeasonSubcategoryTemplatesRequest(
|
||||
AdminSubcategoryTemplateDto[] Templates);
|
||||
|
||||
public sealed record UpsertCategoryGroupRequest(
|
||||
string GroupName,
|
||||
string Description,
|
||||
int SortOrder,
|
||||
int MaxNomineesPerUser);
|
||||
|
||||
public sealed record UpsertCandidateRequest(
|
||||
|
||||
@@ -4,6 +4,8 @@ public sealed record AdminSiteSettingsResponse(
|
||||
string HostDisplayName,
|
||||
string HostTagline,
|
||||
string NewsletterUrl,
|
||||
string ShareXUrl,
|
||||
string ShareDiscordUrl,
|
||||
string PrivacyEmail,
|
||||
string PrivacyPolicyContent,
|
||||
string? PrivacyPolicyUpdatedBy,
|
||||
@@ -17,12 +19,15 @@ public sealed record AdminSiteSettingsResponse(
|
||||
string ShowactsUrl,
|
||||
string ShowactsContent,
|
||||
IEnumerable<PublicSocialLinkDto> SocialLinks,
|
||||
IEnumerable<FaqItemDto> Faq);
|
||||
IEnumerable<FaqItemDto> Faq,
|
||||
string ShowactFormSchemaJson);
|
||||
|
||||
public sealed record UpdateSiteSettingsRequest(
|
||||
string HostDisplayName,
|
||||
string HostTagline,
|
||||
string NewsletterUrl,
|
||||
string ShareXUrl,
|
||||
string ShareDiscordUrl,
|
||||
string PrivacyEmail,
|
||||
string PrivacyPolicyContent,
|
||||
string ImprintUrl,
|
||||
@@ -34,7 +39,8 @@ public sealed record UpdateSiteSettingsRequest(
|
||||
string ShowactsUrl,
|
||||
string ShowactsContent,
|
||||
PublicSocialLinkDto[] SocialLinks,
|
||||
FaqItemDto[] Faq);
|
||||
FaqItemDto[] Faq,
|
||||
string? ShowactFormSchemaJson = null);
|
||||
|
||||
public sealed record AdminOperationalSettingsResponse(
|
||||
bool DemoLoginManagedByDatabase,
|
||||
@@ -49,6 +55,7 @@ public sealed record AdminOperationalSettingsResponse(
|
||||
bool TwitchClientSecretSet,
|
||||
string TwitchRedirectUri,
|
||||
string TwitchScope,
|
||||
int SessionIdleTimeoutHours,
|
||||
bool MaintenanceModeEnabled,
|
||||
string MaintenanceTitle,
|
||||
string MaintenanceMessage);
|
||||
@@ -59,6 +66,9 @@ public sealed record AdminOptionalFeatureSettingsResponse(
|
||||
bool ClipAdminMenuVisible,
|
||||
string ClipSubmissionDisabledMessage,
|
||||
bool ShowactApplicationsEnabled,
|
||||
DateOnly? ShowactApplicationStartsAt,
|
||||
DateOnly? ShowactApplicationEndsAt,
|
||||
bool ShowactApplicationsOpenNow,
|
||||
string ShowactApplicationDisabledMessage,
|
||||
bool SponsorsVisible);
|
||||
|
||||
@@ -68,6 +78,8 @@ public sealed record UpdateOptionalFeatureSettingsRequest(
|
||||
bool ClipAdminMenuVisible,
|
||||
string ClipSubmissionDisabledMessage,
|
||||
bool ShowactApplicationsEnabled,
|
||||
DateOnly? ShowactApplicationStartsAt,
|
||||
DateOnly? ShowactApplicationEndsAt,
|
||||
string ShowactApplicationDisabledMessage,
|
||||
bool SponsorsVisible);
|
||||
|
||||
@@ -81,6 +93,71 @@ public sealed record UpdateOperationalSettingsRequest(
|
||||
string? TwitchClientSecret,
|
||||
string TwitchRedirectUri,
|
||||
string TwitchScope,
|
||||
int SessionIdleTimeoutHours,
|
||||
bool MaintenanceModeEnabled,
|
||||
string MaintenanceTitle,
|
||||
string MaintenanceMessage);
|
||||
|
||||
public sealed record AdminTrackingSourceDto(
|
||||
string ProviderKey,
|
||||
string ProviderLabel,
|
||||
string BaseUrl,
|
||||
string NotesSummary,
|
||||
bool ShowManualReviewNotesInReview);
|
||||
|
||||
public sealed record AdminTrackingMetricRuleDto(
|
||||
string Key,
|
||||
string Label,
|
||||
bool Enabled,
|
||||
string SourceSupport,
|
||||
string Description,
|
||||
bool RequiredForAutoClassification,
|
||||
bool ShowInReview,
|
||||
bool ShowInAdminSummary,
|
||||
bool ManualOverrideAllowed,
|
||||
string WindowKey,
|
||||
string[] AutoSupportedWindowKeys,
|
||||
string? ProviderFieldKey,
|
||||
int? TopCount,
|
||||
int? MinPrimaryCategorySharePercent,
|
||||
int? MinPrimaryCategoryHours,
|
||||
int? MaxDistinctCategoriesBeforeFlag,
|
||||
string[] IgnoredCategories,
|
||||
bool MatchAwardCategoryAgainstTopCategories,
|
||||
bool FlagIfAwardCategoryNotInTopX,
|
||||
bool FlagIfCategorySpreadTooWide,
|
||||
bool FlagIfNoCategoryContextAvailable,
|
||||
int? MinValue,
|
||||
int? MaxValue);
|
||||
|
||||
public sealed record AdminTrackingFlagRuleDto(
|
||||
string Key,
|
||||
string Label,
|
||||
bool Enabled,
|
||||
string Severity,
|
||||
string Description,
|
||||
bool AutoTriggerEnabled,
|
||||
bool RequiresManualReview,
|
||||
bool BlocksApproval,
|
||||
bool AdminNoteRequiredOnOverride);
|
||||
|
||||
public sealed record AdminTrackingRulesResponse(
|
||||
AdminTrackingSourceDto Source,
|
||||
AdminTrackingMetricRuleDto[] ImportantMetrics,
|
||||
AdminTrackingMetricRuleDto[] OptionalMetrics,
|
||||
AdminTrackingFlagRuleDto[] Flags,
|
||||
string ManualReviewNotes);
|
||||
|
||||
public sealed record UpdateTrackingRulesRequest(
|
||||
AdminTrackingSourceDto Source,
|
||||
AdminTrackingMetricRuleDto[] ImportantMetrics,
|
||||
AdminTrackingMetricRuleDto[] OptionalMetrics,
|
||||
AdminTrackingFlagRuleDto[] Flags,
|
||||
string ManualReviewNotes);
|
||||
|
||||
public sealed record UpdateTrackingSourceRequest(
|
||||
AdminTrackingSourceDto Source);
|
||||
|
||||
public sealed record UpdateTrackingReviewNotesRequest(
|
||||
string ManualReviewNotes,
|
||||
bool ShowManualReviewNotesInReview);
|
||||
|
||||
@@ -32,6 +32,7 @@ public sealed record AuthSessionDto(
|
||||
string DisplayName,
|
||||
string Role,
|
||||
IEnumerable<string> PermissionKeys,
|
||||
int SessionIdleTimeoutHours,
|
||||
bool MustChangePassword = false,
|
||||
string? TeamLogin = null,
|
||||
string? BoundTwitchUserId = null,
|
||||
|
||||
@@ -36,16 +36,18 @@ public sealed record ShowactApplicationDto(
|
||||
string Status,
|
||||
string? ReviewNote,
|
||||
DateTimeOffset CreatedAt,
|
||||
DateTimeOffset? ReviewedAt);
|
||||
DateTimeOffset? ReviewedAt,
|
||||
string FieldResponsesJson);
|
||||
|
||||
public sealed record CreateShowactApplicationRequest(
|
||||
string ArtistName,
|
||||
string ContactEmail,
|
||||
string ContactDiscord,
|
||||
string PlatformUrl,
|
||||
string PerformanceType,
|
||||
string Description,
|
||||
string TechnicalNotes,
|
||||
string ReferenceUrl);
|
||||
string? ArtistName = null,
|
||||
string? ContactEmail = null,
|
||||
string? ContactDiscord = null,
|
||||
string? PlatformUrl = null,
|
||||
string? PerformanceType = null,
|
||||
string? Description = null,
|
||||
string? TechnicalNotes = null,
|
||||
string? ReferenceUrl = null,
|
||||
string? FieldResponsesJson = null);
|
||||
|
||||
public sealed record UpdateShowactStatusRequest(string Status, string? ReviewNote);
|
||||
|
||||
@@ -50,6 +50,8 @@ public sealed record PublicSiteContentDto(
|
||||
string HostDisplayName,
|
||||
string HostTagline,
|
||||
string NewsletterUrl,
|
||||
string ShareXUrl,
|
||||
string ShareDiscordUrl,
|
||||
string PrivacyEmail,
|
||||
string PrivacyPolicyContent,
|
||||
IEnumerable<PublicSocialLinkDto> SocialLinks,
|
||||
@@ -66,8 +68,11 @@ public sealed record PublicFeatureFlagsDto(
|
||||
bool ClipReviewEnabled,
|
||||
string ClipSubmissionDisabledMessage,
|
||||
bool ShowactApplicationsEnabled,
|
||||
DateOnly? ShowactApplicationStartsAt,
|
||||
DateOnly? ShowactApplicationEndsAt,
|
||||
string ShowactApplicationDisabledMessage,
|
||||
bool SponsorsVisible);
|
||||
bool SponsorsVisible,
|
||||
string ShowactFormSchemaJson);
|
||||
|
||||
public sealed record OverviewResponse(
|
||||
int SeasonId,
|
||||
|
||||
@@ -17,6 +17,8 @@ public sealed record PublicCategoryDetailDto(
|
||||
string GroupName,
|
||||
string Description,
|
||||
int MaxNomineesPerUser,
|
||||
int? ViewerRangeMin,
|
||||
int? ViewerRangeMax,
|
||||
IEnumerable<CandidateSummaryDto> Candidates);
|
||||
|
||||
public sealed record SeasonCategoriesResponse(
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
namespace Backend.Contracts;
|
||||
|
||||
public sealed record UserNominationStateDto(
|
||||
int CategoryId,
|
||||
int? CategoryId,
|
||||
string CategoryGroupName,
|
||||
string[] Nominees);
|
||||
|
||||
public sealed record UserVoteStateDto(
|
||||
|
||||
@@ -6,7 +6,8 @@ public sealed record NominationEntryRequest(
|
||||
|
||||
public sealed record CreateNominationRequest(
|
||||
int Year,
|
||||
int CategoryId,
|
||||
int? CategoryId,
|
||||
string? CategoryGroupName,
|
||||
string TwitchUserId,
|
||||
string[]? Nominees,
|
||||
NominationEntryRequest[]? Nominations);
|
||||
|
||||
Reference in New Issue
Block a user