using System.ComponentModel.DataAnnotations; namespace GerbilManagerWebAPI.Models { /// Triage state of an incoming Gmail request (serialised as string name). public enum RequestStatus { New = 0, InProgress = 1, Assigned = 2, Answered = 3, Abandoned = 4, } /// /// An incoming inquiry imported from Gmail (INBOX epic). One row per email, /// deduped on the RFC Message-Id. /// public class Request { [Key] public Guid Id { get; set; } /// RFC 5322 Message-Id — unique; the dedup key. public required string GmailMessageId { get; set; } /// Gmail conversation id (X-GM-THRID). public string? ThreadId { get; set; } public string? InReplyToMessageId { get; set; } public string? ReferencesHeader { get; set; } public required string FromAddress { get; set; } public string? FromName { get; set; } public string? Subject { get; set; } public string? BodyText { get; set; } public DateTimeOffset ReceivedAt { get; set; } public RequestStatus Status { get; set; } = RequestStatus.New; public Guid? AssignedContactId { get; set; } public Contact? AssignedContact { get; set; } /// AI/edited draft reply (INBOX-2); send is INBOX-3. Null until drafted. public string? DraftReply { get; set; } public DateTimeOffset? AnsweredAt { get; set; } } /// /// Singleton mail configuration (INBOX epic). The Gmail App Password is stored /// ENCRYPTED at rest (ASP.NET Data Protection) and never returned over the wire. /// public class MailSettings { public static readonly Guid SingletonId = new("ab0c0000-0000-0000-0000-000000000001"); [Key] public Guid Id { get; set; } public string? GmailAddress { get; set; } /// Data-Protection-encrypted Gmail App Password (never plaintext, never on the wire). public string? AppPasswordProtected { get; set; } public int PollIntervalMinutes { get; set; } = 15; public string Folder { get; set; } = "INBOX"; public bool BackgroundPollEnabled { get; set; } /// Highest IMAP UID seen, to avoid rescanning the whole folder. public uint LastUid { get; set; } } }