feat: kimlik doğrulama, ödeme, kredi ve AI rapor sihirbazı ekle

- better-auth ile giriş/oturum yönetimi (src/lib/auth, giris sayfası)
- iyzico ödeme entegrasyonu ve paket satın alma akışı
- kredi sistemi ve uygulama veritabanı şeması (drizzle)
- AI destekli rapor üretimi ve tercih sihirbazı
- rapor yazdırma sayfası ve site header/kullanıcı menüsü

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
bilalgursen
2026-07-22 02:13:39 +03:00
parent 7c3f17b9b5
commit cee6200237
64 changed files with 7966 additions and 89 deletions

112
src/lib/iyzico.ts Normal file
View File

@@ -0,0 +1,112 @@
import Iyzipay from "iyzipay";
// iyzipay CJS + callback tabanlı; burada promisify'lı ince bir katman var.
// Anahtarlar boşsa (henüz sandbox hesabı yoksa) çağrı anlaşılır bir hatayla düşer.
const globalForIyzi = globalThis as unknown as { __iyzipay?: Iyzipay };
function getClient(): Iyzipay {
if (!process.env.IYZICO_API_KEY || !process.env.IYZICO_SECRET_KEY) {
throw new Error("IYZICO_KEYS_MISSING");
}
if (!globalForIyzi.__iyzipay) {
globalForIyzi.__iyzipay = new Iyzipay({
apiKey: process.env.IYZICO_API_KEY,
secretKey: process.env.IYZICO_SECRET_KEY,
uri: process.env.IYZICO_BASE_URL ?? "https://sandbox-api.iyzipay.com",
});
}
return globalForIyzi.__iyzipay;
}
export interface CheckoutFormInitSonuc {
status: string;
token?: string;
paymentPageUrl?: string;
errorMessage?: string;
}
export interface CheckoutFormSonuc {
status: string;
paymentStatus?: string; // "SUCCESS" beklenir
conversationId?: string;
paymentId?: string;
paidPrice?: string | number;
errorMessage?: string;
}
export function initializeCheckoutForm(opts: {
orderId: string;
fiyatKurus: number;
urunAdi: string;
email: string;
userId: string;
callbackUrl: string;
buyerIp: string;
}): Promise<CheckoutFormInitSonuc> {
const price = (opts.fiyatKurus / 100).toFixed(2);
// iyzico buyer bloğu zorunlu alanlar ister; dijital üründe adres sembolik
const adres = {
contactName: "KolayTercih Kullanıcısı",
city: "Istanbul",
country: "Turkey",
address: "Dijital teslimat",
};
const request = {
locale: Iyzipay.LOCALE.TR,
conversationId: opts.orderId,
price,
paidPrice: price,
currency: Iyzipay.CURRENCY.TRY,
basketId: opts.orderId,
paymentGroup: Iyzipay.PAYMENT_GROUP.PRODUCT,
callbackUrl: opts.callbackUrl,
enabledInstallments: [1],
buyer: {
id: opts.userId,
name: "KolayTercih",
surname: "Kullanıcısı",
gsmNumber: "+905000000000",
email: opts.email,
identityNumber: "11111111111",
registrationAddress: adres.address,
ip: opts.buyerIp,
city: adres.city,
country: adres.country,
},
shippingAddress: adres,
billingAddress: adres,
basketItems: [
{
id: opts.orderId,
name: opts.urunAdi,
category1: "Dijital Hizmet",
itemType: Iyzipay.BASKET_ITEM_TYPE.VIRTUAL,
price,
},
],
};
return new Promise((resolve, reject) => {
getClient().checkoutFormInitialize.create(
request as never,
(err: unknown, result: CheckoutFormInitSonuc) => {
if (err) reject(err);
else resolve(result);
},
);
});
}
export function retrieveCheckoutForm(
token: string,
): Promise<CheckoutFormSonuc> {
return new Promise((resolve, reject) => {
getClient().checkoutForm.retrieve(
{ locale: Iyzipay.LOCALE.TR, token } as never,
(err: unknown, result: CheckoutFormSonuc) => {
if (err) reject(err);
else resolve(result);
},
);
});
}