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;
|
||||
tur?: string;
|
||||
sihirbaz?: string;
|
||||
kaynak?: string;
|
||||
hazir?: string;
|
||||
il?: string | string[];
|
||||
tip?: string;
|
||||
@@ -122,6 +123,7 @@ export default function SonucPage({
|
||||
sira={sira}
|
||||
tur={turKey}
|
||||
otomatikAc={params.sihirbaz === "1"}
|
||||
kaynak={params.kaynak}
|
||||
secimlerHazir={params.hazir === "1"}
|
||||
/>
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ export function AramaFunnelKarti({ onSec }: { onSec: () => void }) {
|
||||
return;
|
||||
}
|
||||
if (profil) {
|
||||
router.push(sonucHref({ sihirbaz: "1" }));
|
||||
router.push(sonucHref({ sihirbaz: "1", kaynak: "arama" }));
|
||||
return;
|
||||
}
|
||||
// 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.
|
||||
* `girisli`, "sihirbaz" hedefinde üretimin otomatik başlayıp başlamayacağını
|
||||
* 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(
|
||||
profil: TercihProfili,
|
||||
girisli = false,
|
||||
): string | null {
|
||||
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);
|
||||
const bekleyen = durum.bekleyen;
|
||||
const hedef = durum.bekleyenHedef;
|
||||
@@ -332,7 +345,15 @@ export function profilTamamlandi(
|
||||
// Yapay Zeka niyetli giriş: kapıda sihirbazı zaten doldurdu, /sonuc'ta
|
||||
// akış kesilmesin — girişliyse üretim otomatik başlar (?sihirbaz=1),
|
||||
// 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();
|
||||
// Düzenleme /sonuc'a götürür: tablo profil çerezinden SSR'lanır
|
||||
|
||||
@@ -21,7 +21,7 @@ export function RaporYokCta() {
|
||||
asChild
|
||||
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
|
||||
<ArrowRight className="size-4" aria-hidden />
|
||||
</Link>
|
||||
|
||||
@@ -25,9 +25,18 @@ import { tercihProfiliOku } from "@/features/sihirbaz/sihirbaz-profil";
|
||||
const IZINLI_KAYNAKLAR = new Set([
|
||||
"sihirbaz",
|
||||
"hazir_cta",
|
||||
// Gerçek giriş dönüşü: /giris callback'i doğrudan /listem'e iner.
|
||||
"giris_donusu",
|
||||
"bos_durum",
|
||||
"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",
|
||||
]);
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ export function CtaSiraForm({
|
||||
const yeniProfil = { sira, tur, secimler };
|
||||
tercihProfiliYaz(yeniProfil);
|
||||
setAcik(false);
|
||||
router.push(sonucHref(girisli ? { sihirbaz: "1" } : { hazir: "1" }));
|
||||
router.push(sonucHref(girisli ? { sihirbaz: "1", kaynak: "cta" } : { hazir: "1" }));
|
||||
}
|
||||
|
||||
function acikDegisti(v: boolean) {
|
||||
|
||||
@@ -101,7 +101,7 @@ export function HeroForm() {
|
||||
const profil = { sira, tur, secimler };
|
||||
tercihProfiliYaz(profil);
|
||||
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.
|
||||
|
||||
@@ -12,11 +12,14 @@ export async function SonucSihirbazi({
|
||||
sira,
|
||||
tur,
|
||||
otomatikAc,
|
||||
kaynak,
|
||||
secimlerHazir,
|
||||
}: {
|
||||
sira: number;
|
||||
tur: PuanTuruKey;
|
||||
otomatikAc: boolean;
|
||||
/** ?sihirbaz=1'i üreten yüzey; otomatik üretimin ölçüm etiketi olur. */
|
||||
kaynak?: string;
|
||||
secimlerHazir: boolean;
|
||||
}) {
|
||||
// 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)}
|
||||
raporVar={Boolean(raporSatiri?.result)}
|
||||
otomatikAc={otomatikAc}
|
||||
kaynak={kaynak}
|
||||
secimlerHazir={secimlerHazir}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -58,6 +58,7 @@ export function SihirbazBolumu({
|
||||
girisliMi,
|
||||
raporVar,
|
||||
otomatikAc,
|
||||
kaynak,
|
||||
secimlerHazir,
|
||||
}: {
|
||||
sira: number;
|
||||
@@ -68,6 +69,7 @@ export function SihirbazBolumu({
|
||||
raporVar: boolean;
|
||||
/** ?sihirbaz=1 ile gelindiyse modalı otomatik aç */
|
||||
otomatikAc?: boolean;
|
||||
kaynak?: string;
|
||||
/** ?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
|
||||
render edilsin. */
|
||||
@@ -222,7 +224,11 @@ export function SihirbazBolumu({
|
||||
if (otomatikGonder && !otomatikBasladi.current) {
|
||||
otomatikBasladi.current = true;
|
||||
// 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
|
||||
}, [otomatikGonder]);
|
||||
|
||||
Reference in New Issue
Block a user