d78fe601ff
CI / backend (push) Successful in 52s
CI / frontend (push) Successful in 14s
Deploy Staging / deploy (push) Successful in 26s
CI / backend (pull_request) Successful in 53s
CI / frontend (pull_request) Successful in 16s
Security / secrets (push) Successful in 4s
Security / dependencies (push) Successful in 55s
Security / secrets (pull_request) Successful in 4s
Security / dependencies (pull_request) Successful in 53s
123 lines
6.2 KiB
C#
123 lines
6.2 KiB
C#
using InboxIntel.Application.Common;
|
|
using InboxIntel.Application.DTOs;
|
|
using InboxIntel.Domain.Enums;
|
|
|
|
namespace InboxIntel.Application.Abstractions;
|
|
|
|
/// <summary>Orchestrates full + incremental Gmail sync, with resume support.</summary>
|
|
public interface ISyncService
|
|
{
|
|
Task RunFullSyncAsync(Guid userId, CancellationToken ct = default);
|
|
Task RunIncrementalSyncAsync(Guid userId, CancellationToken ct = default);
|
|
/// <summary>Marks the sync as starting and queues it for the background worker.</summary>
|
|
Task QueueSyncAsync(Guid userId, bool fullSync, CancellationToken ct = default);
|
|
Task<SyncStatus> GetStatusAsync(Guid userId, CancellationToken ct = default);
|
|
/// <summary>Progress snapshot for the sync splash screen.</summary>
|
|
Task<DTOs.SyncProgressDto> GetProgressAsync(Guid userId, CancellationToken ct = default);
|
|
}
|
|
|
|
public interface IAnalyticsService
|
|
{
|
|
Task<DashboardSummaryDto> GetDashboardAsync(Guid userId, CancellationToken ct = default);
|
|
Task<InboxHealthDto> GetInboxHealthAsync(Guid userId, CancellationToken ct = default);
|
|
Task<IReadOnlyList<SenderStatDto>> GetTopSendersAsync(Guid userId, int take = 20, CancellationToken ct = default);
|
|
Task<IReadOnlyList<TimeSeriesPointDto>> GetVolumeOverTimeAsync(Guid userId, int days = 90, CancellationToken ct = default);
|
|
Task<IReadOnlyList<HeatmapCellDto>> GetHeatmapAsync(Guid userId, CancellationToken ct = default);
|
|
Task<IReadOnlyList<CategoryHeatmapCellDto>> GetCategoryHeatmapAsync(Guid userId, CancellationToken ct = default);
|
|
Task<IReadOnlyList<AttachmentBreakdownDto>> GetAttachmentBreakdownAsync(Guid userId, CancellationToken ct = default);
|
|
Task<SidebarCountsDto> GetSidebarCountsAsync(Guid userId, CancellationToken ct = default);
|
|
Task RefreshAggregatesAsync(Guid userId, CancellationToken ct = default);
|
|
}
|
|
|
|
public interface ISearchService
|
|
{
|
|
Task<PagedResult<EmailSummaryDto>> SearchAsync(Guid userId, SearchRequestDto request, CancellationToken ct = default);
|
|
}
|
|
|
|
public interface ICleanupService
|
|
{
|
|
Task<CleanupPreviewDto> PreviewAsync(Guid userId, CleanupRequestDto request, CancellationToken ct = default);
|
|
Task<Result<CleanupResultDto>> ExecuteAsync(Guid userId, CleanupRequestDto request, CancellationToken ct = default);
|
|
}
|
|
|
|
public interface IUnsubscribeService
|
|
{
|
|
Task<IReadOnlyList<UnsubscribeItemDto>> GetSafeToUnsubscribeAsync(Guid userId, CancellationToken ct = default);
|
|
Task DetectAsync(Guid userId, CancellationToken ct = default);
|
|
Task<Result<CleanupResultDto>> ProcessQueueAsync(Guid userId, UnsubscribeRequestDto request, CancellationToken ct = default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// AI layer. May be disabled, local (Ollama) or cloud (OpenAI). Per the
|
|
/// safety rules, AI NEVER executes destructive actions - it only suggests.
|
|
/// </summary>
|
|
public interface IAiService
|
|
{
|
|
bool IsEnabled { get; }
|
|
Task<AiClassificationDto> ClassifyAsync(Guid userId, Guid emailId, CancellationToken ct = default);
|
|
/// <summary>
|
|
/// Lightweight classification used as a sync-time fallback when the
|
|
/// heuristic rule set doesn't match anything specific. Takes raw fields
|
|
/// directly (no DB lookup) since the email entity may not be persisted
|
|
/// yet during sync.
|
|
/// </summary>
|
|
Task<EmailCategory> ClassifyFallbackAsync(string? subject, string senderAddress, string? snippet, CancellationToken ct = default);
|
|
/// <summary>
|
|
/// AI opinion (0-1) on how safe it is to unsubscribe from a sender, given
|
|
/// the sender address and a recent subject line. Returns 0.5 (neutral) if
|
|
/// AI is disabled or the call fails - callers blend this with a heuristic.
|
|
/// </summary>
|
|
Task<double> ScoreUnsubscribeConfidenceAsync(string senderAddress, string? recentSubject, int emailCount, CancellationToken ct = default);
|
|
/// <summary>One-line plain-language summary of a single email, for list/preview UIs.</summary>
|
|
Task<string> SummarizeEmailAsync(string? subject, string? snippet, string? bodyText, CancellationToken ct = default);
|
|
Task<InboxSummaryDto> SummarizeInboxAsync(Guid userId, CancellationToken ct = default);
|
|
Task<IReadOnlyList<AiCleanupSuggestionDto>> SuggestCleanupAsync(Guid userId, CancellationToken ct = default);
|
|
Task<GeneratedQueryDto> GenerateQueryAsync(Guid userId, string naturalLanguage, CancellationToken ct = default);
|
|
}
|
|
|
|
/// <summary>Low-level chat completion abstraction implemented by Ollama / OpenAI providers.</summary>
|
|
public interface IAiProvider
|
|
{
|
|
AiProviderMode Mode { get; }
|
|
Task<string> CompleteAsync(string systemPrompt, string userPrompt, CancellationToken ct = default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Produces vector embeddings for text (the foundation for semantic search, near-duplicate
|
|
/// detection, and "find similar"). Kept separate from <see cref="IAiProvider"/> because
|
|
/// embeddings are a distinct capability with their own model. The Null implementation returns
|
|
/// an empty vector and <see cref="IsAvailable"/> = false, so callers detect unavailability and
|
|
/// fall back to lexical search — AI is never required for core functionality.
|
|
/// </summary>
|
|
public interface IEmbeddingProvider
|
|
{
|
|
/// <summary>False for the Null provider (AI off / no embedding model configured).</summary>
|
|
bool IsAvailable { get; }
|
|
|
|
/// <summary>Embed a single text. Returns an empty array when unavailable.</summary>
|
|
Task<float[]> EmbedAsync(string text, CancellationToken ct = default);
|
|
|
|
/// <summary>Embed many texts, result aligned to input order. Empty list when unavailable.</summary>
|
|
Task<IReadOnlyList<float[]>> EmbedBatchAsync(IReadOnlyList<string> texts, CancellationToken ct = default);
|
|
}
|
|
|
|
public enum ExportFormat { Pdf, Csv, Json }
|
|
|
|
public interface IExportService
|
|
{
|
|
Task<(byte[] Content, string ContentType, string FileName)> ExportReportAsync(Guid userId, ExportFormat format, CancellationToken ct = default);
|
|
}
|
|
|
|
/// <summary>SMTP-backed email delivery, used for digest notifications. No-ops if SMTP is not configured.</summary>
|
|
public interface IEmailSender
|
|
{
|
|
bool IsEnabled { get; }
|
|
Task SendAsync(string toAddress, string subject, string htmlBody, CancellationToken ct = default);
|
|
}
|
|
|
|
/// <summary>Builds and sends the periodic inbox digest for opted-in users.</summary>
|
|
public interface IDigestService
|
|
{
|
|
Task SendDigestAsync(Guid userId, CancellationToken ct = default);
|
|
}
|