Skip to main content
Site Build Details

Colophon

How was this site built? An honest, thorough breakdown of the technology, the decisions behind it, the infrastructure, and the daily measurement series.

Technology Stack

Framework

  • Next.js16.2.10App Router, standalone SSR, Turbopack
  • React19.2.3Server Components + use() hook
  • TypeScript5.9.3Strict mode

Styling

  • Tailwind CSS4.1.18@theme + @custom-variant dark, OKLCH
  • CSS VariablesDesign tokens, runtime theme switch
  • Apple HIG colorsCanonical iOS Blue (#007AFF / #0A84FF dark)

Animation

  • Motion12.38.0LazyMotion + domAnimation strict
  • Lenis Smooth ScrollGPU-accelerated scroll
  • GPU-only propertiestransform + opacity, layout reflow yok

State

  • Zustand5.0.11Hafif client state
  • TanStack Query5.100.10Server state + cache
  • nuqs2.8.8Type-safe URL search params

Data

  • Prisma6.19.2Type-safe ORM
  • PostgreSQL16Engagement + analytics
  • ResendNewsletter delivery

Quality

  • Vitest4.1.4Unit + integration
  • Playwright + axe-core1.58.1WCAG 2.2 AA E2E
  • Lighthouse CIPerf / a11y / SEO bütçe denetimi

Deploy

  • Hetzner VPSStandalone Node SSR
  • CloudflareCDN + Brotli + 0-RTT + HTTP/3
  • Let's EncryptTLS 1.3 + HSTS preload

Observability

  • PostgreSQL analytics1st party, GDPR/KVKK uyumlu
  • Microsoft ClarityConsent-gated heatmap
  • Real User MonitoringCWV via web-vitals lib

Typography

DisplaySF Pro Display100-900 variableApple system font, opsz axis
BodySF Pro Text100-900 variableAynı SF Pro, küçük opsz
MonoSF Mono400 / 500 / 700Code blocks, version numbers

Design Principles

Önce Performans

Standalone SSR, ISR, dynamic import, GPU-only animasyon

Amaçlı Hareket

Her animasyon kullanıcıyı yönlendirir, dekoratif değil

Varsayılan Erişilebilirlik

WCAG 2.2 AA, prefers-reduced-motion, 44×44px hedef

Doğal Karanlık Mod

Sistem tercihiyle senkron, custom-variant Tailwind v4

Infrastructure

Origin
Hetzner VPS (EU)
Runtime
Node v22.23.1
Process
systemd (portfolio-ssr.service, User=portfolio)
CDN
Cloudflare
Edge cache
s-maxage=60
TLS
1.3 + HSTS preload
DB
PostgreSQL 16

Chose / Rejected

Six decisions that are live on this server right now, each with the option it replaced, the reason it was needed here, what it costs, and the file and line where you can check it. They are all good tools — these cards are about fit, not ranking.

  • ChoseMotion v12

    RejectedGSAP

    Every page is a React tree, and animation state had to live in the same place as component lifecycle. `LazyMotion` + `domAnimation` keeps the feature bundle out of the first load, and heavier features such as drag stay scoped to the one component that needs them.

    CostFor timeline-driven, frame-exact choreography GSAP remains stronger; if such a scene is ever needed this decision gets reopened.

    Evidencepackage.json:64

  • ChoseSF Pro (self-host, woff2)

    RejectedInter (Google Fonts)

    The whole site is about the Apple ecosystem, so matching the reader's own system typeface is part of the content. The files are served from our own origin through `next/font/local`, which removes the third-party font request and its connection cost.

    CostApple's Personal Use licence: the same choice would not be available in a commercial product, and two variable files (including latin-ext) have to be carried.

    Evidencesrc/app/(main)/layout.tsx:26

  • ChosePrisma client → src/generated/prisma

    RejectedVarsayılan node_modules/@prisma/client yolu

    The standalone SSR output only copies what it can trace. With the client inside the repo under `src/`, `next build` treats it as an ordinary module and the whole class of "missing from the `.next/standalone` copy" failures disappears.

    Cost`prisma generate` becomes mandatory on every schema change and the generated directory sits in the repo tree — which is why it is the first step of the prebuild chain.

    Evidenceprisma/schema.prisma:7

  • Chosesystemd, User=portfolio (non-root)

    Rejectedroot altında pm2

    The SSR process was taken off root on 14 Jul 2026. The unit ships `NoNewPrivileges`, `ProtectSystem`, `ProtectHome` and `PrivateTmp`; `ProtectHome` alone means the app can no longer read the deployment credentials under `/root`. The line above does not hard-code any of this — it asks the unit on every build.

    CostThe build still runs as root, so `.next` ownership has to be handed back after every build; `ProtectSystem=strict` and `MemoryDenyWriteExecute` are deliberately left off because of V8's JIT.

    Evidencescripts/generate-colophon-stack.ts:63

  • ChoseTailwind v4 `@theme inline` köprüsü

    Rejectedshadcn adlarını ham haliyle kullanmak

    The project's colour vocabulary is its own semantic tokens (`--color-bg-primary`, `--color-text-primary`). shadcn's 19 names — `bg-muted`, `text-foreground` and the rest — are bound to those through `@theme inline`; `inline` is required because the theme switches at runtime via the `.dark` / `.admin-v2` classes.

    CostUsing a new shadcn name means adding a bridge line and checking its light/dark contrast before it can be used.

    Evidencesrc/app/globals.css:42

  • Choseİçerik PostgreSQL'de (Prisma)

    RejectedTypeScript sabit dizileri

    While content lived in TS files every correction required a build, and what the admin panel saw could drift from what the page printed. The database is now the single source; the prebuild step turns those records into static JSON so the page never queries at request time.

    CostA content change only reaches production through a build, and the backup burden moved from the repository to the database.

    Evidencescripts/generate-content-json.ts:192

Measurement Series

A cron on this server has been storing a Lighthouse run per page type every night and a PageSpeed Insights mobile run every morning. These are those files, unedited: the highs and the bad days both.

Home

/

Performance865992
Accessibility100100100
Best Practices100100100
SEO100100100
View as a table
CategoryLastMinMaxRuns
Performance86599286
Accessibility10010010086
Best Practices10010010086
SEO10010010086

Blog post

/blog/swift-6-neler-yeni/

Performance969398
Accessibility100100100
Best Practices100100100
SEO100100100
View as a table
CategoryLastMinMaxRuns
Performance96939844
Accessibility10010010044
Best Practices10010010044
SEO10010010044

Comparison

/comparisons/swiftui-vs-uikit/

Performance979599
Accessibility9797100
Best Practices100100100
SEO100100100
View as a table
CategoryLastMinMaxRuns
Performance97959944
Accessibility979710044
Best Practices10010010044
SEO10010010044

Project

/projects/part-to-time/

Performance955999
Accessibility10096100
Best Practices100100100
SEO100100100
View as a table
CategoryLastMinMaxRuns
Performance95599944
Accessibility1009610044
Best Practices10010010044
SEO10010010044

Lighthouse CI · 2026-06-192026-09-16 · 90 daily files

PageSpeed Insights — 28-day p75 (mobile)

PSI mobile lab, 4x CPU throttled emulation — not field Core Web Vitals.

PageSpeed Insights 75th percentile by URL
URLScoreLCPTBTCLSn
/824.59 s272 ms0.00127
/blog/apple-foundation-models-framework-on-device-llm/854.35 s112 ms0.00928
/comparisons/swiftui-vs-uikit/894.00 s206 ms0.00127
/quiz/903.75 s255 ms0.00128

2026-08-202026-09-16 · 28 daily files

License & Credits

  • Design and content © 2026 Muhittin Çamdalı
  • Icons: Lucide (ISC) + SF Symbols (Apple sistem)
  • Fonts: SF Pro + SF Mono (Apple Personal Use License, self-hosted woff2)
  • For the detailed credits and reference list, see /credits/ page

Infrastructure consulting

Let me set this stack up for your team

Everything on this page — the standalone SSR build, the non-root systemd unit, the token-based theme bridge, the nightly measurement archive — is a setup I install and hand over, documented, on your own servers. If your team is somewhere in the middle of that road, tell me where it is stuck and I will tell you what I would do.

This site is crafted with love and lots of .