
Client
Konak Tel Çit
React Web Design
Konak Tel Çit
Konak Tel Çit Web Sitesinin Tüm Web Mimarisini Yenileme ve Next.js İle Yeniden Yapılandırma Çalışmalarıdır.

For Konak Tel Çit a manufacturer of wire fencing and security systems since 1972 we did not build a typical corporate website. We designed the company's digital backbone. The platform combines a 40+ product catalog, content in 5 languages, 11 technical calculators, TKGM parcel/block integration, an AI-powered technical advisor, and a full admin panel in a single Next.js application.
This project goes far beyond a static landing page: App Router, Server Components, edge proxy, streaming API, function calling, and a database-driven CMS all run in the same codebase.
Technology Stack
Framework: Next.js 16.2 — App Router, edge proxy, RSC, dynamic metadata
UI: React 19 + React Compiler — automatic optimization, less client JavaScript
Language: TypeScript 5 — type safety across 395+ files
Database: PostgreSQL 16 + Prisma 6 — relational model, migrations, seeding
Styling: Tailwind CSS 4 — typography plugin
AI: Google Gemini — advisor, translation, function calling
Auth: jose (JWT) — edge-compatible session verification
Security: isomorphic-dompurify — XSS-safe HTML sanitization
DevOps: Docker Compose — local PostgreSQL development environment
Architecture: Next.js 16 in Production
Edge Proxy
In Next.js 16, the middleware convention was replaced by the proxy rule. Three responsibilities in one file:
Admin auth guard — /yonetim protected via JWT cookie
i18n rewrite — Turkish URLs show no prefix; /urunlerimiz is rewritten to /tr/urunlerimiz behind the scenes
Static and API bypass — _next, /api, and file extensions skip the proxy
This approach combines SEO-friendly short URLs for Turkish and multilingual routing with /en/, /de/, /ar/, /es/ prefixes in the same route tree.
App Router and Server Components
Nearly all page components are async Server Components. Data is fetched on the server; no unnecessary client bundles. The homepage loads 6 data sources in parallel via Promise.all. Language and city pages are prerendered at build time with generateStaticParams.
Root-Level Product URLs
Products are served at slug level, not deep paths: /3d-panel-cit, /en/3d-panel-cit, /de/jiletli-panel-cit. Legacy /urunler/:slug URLs are preserved with permanent 308 redirects in next.config.ts — no backlink or SEO loss.
Type-Safe Content System
Static copy lives under src/content/ with schema versioning and locale invariants. Dynamic content (products, news, guides, solution sectors) is stored in PostgreSQL; each model has locale-based translation tables across 5 languages.
Database Design
The Prisma schema includes 20+ models shaped around a real manufacturing workflow:
Product + ProductTranslation — 40+ products, JSON spec (dimensions, colors, certifications, FAQs)
Insight + InsightTranslation — newsroom and technical guides
City + Dealer — 81 city SEO pages, dealer map
SolutionSector — industry solution matrices (industrial, sports, residential…)
BomMapping — calculator bill-of-materials to product price mapping
ToolFormulaOverride — admin-editable formula parameters
ContactRequest / DealerApplication — lead management
AiSettings + AiTrainingDoc — AI advisor configuration
SiteSettings — singleton site configuration
Translation provenance is tracked: isMachineTranslated, translatedAt, reviewedAt — human review vs. machine translation is visible in the admin panel.
AI Technical Advisor
The site's flagship feature: a Gemini-based technical advisor with function calling. It does not hallucinate specs or prices. When a user asks a question, the model invokes defined tools:
Galvanized wire calculation — diameter, length, coating life (EN 10244-2, ISO 9223)
2D and 3D panel fence m² weight calculation
Chain-link fence material calculation
Post concrete and clamp calculation
Gate weight and material calculation
Parcel material estimate — fence BOM from TKGM block/parcel data
Product catalog search
City-based dealer lookup
Contact request creation (when enabled)
The API endpoint streams via SSE (Server-Sent Events): text chunks, tool-call status, completion, and error events. A floating widget appears on every page; Arabic RTL is supported. Model selection, persona, training docs, rate limits, and lead capture are managed from the admin panel.
Calculator Tools Hub
11 standalone technical calculators under /araclar:
Fence calculation (block/parcel + TKGM)
Galvanized wire weight
2D panel fence m² weight
3D panel fence m² weight
Chain-link fence m² weight
Barbed wire roll
Post concrete
Post clamp calculation
Tube profile weight
Box profile weight
Gate calculation
AWG ↔ mm conversion
Each tool runs pure TypeScript logic in its own compute module. Admins can override parameters via ToolFormulaOverride, toggle optional pricing, and link BOM keys to the product catalog through BomMapping.
The fence calculator is especially notable: real parcel geometry is fetched via the TKGM CBS API (province → district → neighborhood → block/parcel chain); perimeter is computed from a GeoJSON polygon, then material and price estimates are generated.
Multilingual (i18n) Strategy
5 languages: Turkish, English, German, Arabic, Spanish.
Turkish = root (/hakkimizda, /3d-panel-cit)
Other languages = prefix (/en/about-us, /de/3d-panel-cit)
UI strings from JSON dictionaries
Product, news, and solution content in DB translation tables
Static blocks in locale-specific TypeScript files
Bulk translation from admin via Google Translate or Gemini
CLI scripts for batch translation pipelines
Arabic layout uses dir="rtl"; the language switcher preserves the current page locale.
SEO and Performance
Dynamic title, description, and Open Graph on 30+ pages (generateMetadata)
Product JSON-LD — schema.org Product, AggregateOffer, Brand, Organization
81 city pages — TR prerender via generateStaticParams; targets queries like "Kayseri wire fence", "Ankara panel fence dealer"
Permanent redirects — legacy URL structure preserved (308)
React Compiler — reactCompiler: true for automatic optimization
Server Components — minimal client JavaScript
next/image — optimized image delivery
Admin Panel (/yonetim)
Full CMS inside the Next.js App Router:
Products — CRUD, rich editor, image upload, BOM mapping
News / Guides — content management, translation
Solutions — sector matrices, FAQs, tool links
Dealers — 81 provinces, map coordinates, authorized dealer badge
Dealer applications — status workflow (NEW → APPROVED)
Contact requests — lead pipeline
Tools — formula overrides, parcel mapping, pricing toggle
AI — model, persona, training docs, test chat
Site settings — singleton config
Users — OWNER, ADMIN, EDITOR roles
Auth: bcryptjs password hashing + jose JWT; admin-session cookie; verification at the edge proxy.
Source Code Examples
The snippets below are taken directly from the project — real code illustrating the Next.js 16 architecture.
1. Edge Proxy — Auth + i18n Rewrite (proxy.ts)
In Next.js 16, middleware is replaced by the proxy rule. Admin JWT verification and Turkish root URL rewrite in one file:
export async function proxy(request: NextRequest) {
const pathname = request.nextUrl.pathname;
// Admin auth guard
if (pathname.startsWith("/yonetim/")) {
const token = request.cookies.get("admin-session")?.value;
const session = token ? await verifySessionToken(token) : null;
if (!session) return NextResponse.redirect("/yonetim/giris");
return NextResponse.next();
}
// Turkish URL rewrite — address bar stays unchanged
const hasLocale = locales.some(
(l) => pathname.startsWith(`/${l}/`)
);
if (!hasLocale) {
const url = request.nextUrl.clone();
url.pathname = `/tr${pathname}`;
return NextResponse.rewrite(url);
}
}2. Async Server Component + generateStaticParams
Static param generation for 5 languages and parallel data loading:
export function generateStaticParams() {
return locales.map((lang) => ({ lang }));
}
export default async function LangLayout({ params }) {
const { lang } = await params;
if (!isLocale(lang)) notFound();
const [dictionary, productMenu] = await Promise.all([
getDictionary(lang),
getProductMenu(lang),
]);
return (
<div>
<SiteHeader dictionary={dictionary} locale={lang} />
<main>{children}</main>
<DanismanWidget lang={lang} />
</div>
);
}3. Turkish Root URL — localizedPath()
No prefix for Turkish; other languages use /en/, /de/ prefixes:
export function localizedPath(locale: string, path: string) {
const normalized = path.startsWith("/") ? path : `/${path}`;
if (locale === "tr") return normalized; // /urunlerimiz
return `/${locale}${normalized}`; // /en/urunlerimiz
}4. Gemini Function Calling — AI Advisor Tool Definition
The model does not guess; it calls a real calculator bound to EN 10244-2 and ISO 9223 standards:
const galvanizTelDecl: FunctionDeclaration = {
name: "galvaniz_tel_hesapla",
description: "Calculates galvanized wire weight or coating life.",
parameters: {
type: Type.OBJECT,
properties: {
islem: {
type: Type.STRING,
enum: ["uzunluktan_agirlik", "kaplama_omru"],
},
capMm: { type: Type.NUMBER, description: "Wire diameter (mm)" },
kaplamaSinifi: {
type: Type.STRING,
enum: ["A", "AB", "B", "bare"], // EN 10244-2
},
atmosfer: {
type: Type.STRING,
enum: ["C1", "C2", "C3", "C4", "C5"], // ISO 9223
},
},
required: ["islem", "capMm"],
},
};5. SSE Stream + Function Calling Loop
The advisor API streams live; when the model calls a tool, it executes and feeds the result back:
const stream = new ReadableStream({
async start(controller) {
for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {
const result = await chat.sendMessageStream({ message: nextMessage });
for await (const chunk of result) {
if (chunk.text) controller.enqueue(
sseLine({ type: "text", value: chunk.text })
);
if (chunk.functionCalls?.length) {
for (const call of chunk.functionCalls) {
controller.enqueue(
sseLine({ type: "tool", name: call.name })
);
const output = await executeTool(call.name, call.args, ctx);
nextMessage = [{
functionResponse: {
name: call.name,
response: output,
},
}];
}
}
}
}
controller.enqueue(sseLine({ type: "done" }));
}});6. Product JSON-LD — Server Component
schema.org Product data injected directly into HTML for Google Rich Results:
export default function ProductJsonLd({ name, slug, images, origin }) {
const data = {
"@context": "https://schema.org",
"@type": "Product",
name,
url: `${origin}/${slug}`,
brand: { "@type": "Brand", name: "Konak Tel Çit" },
manufacturer: {
"@type": "Organization",
name: "Konak Tel Çit",
foundingDate: "1972",
},
offers: {
"@type": "AggregateOffer",
availability: "https://schema.org/InStock",
priceCurrency: "TRY",
},
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
/>
);
}7. SEO Redirect — next.config.ts
Legacy URL structure preserved with permanent 308 redirects; no backlink loss:
const nextConfig: NextConfig = {
reactCompiler: true,
async redirects() {
return [
{
source: "/:lang(tr|en|de|es|ar)/urunler/:slug",
destination: "/:lang/:slug",
permanent: true, // 308
},
{
source: "/urunler/:slug",
destination: "/:slug",
permanent: true,
},
];
},
};Project at a Glance
395+ TypeScript/TSX files
15+ Prisma migrations
5 supported languages
11+ calculators
40+ API routes
30+ admin pages
Product categories: panel fence, chain link, barbed wire, gates, posts, sports…
Why This Project Is a Next.js Reference
Latest framework stack — Next.js 16 proxy, React 19, React Compiler
True full-stack — RSC + API Routes + edge auth + streaming AI + Prisma; no separate backend
Domain depth — TKGM parcel API, galvanized coating life (EN 10244-2), BOM price mapping
AI integration — not a chatbot; a technical advisor wired to calculators and catalog via function calling
i18n architecture — Turkish root URL + 4 language prefixes + DB translations + automated MT pipeline
Operational readiness — Docker, seed scripts, migrations, admin panel, lead management
The Konak Tel Çit platform is Hitit Medya's reference work demonstrating what Next.js can deliver for enterprise B2B manufacturing companies.