fix(olcum): otomatik üretimin kaynağı gerçek yüzeyden gelir (G3)
/sonuc'taki otomatik üretim kaynağı sabit "giris_donusu" yazıyordu; oysa ?sihirbaz=1 üreten hiçbir yer giriş dönüşü değil — gerçek giriş dönüşü /listem'e doğrudan iniyor, /sonuc'a uğramıyor. Hero, CTA formu, arama kartı, + kapısı, boş liste ekranı ve rapor-yok CTA'sı tek yanlış kovada toplanıyordu, yani P2'nin ölçmek istediği soru ölçülmüyordu. Etiket artık ?sihirbaz=1'i üreten tarafta kuruluyor ve /sonuc üzerinden geçiriliyor; kapıdan gelenler tetikten türetiliyor. giris_donusu yalnız gerçek callback yolunda kalıyor. Güvenlik denetimi G3 · docs/ekip-raporlari/2026-09-22/07-guvenlik-denetimi.md Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,7 @@ export default function SonucPage({
|
|||||||
sira?: string;
|
sira?: string;
|
||||||
tur?: string;
|
tur?: string;
|
||||||
sihirbaz?: string;
|
sihirbaz?: string;
|
||||||
|
kaynak?: string;
|
||||||
hazir?: string;
|
hazir?: string;
|
||||||
il?: string | string[];
|
il?: string | string[];
|
||||||
tip?: string;
|
tip?: string;
|
||||||
@@ -122,6 +123,7 @@ export default function SonucPage({
|
|||||||
sira={sira}
|
sira={sira}
|
||||||
tur={turKey}
|
tur={turKey}
|
||||||
otomatikAc={params.sihirbaz === "1"}
|
otomatikAc={params.sihirbaz === "1"}
|
||||||
|
kaynak={params.kaynak}
|
||||||
secimlerHazir={params.hazir === "1"}
|
secimlerHazir={params.hazir === "1"}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export function AramaFunnelKarti({ onSec }: { onSec: () => void }) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (profil) {
|
if (profil) {
|
||||||
router.push(sonucHref({ sihirbaz: "1" }));
|
router.push(sonucHref({ sihirbaz: "1", kaynak: "arama" }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Yapay Zeka niyetli CTA: kapı tamamlanınca /sonuc'ta üretim akışı devam
|
// Yapay Zeka niyetli CTA: kapı tamamlanınca /sonuc'ta üretim akışı devam
|
||||||
|
|||||||
@@ -298,11 +298,24 @@ export function programEkleIste(opts: {
|
|||||||
/** Profil yazıldıktan sonra; bekleyen hedef varsa yönlendirme href'i döner.
|
/** Profil yazıldıktan sonra; bekleyen hedef varsa yönlendirme href'i döner.
|
||||||
* `girisli`, "sihirbaz" hedefinde üretimin otomatik başlayıp başlamayacağını
|
* `girisli`, "sihirbaz" hedefinde üretimin otomatik başlayıp başlamayacağını
|
||||||
* belirler (kapı bileşeni oturumu facet isteğiyle paralel çözer). */
|
* belirler (kapı bileşeni oturumu facet isteğiyle paralel çözer). */
|
||||||
|
/** Kapı tetiği → üretim denemesinin ölçüm etiketi. Yalnız `hedef="sihirbaz"`
|
||||||
|
* dalında kullanılır; listede olmayan tetik `bilinmiyor` sayılır (izinli
|
||||||
|
* değerlerin tek kaynağı: rapor/components/uretim-basladi-olayi.tsx). */
|
||||||
|
const KAYNAK_TETIKTEN: Partial<Record<KapiTetik, string>> = {
|
||||||
|
arti: "arti",
|
||||||
|
arti_toast: "arti",
|
||||||
|
listem_bos: "bos_durum",
|
||||||
|
sihirbaz: "sihirbaz",
|
||||||
|
sonuc: "sonuc_kapi",
|
||||||
|
};
|
||||||
|
|
||||||
export function profilTamamlandi(
|
export function profilTamamlandi(
|
||||||
profil: TercihProfili,
|
profil: TercihProfili,
|
||||||
girisli = false,
|
girisli = false,
|
||||||
): string | null {
|
): string | null {
|
||||||
const duzenle = durum.duzenle;
|
const duzenle = durum.duzenle;
|
||||||
|
// durum aşağıda sıfırlanıyor (tetik: "diger"); ölçüm etiketi için önce yakala
|
||||||
|
const tetik = durum.tetik;
|
||||||
riskleriYenile(profil);
|
riskleriYenile(profil);
|
||||||
const bekleyen = durum.bekleyen;
|
const bekleyen = durum.bekleyen;
|
||||||
const hedef = durum.bekleyenHedef;
|
const hedef = durum.bekleyenHedef;
|
||||||
@@ -332,7 +345,15 @@ export function profilTamamlandi(
|
|||||||
// Yapay Zeka niyetli giriş: kapıda sihirbazı zaten doldurdu, /sonuc'ta
|
// Yapay Zeka niyetli giriş: kapıda sihirbazı zaten doldurdu, /sonuc'ta
|
||||||
// akış kesilmesin — girişliyse üretim otomatik başlar (?sihirbaz=1),
|
// akış kesilmesin — girişliyse üretim otomatik başlar (?sihirbaz=1),
|
||||||
// girişsizse ücretsiz tablo + giriş CTA paneli (?hazir=1) karşılar.
|
// girişsizse ücretsiz tablo + giriş CTA paneli (?hazir=1) karşılar.
|
||||||
return sonucHref(girisli ? { sihirbaz: "1" } : { hazir: "1" });
|
//
|
||||||
|
// `kaynak`: girişli dalda /sonuc üretimi kendiliğinden başlatıyor, yani
|
||||||
|
// denemeyi başlatan yüzey bu kapıdır. Tetikten türetiliyor ki hero ya da
|
||||||
|
// arama kartıyla aynı kovaya düşmesin (bkz. uretim-basladi-olayi.tsx).
|
||||||
|
return sonucHref(
|
||||||
|
girisli
|
||||||
|
? { sihirbaz: "1", kaynak: KAYNAK_TETIKTEN[tetik] ?? "bilinmiyor" }
|
||||||
|
: { hazir: "1" },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (hedef === "sonuc") return sonucHref();
|
if (hedef === "sonuc") return sonucHref();
|
||||||
// Düzenleme /sonuc'a götürür: tablo profil çerezinden SSR'lanır
|
// Düzenleme /sonuc'a götürür: tablo profil çerezinden SSR'lanır
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export function RaporYokCta() {
|
|||||||
asChild
|
asChild
|
||||||
className="h-11 cursor-pointer bg-orange-500 text-white transition-colors duration-200 hover:bg-orange-600"
|
className="h-11 cursor-pointer bg-orange-500 text-white transition-colors duration-200 hover:bg-orange-600"
|
||||||
>
|
>
|
||||||
<Link href={profil ? sonucHref({ sihirbaz: "1" }) : "/"}>
|
<Link href={profil ? sonucHref({ sihirbaz: "1", kaynak: "rapor_yok" }) : "/"}>
|
||||||
24'lük listeni oluştur
|
24'lük listeni oluştur
|
||||||
<ArrowRight className="size-4" aria-hidden />
|
<ArrowRight className="size-4" aria-hidden />
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -25,9 +25,18 @@ import { tercihProfiliOku } from "@/features/sihirbaz/sihirbaz-profil";
|
|||||||
const IZINLI_KAYNAKLAR = new Set([
|
const IZINLI_KAYNAKLAR = new Set([
|
||||||
"sihirbaz",
|
"sihirbaz",
|
||||||
"hazir_cta",
|
"hazir_cta",
|
||||||
|
// Gerçek giriş dönüşü: /giris callback'i doğrudan /listem'e iner.
|
||||||
"giris_donusu",
|
"giris_donusu",
|
||||||
"bos_durum",
|
"bos_durum",
|
||||||
"odeme_sonrasi",
|
"odeme_sonrasi",
|
||||||
|
// /sonuc'ta ?sihirbaz=1 ile otomatik başlayan üretimin gerçek yüzeyleri.
|
||||||
|
// Eskiden hepsi "giris_donusu" sayılıyordu (güvenlik denetimi G3).
|
||||||
|
"hero",
|
||||||
|
"cta",
|
||||||
|
"arama",
|
||||||
|
"arti",
|
||||||
|
"sonuc_kapi",
|
||||||
|
"rapor_yok",
|
||||||
"bilinmiyor",
|
"bilinmiyor",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ export function CtaSiraForm({
|
|||||||
const yeniProfil = { sira, tur, secimler };
|
const yeniProfil = { sira, tur, secimler };
|
||||||
tercihProfiliYaz(yeniProfil);
|
tercihProfiliYaz(yeniProfil);
|
||||||
setAcik(false);
|
setAcik(false);
|
||||||
router.push(sonucHref(girisli ? { sihirbaz: "1" } : { hazir: "1" }));
|
router.push(sonucHref(girisli ? { sihirbaz: "1", kaynak: "cta" } : { hazir: "1" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
function acikDegisti(v: boolean) {
|
function acikDegisti(v: boolean) {
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export function HeroForm() {
|
|||||||
const profil = { sira, tur, secimler };
|
const profil = { sira, tur, secimler };
|
||||||
tercihProfiliYaz(profil);
|
tercihProfiliYaz(profil);
|
||||||
setModalAcik(false);
|
setModalAcik(false);
|
||||||
router.push(sonucHref(girisli ? { sihirbaz: "1" } : { hazir: "1" }));
|
router.push(sonucHref(girisli ? { sihirbaz: "1", kaynak: "hero" } : { hazir: "1" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kayıtlı profil varsa sihirbazı atla, doğrudan sonuç sayfasına götür.
|
// Kayıtlı profil varsa sihirbazı atla, doğrudan sonuç sayfasına götür.
|
||||||
|
|||||||
@@ -12,11 +12,14 @@ export async function SonucSihirbazi({
|
|||||||
sira,
|
sira,
|
||||||
tur,
|
tur,
|
||||||
otomatikAc,
|
otomatikAc,
|
||||||
|
kaynak,
|
||||||
secimlerHazir,
|
secimlerHazir,
|
||||||
}: {
|
}: {
|
||||||
sira: number;
|
sira: number;
|
||||||
tur: PuanTuruKey;
|
tur: PuanTuruKey;
|
||||||
otomatikAc: boolean;
|
otomatikAc: boolean;
|
||||||
|
/** ?sihirbaz=1'i üreten yüzey; otomatik üretimin ölçüm etiketi olur. */
|
||||||
|
kaynak?: string;
|
||||||
secimlerHazir: boolean;
|
secimlerHazir: boolean;
|
||||||
}) {
|
}) {
|
||||||
// Kullanıcının kayıtlı raporu var mı? Yalnızca CTA'nın hangi hâlde render
|
// Kullanıcının kayıtlı raporu var mı? Yalnızca CTA'nın hangi hâlde render
|
||||||
@@ -35,6 +38,7 @@ export async function SonucSihirbazi({
|
|||||||
girisliMi={Boolean(session)}
|
girisliMi={Boolean(session)}
|
||||||
raporVar={Boolean(raporSatiri?.result)}
|
raporVar={Boolean(raporSatiri?.result)}
|
||||||
otomatikAc={otomatikAc}
|
otomatikAc={otomatikAc}
|
||||||
|
kaynak={kaynak}
|
||||||
secimlerHazir={secimlerHazir}
|
secimlerHazir={secimlerHazir}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export function SihirbazBolumu({
|
|||||||
girisliMi,
|
girisliMi,
|
||||||
raporVar,
|
raporVar,
|
||||||
otomatikAc,
|
otomatikAc,
|
||||||
|
kaynak,
|
||||||
secimlerHazir,
|
secimlerHazir,
|
||||||
}: {
|
}: {
|
||||||
sira: number;
|
sira: number;
|
||||||
@@ -68,6 +69,7 @@ export function SihirbazBolumu({
|
|||||||
raporVar: boolean;
|
raporVar: boolean;
|
||||||
/** ?sihirbaz=1 ile gelindiyse modalı otomatik aç */
|
/** ?sihirbaz=1 ile gelindiyse modalı otomatik aç */
|
||||||
otomatikAc?: boolean;
|
otomatikAc?: boolean;
|
||||||
|
kaynak?: string;
|
||||||
/** ?hazir=1 (hero sihirbazından girişsiz geliş): seçimler storage'da,
|
/** ?hazir=1 (hero sihirbazından girişsiz geliş): seçimler storage'da,
|
||||||
panel giriş CTA'sına döner. URL'den gelir ki SSR'da doğru panel
|
panel giriş CTA'sına döner. URL'den gelir ki SSR'da doğru panel
|
||||||
render edilsin. */
|
render edilsin. */
|
||||||
@@ -222,7 +224,11 @@ export function SihirbazBolumu({
|
|||||||
if (otomatikGonder && !otomatikBasladi.current) {
|
if (otomatikGonder && !otomatikBasladi.current) {
|
||||||
otomatikBasladi.current = true;
|
otomatikBasladi.current = true;
|
||||||
// replace: geri tuşu bu sayfaya dönünce tekrar /listem'e sekmesin
|
// replace: geri tuşu bu sayfaya dönünce tekrar /listem'e sekmesin
|
||||||
router.replace(listemUretHref("giris_donusu"));
|
// Etiket ?sihirbaz=1'i ÜRETEN yüzeyden gelir. Eskiden burası sabit
|
||||||
|
// "giris_donusu" yazıyordu; oysa gerçek giriş dönüşü /listem'e
|
||||||
|
// doğrudan iner, /sonuc'a hiç uğramaz — hero, katalog, arama, + ve
|
||||||
|
// ödeme-sonrası tek yanlış kovada toplanıyordu.
|
||||||
|
router.replace(listemUretHref(kaynak ?? "bilinmiyor"));
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [otomatikGonder]);
|
}, [otomatikGonder]);
|
||||||
|
|||||||
Reference in New Issue
Block a user