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
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.
Evidence
package.json:64ChoseSF 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.
Evidence
src/app/(main)/layout.tsx:26ChosePrisma 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.
Evidence
prisma/schema.prisma:7Chosesystemd, 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.
Evidence
scripts/generate-colophon-stack.ts:63ChoseTailwind 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.
Evidence
src/app/globals.css:42Choseİç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.
Evidence
scripts/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
/
View as a table
| Category | Last | Min | Max | Runs |
|---|---|---|---|---|
| Performance | 86 | 59 | 92 | 86 |
| Accessibility | 100 | 100 | 100 | 86 |
| Best Practices | 100 | 100 | 100 | 86 |
| SEO | 100 | 100 | 100 | 86 |
Blog post
/blog/swift-6-neler-yeni/
View as a table
| Category | Last | Min | Max | Runs |
|---|---|---|---|---|
| Performance | 96 | 93 | 98 | 44 |
| Accessibility | 100 | 100 | 100 | 44 |
| Best Practices | 100 | 100 | 100 | 44 |
| SEO | 100 | 100 | 100 | 44 |
Comparison
/comparisons/swiftui-vs-uikit/
View as a table
| Category | Last | Min | Max | Runs |
|---|---|---|---|---|
| Performance | 97 | 95 | 99 | 44 |
| Accessibility | 97 | 97 | 100 | 44 |
| Best Practices | 100 | 100 | 100 | 44 |
| SEO | 100 | 100 | 100 | 44 |
Project
/projects/part-to-time/
View as a table
| Category | Last | Min | Max | Runs |
|---|---|---|---|---|
| Performance | 95 | 59 | 99 | 44 |
| Accessibility | 100 | 96 | 100 | 44 |
| Best Practices | 100 | 100 | 100 | 44 |
| SEO | 100 | 100 | 100 | 44 |
Lighthouse CI · 2026-06-19 → 2026-09-16 · 90 daily files
PageSpeed Insights — 28-day p75 (mobile)
PSI mobile lab, 4x CPU throttled emulation — not field Core Web Vitals.
| URL | Score | LCP | TBT | CLS | n |
|---|---|---|---|---|---|
| / | 82 | 4.59 s | 272 ms | 0.001 | 27 |
| /blog/apple-foundation-models-framework-on-device-llm/ | 85 | 4.35 s | 112 ms | 0.009 | 28 |
| /comparisons/swiftui-vs-uikit/ | 89 | 4.00 s | 206 ms | 0.001 | 27 |
| /quiz/ | 90 | 3.75 s | 255 ms | 0.001 | 28 |
2026-08-20 → 2026-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 .