using Microsoft.AspNetCore.Http; namespace SeaHaven.Services.Interfaces { public interface IWorkOrderJobRunStateAccessor { WorkOrderJobRunState State { get; } } public sealed class WorkOrderJobRunState { public DateTime? LastWeekRolledRunUtc { get; set; } public DateTime? LastPastDueCacheRunUtc { get; set; } public string? LastWeekRolledError { get; set; } public string? LastPastDueCacheError { get; set; } } public interface IFileStoragePort { Task SaveFileAsync(IFormFile file); /// /// Best-effort delete of a previously saved file URL. Returns false when the file /// cannot be resolved or removed; never throws for missing paths. /// bool TryDelete(string fileUrl); /// /// Opens a previously saved file URL for reading. Returns null when the URL or file /// cannot be safely resolved. /// Stream? OpenRead(string fileUrl); } /// /// Narrow vendor completion-document storage port. Implemented in the API layer so the /// service layer can persist/read uploaded vendor documents without owning filesystem paths. /// Path resolution is shared with the scan worker to avoid duplicate rules. /// public interface IVendorDocumentStoragePort { Task SaveAsync(int vendorId, int dispatchId, string storedFileName, Stream content, CancellationToken cancellationToken); Stream OpenRead(int vendorId, int dispatchId, string storedFileName); void Delete(int vendorId, int dispatchId, string storedFileName); } public interface IDispatchEmailPort { Task SendDispatchEmailAsync(string emailTo, string subject, string htmlBody, string? replyTo); } public interface IVendorTokenPort { Task GetOrCreateActiveTokenAsync(int vendorId); } }