mirror of
https://github.com/Sea-Haven-Industries/proposal-system.git
synced 2026-10-07 11:38:56 +00:00
Makes the system's namesake feature real: marking a proposal Sent now emails the customer an expiring link to the branded PDF, and customers are managed (with contact emails) instead of hardcoded. v1 PR4. API: - Customer.ContactEmail + migration; Customer list/update endpoints. Search stays additive at GET /api/customers?query= (frozen-mobile + web compat); new paginated list at GET /api/customers/list (admin). - IEmailService (SesEmailService v2 / DevEmailService, dev-gated). MarkSentAsync resolves the customer's email, presigns the latest PDF (7d), and sends via SES. Email/presign failures are caught + audited and NEVER roll back the Sent transition. - Startup EF migration guarded by a Postgres advisory lock (concurrency-safe). Infra: - SES email identity (proposals@seahavenind.com); least-privilege ses:SendEmail/ SendRawEmail scoped to the identity ARN + ses:FromAddress condition; SES_FROM_ADDRESS env. SES starts in sandbox — production access needed for unverified recipients. Web: - Customer management page (/admin/customers): list / create / edit incl. contact email. - New-proposal form searches real customers (free-solo) instead of a hardcoded value. - Mark-as-Sent dialog notes the PDF will be emailed to the customer. GPT-4.1 cross-review (SES IAM): no BLOCK (ses:FromAddress condition applied). Verified: api build + 121 tests; web tsc + 26 tests; infra tsc; ruff clean.
26 lines
717 B
C#
26 lines
717 B
C#
using ProposalSystem.Application.Interfaces;
|
|
|
|
namespace ProposalSystem.Api.Services;
|
|
|
|
public class DevEmailService : IEmailService
|
|
{
|
|
private readonly ILogger<DevEmailService> _logger;
|
|
|
|
public DevEmailService(ILogger<DevEmailService> logger)
|
|
{
|
|
_logger = logger;
|
|
}
|
|
|
|
public Task SendProposalDeliveryAsync(
|
|
string toEmail,
|
|
string proposalNumber,
|
|
string customerName,
|
|
string pdfUrl,
|
|
CancellationToken ct = default)
|
|
{
|
|
_logger.LogInformation(
|
|
"Dev mode - skipping email delivery: proposal {ProposalNumber} to {Recipient}, PDF link: {PdfUrl}",
|
|
proposalNumber, toEmail, pdfUrl);
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|