From a7c4b6fc22d3553c32993f443339d821cb0d49dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Balc=C4=B1?= <138722058+UAJOP@users.noreply.github.com> Date: Thu, 20 Aug 2026 01:25:32 +0300 Subject: [PATCH 01/32] feat: add centralized portfolio content registry --- portfolio-data.js | 268 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 portfolio-data.js diff --git a/portfolio-data.js b/portfolio-data.js new file mode 100644 index 0000000..55ce4c1 --- /dev/null +++ b/portfolio-data.js @@ -0,0 +1,268 @@ +(function () { + const t = (en, tr) => ({ en, tr }); + + window.KAAN_PORTFOLIO = Object.freeze({ + version: "2.0.0", + updatedAt: "2026-08-20", + profile: { + name: "Kaan Balcı", + title: t("AI Designer & Software Developer", "AI Designer & Software Developer"), + location: t("Istanbul / Remote", "İstanbul / Remote"), + availability: t("Open for work", "İşe açık"), + direction: t( + "Applied AI, AI Solutions, Forward Deployed / Solution Engineering and product-minded software engineering.", + "Applied AI, AI Solutions, Forward Deployed / Solution Engineering ve ürün odaklı yazılım mühendisliği." + ), + resume: "https://drive.google.com/file/d/1eERVaYoP-ICuP3xfbzpaDaCo5amwqA8u/view?usp=sharing", + linkedin: "https://www.linkedin.com/in/balcikaan/", + github: "https://github.com/UAJOP", + email: "mailto:kaanb8776@gmail.com" + }, + projects: { + sinama: { + id: "sinama", + name: "SINAMA — AI Agent Reliability Lab", + status: t("Live MVP", "Canlı MVP"), + category: t("Applied AI / Reliability Engineering", "Applied AI / Reliability Engineering"), + role: t("Product Designer & Full-Stack Developer", "Product Designer & Full-Stack Developer"), + summary: t( + "A Turkish-first reliability lab for repeatable multi-turn agent testing, deterministic workflow evidence, regression comparison, version trends and release-readiness decisions.", + "Tekrarlanabilir multi-turn agent testleri, deterministik workflow kanıtı, regression karşılaştırması, version trendleri ve release-readiness kararları için Turkish-first reliability lab." + ), + stack: ["Next.js", "React", "Python", "FastAPI", "PostgreSQL", "AI Evaluation", "Vercel", "Railway"], + proof: [ + t("14-scenario typed cross-vertical suite", "14 senaryolu typed cross-vertical suite"), + t("Insurance + e-commerce reliability packs", "Insurance + e-commerce reliability pack'leri"), + t("Deterministic tool and workflow contracts", "Deterministik tool ve workflow contract'ları"), + t("Baseline/regression comparison and version trends", "Baseline/regression karşılaştırması ve version trendleri"), + t("READY / WARNING / BLOCKED release-readiness policy", "READY / WARNING / BLOCKED release-readiness politikası"), + t("Compatible external HTTPS agent testing", "Uyumlu external HTTPS agent testing") + ], + links: { + caseStudy: "sinama-case-study.html", + live: "https://sinama.kaanbalci.com", + github: "https://github.com/UAJOP/sinama" + }, + currentFocus: t("Semantic-judge calibration and stabilization", "Semantic-judge calibration ve stabilizasyon") + }, + mergeRush: { + id: "mergeRush", + name: "Merge Rush: Tiny Factory", + status: t("Active Development", "Aktif Geliştirme"), + category: t("Game Product Engineering", "Oyun Ürünü Mühendisliği"), + role: t("Game Developer & Product Designer", "Game Developer & Ürün Tasarımcısı"), + summary: t( + "A Phaser 3 + TypeScript merge-game product connecting timed orders, factory restoration, progressive board unlocks, multi-cell pieces and platform-aware architecture for a YouTube Playables direction.", + "Timed order'lar, fabrika onarımı, aşamalı board unlock, multi-cell parçalar ve YouTube Playables yönü için platform-aware mimariyi birleştiren Phaser 3 + TypeScript merge-game ürünü." + ), + stack: ["Phaser 3", "TypeScript", "Vite", "Vitest", "Responsive UI", "Game State", "Platform Adapter"], + proof: [ + t("4-minute Factory Run target", "4 dakikalık Factory Run hedefi"), + t("5 restoration stages", "5 fabrika onarım aşaması"), + t("25 progressively unlocked board cells", "Aşamalı açılan 25 board hücresi"), + t("Factory Run + Endless modes", "Factory Run + Endless modları"), + t("Footprint-aware placement, merge and deadlock logic", "Footprint-aware placement, merge ve deadlock mantığı"), + t("Platform lifecycle, save, audio and language abstractions", "Platform lifecycle, save, audio ve language abstraction'ları") + ], + qaEvidence: [ + { viewport: "1440×900", state: t("Wide live run", "Wide canlı run") }, + { viewport: "390×844", state: t("Portrait mobile", "Portrait mobil") }, + { viewport: "844×390", state: t("Landscape mobile", "Landscape mobil") }, + { viewport: "768×768", state: t("Square / tablet", "Square / tablet") }, + { viewport: "1262×624", state: t("Combo x2 state", "Combo x2 state") }, + { viewport: "1440×900", state: t("Game-over state", "Game-over state") } + ], + links: { caseStudy: "merge-rush-case-study.html", games: "games.html" }, + currentFocus: t("Gameplay pacing, retention and production readiness", "Gameplay pacing, retention ve production readiness") + }, + joyday: { + id: "joyday", + name: "Atölye Joyday Official Website", + status: t("Live", "Canlı"), + category: t("Real Business Product", "Gerçek İşletme Ürünü"), + summary: t( + "A customer-facing workshop website with package discovery, reservation journeys and operational automation.", + "Paket keşfi, rezervasyon yolculukları ve operasyon otomasyonu içeren müşteriye dönük atölye web ürünü." + ), + links: { caseStudy: "atolye-joyday-case-study.html", live: "https://atolyejoyday.com/" } + }, + chatbotFlow: { + id: "chatbotFlow", + name: "AI Chatbot Flow Design", + status: t("Case Study", "Case Study"), + category: t("Enterprise Conversational AI", "Kurumsal Conversational AI"), + summary: t( + "Enterprise chatbot QA, stabilization, flow restructuring and multi-channel workflow evidence.", + "Kurumsal chatbot QA, stabilizasyon, flow restructuring ve multi-channel workflow kanıtı." + ), + links: { caseStudy: "project-detail.html?project=ai-chatbot-flow-design" } + }, + hospital: { + id: "hospital", + name: "Hospital Form App", + status: t("Source Archive", "Kaynak Arşivi"), + category: t("C#/.NET Software", "C#/.NET Yazılım"), + summary: t( + "A database-backed Windows Forms workflow project for patient, doctor, secretary and appointment operations.", + "Hasta, doktor, sekreter ve randevu operasyonları için veritabanı destekli Windows Forms workflow projesi." + ), + links: { caseStudy: "hospital-system-case-study.html", github: "https://github.com/UAJOP/Hospital-System" } + } + }, + recruiterProfiles: { + "applied-ai": { + label: t("Applied AI", "Applied AI"), + profile: t("Applied AI / AI Reliability Engineer", "Applied AI / AI Reliability Engineer"), + focus: ["AI Agent Reliability", "LLM Evaluation", "Conversational AI", "Python / FastAPI", "Regression Testing"], + roles: ["Applied AI Engineer", "AI Solutions Engineer", "Forward Deployed Engineer", "AI Product Engineer", "Solution Engineer"], + skills: [ + t("Multi-turn scenario and agent evaluation", "Multi-turn senaryo ve agent değerlendirme"), + t("Deterministic tool/workflow contracts and regression evidence", "Deterministik tool/workflow contract'ları ve regression kanıtı"), + t("Python / FastAPI services and PostgreSQL persistence", "Python / FastAPI servisleri ve PostgreSQL persistence"), + t("LLM response, reasoning, code and multimodal evaluation", "LLM yanıt, reasoning, code ve multimodal değerlendirme"), + t("Enterprise conversational-AI workflow design", "Kurumsal conversational-AI workflow tasarımı") + ], + evidence: ["sinama", "chatbotFlow", "joyday"] + }, + "solution-engineering": { + label: t("Solution Engineering", "Solution Engineering"), + profile: t("AI Solutions / Solution Engineer", "AI Solutions / Solution Engineer"), + focus: ["Customer Workflows", "Conversational AI", "Automation", "API Integration", "Product Delivery"], + roles: ["Solution Engineer", "Technical Solutions Engineer", "Forward Deployed Engineer", "AI Solutions Engineer", "Implementation Engineer"], + skills: [ + t("Translating business requirements into testable workflows", "İş gereksinimlerini test edilebilir workflow'lara çevirme"), + t("Chatbot QA, stabilization and multi-channel handoffs", "Chatbot QA, stabilizasyon ve multi-channel handoff'lar"), + t("External-agent and API integration thinking", "External-agent ve API integration düşüncesi"), + t("Customer-facing product ownership", "Müşteriye dönük ürün sahipliği"), + t("Release-readiness and evidence-based delivery", "Release-readiness ve kanıt odaklı delivery") + ], + evidence: ["chatbotFlow", "sinama", "joyday"] + }, + software: { + label: t("Software", "Yazılım"), + profile: t("Software / Product Engineer", "Software / Product Engineer"), + focus: ["Python", "FastAPI", "TypeScript", "C#/.NET", "Databases"], + roles: ["Software Developer", "Backend Developer", "Product Engineer", "Junior Full-Stack Developer", "Technical Product Engineer"], + skills: [ + t("Backend APIs and persistence", "Backend API'ler ve persistence"), + t("TypeScript and responsive product interfaces", "TypeScript ve responsive ürün arayüzleri"), + t("C#/.NET and database-backed desktop workflows", "C#/.NET ve veritabanı destekli desktop workflow'lar"), + t("Automated quality gates and regression testing", "Automated quality gate'ler ve regression testing"), + t("Stateful product architecture", "Stateful ürün mimarisi") + ], + evidence: ["sinama", "hospital", "joyday"] + }, + game: { + label: t("Game / Interactive", "Oyun / İnteraktif"), + profile: t("Game / Interactive Product Developer", "Oyun / İnteraktif Ürün Geliştirici"), + focus: ["Phaser 3", "TypeScript", "Gameplay State", "Responsive UI", "Platform Architecture"], + roles: ["Game Developer", "Gameplay Programmer", "Interactive Developer", "Web Game Developer", "Technical Game Designer"], + skills: [ + t("Merge-game state, progression and timed-order systems", "Merge-game state, progression ve timed-order sistemleri"), + t("Footprint-aware placement and deadlock logic", "Footprint-aware placement ve deadlock mantığı"), + t("Responsive browser-game UI", "Responsive browser-game UI"), + t("Platform lifecycle, save, language and audio abstractions", "Platform lifecycle, save, language ve audio abstraction'ları"), + t("Playtesting-driven iteration", "Playtesting odaklı iterasyon") + ], + evidence: ["mergeRush", "hospital"] + } + }, + buildLog: [ + { + date: "2026-08-20", + area: "Portfolio", + title: t("Portfolio Architecture V2", "Portfolio Architecture V2"), + detail: t("Centralizing project truth, recruiter profiles, evidence and build status into one registry.", "Project truth, recruiter profilleri, evidence ve build status tek registry'de merkezileştiriliyor."), + status: "building" + }, + { + date: "2026-08-19", + area: "Portfolio", + title: t("SINAMA + Merge Rush flagship refresh", "SINAMA + Merge Rush flagship yenilemesi"), + detail: t("Refreshed the public portfolio around the two current flagship products.", "Public portfolyo iki güncel flagship ürün etrafında yenilendi."), + status: "shipped" + }, + { + date: "2026-08-18", + area: "SINAMA", + title: t("Semantic Judge shadow integration", "Semantic Judge shadow entegrasyonu"), + detail: t("Added an advisory semantic layer without letting it override deterministic reliability verdicts.", "Deterministik reliability kararlarını değiştirmeyen advisory semantic katman eklendi."), + status: "integration" + }, + { + date: "2026-08-14", + area: "Merge Rush", + title: t("Gameplay pacing and retention pass", "Gameplay pacing ve retention pass"), + detail: t("Deepened progression, board pressure and production architecture for the current game direction.", "Güncel oyun yönünde progression, board pressure ve production architecture derinleştirildi."), + status: "building" + } + ], + labs: [ + { + id: "ai-flow-puzzle", + title: "AI Flow Puzzle", + type: t("Workflow logic experiment", "Workflow logic deneyi"), + description: t("Build n8n-inspired chatbot flows with intent, fallback and validation nodes.", "Intent, fallback ve validation node'larıyla n8n-inspired chatbot flow'ları kur."), + url: "ai-flow-puzzle.html", + tags: ["JavaScript", "Node Logic", "Conversational AI"] + }, + { + id: "math-lab", + title: "Algorithmic 3D Lab", + type: t("Canvas / math experiment", "Canvas / matematik deneyi"), + description: t("A vanilla-JS parametric mesh with perspective projection, depth sorting and pointer interaction.", "Perspective projection, depth sorting ve pointer interaction içeren vanilla-JS parametric mesh."), + url: "labs.html#algorithmic-3d-lab", + tags: ["Canvas", "3D Projection", "Vanilla JS"] + }, + { + id: "career-adventure", + title: "Kaan's Career Adventure", + type: t("Career mini game", "Kariyer mini oyunu"), + description: t("A playful merge-style interpretation of learning, tools, experience and portfolio proof.", "Öğrenme, araçlar, deneyim ve portfolyo kanıtını merge mantığıyla yorumlayan mini oyun."), + url: "adventure.html", + tags: ["Canvas", "Merge", "Career"] + }, + { + id: "joyday-paint", + title: "Joyday Action Painting", + type: t("Creative canvas experiment", "Yaratıcı canvas deneyi"), + description: t("Virtual action-painting tools with multiple canvas shapes and PNG export.", "Birden fazla tuval formu, sanal action-painting araçları ve PNG export."), + url: "joyday-paint.html", + tags: ["Canvas", "Creative", "PNG Export"] + } + ], + sinamaEvidence: { + healthy: { + label: t("Healthy run", "Healthy run"), + status: "READY", + summary: t("Required evidence is collected before the side effect is allowed.", "Side effect'e izin verilmeden önce gerekli kanıtlar toplanıyor."), + conversation: [ + { speaker: "Customer", text: t("My car was damaged. Can you open a claim?", "Aracım hasar gördü. Hasar kaydı açabilir misiniz?") }, + { speaker: "Agent", text: t("I can help. First I need to verify your contact details and collect the required damage documents.", "Yardımcı olabilirim. Önce iletişim bilgilerinizi doğrulayıp gerekli hasar belgelerini toplamam gerekiyor.") }, + { speaker: "Customer", text: t("Okay, I can send the photos now.", "Tamam, fotoğrafları şimdi gönderebilirim.") } + ], + toolTrace: ["verify_contact()", "collect_required_documents()", "submit_claim()"], + findings: [ + { level: "PASS", text: t("Prerequisite order respected", "Prerequisite sırası korundu") }, + { level: "PASS", text: t("No forbidden early submission", "Yasak erken submission yok") }, + { level: "PASS", text: t("Required tool evidence present", "Gerekli tool kanıtı mevcut") } + ] + }, + broken: { + label: t("Broken run", "Broken run"), + status: "BLOCKED", + summary: t("The agent performs a claim-submission side effect before collecting prerequisites.", "Agent prerequisite'leri toplamadan claim-submission side effect'i gerçekleştiriyor."), + conversation: [ + { speaker: "Customer", text: t("My car was damaged. Can you open a claim?", "Aracım hasar gördü. Hasar kaydı açabilir misiniz?") }, + { speaker: "Agent", text: t("Sure. I am submitting the claim immediately.", "Tabii. Hasar kaydını hemen oluşturuyorum.") } + ], + toolTrace: ["submit_claim()"], + findings: [ + { level: "FAIL", text: t("Missing prerequisite: verify_contact", "Eksik prerequisite: verify_contact") }, + { level: "FAIL", text: t("Missing prerequisite: collect_required_documents", "Eksik prerequisite: collect_required_documents") }, + { level: "FAIL", text: t("Forbidden premature side effect", "Yasak premature side effect") } + ] + } + } + }); +})(); From f7eb1ec23c490106e01f1ff402a9d80e0035dfd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Balc=C4=B1?= <138722058+UAJOP@users.noreply.github.com> Date: Thu, 20 Aug 2026 01:26:48 +0300 Subject: [PATCH 02/32] feat: add portfolio architecture v2 runtime --- portfolio-v2.js | 360 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 portfolio-v2.js diff --git a/portfolio-v2.js b/portfolio-v2.js new file mode 100644 index 0000000..922b345 --- /dev/null +++ b/portfolio-v2.js @@ -0,0 +1,360 @@ +(function () { + const registry = window.KAAN_PORTFOLIO; + if (!registry) return; + + const state = { + role: "applied-ai", + evidenceScenario: "healthy" + }; + + const lang = () => (document.documentElement.lang === "tr" ? "tr" : "en"); + const pick = (value, language = lang()) => { + if (value && typeof value === "object" && ("en" in value || "tr" in value)) { + return value[language] || value.en || value.tr || ""; + } + return value ?? ""; + }; + const esc = (value) => String(value ?? "") + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'"); + + function applyUnifiedCopy() { + const language = lang(); + const pairs = [ + ["pv2", "data-pv2-en", "data-pv2-tr"], + ["flagship", "data-flagship-en", "data-flagship-tr"], + ["sinama", "data-sinama-en", "data-sinama-tr"], + ["mr", "data-mr-en", "data-mr-tr"] + ]; + pairs.forEach(([, enAttr, trAttr]) => { + document.querySelectorAll(`[${enAttr}][${trAttr}]`).forEach((node) => { + const value = node.getAttribute(language === "tr" ? trAttr : enAttr); + if (value !== null) node.textContent = value; + }); + }); + document.querySelectorAll("[data-pv2-aria-en][data-pv2-aria-tr]").forEach((node) => { + node.setAttribute("aria-label", node.getAttribute(language === "tr" ? "data-pv2-aria-tr" : "data-pv2-aria-en") || ""); + }); + } + + function projectLinkMarkup(projectId, language = lang()) { + const project = registry.projects[projectId]; + if (!project) return ""; + const href = project.links?.caseStudy || project.links?.live || "works.html"; + return `${esc(project.name)}${esc(pick(project.summary, language))}${language === "tr" ? "Kanıtı aç" : "Open evidence"}`; + } + + function getRoleFromUrl() { + const requested = new URLSearchParams(window.location.search).get("role"); + return requested && registry.recruiterProfiles[requested] ? requested : null; + } + + function setRole(roleId, { updateUrl = true, rerender = true } = {}) { + if (!registry.recruiterProfiles[roleId]) return; + state.role = roleId; + if (updateUrl) { + const url = new URL(window.location.href); + url.searchParams.set("role", roleId); + history.replaceState({}, "", `${url.pathname}${url.search}${url.hash}`); + } + if (rerender && typeof renderRecruiterDrawer === "function") renderRecruiterDrawer(lang()); + } + + function recruiterCopy(language) { + return language === "tr" + ? { + label: "İK MODU V2", + title: "Role göre kanıt özeti", + lead: "Aynı portfolyoyu hedef role göre yeniden sıralar; iddia yerine ilgili proje ve deneyim kanıtını öne çıkarır.", + choose: "Profil odağı", + primary: "Ana kimlik", + focus: "Odak", + skills: "Ana yetkinlikler", + roles: "Rol uyumu", + proof: "Önerilen kanıt", + cv: "CV'yi Görüntüle", + email: "E-posta", + close: "Kapat", + updated: "Portfolyo verisi" + } + : { + label: "RECRUITER MODE V2", + title: "Evidence summary by role", + lead: "Reorders the same portfolio for a target role and prioritizes project evidence over generic claims.", + choose: "Profile focus", + primary: "Primary profile", + focus: "Focus", + skills: "Core capabilities", + roles: "Role fit", + proof: "Recommended evidence", + cv: "View Resume", + email: "Email Me", + close: "Close", + updated: "Portfolio data" + }; + } + + function renderRecruiterV2(language = lang()) { + const drawer = document.querySelector("[data-recruiter-drawer]"); + if (!drawer) return; + const hadFocus = drawer.contains(document.activeElement); + const profile = registry.recruiterProfiles[state.role] || registry.recruiterProfiles["applied-ai"]; + const copy = recruiterCopy(language); + drawer.innerHTML = ` +
+ +

${esc(copy.label)}

+

${esc(copy.title)}

+

${esc(copy.lead)}

+
${esc(pick(registry.profile.availability, language))}
+
${esc(copy.updated)} · ${esc(registry.updatedAt)}
+

${esc(copy.choose)}

+
+ ${Object.entries(registry.recruiterProfiles).map(([id, item]) => ``).join("")} +
+

${esc(copy.primary)}

+
${esc(pick(profile.profile, language))}
+

${esc(copy.focus)}

+
${profile.focus.map((item) => `${esc(item)}`).join("")}
+

${esc(copy.skills)}

+ +

${esc(copy.roles)}

+
${profile.roles.map((item) => `${esc(item)}`).join("")}
+

${esc(copy.proof)}

+ +
+ ${esc(copy.cv)} + ${esc(copy.email)} + LinkedIn +
+
`; + drawer.querySelector("[data-recruiter-close]")?.addEventListener("click", () => setRecruiterMode(false)); + drawer.querySelectorAll("[data-recruiter-role]").forEach((button) => { + button.addEventListener("click", () => setRole(button.dataset.recruiterRole)); + }); + if (hadFocus) drawer.querySelector("[data-recruiter-close]")?.focus(); + } + + function installRecruiterV2() { + if (typeof renderRecruiterDrawer !== "function" || typeof setRecruiterMode !== "function") return; + try { + renderRecruiterDrawer = renderRecruiterV2; + const initialRole = getRoleFromUrl(); + if (initialRole) state.role = initialRole; + renderRecruiterDrawer(lang()); + if (initialRole) setTimeout(() => setRecruiterMode(true, { restoreFocus: false }), 120); + } catch (error) { + console.warn("Recruiter Mode V2 could not replace legacy renderer", error); + } + } + + function syncAjoop() { + if (typeof portfolioChatbotContent === "undefined" || typeof chatbotKeywordMap === "undefined") return; + const p = registry.projects; + const roleSummary = (language) => Object.values(registry.recruiterProfiles) + .map((item) => pick(item.label, language)) + .join(" · "); + + const copy = { + en: { + greeting: "Hey — Ajoop 3.0 here. I use the portfolio evidence registry to explain Kaan's current projects, role fit and proof. Ask about SINAMA, Merge Rush, Applied AI, Solution Engineering or the latest build.", + quicks: [ + { id: "sinama", label: "SINAMA evidence" }, + { id: "mergeRush", label: "Merge Rush evidence" }, + { id: "roles", label: "Role fit" }, + { id: "latestBuild", label: "Latest build" }, + { id: "projects", label: "Best projects" }, + { id: "cv", label: "CV & contact" } + ] + }, + tr: { + greeting: "Selam — Ajoop 3.0 burada. Kaan'ın güncel projelerini, role uygunluğunu ve kanıtlarını portfolio evidence registry üzerinden anlatıyorum. SINAMA, Merge Rush, Applied AI, Solution Engineering veya son build'i sorabilirsin.", + quicks: [ + { id: "sinama", label: "SINAMA kanıtı" }, + { id: "mergeRush", label: "Merge Rush kanıtı" }, + { id: "roles", label: "Role uygunluk" }, + { id: "latestBuild", label: "Son build" }, + { id: "projects", label: "En iyi projeler" }, + { id: "cv", label: "CV & iletişim" } + ] + } + }; + + ["en", "tr"].forEach((language) => { + const target = portfolioChatbotContent[language]; + if (!target) return; + target.greeting = copy[language].greeting; + target.quicks = copy[language].quicks; + target.answers.sinama = { + text: [ + `${p.sinama.name}: ${pick(p.sinama.summary, language)} Evidence: ${p.sinama.proof.slice(0, 3).map((item) => pick(item, language)).join("; ")}.`, + language === "tr" ? "SINAMA'nın güçlü tarafı yalnızca chat çıktısını değil transcript + Tool Trace + workflow contract kanıtını release kararına bağlaması." : "SINAMA's strongest proof is that it connects transcript + Tool Trace + workflow-contract evidence to a release decision." + ], + links: [ + { label: language === "tr" ? "SINAMA Vaka Çalışması" : "SINAMA Case Study", url: p.sinama.links.caseStudy }, + { label: language === "tr" ? "Canlı Ürün" : "Live Product", url: p.sinama.links.live }, + { label: "GitHub", url: p.sinama.links.github } + ] + }; + target.answers.mergeRush = { + text: [ + `${p.mergeRush.name}: ${pick(p.mergeRush.summary, language)} Evidence: ${p.mergeRush.proof.slice(0, 4).map((item) => pick(item, language)).join("; ")}.`, + language === "tr" ? "Proje aktif geliştirmede; public case study gerçek implementasyon ve QA kanıtını gösteriyor, private repo'yu açmıyor." : "The project is in active development; the public case study exposes implemented systems and QA evidence without exposing the private repository." + ], + links: [{ label: language === "tr" ? "Merge Rush Vaka Çalışması" : "Merge Rush Case Study", url: p.mergeRush.links.caseStudy }] + }; + target.answers.roles = { + text: [ + language === "tr" ? `Role profilleri: ${roleSummary(language)}. İK Modu V2 aynı portfolyoyu seçilen role göre kanıt sırasıyla yeniden düzenler.` : `Role profiles: ${roleSummary(language)}. Recruiter Mode V2 reorders the same portfolio by evidence for the selected role.`, + language === "tr" ? "Applied AI için SINAMA + CBOT yönü; Solution Engineering için CBOT + SINAMA + Joyday; Software için SINAMA backend + Hospital; Game için Merge Rush öne çıkar." : "Applied AI prioritizes SINAMA + CBOT; Solution Engineering prioritizes CBOT + SINAMA + Joyday; Software prioritizes SINAMA backend + Hospital; Game prioritizes Merge Rush." + ], + links: [{ label: language === "tr" ? "İK Modunu aç" : "Open Recruiter Mode", url: "index.html?role=applied-ai" }, { label: language === "tr" ? "Hakkımda" : "About", url: "about.html" }] + }; + target.answers.latestBuild = { + text: registry.buildLog.slice(0, 3).map((entry) => `${entry.date} · ${entry.area} · ${pick(entry.title, language)} — ${pick(entry.detail, language)}`), + links: [{ label: language === "tr" ? "Build Log" : "Build Log", url: "now.html" }] + }; + target.answers.projects = { + text: [ + language === "tr" ? "Güncel iki flagship ürün SINAMA ve Merge Rush. SINAMA Applied AI / reliability engineering; Merge Rush game-system / interactive product engineering tarafının ana kanıtı. Joyday gerçek işletme ürünü, AI Chatbot Flow Design ise enterprise conversational-AI deneyiminin güçlü desteği." : "The two current flagship products are SINAMA and Merge Rush. SINAMA is the main Applied AI / reliability-engineering proof; Merge Rush is the main game-system / interactive-product proof. Joyday adds real-business product ownership and AI Chatbot Flow Design adds enterprise conversational-AI evidence." + ], + links: [{ label: language === "tr" ? "Projeler" : "Works", url: "works.html" }, { label: "SINAMA", url: p.sinama.links.caseStudy }, { label: "Merge Rush", url: p.mergeRush.links.caseStudy }] + }; + }); + + const upsert = (id, keywords) => { + let entry = chatbotKeywordMap.find((item) => item.id === id); + if (!entry) { + entry = { id, keywords: [] }; + chatbotKeywordMap.unshift(entry); + } + const known = new Set(entry.keywords.map((item) => item.toLowerCase())); + keywords.forEach((keyword) => { + if (!known.has(keyword.toLowerCase())) entry.keywords.push(keyword); + }); + }; + upsert("sinama", ["sinama", "reliability", "regression", "readiness", "tool trace", "agent test"]); + upsert("mergeRush", ["merge rush", "tiny factory", "phaser", "playables", "factory run", "endless"]); + upsert("roles", ["applied ai", "solution engineer", "forward deployed", "role fit", "pozisyon", "uygunluk"]); + upsert("latestBuild", ["latest", "build", "now", "son build", "güncel", "ne yapıyor"]); + if (typeof updatePortfolioChatbotLanguage === "function") updatePortfolioChatbotLanguage(lang()); + } + + function extendCommands() { + if (typeof ultimateContent === "undefined") return; + const commands = { + en: [ + { id: "labs-v2", label: "Open Kaan Labs", hint: "Technical experiments", keywords: "labs experiments canvas ai flow", type: "nav", value: "labs.html" }, + { id: "now-v2", label: "Open Build Log", hint: "What is being built now", keywords: "now build log latest status", type: "nav", value: "now.html" }, + { id: "applied-ai-role", label: "Applied AI Recruiter View", hint: "Open role-specific evidence", keywords: "applied ai role recruiter", type: "nav", value: "index.html?role=applied-ai" } + ], + tr: [ + { id: "labs-v2", label: "Kaan Labs'i Aç", hint: "Teknik deneyler", keywords: "labs deneyler canvas ai flow", type: "nav", value: "labs.html" }, + { id: "now-v2", label: "Build Log'u Aç", hint: "Şu an ne geliştiriliyor", keywords: "now build log son durum güncel", type: "nav", value: "now.html" }, + { id: "applied-ai-role", label: "Applied AI İK Görünümü", hint: "Role özel kanıt görünümü", keywords: "applied ai role ik recruiter", type: "nav", value: "index.html?role=applied-ai" } + ] + }; + ["en", "tr"].forEach((language) => { + commands[language].forEach((command) => { + if (!ultimateContent[language].commands.some((item) => item.id === command.id)) ultimateContent[language].commands.push(command); + }); + }); + if (typeof renderCommandPalette === "function") renderCommandPalette(lang()); + } + + function buildLogMarkup(entry, language) { + const statusLabel = { + shipped: language === "tr" ? "Shipped" : "Shipped", + building: language === "tr" ? "Building" : "Building", + integration: language === "tr" ? "Integration" : "Integration" + }[entry.status] || entry.status; + return `
${esc(entry.area)}${esc(statusLabel)}

${esc(pick(entry.title, language))}

${esc(pick(entry.detail, language))}

`; + } + + function renderBuildLogs() { + document.querySelectorAll("[data-build-log]").forEach((container) => { + const limit = Number(container.dataset.buildLogLimit || registry.buildLog.length); + container.innerHTML = registry.buildLog.slice(0, limit).map((entry) => buildLogMarkup(entry, lang())).join(""); + }); + } + + function renderLabCards() { + document.querySelectorAll("[data-labs-grid]").forEach((container) => { + container.innerHTML = registry.labs.map((item) => `
${esc(pick(item.type))}

${esc(item.title)}

${esc(pick(item.description))}

${item.tags.map((tag) => `${esc(tag)}`).join("")}
${lang() === "tr" ? "Deneyi aç" : "Open experiment"}
`).join(""); + }); + } + + function renderEvidenceExplorer() { + const root = document.querySelector("[data-sinama-evidence]"); + if (!root) return; + const language = lang(); + const scenario = registry.sinamaEvidence[state.evidenceScenario]; + const labels = language === "tr" + ? { conversation: "Conversation", tools: "Tool Trace", evaluation: "Evaluation", healthy: "Healthy Run", broken: "Broken Run", verdict: "Release verdict" } + : { conversation: "Conversation", tools: "Tool Trace", evaluation: "Evaluation", healthy: "Healthy Run", broken: "Broken Run", verdict: "Release verdict" }; + root.innerHTML = ` +
+ + +
+
${esc(labels.verdict)}${esc(scenario.status)}

${esc(pick(scenario.summary, language))}

+
+

${esc(labels.conversation)}

${scenario.conversation.map((turn) => `
${esc(turn.speaker)}

${esc(pick(turn.text, language))}

`).join("")}
+

${esc(labels.tools)}

    ${scenario.toolTrace.map((tool) => `
  1. ${esc(tool)}
  2. `).join("")}
+

${esc(labels.evaluation)}

+
`; + root.querySelectorAll("[data-evidence-scenario]").forEach((button) => { + button.addEventListener("click", () => { + state.evidenceScenario = button.dataset.evidenceScenario; + renderEvidenceExplorer(); + }); + }); + } + + function installRequestReceipt() { + const status = document.querySelector("[data-request-status]"); + if (!status || !window.MutationObserver) return; + const observer = new MutationObserver(() => { + if (!status.classList.contains("success") || status.querySelector("[data-request-receipt]")) return; + const receipt = document.createElement("div"); + receipt.className = "request-receipt"; + receipt.dataset.requestReceipt = ""; + const stamp = new Date(); + const reference = `KB-${stamp.getFullYear()}${String(stamp.getMonth() + 1).padStart(2, "0")}${String(stamp.getDate()).padStart(2, "0")}-${String(stamp.getHours()).padStart(2, "0")}${String(stamp.getMinutes()).padStart(2, "0")}`; + receipt.innerHTML = `${lang() === "tr" ? "Tarayıcı gönderim referansı" : "Browser submission reference"}: ${esc(reference)}${lang() === "tr" ? "Bu referans server confirmation değildir; Apps Script no-cors akışı nedeniyle tarayıcı teslimatı doğrulayamaz." : "This is not a server confirmation; the browser cannot verify delivery through the Apps Script no-cors flow."}`; + status.appendChild(receipt); + }); + observer.observe(status, { childList: true, subtree: true, attributes: true }); + } + + function installLanguageObserver() { + const observer = new MutationObserver((records) => { + if (!records.some((record) => record.attributeName === "lang")) return; + applyUnifiedCopy(); + syncAjoop(); + renderBuildLogs(); + renderLabCards(); + renderEvidenceExplorer(); + if (typeof renderRecruiterDrawer === "function") renderRecruiterDrawer(lang()); + }); + observer.observe(document.documentElement, { attributes: true, attributeFilter: ["lang"] }); + } + + function init() { + applyUnifiedCopy(); + installRecruiterV2(); + syncAjoop(); + extendCommands(); + renderBuildLogs(); + renderLabCards(); + renderEvidenceExplorer(); + installRequestReceipt(); + installLanguageObserver(); + } + + if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init, { once: true }); + else init(); +})(); From 833e48e5d642319b49b2a5ff347ad7ed8b1fe3df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Balc=C4=B1?= <138722058+UAJOP@users.noreply.github.com> Date: Thu, 20 Aug 2026 01:27:11 +0300 Subject: [PATCH 03/32] feat: add portfolio v2 interface styles --- portfolio-v2.css | 1 + 1 file changed, 1 insertion(+) create mode 100644 portfolio-v2.css diff --git a/portfolio-v2.css b/portfolio-v2.css new file mode 100644 index 0000000..7790da3 --- /dev/null +++ b/portfolio-v2.css @@ -0,0 +1 @@ +.recruiter-card-v2{max-width:680px}.recruiter-data-note{display:inline-flex;align-items:center;gap:.45rem;margin:.25rem 0 1.15rem;color:var(--muted);font-size:.78rem;font-weight:800}.recruiter-role-switch{display:flex;flex-wrap:wrap;gap:.55rem;margin:.55rem 0 1.2rem}.recruiter-role-switch button{border:1px solid var(--line);border-radius:999px;background:rgba(255,255,255,.05);color:var(--muted);padding:.6rem .8rem;font:inherit;font-size:.78rem;font-weight:850;cursor:pointer}.recruiter-role-switch button:hover,.recruiter-role-switch button.active{color:var(--text);border-color:rgba(56,189,248,.45);background:rgba(56,189,248,.12)}.recruiter-capability-list{display:grid;gap:.6rem}.build-log-list{display:grid;gap:1rem}.build-log-item{display:grid;grid-template-columns:110px minmax(0,1fr);gap:1.2rem;padding:1.1rem 0;border-bottom:1px solid var(--line)}.build-log-item time{color:var(--muted);font-size:.8rem;font-weight:850}.build-log-item h3{margin:.25rem 0 .35rem;font-size:1.05rem}.build-log-item p{color:var(--muted)}.build-log-meta{display:flex;align-items:center;gap:.55rem;flex-wrap:wrap}.build-log-meta>span:first-child{color:var(--brand);font-size:.76rem;font-weight:900;text-transform:uppercase;letter-spacing:.08em}.build-log-status{padding:.26rem .5rem;border:1px solid var(--line);border-radius:999px;font-size:.68rem;font-weight:900}.build-log-status.is-shipped{color:var(--success);border-color:rgba(52,211,153,.3);background:rgba(52,211,153,.08)}.build-log-status.is-building{color:var(--warning);border-color:rgba(251,191,36,.3);background:rgba(251,191,36,.08)}.build-log-status.is-integration{color:var(--brand);border-color:rgba(56,189,248,.3);background:rgba(56,189,248,.08)}.labs-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1rem}.lab-card{padding:1.3rem;border:1px solid var(--line);border-radius:22px;background:var(--surface);box-shadow:var(--shadow)}.lab-card-top{display:flex;justify-content:space-between;gap:1rem;align-items:center;margin-bottom:1rem;color:var(--brand);font-size:.78rem;font-weight:900;text-transform:uppercase;letter-spacing:.08em}.lab-card-top i{font-size:1.35rem}.lab-card h3{font-size:1.25rem;margin-bottom:.45rem}.lab-card p{color:var(--muted);margin-bottom:1rem}.lab-card>a{display:inline-flex;align-items:center;gap:.35rem;margin-top:1rem;color:var(--brand);font-weight:850}.evidence-explorer{padding:1.2rem;border:1px solid var(--line);border-radius:26px;background:var(--surface);box-shadow:var(--shadow)}.evidence-toolbar{display:flex;gap:.55rem;flex-wrap:wrap;margin-bottom:1rem}.evidence-toolbar button{border:1px solid var(--line);border-radius:999px;background:rgba(255,255,255,.05);color:var(--muted);padding:.62rem .85rem;font:inherit;font-size:.8rem;font-weight:900;cursor:pointer}.evidence-toolbar button.active{color:var(--text);border-color:rgba(56,189,248,.45);background:rgba(56,189,248,.12)}.evidence-verdict{padding:1rem 1.1rem;border:1px solid var(--line);border-radius:18px;margin-bottom:1rem}.evidence-verdict span{display:block;color:var(--muted);font-size:.72rem;font-weight:900;text-transform:uppercase;letter-spacing:.08em}.evidence-verdict strong{display:block;font-size:1.45rem;margin:.2rem 0}.evidence-verdict p{color:var(--muted)}.evidence-verdict.is-ready{border-color:rgba(52,211,153,.3);background:rgba(52,211,153,.06)}.evidence-verdict.is-ready strong{color:var(--success)}.evidence-verdict.is-blocked{border-color:rgba(251,113,133,.32);background:rgba(251,113,133,.06)}.evidence-verdict.is-blocked strong{color:var(--danger)}.evidence-grid{display:grid;grid-template-columns:1.15fr .85fr 1fr;gap:1rem}.evidence-grid>article{padding:1rem;border:1px solid var(--line);border-radius:18px;background:rgba(255,255,255,.03)}.evidence-conversation{display:grid;gap:.75rem}.evidence-conversation>div{padding:.8rem;border-radius:14px;background:rgba(255,255,255,.045)}.evidence-conversation strong{display:block;color:var(--brand);font-size:.74rem;text-transform:uppercase;letter-spacing:.07em}.evidence-conversation p{margin-top:.25rem;color:var(--text)}.evidence-tools,.evidence-findings{display:grid;gap:.65rem;list-style:none}.evidence-tools li{padding:.72rem;border:1px solid var(--line);border-radius:12px}.evidence-tools code{color:var(--brand);font-size:.8rem}.evidence-findings li{display:grid;grid-template-columns:auto 1fr;gap:.6rem;align-items:start;padding:.72rem;border:1px solid var(--line);border-radius:12px}.evidence-findings li strong{font-size:.72rem}.evidence-findings li.is-pass strong{color:var(--success)}.evidence-findings li.is-fail strong{color:var(--danger)}.request-receipt{display:grid;gap:.2rem;margin-top:.8rem;padding:.8rem;border:1px solid var(--line);border-radius:12px;background:rgba(255,255,255,.04);font-size:.78rem}.request-receipt span{color:var(--muted)}.flagship-pair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1rem}.flagship-focus-card{display:flex;flex-direction:column;min-height:100%;padding:1.35rem;border:1px solid var(--line);border-radius:24px;background:var(--surface);box-shadow:var(--shadow)}.flagship-focus-card .project-status{align-self:flex-start}.flagship-focus-card h3{margin:.8rem 0 .55rem;font-size:1.35rem}.flagship-focus-card p{color:var(--muted)}.flagship-focus-card .hero-actions{margin-top:auto;padding-top:1rem}.qa-proof-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.75rem}.qa-proof-grid article{padding:.9rem;border:1px solid var(--line);border-radius:16px;background:rgba(255,255,255,.035)}.qa-proof-grid strong{display:block;color:var(--brand)}.qa-proof-grid span{color:var(--muted);font-size:.82rem}.section-kicker-row{display:flex;align-items:end;justify-content:space-between;gap:1rem;margin-bottom:1rem}.section-kicker-row>a{color:var(--brand);font-weight:850}.compact-evidence-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem}.compact-evidence-grid article{padding:1.15rem;border:1px solid var(--line);border-radius:20px;background:var(--surface)}.compact-evidence-grid p{color:var(--muted)}html[data-theme="light"] .lab-card,html[data-theme="light"] .evidence-explorer,html[data-theme="light"] .flagship-focus-card,html[data-theme="light"] .compact-evidence-grid article{background:rgba(255,255,255,.9)}@media(max-width:900px){.evidence-grid{grid-template-columns:1fr}.qa-proof-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.compact-evidence-grid{grid-template-columns:1fr}.flagship-pair{grid-template-columns:1fr}}@media(max-width:680px){.labs-grid{grid-template-columns:1fr}.build-log-item{grid-template-columns:1fr;gap:.45rem}.qa-proof-grid{grid-template-columns:1fr}.recruiter-role-switch{display:grid;grid-template-columns:1fr 1fr}.recruiter-role-switch button{width:100%}} \ No newline at end of file From c44cd90eb5905a619015a96ec62b36076db00974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Balc=C4=B1?= <138722058+UAJOP@users.noreply.github.com> Date: Thu, 20 Aug 2026 01:28:03 +0300 Subject: [PATCH 04/32] refactor: simplify homepage around flagship evidence --- index.html | 138 +++++++++++++++++------------------------------------ 1 file changed, 44 insertions(+), 94 deletions(-) diff --git a/index.html b/index.html index 15afac9..1c88e73 100644 --- a/index.html +++ b/index.html @@ -3,44 +3,31 @@ - - + + - - +Kaan Balcı | Applied AI, Solutions & Software + + + + + + + - + - -Kaan Balcı | AI Designer & Software Developer - + + + - - - - - - - - - - +