using InboxIntel.Domain.Common; using InboxIntel.Domain.Enums; namespace InboxIntel.Domain.Entities; /// /// A single Gmail message stored locally. Designed for 100k+ rows per user: /// search fields are indexed (see EmailConfiguration) and a generated /// tsvector column backs PostgreSQL full-text search. /// public class Email : AuditableEntity { public Guid Id { get; set; } = Guid.NewGuid(); public Guid UserId { get; set; } /// Gmail message id (stable, unique per account). public string GmailMessageId { get; set; } = string.Empty; public Guid ThreadId { get; set; } public MailThread? Thread { get; set; } public Guid SenderId { get; set; } public Sender? Sender { get; set; } public string? Subject { get; set; } public string? Snippet { get; set; } /// Plain-text body. Indexed for FTS via SearchVector. public string? BodyText { get; set; } public DateTimeOffset SentAtUtc { get; set; } public DateTimeOffset? ReceivedAtUtc { get; set; } public long SizeEstimateBytes { get; set; } public bool IsUnread { get; set; } public bool IsStarred { get; set; } public bool IsImportant { get; set; } public bool IsInInbox { get; set; } public bool IsTrashed { get; set; } public bool HasAttachments { get; set; } // Unsubscribe signals captured at parse time. public bool HasListUnsubscribe { get; set; } public string? ListUnsubscribeRaw { get; set; } public bool SupportsOneClickUnsubscribe { get; set; } /// Heuristic/AI classification. Defaults to Unknown until classified. public EmailCategory Category { get; set; } = EmailCategory.Unknown; /// /// PostgreSQL tsvector, maintained as a generated column. Never set in code; /// mapped read-only for querying. Nullable so non-Postgres test providers work. /// public NpgsqlTypes.NpgsqlTsVector? SearchVector { get; set; } public ICollection EmailLabels { get; set; } = new List(); public ICollection Attachments { get; set; } = new List(); }