email service and template using resend

This commit is contained in:
2026-05-18 20:47:05 +07:00
parent f0ce22bbb8
commit bf5c97c442
16 changed files with 1152 additions and 2 deletions
+45
View File
@@ -467,6 +467,51 @@ model Refund {
@@index([status, createdAt])
}
/// Log append-only setiap email yang berhasil terkirim. `idempotencyKey`
/// UNIQUE cegah double-send saat webhook retry / cron rerun.
model EmailSent {
id String @id @default(cuid())
idempotencyKey String @unique
to String
template String
subject String
/// ID dari Resend (atau provider lain) untuk troubleshooting di dashboard mereka.
providerMessageId String?
sentAt DateTime @default(now())
@@index([to, sentAt(sort: Desc)])
@@index([template, sentAt(sort: Desc)])
}
/// Retry queue untuk email yang gagal saat sync send. Cron pick PENDING/FAILED
/// (attempts<5) → retry dengan exponential backoff. Idempotent via `idempotencyKey`.
model EmailJob {
id String @id @default(cuid())
idempotencyKey String
to String
template String
subject String
html String
status EmailJobStatus @default(PENDING)
attempts Int @default(0)
scheduledAt DateTime @default(now())
lastAttemptAt DateTime?
lastError String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([status, scheduledAt])
@@index([idempotencyKey])
}
enum EmailJobStatus {
PENDING
PROCESSING
SUCCESS
FAILED
}
/// Log polymorphic untuk admin actions lintas entity. Append-only — kalau
/// admin dihapus, `adminId` di-set NULL tapi `adminEmail` snapshot tetap.
/// Dipakai untuk compliance & investigasi (siapa approve/reject/cancel/