Mail / SMS Call-Site Rehberi
DetayYeni veya değiştirilen sendMail(...) / sendSms(...) çağrılarında uyulması gereken kurallar. Code review (feature-dev:code-reviewer subagent veya /ultrareview) sırasında bu listeden geçilmeli.
1. Explicit context.customerId pass et
Bölüm başlığı “1. Explicit context.customerId pass et”// YANLIŞ — context yok, service auto-resolve fallback'ine güvenirawait sendMail({ to: customer.email, template: 'admin-custom-message', data: { ... },});
// DOĞRU — explicit passawait sendMail({ to: customer.email, template: 'admin-custom-message', data: { ... }, context: { customerId: customer.id, adminId: admin.adminId },});Neden: Service tarafında Customer.findUnique({ where: { email } }) ek query gerek kalmaz; çoklu Customer aynı email kullanırsa (gelecek senaryo) doğru bağlanır. Auto-resolve fallback defensive last-resort olarak servis tarafında kalır — yeni kod yolunda güvenilmemeli.
2. Audit context tam olsun
Bölüm başlığı “2. Audit context tam olsun”customerId— customer-facing iletişimde ZORUNLUadminId— admin tetikli iletişimde (mailler customer panel’inde forensic için adminId’yi gösterir)ipAddress— webhook / public endpoint’lerde tetiklenen mail için (request.headers.get('x-forwarded-for')veya helper)
3. Multi-recipient (to: string[]) durumunda auto-resolve atlanır
Bölüm başlığı “3. Multi-recipient (to: string[]) durumunda auto-resolve atlanır”Çoklu alıcılı mail’lerde service customerId resolve etmez. Broadcast scenario’da bu doğru davranış. Müşteriye özgü mail tek alıcı kullanmalı.
4. SMS recipient telefon formatı
Bölüm başlığı “4. SMS recipient telefon formatı”Customer.phone E.164 normalize edilmemişse (örn. "+44 0857213415" boşluklu) auto-resolve miss olur. Yeni SMS call-site’larda explicit context.customerId zorunlu, recipient eşleştirmesine güvenme.
5. Test data: bcrypt hash format
Bölüm başlığı “5. Test data: bcrypt hash format”Yeni unit test’lerde Customer.create yaparken password: 'placeholder' yazma. Şu helper’ı kullan:
import { hashPassword } from '@/lib/auth/password';const c = await prisma.customer.create({ data: { email: '...', password: await hashPassword('test-not-used'), name: '...' },});lib/auth/password.ts > isValidBcryptHash() ileride şema validation eklendiğinde placeholder testleri kıracak.
6. Mevcut audit / cleanup pattern’i koru
Bölüm başlığı “6. Mevcut audit / cleanup pattern’i koru”- Mail gönderim sonrası
customerAuditLog.create({ ... emailLogId, action, target })— forensic UI navigasyonu için mailResult.success === falsehalinde retry/fallback davranışı çağıran kararına bağlı, ama audit kaydı her durumda yazılır (status: ‘success’ veya ‘failed’)
7. Mevcut Call-Site Refactor Durumu
Bölüm başlığı “7. Mevcut Call-Site Refactor Durumu”2026-05-13 itibariyle:
- ✅
/api/admin/customers/[id]/send-mail - ✅
/api/admin/customers/[id]/password-reset - ✅
/api/admin/customers/[id]/notifications - ⏳ Diğer ~22 call-site auto-resolve fallback’ine güveniyor — yeni iş yaparken geçişi de fırsat bul.
Yardımcılar
Bölüm başlığı “Yardımcılar”lib/admin/portal-details.ts > fetchPortalBundle()— credential reveal flow’larında audit log otomatiklib/auth/password.ts > hashPassword() / verifyPassword() / isValidBcryptHash()— yeni Customer create / parola değişimilib/audit-actions.ts > CREDENTIAL_REVEAL_CONTEXTS— UI bağlamı string sabit (raw string YASAK)