# SMS ve OTP

> Netgsm ile bilgilendirme/ticari SMS ve güvenli telefon doğrulama.

## Kurulum

```bash
npx trkit add sms
```

```bash title=".env.local"
TRKIT_SMS_PROVIDER=netgsm   # geliştirmede: dev (konsola yazar)
NETGSM_USERCODE=850xxxxxxx
NETGSM_PASSWORD=...
NETGSM_HEADER=MARKANIZ      # onaylı gönderici başlığı
OTP_SECRET=uzun-rastgele-deger
```

## Bilgilendirme ve ticari SMS

```ts
import { sms } from "@/lib/sms";

// Sipariş, kargo, şifre: İYS onayı gerekmez
await sms.send({ to: "0532 123 45 67", text: "Siparişiniz kargoya verildi.", kind: "transactional" });

// Kampanya: alıcının İYS'de onayı olmalı; Netgsm İYS filtresi uygulanır
await sms.send({ to: aliciListesi, text: "Hafta sonu %20 indirim!", kind: "commercial-individual" });
```

`kind` değerine göre Netgsm'e İYS filtresi gönderilir: bilgilendirme `0`, bireysel ticari `11`, tacir ticari `12`.

## Telefon doğrulama (OTP)

```ts title="app/dogrula/actions.ts"
"use server";
import { otp } from "@/lib/sms";

export async function kodGonder(telefon: string) {
  const r = await otp.send(telefon);
  if (!r.sent) return { hata: `${r.retryAfter} saniye sonra tekrar deneyin` };
  return { ok: true };
}

export async function kodDogrula(telefon: string, kod: string) {
  const r = await otp.verify(telefon, kod);
  if (!r.ok) return { hata: { invalid: "Kod hatalı", expired: "Kodun süresi doldu", too_many_attempts: "Çok fazla deneme", invalid_number: "Geçersiz numara" }[r.reason] };
  // telefonu doğrulanmış olarak işaretle
}
```

Güvenlik:

- Kod düz metin saklanmaz (HMAC-SHA256)
- Varsayılan: 6 hane, 3 dakika geçerlilik, 5 deneme, 60 saniye yeniden gönderim beklemesi
- Kod üretiminde modulo yanlılığı olmayan kriptografik rastgelelik

## Serverless ortamda depolama

`memoryOtpStore()` yalnızca tek süreçli geliştirme ortamı içindir. Vercel gibi ortamlarda istekler farklı örneklere gider; paylaşımlı bir depo yazın:

```ts title="lib/otp-store.ts"
import type { OtpStore } from "@trkit-app-pack/sms";
import { redis } from "./redis";

export const redisOtpStore: OtpStore = {
  async get(k) { return (await redis.get(k)) ?? null; },
  async set(k, v, ttl) { await redis.set(k, v, { ex: ttl }); },
  async delete(k) { await redis.del(k); },
};
```

## Netgsm hata kodları

| Kod | Anlamı |
|---|---|
| 20 | Mesaj metni hatalı veya çok uzun |
| 30 | Kullanıcı adı/şifre hatalı veya API erişim izni yok (IP kısıtlamasını kontrol edin) |
| 40 | Gönderici başlığı tanımlı değil |
| 50 / 51 | İYS ayarı veya marka bilgisi eksik |
| 70 | Hatalı parametre |
| 80 / 85 | Gönderim sınırı aşıldı |
