vefacaglar com
what's the point of this site?
for years i wanted to build a simple little hobby site, but i never had enough time or energy to actually make the thing i had in my head. for the past 6 months or so, though, i've had some nice free time, development cycles have gotten way shorter, and the tech has come a long way. the old "rent some hosting, push it up with filezilla" approach isn't really a thing anymore either.
when i started working at art dada back in 2017, i got into building websites. i'd turn psd designs into html and css, but the way the page refreshed every time you navigated between pages always bugged me. i'd tried technologies like angular and react, but since those render after the page loads, there was no seo to speak of. i'd learned that there was this thing called ssr, and every now and then i'd lean toward picking it up, but since my career kept pushing me more toward the backend, i drifted away from the frontend. in fact, for the last 6 years i've worked almost exclusively with backend and microservices.
even if i'd sorted out the ssr side of things, i had another problem: back then the number of hosts that could even run nodejs or .net core was pretty small. i'd managed to rent a droplet from somewhere like digitalocean, jump through all kinds of hoops connecting to a remote server over linux, set up nginx, and deploy and run very basic nodejs apps — but all of this ate up hours of my time. and since my career was steering me toward the architecture side anyway, i focused more on the microservices parts and the architecture.
these days, with ai tools, turning the things in my head into code — without having to be super fluent in the syntax, just leaning on what i know about architecture and the tech side — has gotten a lot quicker. plus i've got plenty of time now. so i built this website as a purely-for-fun thing where i wanted to share the experiences i've had on the projects i've worked on, post my thoughts on the films i've watched, share the games i've played, and the concerts i've been to.
how the site is structured
i set up a markdown-focused structure to keep things as flexible as possible. without over-engineering it too much, the mdx-focused content lets me stretch and shape the content and pages as much as i want.
i designed a separate table structure for sharing the projects i've worked on. i haven't linked posts to projects yet, but i can set up that relationship — thinking of it like a project page.
pages live in a separate table; they're not like blog posts. for the home and about pages, i pull from the pages data tied to the fixed `home` and `about` slugs.
architecture overview
monorepo structure: turborepo + pnpm workspace. two apps, two packages.
the general setup
the project is organized as a Turborepo + pnpm workspace. there are two apps and two shared packages in a single repo:
- `apps/web` — Next.js 14, the public site and dashboard
- `apps/api` — a REST API written with Fastify
- `packages/db` — Drizzle ORM schemas and migrations
- `packages/shared` — small TypeScript helpers that both sides use
my reason for going with a monorepo is simple: the frontend, backend, and database schemas all evolve together. when i change the schema, being able to update the API and the UI in the same commit makes life a lot easier.
frontend — `apps/web`
on the frontend i'm using Next.js 14's App Router. the public pages (`/`, `/about`, `/blog`, `/projects`) sit under `src/app/` in the classic App Router layout. there's a separate route group for content management: `src/app/dashboard/`. this is where i manage posts and pages.
the public pages use plain `fetch` when pulling data from the API. the dashboard, on the other hand, goes to the API through Next.js server actions — so form posts run directly on the server and i don't have to spin up a separate endpoint. thanks to this split, the "read" paths and the "write" paths stay cleanly separated.
on the styling side i deliberately kept things plain: vanilla CSS and CSS Modules. i didn't add Tailwind or any heavy UI library. for a personal site those are extra baggage; CSS Modules are isolated enough and readable enough.
the body of the blog posts lives in the database as markdown and gets rendered on the page with `next-mdx-remote`.
backend — `apps/api`
on the API side i'm using Fastify. it's faster than Express, and more importantly, it naturally fits a schema-based way of working.
for schema definitions i went with TypeBox. the nice thing about it is that from a single schema i get both runtime validation and TypeScript types (`Static<typeof Schema>`). as a bonus on top of that, swagger documentation is generated automatically — you can browse it at `/swagger`.
i organize the API internals with the Feature Folder / Handler pattern. since i've spent the last 2 years developing on the .net side with a cqrs approach, i didn't want to break out of that structure.
you can find the repo here.
deployment
this turned out to be way easier and cheaper than i expected. honestly, i'd say zero cost. back in the day, to publish a free website we could use something like heroku or azurewebsites, but they'd want us to pay just to set up dns forwarding.
these days we can publish everything for free, from the database to the apps — we can even use full devops tooling for free and very easily.
first i looked for a free db. i was thinking about using mongo or postgresql, but since i wanted to go typesafe i stuck with postgresql. neon and vercel both had free tiers that didn't ask for a credit card. i used one of those.
i'd planned to put the frontend on vercel and deploy the api side to render, but while publishing the frontend i noticed vercel also supports fastify, so i ended up deploying both to the same place. if the resources turn out not to be enough, i can switch over to a vercel + render setup, or just not bother and pay whatever it costs.
anyway, i deployed both with a few clicks. the frontend side gave me no trouble at all, but i ran into a few problems on the backend — i sorted them out in a couple of tries by going through the logs. deployment stuff has gotten waaay simpler than i imagined.