feat: enhance landing page, Telegram webhook, SEO suite, and cookie consent banner

This commit is contained in:
ayrisdev
2026-08-22 22:57:03 +03:00
parent 5ac5988a3a
commit 61dd85133c
26 changed files with 3264 additions and 896 deletions
+55 -45
View File
@@ -2,74 +2,82 @@
import { signOut } from 'next-auth/react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import Image from 'next/image'
import { usePathname, useParams } from 'next/navigation'
import { LayoutDashboard, Users, Settings, LogOut, Menu, X } from 'lucide-react'
import { useState } from 'react'
export default function AdminLayout({ children }: { children: React.ReactNode }) {
const pathname = usePathname()
const params = useParams()
const locale = (params?.locale as string) || 'tr'
const [sidebarOpen, setSidebarOpen] = useState(false)
const navigation = [
{ name: 'Dashboard', href: '/admin', icon: LayoutDashboard },
{ name: 'Kullanıcılar', href: '/admin/users', icon: Users },
{ name: 'Ayarlar', href: '/admin/settings', icon: Settings },
{ name: 'Dashboard', href: `/${locale}/admin`, icon: LayoutDashboard },
{ name: 'Kullanıcılar', href: `/${locale}/admin/users`, icon: Users },
{ name: 'Ayarlar', href: `/${locale}/admin/settings`, icon: Settings },
]
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex">
<div className="min-h-screen bg-zinc-50 flex">
{/* Mobile sidebar backdrop */}
{sidebarOpen && (
<div
className="fixed inset-0 z-40 bg-gray-900/80 lg:hidden"
className="fixed inset-0 z-40 bg-zinc-950/60 lg:hidden"
onClick={() => setSidebarOpen(false)}
/>
)}
{/* Sidebar */}
<div className={`
fixed inset-y-0 left-0 z-50 w-64 bg-white dark:bg-gray-950 border-r border-gray-200 dark:border-gray-800
fixed inset-y-0 left-0 z-50 w-64 bg-white border-r border-zinc-200
transform transition-transform duration-200 ease-in-out lg:translate-x-0 lg:static lg:inset-0
${sidebarOpen ? 'translate-x-0' : '-translate-x-full'}
`}>
<div className="h-full flex flex-col">
<div className="h-16 flex items-center px-6 border-b border-gray-200 dark:border-gray-800">
<h1 className="text-lg font-bold text-gray-900 dark:text-white">Admin Paneli</h1>
<button
className="ml-auto lg:hidden text-gray-500"
onClick={() => setSidebarOpen(false)}
>
<X className="h-5 w-5" />
</button>
<div className="h-full flex flex-col justify-between">
<div>
<div className="h-16 flex items-center justify-between px-6 border-b border-zinc-100">
<Link href={`/${locale}`} className="flex items-center gap-2">
<Image src="/logo.png" alt="AyrisLegal" width={110} height={22} className="h-5 w-auto object-contain" priority />
</Link>
<button
className="lg:hidden text-zinc-500 hover:text-zinc-900"
onClick={() => setSidebarOpen(false)}
aria-label="Menüyü Kapat"
>
<X className="h-5 w-5" />
</button>
</div>
<nav className="px-4 py-6 space-y-1 overflow-y-auto">
{navigation.map((item) => {
const isActive = pathname === item.href || (item.href !== `/${locale}/admin` && pathname.startsWith(item.href))
return (
<Link
key={item.name}
href={item.href}
className={`
flex items-center px-3.5 py-2.5 text-sm font-semibold rounded-xl transition-all
${isActive
? 'bg-[#FDEEEC] text-[#B8140F]'
: 'text-zinc-600 hover:bg-zinc-100/70 hover:text-zinc-900'}
`}
>
<item.icon className={`mr-3 flex-shrink-0 h-4 w-4 ${isActive ? 'text-[#B8140F]' : 'text-zinc-500'}`} />
{item.name}
</Link>
)
})}
</nav>
</div>
<nav className="flex-1 px-4 py-6 space-y-1 overflow-y-auto">
{navigation.map((item) => {
const isActive = pathname.endsWith(item.href)
return (
<Link
key={item.name}
href={item.href}
className={`
flex items-center px-3 py-2.5 text-sm font-medium rounded-md transition-colors
${isActive
? 'bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-white'
: 'text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-white'}
`}
>
<item.icon className={`mr-3 flex-shrink-0 h-5 w-5 ${isActive ? 'text-gray-900 dark:text-white' : 'text-gray-400'}`} />
{item.name}
</Link>
)
})}
</nav>
<div className="p-4 border-t border-gray-200 dark:border-gray-800">
<div className="p-4 border-t border-zinc-100">
<button
onClick={() => signOut({ callbackUrl: '/' })}
className="flex w-full items-center px-3 py-2.5 text-sm font-medium text-red-600 dark:text-red-400 rounded-md hover:bg-red-50 dark:hover:bg-red-950/30 transition-colors"
onClick={() => signOut({ callbackUrl: `/${locale}` })}
className="flex w-full items-center px-3.5 py-2.5 text-sm font-semibold text-zinc-700 hover:text-[#B8140F] rounded-xl hover:bg-[#FDEEEC] transition-colors"
>
<LogOut className="mr-3 h-5 w-5" />
<LogOut className="mr-3 h-4 w-4" />
Çıkış Yap
</button>
</div>
@@ -78,17 +86,19 @@ export default function AdminLayout({ children }: { children: React.ReactNode })
{/* Main content */}
<div className="flex-1 flex flex-col min-w-0 overflow-hidden">
<header className="h-16 flex items-center lg:hidden bg-white dark:bg-gray-950 border-b border-gray-200 dark:border-gray-800 px-4">
<header className="h-16 flex items-center justify-between lg:hidden bg-white border-b border-zinc-200 px-4">
<button
onClick={() => setSidebarOpen(true)}
className="text-gray-500 hover:text-gray-900 dark:hover:text-white focus:outline-none"
className="text-zinc-600 hover:text-zinc-900 focus:outline-none"
aria-label="Menüyü Aç"
>
<Menu className="h-6 w-6" />
</button>
<span className="ml-4 text-lg font-bold text-gray-900 dark:text-white">Admin Paneli</span>
<span className="text-sm font-bold text-zinc-900">Admin Paneli</span>
<div className="w-6" />
</header>
<main className="flex-1 overflow-y-auto p-4 sm:p-6 lg:p-8">
<main className="flex-1 overflow-y-auto p-5 sm:p-8 max-w-[1400px]">
{children}
</main>
</div>
+16 -19
View File
@@ -4,41 +4,38 @@ export default async function AdminDashboardPage() {
const session = await auth()
return (
<div className="space-y-6">
<div className="space-y-8">
<div>
<h2 className="text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Dashboard</h2>
<p className="text-gray-500 dark:text-gray-400 mt-2">
Hoş geldiniz, {session?.user?.name || session?.user?.email}. İşte projenizin genel görünümü.
<h1 className="text-2xl font-extrabold tracking-tight text-zinc-950">Yönetim Paneli</h1>
<p className="text-zinc-600 text-sm mt-1.5">
Hoş geldiniz, <span className="font-semibold text-zinc-900">{session?.user?.name || session?.user?.email}</span>. İşte platformun genel görünümü.
</p>
</div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
{/* Placeholder Stat Cards */}
{[
{ name: 'Toplam Kullanıcı', stat: '1,245' },
{ name: 'Aktif Oturumlar', stat: '42' },
{ name: 'Yeni Kayıtlar', stat: '8' },
{ name: 'Sistem Durumu', stat: 'Online' },
{ name: 'Toplam Demo Talebi', stat: '28' },
{ name: 'Aktif Pilot Bürolar', stat: '14' },
{ name: 'Haftalık Analiz Sayısı', stat: '342' },
{ name: 'Sistem Durumu', stat: 'Aktif / Çevrimiçi' },
].map((item) => (
<div
key={item.name}
className="overflow-hidden rounded-lg bg-white dark:bg-gray-950 border border-gray-200 dark:border-gray-800 px-4 py-5 shadow-sm sm:p-6"
className="overflow-hidden rounded-2xl bg-white border border-zinc-200/80 p-5 shadow-sm"
>
<dt className="truncate text-sm font-medium text-gray-500 dark:text-gray-400">{item.name}</dt>
<dd className="mt-1 text-3xl font-semibold tracking-tight text-gray-900 dark:text-white">
<dt className="truncate text-xs font-bold uppercase tracking-wide text-zinc-500">{item.name}</dt>
<dd className="mt-2 text-2xl font-extrabold tracking-tight text-zinc-950 font-mono">
{item.stat}
</dd>
</div>
))}
</div>
<div className="rounded-lg bg-white dark:bg-gray-950 border border-gray-200 dark:border-gray-800 shadow-sm">
<div className="p-6">
<h3 className="text-lg font-medium text-gray-900 dark:text-white">Son Aktiviteler</h3>
<div className="mt-4 border-t border-gray-100 dark:border-gray-800">
<div className="py-4 text-sm text-gray-500">
Henüz aktivite kaydı bulunmuyor.
</div>
<div className="rounded-2xl bg-white border border-zinc-200/80 p-6 shadow-sm">
<h2 className="text-base font-bold text-zinc-950">Son Aktiviteler &amp; Demo Başvuruları</h2>
<div className="mt-4 border-t border-zinc-100 divide-y divide-zinc-100">
<div className="py-4 text-sm text-zinc-500">
Henüz bekleyen aktivite kaydı bulunmuyor. Yeni talepler anlık olarak burada listelenecektir.
</div>
</div>
</div>
+125
View File
@@ -0,0 +1,125 @@
import type { Metadata } from 'next'
import Link from 'next/link'
import Image from 'next/image'
import { ArrowLeft, ShieldCheck, Lock, Sparkles, CheckCircle2, Clock } from 'lucide-react'
import ContactForm from '@/components/contact-form'
export const metadata: Metadata = {
title: 'Demo Talep Edin | AyrisLegal',
description: 'AyrisLegal kurucu ekibiyle 15 dakikalık birebir canlı demo planlayın. Dava dosyası analizi, çelişki tespiti ve içtihat arama yeteneklerini kendi çalışma pratiğinizde test edin.',
}
export default async function ContactPage({
params,
}: {
params: Promise<{ locale: string }>
}) {
const { locale } = await params
return (
<div className="min-h-[100dvh] bg-white text-zinc-900 flex flex-col justify-between">
{/* ══════════════════════════════ TOP NAV ═════════════════════════════ */}
<header className="sticky top-0 z-30 border-b border-zinc-100 bg-white/90 px-5 py-4 backdrop-blur-md md:px-16">
<div className="mx-auto flex max-w-[1400px] items-center justify-between">
<Link href={`/${locale}`} className="flex items-center gap-2 group">
<Image src="/logo.png" alt="AyrisLegal" width={120} height={24} className="h-6 w-auto object-contain" priority />
</Link>
<Link
href={`/${locale}`}
className="inline-flex items-center gap-1.5 text-sm font-semibold text-zinc-600 transition-colors hover:text-zinc-950"
>
<ArrowLeft size={15} strokeWidth={2} aria-hidden="true" />
Ana Sayfaya Dön
</Link>
</div>
</header>
{/* ══════════════════════════════ MAIN CONTENT ════════════════════════ */}
<main className="mx-auto w-full max-w-[1280px] px-5 py-12 md:px-16 md:py-20 flex-1">
<div className="grid grid-cols-1 gap-12 lg:grid-cols-[1.1fr_1fr] lg:gap-16 items-start">
{/* Sol Kolon: Değer Önerisi ve Güven Taahhütleri */}
<div>
<span className="inline-flex items-center gap-2 rounded-full px-4 py-1.5 text-[13px] font-semibold bg-[#FDEEEC] text-[#B8140F]">
<Sparkles size={14} strokeWidth={2.5} aria-hidden="true" /> Birebir Kurucu Demosu
</span>
<h1 className="mt-5 text-[clamp(32px,4.5vw,52px)] font-extrabold leading-[1.08] tracking-tight text-zinc-950">
Kendi dava dosyalarınızla{' '}
<span className="text-[#E61919]">15 dakikada</span> test edin.
</h1>
<p className="mt-5 max-w-[50ch] text-base leading-relaxed text-zinc-600">
AyrisLegal genel bir sohbet botu değil; dava dosyalarındaki tanık ve bilirkişi çelişkilerini yakalayan aktif bir düşünce ortağıdır. Formu doldurun, kurucu ekiple canlı demoda büronuza özel ihtiyaçları birlikte inceleyelim.
</p>
{/* Adım Adım Süreç */}
<div className="mt-10 space-y-6 border-t border-zinc-100 pt-8">
<div className="flex items-start gap-4">
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-zinc-100 text-zinc-900 font-bold text-sm font-mono">
1
</div>
<div>
<h2 className="text-sm font-bold text-zinc-900">15 Dakikalık Canlı Demo</h2>
<p className="mt-1 text-sm leading-relaxed text-zinc-600">
Büronuzun baktığı temel dava türlerine (Kira, Ticaret, İş, Ceza) göre dosya analizi ve çelişki tespitini canlı olarak gösteriyoruz.
</p>
</div>
</div>
<div className="flex items-start gap-4">
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-zinc-100 text-zinc-900 font-bold text-sm font-mono">
2
</div>
<div>
<h2 className="text-sm font-bold text-zinc-900">Pilot Erişim Kurulumu</h2>
<p className="mt-1 text-sm leading-relaxed text-zinc-600">
Masaüstü (Electron) ve Mobil (Expo) uygulamalarımıza pilot erişim yetkisi tanımlanır.
</p>
</div>
</div>
<div className="flex items-start gap-4">
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-zinc-100 text-zinc-900 font-bold text-sm font-mono">
3
</div>
<div>
<h2 className="text-sm font-bold text-zinc-900">Doğrudan Mühendislik Desteği</h2>
<p className="mt-1 text-sm leading-relaxed text-zinc-600">
Pilot sürecinde karşılaştığınız her özel format veya içtihat gereksinimi için doğrudan kurucu ekiple iletişimde kalırsınız.
</p>
</div>
</div>
</div>
{/* Güven Güvencesi */}
<div className="mt-10 rounded-2xl border border-zinc-200/80 bg-zinc-50/80 p-5 flex items-start gap-3.5">
<ShieldCheck size={20} className="text-zinc-900 shrink-0 mt-0.5" aria-hidden="true" />
<div className="text-xs leading-relaxed text-zinc-600">
<span className="font-bold text-zinc-900 block mb-0.5">Sıkı Veri Mahremiyeti:</span>
Dosyalarınız kamuya açık yapay zekâ modellerini eğitmek amacıyla kullanılmaz. Yerel şifreli çalışma prensibi esastır.
</div>
</div>
</div>
{/* Sağ Kolon: Form */}
<div className="w-full lg:sticky lg:top-24">
<ContactForm />
</div>
</div>
</main>
{/* ══════════════════════════════ FOOTER ══════════════════════════════ */}
<footer className="border-t border-zinc-100 bg-white py-8 px-5 md:px-16 text-center text-xs text-zinc-500">
<div className="mx-auto flex max-w-[1400px] flex-col items-center justify-between gap-3 sm:flex-row">
<span>© {new Date().getFullYear()} AyrisLegal. Tüm hakları saklıdır.</span>
<a
href="https://ayris.tech"
target="_blank"
rel="noopener noreferrer"
className="font-medium text-zinc-700 underline-offset-4 hover:underline"
>
Created by ayris.tech
</a>
</div>
</footer>
</div>
)
}
+171 -15
View File
@@ -1,9 +1,10 @@
import type { Metadata } from "next";
import { Archivo } from "next/font/google";
import { Archivo, JetBrains_Mono } from "next/font/google";
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, setRequestLocale } from 'next-intl/server';
import { notFound } from 'next/navigation';
import { routing } from '@/i18n/routing';
import CookieBanner from '@/components/cookie-banner';
import "../globals.css";
const archivo = Archivo({
@@ -12,38 +13,82 @@ const archivo = Archivo({
display: "swap",
});
const jetbrainsMono = JetBrains_Mono({
subsets: ["latin"],
variable: "--font-jetbrains-mono",
display: "swap",
});
export const metadata: Metadata = {
metadataBase: new URL("https://ayrislegal.com"),
title: {
default: "AyrisLegal — Hukuki Düşünce Ortağınız",
default: "AyrisLegal — Avukatlar İçin Yapay Zekâ Destekli Hukuk Çalışma Alanı",
template: "%s | AyrisLegal",
},
description:
"AyrisLegal, solo ve küçük büro avukatları için yapay zeka destekli hukuki asistanıdır. Dosya analizi, çok turlu hukuki sohbet ve emsal karar arama tek bir platformda.",
keywords: ["avukat yazılımı", "hukuki yapay zeka", "emsal karar arama", "hukuk ofisi yönetim", "AyrisLegal"],
authors: [{ name: "ayris.tech", url: "https://ayris.tech" }],
creator: "ayris.tech",
"AyrisLegal; dava dosyası analizi, tanık ve bilirkişi çelişkisi tespiti, 18M+ emsal içtihat taraması, duruşma simülasyonu ve doğrudan UYAP uyumlu UDF dilekçe üretim platformudur.",
keywords: [
"avukat programı",
"hukuki yapay zeka",
"çelişki avcısı",
"emsal içtihat arama",
"udf dilekçe hazırlama",
"uyap eklentisi",
"hukuk bürosu otomasyonu",
"tensip zaptı analizi",
"yargıtay emsal kararlar",
"hukuk çalışma alanı",
"AyrisLegal"
],
authors: [{ name: "Ayris Tech", url: "https://ayris.tech" }],
creator: "Ayris Tech",
publisher: "Ayris Tech",
alternates: {
canonical: "https://ayrislegal.com/tr",
languages: {
"tr-TR": "https://ayrislegal.com/tr",
"en-US": "https://ayrislegal.com/en",
},
},
openGraph: {
type: "website",
locale: "tr_TR",
url: "https://ayrislegal.com",
siteName: "AyrisLegal",
title: "AyrisLegal — Hukuki Düşünce Ortağınız",
title: "AyrisLegal — Avukatlar İçin Yapay Zekâ Destekli Hukuk Çalışma Alanı",
description:
"Pasif araştırma değil, aktif düşünce ortağı. Avukatlar için yapay zeka destekli hukuki asistan.",
"Pasif araştırma değil, aktif düşünce ortağı. Dava analizi, çelişki tespiti, 18M+ içtihat ve UDF dilekçe motoru.",
images: [
{
url: "/og-image.jpg",
width: 1200,
height: 630,
alt: "AyrisLegal Hukuk Çalışma Alanı",
},
],
},
twitter: {
card: "summary_large_image",
title: "AyrisLegal — Hukuki Düşünce Ortağınız",
title: "AyrisLegal — Avukatlar İçin Yapay Zekâ Destekli Hukuk Çalışma Alanı",
description:
"Pasif araştırma değil, aktif düşünce ortağı. Avukatlar için yapay zeka destekli hukuki asistan.",
"Dava analizi, çelişki tespiti, 18M+ içtihat ve UDF dilekçe motoru tek ekranda.",
images: ["/og-image.jpg"],
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
"max-video-preview": -1,
"max-image-preview": "large",
"max-snippet": -1,
},
},
};
export function generateStaticParams() {
return routing.locales.map((locale) => ({locale}));
return routing.locales.map((locale) => ({ locale }));
}
export default async function RootLayout({
@@ -54,22 +99,133 @@ export default async function RootLayout({
params: Promise<{ locale: string }>;
}>) {
const { locale } = await params;
if (!routing.locales.includes(locale as any)) {
notFound();
}
setRequestLocale(locale);
const messages = await getMessages();
// Schema.org JSON-LD Yapılandırılmış Verileri
const softwareSchema = {
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "AyrisLegal",
"operatingSystem": "Windows, macOS, Linux, iOS, Android",
"applicationCategory": "BusinessApplication",
"applicationSubCategory": "Legal Practice Management Software",
"description": "Türk avukatları için yapay zekâ destekli dava analizi, 18M+ emsal içtihat arama ve UYAP UDF dilekçe üretim platformu.",
"offers": {
"@type": "Offer",
"price": "30000",
"priceCurrency": "TRY",
"priceValidUntil": "2027-12-31",
"availability": "https://schema.org/InStock",
},
"publisher": {
"@type": "Organization",
"name": "Ayris Tech",
"url": "https://ayris.tech",
"logo": "https://ayrislegal.com/logo.png",
},
};
const organizationSchema = {
"@context": "https://schema.org",
"@type": "Organization",
"name": "AyrisLegal",
"url": "https://ayrislegal.com",
"logo": "https://ayrislegal.com/logo.png",
"sameAs": [
"https://ayris.tech"
],
"contactPoint": {
"@type": "ContactPoint",
"contactType": "Customer Support",
"email": "info@ayris.tech",
"availableLanguage": ["Turkish", "English"]
}
};
const faqSchema = {
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Müvekkil dosyalarım nerede saklanıyor, kim görebilir?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Belgeleriniz cihazınızda yerel şifreli depolamada tutulur. Yedeklemeler merkezi sunucularımıza değil, büronuzun kendi Google Drive hesabına şifreli olarak aktarılır. Başka bir avukat veya üçüncü tarafla kesinlikle paylaşılmaz ve kamuya açık modellerin eğitiminde kullanılmaz."
}
},
{
"@type": "Question",
"name": "UYAP şifremi veya e-imzamı AyrisLegal ile paylaşmam gerekiyor mu?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Hayır. UYAP Tarayıcı Eklentisi sisteminizde zaten açık olan güvenli oturumunuzu kullanır; kimlik, e-imza veya şifre bilgileriniz hiçbir zaman AyrisLegal sunucularına iletilmez."
}
},
{
"@type": "Question",
"name": "Yapay zekâ yanlış bir çıkarım yaparsa sorumluluk kimde?",
"acceptedAnswer": {
"@type": "Answer",
"text": "AyrisLegal bir karar organı değildir; analitik bir düşünce ortağıdır. Ürettiği tüm emsal kararlar gerçek mahkeme esas ve karar numaralarıyla sunulur ve doğrulanabilir bağlantılar içerir. Nihai hukuki değerlendirme ve imza sorumluluğu daima avukata aittir."
}
},
{
"@type": "Question",
"name": "Dilekçeleri doğrudan UYAP Doküman Editörü (.udf) formatında indirebilir miyim?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Evet. AyrisLegal bünyesindeki yerel UDF motoru, editörde yazılan dilekçeleri tek tıkla resmi Adalet Bakanlığı UYAP formatına (.udf), Word (.docx) veya PDF formatına dönüştürür."
}
},
{
"@type": "Question",
"name": "İnternet bağlantısı olmadığında çevrimdışı çalışabilir miyim?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Evet. Önceden taranmış dava dosyaları, yerel arşivi ve 26.900+ kanun maddesi internetsiz ortamda bile anında görüntülenebilir ve aranabilir."
}
},
{
"@type": "Question",
"name": "Büromdaki diğer avukatlarla aynı anda ortak dava havuzunu kullanabilir miyim?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Evet. Hukuk Bürosu planı kapsamında büro içi çoklu avukat ve stajyer lisansı, ortak emsal havuzu ve paylaşımlı dava çalışma alanı sunulmaktadır."
}
}
]
};
return (
<html
lang={locale}
className={`${archivo.variable} h-full antialiased`}
className={`${archivo.variable} ${jetbrainsMono.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col" suppressHydrationWarning>
<head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(softwareSchema) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationSchema) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }}
/>
</head>
<body className="min-h-full flex flex-col font-sans" suppressHydrationWarning>
<NextIntlClientProvider messages={messages}>
{children}
<CookieBanner />
</NextIntlClientProvider>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Yönetici Girişi',
description: 'AyrisLegal yönetim paneli erişim sayfası.',
robots: {
index: false,
follow: false,
},
}
export default function LoginLayout({
children,
}: {
children: React.ReactNode
}) {
return <>{children}</>
}
+35 -16
View File
@@ -2,10 +2,15 @@
import { useState } from 'react'
import { signIn } from 'next-auth/react'
import { useRouter } from 'next/navigation'
import { useRouter, useParams } from 'next/navigation'
import Link from 'next/link'
import Image from 'next/image'
import { Lock, ArrowLeft } from 'lucide-react'
export default function LoginPage() {
const router = useRouter()
const params = useParams()
const locale = (params?.locale as string) || 'tr'
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
@@ -26,29 +31,39 @@ export default function LoginPage() {
setError('Geçersiz e-posta veya şifre')
setLoading(false)
} else {
router.push('/admin')
router.push(`/${locale}/admin`)
router.refresh()
}
}
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 px-4">
<div className="w-full max-w-md bg-white dark:bg-gray-800 rounded-xl shadow-lg border border-gray-100 dark:border-gray-800 overflow-hidden">
<div className="p-8">
<div className="min-h-[100dvh] flex flex-col justify-between bg-zinc-50/80 px-4 py-8">
<div>
<Link
href={`/${locale}`}
className="inline-flex items-center gap-1.5 text-xs font-semibold text-zinc-500 hover:text-zinc-900 transition-colors"
>
<ArrowLeft size={14} /> Ana Sayfaya Dön
</Link>
</div>
<div className="w-full max-w-md mx-auto bg-white rounded-3xl shadow-[0_20px_60px_-30px_rgba(24,24,27,0.15)] border border-zinc-200/80 overflow-hidden">
<div className="p-8 sm:p-10">
<div className="text-center mb-8">
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">Admin Girişi</h1>
<p className="text-sm text-gray-500 mt-2">Yönetim paneline erişmek için giriş yapın</p>
<Image src="/logo.png" alt="AyrisLegal" width={120} height={24} className="h-6 w-auto mx-auto object-contain mb-5" priority />
<h1 className="text-2xl font-extrabold tracking-tight text-zinc-950">Yönetici Girişi</h1>
<p className="text-xs font-medium text-zinc-500 mt-1.5">Yönetim paneline erişmek için giriş yapın</p>
</div>
{error && (
<div className="bg-red-50 text-red-600 p-3 rounded-md text-sm mb-6 border border-red-100">
<div role="alert" className="bg-red-50 text-red-700 p-3.5 rounded-xl text-xs font-semibold mb-6 border border-red-200">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-5">
<form onSubmit={handleSubmit} className="space-y-4" noValidate>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" htmlFor="email">
<label className="block text-xs font-bold text-zinc-900 mb-1.5" htmlFor="email">
E-posta
</label>
<input
@@ -57,12 +72,12 @@ export default function LoginPage() {
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-900 text-gray-900 dark:text-white transition-colors"
className="w-full min-h-[44px] px-4 py-2.5 border border-zinc-200 rounded-xl focus:outline-none focus:border-[#E61919] focus:ring-2 focus:ring-[#E61919]/20 bg-white text-zinc-900 text-sm transition-all"
placeholder="admin@ayris.tech"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" htmlFor="password">
<label className="block text-xs font-bold text-zinc-900 mb-1.5" htmlFor="password">
Şifre
</label>
<input
@@ -71,24 +86,28 @@ export default function LoginPage() {
value={password}
onChange={(e) => setPassword(e.target.value)}
required
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-900 text-gray-900 dark:text-white transition-colors"
className="w-full min-h-[44px] px-4 py-2.5 border border-zinc-200 rounded-xl focus:outline-none focus:border-[#E61919] focus:ring-2 focus:ring-[#E61919]/20 bg-white text-zinc-900 text-sm transition-all"
placeholder="••••••••"
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2.5 px-4 rounded-md transition-colors disabled:opacity-70 disabled:cursor-not-allowed"
className="w-full bg-[#E61919] hover:bg-[#B8140F] text-white font-bold py-3.5 px-4 rounded-full text-sm transition-all disabled:opacity-60 disabled:cursor-not-allowed active:scale-[0.98] shadow-sm mt-2"
>
{loading ? 'Giriş yapılıyor...' : 'Giriş Yap'}
</button>
</form>
<div className="mt-6 text-center text-xs text-gray-400">
Demo credentials: admin@ayris.tech / admin
<div className="mt-8 text-center text-xs font-mono text-zinc-500 bg-zinc-50 p-2.5 rounded-xl border border-zinc-100">
Demo: admin@ayris.tech / admin
</div>
</div>
</div>
<div className="text-center text-xs text-zinc-500">
© {new Date().getFullYear()} AyrisLegal · <a href="https://ayris.tech" target="_blank" rel="noopener noreferrer" className="hover:underline">Created by ayris.tech</a>
</div>
</div>
)
}
+906 -489
View File
File diff suppressed because it is too large Load Diff
+138 -76
View File
@@ -1,92 +1,154 @@
import React from 'react';
import type { Metadata } from 'next'
import Link from 'next/link'
import Image from 'next/image'
import { ArrowLeft, Lock } from 'lucide-react'
export default function PrivacyPolicy() {
export const metadata: Metadata = {
title: 'Masaüstü Uygulaması Gizlilik Politikası | AyrisLegal',
description: 'AyrisLegal masaüstü uygulaması ve web platformu gizlilik politikası, veri işleme ve KVKK aydınlatma metni.',
}
export default async function AppPrivacyPolicyPage({
params,
}: {
params: Promise<{ locale: string }>
}) {
const { locale } = await params
return (
<div className="container mx-auto px-4 py-16 max-w-4xl">
<h1 className="text-4xl font-bold mb-8">Gizlilik Politikası</h1>
<p className="mb-6 text-gray-500">Son Güncellenme Tarihi: 11 Ağustos 2026</p>
<div className="min-h-[100dvh] bg-white text-zinc-900 flex flex-col justify-between selection:bg-[#FDEEEC] selection:text-[#B8140F]">
{/* ══════════════════════════════ TOP NAV ═════════════════════════════ */}
<header className="sticky top-0 z-30 border-b border-zinc-100 bg-white/90 px-5 py-4 backdrop-blur-md md:px-16">
<div className="mx-auto flex max-w-[1400px] items-center justify-between">
<Link href={`/${locale}`} className="flex items-center gap-2">
<Image src="/logo.png" alt="AyrisLegal" width={120} height={24} className="h-6 w-auto object-contain" priority />
</Link>
<Link
href={`/${locale}`}
className="inline-flex items-center gap-1.5 text-sm font-semibold text-zinc-600 transition-colors hover:text-zinc-950"
>
<ArrowLeft size={15} strokeWidth={2} aria-hidden="true" />
Ana Sayfaya Dön
</Link>
</div>
</header>
<div className="prose max-w-none">
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">1. Giriş</h2>
<p className="mb-4">
AyrisLegal (&quot;biz&quot;, &quot;bizim&quot; veya &quot;bize&quot;), gizliliğinize saygı duymakta ve kişisel verilerinizi korumayı taahhüt etmektedir. Bu Gizlilik Politikası, ayrislegal.com tanıtım web sitesini ve AyrisLegal masaüstü uygulamasını (&quot;Uygulama&quot;) kullandığınızda kişisel bilgilerinizi nasıl işlediğimizi açıklar.
{/* ══════════════════════════════ MAIN CONTENT ════════════════════════ */}
<main className="mx-auto w-full max-w-[860px] px-5 py-12 md:px-8 md:py-20 flex-1">
<div className="mb-10 border-b border-zinc-100 pb-8">
<span className="inline-flex items-center gap-1.5 rounded-full px-3.5 py-1 text-xs font-mono font-semibold bg-zinc-100 text-zinc-700">
<Lock size={14} className="text-zinc-600" aria-hidden="true" />
Masaüstü &amp; Mobil Uygulama
</span>
<h1 className="mt-4 text-[clamp(28px,3.8vw,42px)] font-extrabold leading-[1.1] tracking-tight text-zinc-950">
Gizlilik Politikası
</h1>
<p className="mt-2.5 font-mono text-xs text-zinc-500">
Son Güncelleme: 11 Ağustos 2026
</p>
</section>
</div>
<div className="space-y-10 text-sm leading-relaxed text-zinc-600">
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">1. Giriş</h2>
<p>
AyrisLegal (&quot;biz&quot;, &quot;bizim&quot; veya &quot;bize&quot;), gizliliğinize saygı duymakta ve kişisel verilerinizi korumayı taahhüt etmektedir. Bu Gizlilik Politikası, ayrislegal.com tanıtım web sitesini ve AyrisLegal masaüstü uygulamasını (&quot;Uygulama&quot;) kullandığınızda kişisel bilgilerinizi nasıl işlediğimizi açıklar.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">2. Web Sitesi Demo Talebi Formu</h2>
<p>
İletişim/demo talebi formunu doldurduğunuzda ad soyad, e-posta, (varsa) büro/kurum adı ve telefon bilgilerinizi topluyoruz. Bu bilgiler yalnızca talebinizi değerlendirmek ve sizinle iletişime geçmek amacıyla kullanılır; üçüncü taraflara satılmaz veya pazarlama amacıyla aktarılmaz.
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">2. Web Sitesi Demo Talebi Formu</h2>
<p className="mb-4">
İletişim/demo talebi formunu doldurduğunuzda ad soyad, e-posta, (varsa) büro/kurum adı ve telefon bilgilerinizi topluyoruz. Bu bilgiler yalnızca talebinizi değerlendirmek ve sizinle iletişime geçmek amacıyla kullanılır; üçüncü taraflara satılmaz veya pazarlama amacıyla aktarılmaz.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">3. Uygulama Hesap Bilgileri</h2>
<p>
AyrisLegal&apos;a kayıt olurken ad soyad, e-posta ve (varsa) baro sicil bilginizi işleriz. Bu bilgiler kimlik doğrulama ve hesabınızı yönetmek amacıyla kullanılır.
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">3. Uygulama Hesap Bilgileri</h2>
<p className="mb-4">
AyrisLegal&apos;a kayıt olurken ad soyad, e-posta ve (varsa) baro sicil bilginizi işleriz. Bu bilgiler kimlik doğrulama ve hesabınızı yönetmek amacıyla kullanılır.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">4. Uygulama Dava Dosyası ve Belge İçeriği</h2>
<p className="mb-3">
AyrisLegal&apos;ın temel işlevi, yüklediğiniz dava dosyalarını ve belgeleri yapay zeka ile analiz etmek, içtihat aramak ve dilekçe taslağı üretmektir. Bu analiz, yapay zeka servis sağlayıcıları aracılığıyla gerçekleştirilir; yani yüklediğiniz belge içeriği, analiz işlemi sırasında bu servislere iletilir.
</p>
<p>
Belgeleriniz yalnızca sizin analizinizi üretmek için kullanılır, başka kullanıcılarla veya üçüncü taraflarla paylaşılmaz. Kullandığımız yapay zeka altyapısı zaman içinde değişebilir; hassas veya gizlilik dereceli belgeleri yüklerken bu konuda dikkatli olmanızı öneririz.
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">4. Uygulama Dava Dosyası ve Belge İçeriği</h2>
<p className="mb-4">
AyrisLegal&apos;ın temel işlevi, yüklediğiniz dava dosyalarını ve belgeleri yapay zeka ile analiz etmek, içtihat aramak ve dilekçe taslağı üretmektir. Bu analiz, yapay zeka servis sağlayıcıları aracılığıyla gerçekleştirilir; yani yüklediğiniz belge içeriği, analiz işlemi sırasında bu servislere iletilir.
</p>
<p className="mb-4">
Belgeleriniz yalnızca sizin analizinizi üretmek için kullanılır, başka kullanıcılarla veya üçüncü taraflarla paylaşılmaz. Kullandığımız yapay zeka altyapısı zaman içinde değişebilir; hassas veya gizlilik dereceli belgeleri yüklerken bu konuda dikkatli olmanızı öneririz.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">5. Lisans ve Cihaz Bilgileri</h2>
<p>
Uygulamanın aktivasyonu için bir lisans anahtarı ve cihazınıza özgü, rastgele üretilmiş bir cihaz kimliği kullanılır. Bu bilgiler bilgisayarınızda, letim sisteminizin kendi güvenli depolama katmanı (macOS Keychain / Windows DPAPI) ile şifrelenerek saklanır.
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">5. Lisans ve Cihaz Bilgileri</h2>
<p className="mb-4">
Uygulamanın aktivasyonu için bir lisans anahtarı ve cihazınıza özgü, rastgele üretilmiş bir cihaz kimliği kullanılır. Bu bilgiler bilgisayarınızda, işletim sisteminizin kendi güvenli depolama katmanı (macOS Keychain / Windows DPAPI) ile şifrelenerek saklanır.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">6. Yedekleme</h2>
<p>
Uygulama içinde isteğe bağlı olarak açabileceğiniz otomatik yedekleme özelliği, dosyalarınızı bizim sunucularımıza değil, doğrudan sizin kendi Google Drive hesabınıza yükler. Bu özellik varsayılan olarak kapalıdır ve yalnızca siz açtığınızda, sizin izninizle çalışır.
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">6. Yedekleme</h2>
<p className="mb-4">
Uygulama içinde isteğe bağlı olarak açabileceğiniz otomatik yedekleme özelliği, dosyalarınızı bizim sunucularımıza değil, doğrudan sizin kendi Google Drive hesabınıza yükler. Bu özellik varsayılan olarak kapalıdır ve yalnızca siz açtığınızda, sizin izninizle çalışır.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">7. Hata Bildirimleri</h2>
<p>
Uygulama bir teknik hatayla karşılaştığında, sorunu çözebilmemiz için anonim bir hata raporu gönderebilir. Bu raporlar; dava dosyası, müvekkil bilgisi, belge içeriği veya başka bir kişisel veri İÇERMEZ yalnızca hatanın teknik ayrıntılarını (hangi modülde, hangi tür hata) kapsar. Bu bildirimi Ayarlar &gt; Gizlilik menüsünden tamamen kapatabilirsiniz.
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">7. Hata Bildirimleri</h2>
<p className="mb-4">
Uygulama bir teknik hatayla karşılaştığında, sorunu çözebilmemiz için anonim bir hata raporu gönderebilir. Bu raporlar; dava dosyası, müvekkil bilgisi, belge içeri veya başka bir kişisel veri İÇERMEZ yalnızca hatanın teknik ayrıntılarını (hangi modülde, hangi tür hata) kapsar. Bu bildirimi Ayarlar &gt; Gizlilik menüsünden tamamen kapatabilirsiniz.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">8. Veri Güvenliği</h2>
<p>
Hassas veriler (lisans bilgisi, kimlik doğrulama bilgileri) cihazınızda şifreli olarak saklanır. Uygulama, geçerli bir lisansı olmayan kişiler tarafından aktive edilemez. Sunucu tarafı altyapımız erişim kontrolleriyle korunmaktadır.
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">8. Veri Güvenliği</h2>
<p className="mb-4">
Hassas veriler (lisans bilgisi, kimlik doğrulama bilgileri) cihazınızda şifreli olarak saklanır. Uygulama, geçerli bir lisansı olmayan kişiler tarafından aktive edilemez. Sunucu tarafı altyapımız erişim kontrolleriyle korunmaktadır.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">9. Haklarınız (KVKK)</h2>
<p>
6698 sayılı Kişisel Verilerin Korunması Kanunu (&quot;KVKK&quot;) kapsamında; verilerinizin işlenip işlenmediğini öğrenme, işlenmişse buna ilişkin bilgi talep etme, düzeltme veya silinmesini isteme haklarına sahipsiniz. Bu haklarınızı kullanmak için aşağıdaki iletişim adresinden bize ulaşabilirsiniz.
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">9. Haklarınız</h2>
<p className="mb-4">
6698 sayılı Kişisel Verilerin Korunması Kanunu (&quot;KVKK&quot;) kapsamında; verilerinizin işlenip işlenmediğini öğrenme, işlenmişse buna ilişkin bilgi talep etme, düzeltme veya silinmesini isteme haklarına sahipsiniz. Bu haklarınızı kullanmak için aşağıdaki iletişim adresinden bize ulaşabilirsiniz.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">10. Değişiklikler</h2>
<p>
Bu Gizlilik Politikasını zaman zaman güncelleyebiliriz. Herhangi bir değişiklik durumunda bu sayfada yeni tarihi belirterek sizi bilgilendireceğiz.
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">10. Değişiklikler</h2>
<p className="mb-4">
Bu Gizlilik Politikasını zaman zaman güncelleyebiliriz. Herhangi bir değişiklik durumunda bu sayfada yeni tarihi belirterek sizi bilgilendireceğiz.
</p>
</section>
<section className="rounded-2xl border border-zinc-200/80 bg-zinc-50/70 p-6">
<h2 className="text-base font-bold text-zinc-950 mb-2">11. İletişim</h2>
<p className="text-xs leading-relaxed text-zinc-600">
Bu Gizlilik Politikası hakkında veya veri güvenliği ile ilgili sorularınız varsa, lütfen{' '}
<a href="mailto:info@ayris.tech" className="font-semibold text-zinc-900 underline underline-offset-4 hover:text-[#E61919]">
info@ayris.tech
</a>{' '}
adresi üzerinden bizimle iletişime geçin.
</p>
</section>
</div>
</main>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">11. İletişim</h2>
<p className="mb-4">
Bu Gizlilik Politikası hakkında veya veri güvenliği ile ilgili sorularınız varsa, lütfen <strong>info@ayris.tech</strong> adresi üzerinden bizimle iletişime geçin.
</p>
</section>
</div>
{/* ══════════════════════════════ FOOTER ══════════════════════════════ */}
<footer className="border-t border-zinc-100 bg-white py-8 px-5 md:px-16 text-xs text-zinc-500">
<div className="mx-auto flex max-w-[1400px] flex-col items-center justify-between gap-3 sm:flex-row">
<span>© {new Date().getFullYear()} AyrisLegal Ayris Tech&apos;in bir ürünüdür.</span>
<a
href="https://ayris.tech"
target="_blank"
rel="noopener noreferrer"
className="font-medium text-zinc-700 underline-offset-4 hover:underline"
>
Created by ayris.tech
</a>
</div>
</footer>
</div>
);
)
}
+120 -52
View File
@@ -1,59 +1,127 @@
import React from 'react';
import type { Metadata } from 'next'
import Link from 'next/link'
import Image from 'next/image'
import { ArrowLeft, ShieldCheck } from 'lucide-react'
export default function PrivacyPolicy() {
export const metadata: Metadata = {
title: 'Gizlilik Politikası (Chrome Eklentisi) | AyrisLegal',
description: 'AyrisLegal UYAP Evrak İndirici Chrome eklentisi gizlilik ve veri güvenliği taahhütleri.',
}
export default async function PrivacyPolicyPage({
params,
}: {
params: Promise<{ locale: string }>
}) {
const { locale } = await params
return (
<div className="container mx-auto px-4 py-16 max-w-4xl">
<h1 className="text-4xl font-bold mb-8">Gizlilik Politikası (Privacy Policy)</h1>
<p className="mb-6 text-gray-500">Son Güncellenme Tarihi: 10 Ağustos 2026</p>
<div className="prose max-w-none">
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">1. Giriş</h2>
<p className="mb-4">
AyrisLegal ("biz", "bizim" veya "bize"), gizliliğinize saygı duymakta ve kişisel verilerinizi korumayı taahhüt etmektedir. Bu Gizlilik Politikası, AyrisLegal UYAP Evrak İndirici Chrome eklentisini ve ilgili hizmetlerimizi ("Eklenti") kullandığınızda kişisel bilgilerinizi nasıl işlediğimizi ve koruduğumuzu açıklar.
<div className="min-h-[100dvh] bg-white text-zinc-900 flex flex-col justify-between selection:bg-[#FDEEEC] selection:text-[#B8140F]">
{/* ══════════════════════════════ TOP NAV ═════════════════════════════ */}
<header className="sticky top-0 z-30 border-b border-zinc-100 bg-white/90 px-5 py-4 backdrop-blur-md md:px-16">
<div className="mx-auto flex max-w-[1400px] items-center justify-between">
<Link href={`/${locale}`} className="flex items-center gap-2">
<Image src="/logo.png" alt="AyrisLegal" width={120} height={24} className="h-6 w-auto object-contain" priority />
</Link>
<Link
href={`/${locale}`}
className="inline-flex items-center gap-1.5 text-sm font-semibold text-zinc-600 transition-colors hover:text-zinc-950"
>
<ArrowLeft size={15} strokeWidth={2} aria-hidden="true" />
Ana Sayfaya Dön
</Link>
</div>
</header>
{/* ══════════════════════════════ MAIN CONTENT ════════════════════════ */}
<main className="mx-auto w-full max-w-[860px] px-5 py-12 md:px-8 md:py-20 flex-1">
<div className="mb-10 border-b border-zinc-100 pb-8">
<span className="inline-flex items-center gap-1.5 rounded-full px-3.5 py-1 text-xs font-mono font-semibold bg-zinc-100 text-zinc-700">
<ShieldCheck size={14} className="text-zinc-600" aria-hidden="true" />
UYAP Evrak İndirici Chrome Eklentisi
</span>
<h1 className="mt-4 text-[clamp(28px,3.8vw,42px)] font-extrabold leading-[1.1] tracking-tight text-zinc-950">
Gizlilik Politikası
</h1>
<p className="mt-2.5 font-mono text-xs text-zinc-500">
Son Güncelleme: 10 Ağustos 2026
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">2. Toplanan Veriler ve Kullanımı</h2>
<p className="mb-4">Eklentimiz, Google hesabınızla giriş yapmanızı (OAuth) gerektirir. Bu bağlamda yalnızca aşağıdaki temel bilgiler işlenir:</p>
<ul className="list-disc pl-6 mb-4 space-y-2">
<li><strong>Google Kullanıcı Verileri:</strong> E-posta adresi ve temel profil bilgileriniz yalnızca kimlik doğrulama amacıyla kullanılır. Bu bilgiler dış sunucularımıza kaydedilmez, yalnızca oturum yönetimi için istemci (tarayıcı) tarafında tutulur.</li>
<li><strong>UYAP Evrak Verileri:</strong> Eklenti, UYAP portalından indirdiğiniz belgeleri <strong>sadece kendi bilgisayarınıza (yerel ağınıza)</strong> kaydeder veya aktarır. Hiçbir yasal belge, dosya detayı veya kişisel veri AyrisLegal sunucularına gönderilmez, saklanmaz veya üçüncü taraflarla paylaşılmaz.</li>
</ul>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">3. Veri Paylaşımı ve İfşası (Chrome Web Store Beyanları)</h2>
<p className="mb-4">Google Chrome Web Mağazası politikaları gereği şunları taahhüt ederiz:</p>
<ul className="list-disc pl-6 mb-4 space-y-2">
<li>Kullanıcı verilerini üçüncü şahıslara satmıyoruz veya aktarmıyoruz.</li>
<li>Kullanıcı verilerini onaylanmış (single purpose) kullanım amacı dışında kullanmıyor veya aktarmıyoruz.</li>
<li>Kullanıcı verilerini kredi notu belirlemek veya borç verme amaçlarıyla kullanmıyor veya aktarmıyoruz.</li>
</ul>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">4. Veri Güvenliği</h2>
<p className="mb-4">
Eklentinin tüm veri alışverişi doğrudan sizin bilgisayarınız (tarayıcınız) ile resmi hedefler (UYAP vb.) arasında gerçekleşir. Kişisel bilgilerinizin güvenliğini korumak için endüstri standartlarında önlemler uyguluyoruz.
</p>
</section>
</div>
<div className="space-y-10 text-sm leading-relaxed text-zinc-600">
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">1. Giriş</h2>
<p>
AyrisLegal (&quot;biz&quot;, &quot;bizim&quot; veya &quot;bize&quot;), gizliliğinize saygı duymakta ve kişisel verilerinizi korumayı taahhüt etmektedir. Bu Gizlilik Politikası, AyrisLegal UYAP Evrak İndirici Chrome eklentisini ve ilgili hizmetlerimizi (&quot;Eklenti&quot;) kullandığınızda kişisel bilgilerinizi nasıl işlediğimizi ve koruduğumuzu açıklar.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">2. Toplanan Veriler ve Kullanımı</h2>
<p className="mb-3">
Eklentimiz, Google hesabınızla giriş yapmanızı (OAuth) gerektirir. Bu bağlamda yalnızca aşağıdaki temel bilgiler işlenir:
</p>
<ul className="space-y-3 pl-4 list-disc marker:text-zinc-400">
<li>
<strong className="text-zinc-900 font-semibold">Google Kullanıcı Verileri:</strong> E-posta adresi ve temel profil bilgileriniz yalnızca kimlik doğrulama amacıyla kullanılır. Bu bilgiler dış sunucularımıza kaydedilmez, yalnızca oturum yönetimi için istemci (tarayıcı) tarafında tutulur.
</li>
<li>
<strong className="text-zinc-900 font-semibold">UYAP Evrak Verileri:</strong> Eklenti, UYAP portalından indirdiğiniz belgeleri <strong className="text-zinc-900 font-semibold">sadece kendi bilgisayarınıza (yerel ağınıza)</strong> kaydeder veya aktarır. Hiçbir yasal belge, dosya detayı veya kişisel veri AyrisLegal sunucularına gönderilmez, saklanmaz veya üçüncü taraflarla paylaşılmaz.
</li>
</ul>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">3. Veri Paylaşımı ve İfşası (Chrome Web Store Beyanları)</h2>
<p className="mb-3">Google Chrome Web Mağazası politikaları gereği şunları taahhüt ederiz:</p>
<ul className="space-y-2 pl-4 list-disc marker:text-zinc-400">
<li>Kullanıcı verilerini üçüncü şahıslara satmıyoruz veya aktarmıyoruz.</li>
<li>Kullanıcı verilerini onaylanmış (single purpose) kullanım amacı dışında kullanmıyor veya aktarmıyoruz.</li>
<li>Kullanıcı verilerini kredi notu belirlemek veya borç verme amaçlarıyla kullanmıyor veya aktarmıyoruz.</li>
</ul>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">4. Veri Güvenliği</h2>
<p>
Eklentinin tüm veri alışverişi doğrudan sizin bilgisayarınız (tarayıcınız) ile resmi hedefler (UYAP vb.) arasında gerçekleşir. Kişisel bilgilerinizin güvenliğini korumak için endüstri standartlarında teknik ve idari güvenlik önlemleri uygulanmaktadır.
</p>
</section>
<section>
<h2 className="text-lg font-bold text-zinc-950 mb-3">5. Değişiklikler</h2>
<p>
Bu Gizlilik Politikasını zaman zaman güncelleyebiliriz. Herhangi bir değişiklik durumunda bu sayfada yeni tarihi belirterek sizi bilgilendireceğiz.
</p>
</section>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">5. Değişiklikler</h2>
<p className="mb-4">
Bu Gizlilik Politikasını zaman zaman güncelleyebiliriz. Herhangi bir değişiklik durumunda bu sayfada yeni tarihi belirterek sizi bilgilendireceğiz.
</p>
</section>
<section className="rounded-2xl border border-zinc-200/80 bg-zinc-50/70 p-6">
<h2 className="text-base font-bold text-zinc-950 mb-2">6. İletişim</h2>
<p className="text-xs leading-relaxed text-zinc-600">
Bu Gizlilik Politikası hakkında veya veri güvenliği ile ilgili her türlü sorunuz için lütfen{' '}
<a href="mailto:info@ayris.tech" className="font-semibold text-zinc-900 underline underline-offset-4 hover:text-[#E61919]">
info@ayris.tech
</a>{' '}
adresi üzerinden bizimle iletişime geçin.
</p>
</section>
</div>
</main>
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">6. İletişim</h2>
<p className="mb-4">
Bu Gizlilik Politikası hakkında veya veri güvenliği ile ilgili sorularınız varsa, lütfen <strong>info@ayris.tech</strong> adresi üzerinden bizimle iletişime geçin.
</p>
</section>
</div>
{/* ══════════════════════════════ FOOTER ══════════════════════════════ */}
<footer className="border-t border-zinc-100 bg-white py-8 px-5 md:px-16 text-xs text-zinc-500">
<div className="mx-auto flex max-w-[1400px] flex-col items-center justify-between gap-3 sm:flex-row">
<span>© {new Date().getFullYear()} AyrisLegal Ayris Tech&apos;in bir ürünüdür.</span>
<a
href="https://ayris.tech"
target="_blank"
rel="noopener noreferrer"
className="font-medium text-zinc-700 underline-offset-4 hover:underline"
>
Created by ayris.tech
</a>
</div>
</footer>
</div>
);
)
}
+82 -14
View File
@@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from 'next/server'
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
// Basit in-memory rate limiting (MVP — production'da Redis kullan)
// Basit in-memory rate limiting
const ipRequestMap = new Map<string, { count: number; resetAt: number }>()
const RATE_LIMIT = 5 // maksimum istek
const WINDOW_MS = 60_000 // 1 dakika
@@ -22,6 +22,69 @@ function checkRateLimit(ip: string): boolean {
return true
}
function escapeHtml(str: string): string {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
}
async function sendTelegramNotification({
name,
email,
org,
phone,
ip,
}: {
name: string
email: string
org?: string | null
phone?: string | null
ip: string
}) {
const botToken = process.env.TELEGRAM_BOT_TOKEN
const chatId = process.env.TELEGRAM_CHAT_ID
if (!botToken || !chatId) {
console.warn('[AyrisLegal] Telegram bildirim ayarları eksik (TELEGRAM_BOT_TOKEN veya TELEGRAM_CHAT_ID ortam değişkeni tanımlanmamış).')
return
}
const now = new Date().toLocaleString('tr-TR', { timeZone: 'Europe/Istanbul' })
const text =
`🎯 <b>Yeni AyrisLegal Demo Talebi!</b>\n\n` +
`👤 <b>Ad Soyad:</b> ${escapeHtml(name)}\n` +
`📧 <b>E-posta:</b> <code>${escapeHtml(email)}</code>\n` +
`🏢 <b>Büro / Kurum:</b> ${org ? escapeHtml(org) : '<i>Belirtilmedi</i>'}\n` +
`📞 <b>Telefon:</b> ${phone ? `<code>${escapeHtml(phone)}</code>` : '<i>Belirtilmedi</i>'}\n` +
`🌐 <b>IP Adresi:</b> <code>${escapeHtml(ip)}</code>\n` +
`⏰ <b>Tarih & Saat:</b> ${now}`
try {
const res = await fetch(`https://api.telegram.org/bot${botToken}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chat_id: chatId,
text,
parse_mode: 'HTML',
disable_web_page_preview: true,
}),
})
if (!res.ok) {
const errText = await res.text()
console.error('[AyrisLegal] Telegram API yanıt hatası:', errText)
} else {
console.log('[AyrisLegal] ✅ Telegram bildirimi başarıyla iletildi.')
}
} catch (error) {
console.error('[AyrisLegal] Telegram gönderim hatası:', error)
}
}
export async function POST(request: NextRequest) {
try {
// IP tespiti
@@ -31,51 +94,56 @@ export async function POST(request: NextRequest) {
// Rate limit
if (!checkRateLimit(ip)) {
return NextResponse.json(
{ success: false, error: 'Çok fazla istek. Lütfen bir dakika bekleyip tekrar deneyin.' },
{ success: false, error: 'Çok fazla istek gönderildi. Lütfen bir dakika bekleyip tekrar deneyin.' },
{ status: 429 }
)
}
const body = await request.json()
const { name, email, barNo, message, _hp } = body
const { name, email, org, phone, barNo, message, _hp } = body
// Honeypot kontrolü
// Honeypot kontrolü (Bot engelleme)
if (_hp) {
// Bot — 200 döndür ama işleme
return NextResponse.json({ success: true })
}
// Zorunlu alan doğrulaması
if (!name || typeof name !== 'string' || name.trim().length < 2) {
return NextResponse.json(
{ success: false, error: 'Ad Soyad zorunludur (en az 2 karakter).' },
{ success: false, error: 'Lütfen ad ve soyadınızı belirtin (en az 2 karakter).' },
{ status: 400 }
)
}
if (!email || typeof email !== 'string' || !EMAIL_REGEX.test(email.trim())) {
return NextResponse.json(
{ success: false, error: 'Geçerli bir e-posta adresi giriniz.' },
{ success: false, error: 'Lütfen geçerli bir e-posta adresi girin.' },
{ status: 400 }
)
}
// MVP: Konsola yaz
// TODO: Resend/SendGrid veya Prisma leads tablosu eklenebilir
console.log('[AyrisLegal] 🎯 Yeni Demo Talebi:', {
timestamp: new Date().toISOString(),
const leadData = {
name: name.trim(),
email: email.trim().toLowerCase(),
barNo: barNo?.trim() || null,
message: message?.trim() || null,
org: org?.trim() || barNo?.trim() || null,
phone: phone?.trim() || message?.trim() || null,
ip,
}
// Konsol logu
console.log('[AyrisLegal] 🎯 Yeni Demo Talebi Alındı:', {
timestamp: new Date().toISOString(),
...leadData,
})
// Telegram Botuna Anlık Bildirim Gönder (Hata durumunda form akışını kesmez)
await sendTelegramNotification(leadData)
return NextResponse.json({ success: true }, { status: 200 })
} catch (err) {
console.error('[AyrisLegal] Contact API hatası:', err)
return NextResponse.json(
{ success: false, error: 'Sunucu hatası oluştu.' },
{ success: false, error: 'Sunucu hatası oluştu. Lütfen tekrar deneyin.' },
{ status: 500 }
)
}
+44 -129
View File
@@ -8,7 +8,7 @@
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-archivo);
--font-mono: var(--font-geist-mono);
--font-mono: var(--font-jetbrains-mono);
--font-heading: var(--font-archivo);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
@@ -39,89 +39,69 @@
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) * 0.6);
--radius-md: calc(var(--radius) * 0.8);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) * 1.4);
--radius-2xl: calc(var(--radius) * 1.8);
--radius-3xl: calc(var(--radius) * 2.2);
--radius-4xl: calc(var(--radius) * 2.6);
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 24px;
--radius-full: 9999px;
}
/* ─── AyrisLegal Marka Renk Sistemi (Lacivert + Teal) ─────────────── */
/* ─── AyrisLegal Design System: "The Modern Jurist Studio" ─────────── */
:root {
/* Lacivert (navy) arka plan / teal vurgu — dark-first marka */
--background: oklch(0.18 0.055 243); /* Derin lacivert */
--foreground: oklch(0.95 0.012 240); /* Neredeyse beyaz */
/* Editorial Paper White & Architectural Zinc */
--background: #FFFFFF;
--foreground: #09090B;
--card: oklch(0.22 0.05 243); /* Biraz açık lacivert kart */
--card-foreground: oklch(0.95 0.012 240);
--card: #FFFFFF;
--card-foreground: #09090B;
--popover: oklch(0.22 0.05 243);
--popover-foreground: oklch(0.95 0.012 240);
--popover: #FFFFFF;
--popover-foreground: #09090B;
/* Teal ana renk */
--primary: oklch(0.63 0.14 183); /* Teal */
--primary-foreground: oklch(0.98 0.008 183);
/* Ayris Legal Red (Primary Conversion Accent) */
--primary: #E61919;
--primary-foreground: #FFFFFF;
--primary-dark: #B8140F;
--primary-soft: #FDEEEC;
--secondary: oklch(0.28 0.05 243); /* Orta lacivert */
--secondary-foreground: oklch(0.90 0.012 240);
--secondary: #FAFAFA;
--secondary-foreground: #18181B;
--muted: oklch(0.25 0.04 243);
--muted-foreground: oklch(0.60 0.035 240);
--muted: #FAFAFA;
--muted-foreground: #71717A;
--accent: oklch(0.68 0.13 183); /* Açık teal vurgu */
--accent-foreground: oklch(0.18 0.055 243);
--accent: #FDEEEC;
--accent-foreground: #B8140F;
--destructive: oklch(0.577 0.245 27.325);
--destructive: #DC2626;
--destructive-foreground: #FFFFFF;
--border: oklch(0.32 0.045 243);
--input: oklch(0.28 0.045 243);
--ring: oklch(0.63 0.14 183); /* Teal focus ring */
--border: #E4E4E7;
--input: #E4E4E7;
--ring: #E61919;
--chart-1: oklch(0.63 0.14 183);
--chart-2: oklch(0.55 0.12 200);
--chart-3: oklch(0.45 0.09 220);
--chart-4: oklch(0.38 0.07 230);
--chart-5: oklch(0.30 0.05 240);
--radius: 1rem;
--radius: 0.75rem;
--sidebar: #FAFAFA;
--sidebar-foreground: #09090B;
--sidebar-primary: #E61919;
--sidebar-primary-foreground: #FFFFFF;
--sidebar-accent: #F4F4F5;
--sidebar-accent-foreground: #18181B;
--sidebar-border: #E4E4E7;
--sidebar-ring: #E61919;
--sidebar: oklch(0.20 0.055 243);
--sidebar-foreground: oklch(0.90 0.012 240);
--sidebar-primary: oklch(0.63 0.14 183);
--sidebar-primary-foreground: oklch(0.98 0.008 183);
--sidebar-accent: oklch(0.25 0.05 243);
--sidebar-accent-foreground: oklch(0.90 0.012 240);
--sidebar-border: oklch(0.30 0.045 243);
--sidebar-ring: oklch(0.63 0.14 183);
caret-color: #E61919;
}
/* Admin/login sayfaları için açık tema (opsiyonel override) */
.light {
--background: oklch(0.98 0.005 240);
--foreground: oklch(0.18 0.055 243);
--card: oklch(1 0 0);
--card-foreground: oklch(0.18 0.055 243);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.18 0.055 243);
--primary: oklch(0.55 0.14 183);
--primary-foreground: oklch(0.98 0.008 183);
--secondary: oklch(0.93 0.02 240);
--secondary-foreground: oklch(0.22 0.05 243);
--muted: oklch(0.95 0.015 240);
--muted-foreground: oklch(0.50 0.04 240);
--accent: oklch(0.90 0.06 183);
--accent-foreground: oklch(0.25 0.05 243);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.88 0.02 240);
--input: oklch(0.88 0.02 240);
--ring: oklch(0.55 0.14 183);
::selection {
background: #FDEEEC;
color: #B8140F;
}
@layer base {
* {
@apply border-border outline-ring/50;
@apply border-border;
}
body {
@apply bg-background text-foreground;
@@ -130,69 +110,4 @@
@apply font-sans;
scroll-behavior: smooth;
}
}
/* ─── AyrisLegal Premium Background Effects ─────────────────────────── */
.orb {
position: fixed;
border-radius: 50%;
filter: blur(110px);
pointer-events: none;
z-index: 0;
will-change: transform;
}
.orb-1 {
width: 700px;
height: 700px;
background: radial-gradient(circle, rgba(45,212,191,0.22) 0%, transparent 70%);
top: -180px;
left: -120px;
animation: orb-float 14s ease-in-out infinite;
}
.orb-2 {
width: 550px;
height: 550px;
background: radial-gradient(circle, rgba(99,102,241,0.16) 0%, transparent 70%);
top: 38%;
right: -120px;
animation: orb-float 18s ease-in-out infinite reverse;
animation-delay: -6s;
}
.orb-3 {
width: 420px;
height: 420px;
background: radial-gradient(circle, rgba(45,212,191,0.12) 0%, transparent 70%);
bottom: 15%;
left: 28%;
animation: orb-float 11s ease-in-out infinite;
animation-delay: -9s;
}
@keyframes orb-float {
0%, 100% { transform: translate(0, 0) scale(1); }
33% { transform: translate(35px, -50px) scale(1.06); }
66% { transform: translate(-25px, 25px) scale(0.95); }
}
.grid-overlay {
position: fixed;
inset: 0;
background-image:
linear-gradient(rgba(255,255,255,0.022) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.022) 1px, transparent 1px);
background-size: 60px 60px;
pointer-events: none;
z-index: 0;
}
/* Gradient text utility */
.text-gradient-teal {
background: linear-gradient(135deg, #2DD4BF 0%, #67E8F9 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
+16
View File
@@ -0,0 +1,16 @@
import { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
const baseUrl = 'https://ayrislegal.com'
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/', '/login', '/*/login', '/*/admin', '/_next/', '/private/'],
},
],
sitemap: `${baseUrl}/sitemap.xml`,
}
}
+35
View File
@@ -0,0 +1,35 @@
import { MetadataRoute } from 'next'
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = 'https://ayrislegal.com'
const locales = ['tr', 'en']
const now = new Date()
const routes = [
{ path: '', priority: 1.0, changeFrequency: 'weekly' as const },
{ path: '/iletisim', priority: 0.9, changeFrequency: 'monthly' as const },
{ path: '/privacy', priority: 0.3, changeFrequency: 'yearly' as const },
]
const entries: MetadataRoute.Sitemap = []
for (const locale of locales) {
for (const route of routes) {
const url = `${baseUrl}/${locale}${route.path}`
entries.push({
url,
lastModified: now,
changeFrequency: route.changeFrequency,
priority: route.priority,
alternates: {
languages: {
tr: `${baseUrl}/tr${route.path}`,
en: `${baseUrl}/en${route.path}`,
},
},
})
}
}
return entries
}