refactor(odeme): update environment variable usage and documentation
All checks were successful
Deploy / deploy (push) Successful in 8m39s
All checks were successful
Deploy / deploy (push) Successful in 8m39s
Replaced `NEXT_PUBLIC_APP_URL` with `APP_URL` in the payment processing logic to ensure proper runtime access. Updated related documentation to clarify the distinction between build-time and runtime environment variables, emphasizing the importance of using `APP_URL` for callback and webhook URLs. Adjusted references in the codebase to reflect this change, enhancing clarity and functionality in the payment flow.
This commit is contained in:
@@ -18,7 +18,10 @@ jobs:
|
|||||||
cat > .env.production <<'EOF'
|
cat > .env.production <<'EOF'
|
||||||
BETTER_AUTH_SECRET=${{ secrets.BETTER_AUTH_SECRET }}
|
BETTER_AUTH_SECRET=${{ secrets.BETTER_AUTH_SECRET }}
|
||||||
BETTER_AUTH_URL=${{ secrets.BETTER_AUTH_URL }}
|
BETTER_AUTH_URL=${{ secrets.BETTER_AUTH_URL }}
|
||||||
NEXT_PUBLIC_APP_URL=${{ secrets.NEXT_PUBLIC_APP_URL }}
|
# Ödeme callback/yönlendirme kökü. Public önekli DEĞİL: build'e değil
|
||||||
|
# runtime'a geçmesi gerekiyor (bkz. src/lib/app-url.ts). Secret adı
|
||||||
|
# geçmişten NEXT_PUBLIC_APP_URL, değeri aynı https kök adres.
|
||||||
|
APP_URL=${{ secrets.NEXT_PUBLIC_APP_URL }}
|
||||||
GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}
|
GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}
|
||||||
GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}
|
GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}
|
||||||
RESEND_API_KEY=${{ secrets.RESEND_API_KEY }}
|
RESEND_API_KEY=${{ secrets.RESEND_API_KEY }}
|
||||||
|
|||||||
@@ -10,14 +10,20 @@ zaman bize ulaşmaz, kullanıcı iyzico'nun barındırdığı ödeme sayfasına
|
|||||||
| `IYZICO_API_KEY` | Merchant Portal → Ayarlar → API anahtarları |
|
| `IYZICO_API_KEY` | Merchant Portal → Ayarlar → API anahtarları |
|
||||||
| `IYZICO_SECRET_KEY` | Aynı ekran. İmza doğrulamasında da kullanılır |
|
| `IYZICO_SECRET_KEY` | Aynı ekran. İmza doğrulamasında da kullanılır |
|
||||||
| `IYZICO_BASE_URL` | Sandbox: `https://sandbox-api.iyzipay.com` · Canlı: `https://api.iyzipay.com` |
|
| `IYZICO_BASE_URL` | Sandbox: `https://sandbox-api.iyzipay.com` · Canlı: `https://api.iyzipay.com` |
|
||||||
| `NEXT_PUBLIC_APP_URL` | callback ve webhook URL'lerinin kökü; **https ve geçerli SSL şart** |
|
| `APP_URL` | callback ve yönlendirme URL'lerinin kökü; **https ve geçerli SSL şart**. Verilmezse `BETTER_AUTH_URL`'e düşer |
|
||||||
|
|
||||||
`IYZICO_BASE_URL` verilmezse sandbox'a düşülür. Prod'da bu durum log'a uyarı
|
`IYZICO_BASE_URL` verilmezse sandbox'a düşülür. Prod'da bu durum log'a uyarı
|
||||||
basar — canlıya çıkarken bu satır mutlaka ayarlanmalı.
|
basar — canlıya çıkarken bu satır mutlaka ayarlanmalı.
|
||||||
|
|
||||||
|
Kök adres `NEXT_PUBLIC_APP_URL` ile **verilemez**: `NEXT_PUBLIC_*` değişkenleri
|
||||||
|
build sırasında koda gömülür, Docker build'i ise `.env.production`'ı görmez
|
||||||
|
(`.dockerignore` `.env*`'i dışlar). Sonuç, env doğru girilmiş olsa bile imaja
|
||||||
|
`http://localhost:3000` çakılması ve iyzico'nun initialize'ı reddetmesiydi.
|
||||||
|
Ayrıntı: `src/lib/app-url.ts`.
|
||||||
|
|
||||||
> Lokal `http://localhost:3000` ile uçtan uca test edilemez: iyzico callback
|
> Lokal `http://localhost:3000` ile uçtan uca test edilemez: iyzico callback
|
||||||
> adresinden geçerli SSL ister. Sandbox testinde tünel (cloudflared/ngrok) açıp
|
> adresinden geçerli SSL ister. Sandbox testinde tünel (cloudflared/ngrok) açıp
|
||||||
> `NEXT_PUBLIC_APP_URL`'i o https adrese ayarla.
|
> `APP_URL`'i o https adrese ayarla.
|
||||||
|
|
||||||
## Akış
|
## Akış
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { NextResponse, type NextRequest } from "next/server";
|
import { NextResponse, type NextRequest } from "next/server";
|
||||||
|
import { appUrl as siteKok } from "@/lib/app-url";
|
||||||
import { appDb, schema } from "@/lib/appdb";
|
import { appDb, schema } from "@/lib/appdb";
|
||||||
import { odemeyiSonuclandir } from "@/lib/odeme";
|
import { odemeyiSonuclandir } from "@/lib/odeme";
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ import { odemeyiSonuclandir } from "@/lib/odeme";
|
|||||||
// SameSite=Lax nedeniyle session çerezi GELMEZ — kullanıcı token'dan çözülür,
|
// SameSite=Lax nedeniyle session çerezi GELMEZ — kullanıcı token'dan çözülür,
|
||||||
// verifySession ÇAĞRILMAZ. Kredi tanımlama odemeyiSonuclandir içinde idempotenttir.
|
// verifySession ÇAĞRILMAZ. Kredi tanımlama odemeyiSonuclandir içinde idempotenttir.
|
||||||
export async function POST(request: NextRequest) {
|
export async function POST(request: NextRequest) {
|
||||||
const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000";
|
const appUrl = siteKok();
|
||||||
|
|
||||||
let token: string | undefined;
|
let token: string | undefined;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { eq } from "drizzle-orm";
|
|||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { verifySession } from "@/lib/session";
|
import { verifySession } from "@/lib/session";
|
||||||
|
import { appUrl as siteKok } from "@/lib/app-url";
|
||||||
import { appDb, schema } from "@/lib/appdb";
|
import { appDb, schema } from "@/lib/appdb";
|
||||||
import { URUNLER } from "@/lib/credits";
|
import { URUNLER } from "@/lib/credits";
|
||||||
import { initializeCheckoutForm, initImzaDurumu } from "@/lib/iyzico";
|
import { initializeCheckoutForm, initImzaDurumu } from "@/lib/iyzico";
|
||||||
@@ -47,7 +48,7 @@ export async function baslatOdeme(
|
|||||||
const h = await headers();
|
const h = await headers();
|
||||||
const buyerIp =
|
const buyerIp =
|
||||||
h.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "85.34.78.112";
|
h.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "85.34.78.112";
|
||||||
const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000";
|
const appUrl = siteKok();
|
||||||
const [ad, soyad] = adSoyadAyir(session.user.name ?? "");
|
const [ad, soyad] = adSoyadAyir(session.user.name ?? "");
|
||||||
|
|
||||||
let init;
|
let init;
|
||||||
|
|||||||
27
src/lib/app-url.ts
Normal file
27
src/lib/app-url.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import "server-only";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uygulamanın dışarıya görünen kök adresi — iyzico callbackUrl'i ve ödeme
|
||||||
|
* yönlendirmeleri buradan okunur.
|
||||||
|
*
|
||||||
|
* NEXT_PUBLIC_APP_URL BİLİNÇLİ OLARAK KULLANILMAZ: `NEXT_PUBLIC_*` değişkenleri
|
||||||
|
* Next tarafından build sırasında koda sabit string olarak gömülür, runtime'da
|
||||||
|
* okunmaz. Docker imajı build edilirken .env.production build katmanına hiç
|
||||||
|
* geçmediği için (.dockerignore `.env*` dosyalarını dışlıyor) o değişken build
|
||||||
|
* anında `undefined` olur ve fallback ("http://localhost:3000") imaja çakılırdı;
|
||||||
|
* compose `env_file` ile değeri container'a verse bile kod artık onu okumazdı.
|
||||||
|
* Sonuç: iyzico'ya localhost callback'i gidiyor ve initialize reddediliyordu.
|
||||||
|
*
|
||||||
|
* Buradaki değişkenler public önekli olmadığı için runtime'da okunur — env
|
||||||
|
* değişince yeniden build gerekmez.
|
||||||
|
*/
|
||||||
|
export function appUrl(): string {
|
||||||
|
const ham =
|
||||||
|
process.env.APP_URL ??
|
||||||
|
// Aynı origin'i zaten gösteriyor ve prod .env'inde mevcut; ayrı bir secret
|
||||||
|
// eklemeden doğru değere düşmek için ikinci sırada.
|
||||||
|
process.env.BETTER_AUTH_URL ??
|
||||||
|
"http://localhost:3000";
|
||||||
|
// Sondaki "/" ile birleştirmelerde "//paket" üretmemek için kırpılır.
|
||||||
|
return ham.replace(/\/+$/, "");
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { URUNLER } from "./credits";
|
import { URUNLER } from "./credits";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kanonik site adresi. NEXT_PUBLIC_APP_URL bilinçli olarak KULLANILMAZ —
|
* Kanonik site adresi. Ödeme akışının kök adresiyle (`appUrl()`,
|
||||||
* o değişken ödeme callback akışına ait ve .env.local'de localhost'a işaret
|
* src/lib/app-url.ts) karıştırılmamalı: o runtime'da okunur, bu ise metadata
|
||||||
* ediyor. .dockerignore .env* dosyalarını dışladığı için prod build burada
|
* için build anında sabitlenir. .dockerignore .env* dosyalarını dışladığı için
|
||||||
* deterministik olarak kolaytercih.com'a düşer.
|
* prod build burada deterministik olarak kolaytercih.com'a düşer.
|
||||||
*/
|
*/
|
||||||
export const SITE_URL =
|
export const SITE_URL =
|
||||||
process.env.NEXT_PUBLIC_SITE_URL ??
|
process.env.NEXT_PUBLIC_SITE_URL ??
|
||||||
|
|||||||
Reference in New Issue
Block a user