Building With Claude Code
A day of finishing a real website, not generating one.
I didn't ask an AI to design my portfolio. I asked it to sit with me for a day while I finished one — and it caught things I hadn't, refused things I shouldn't have asked for, and got stuck on the same dumb infrastructure problems I would have. This is what that day actually looked like.
Two different AI tools were involved in this, doing two different jobs, and I want to be upfront about which did which — including exactly which models — rather than let one name stand in for both.
Model: GPT Astra, run at high / extra-high reasoning. Helped me think through and draft the prompts I'd bring to Claude Code, and separately analysed parts of the existing site on its own. Extra-high reasoning is thorough — it also burns through tokens fast, worth knowing before you pick that setting.
Model: Claude Sonnet 5, run at high reasoning. Did the actual work on the live repository — reading the real files, editing them, running the deploys, and making the judgment calls documented below.
One more thing worth naming: no Figma touched this project. Every layout, spacing, and copy decision happened directly in code, checked in a live browser preview — not mocked up first and built second.
Everything from here on describes what happened inside that second part — the hands-on session with Claude Code against my real site.
It found a page I'd forgotten to delete
Before touching anything, it read through the whole site — every HTML file, every asset — and came back with a short list of things that didn't add up. A case study I'd removed from the homepage grid weeks earlier was still live at its own URL and still sitting in my sitemap, quietly indexable by Google with no way for a visitor to actually find it from the site itself. It also found a duplicate image, byte-for-byte identical to one already in use, just taking up space in every future deploy.
Neither of these were bugs I'd have caught by looking at the live site. They only show up when something actually reads the whole repo end to end and cross-references what's linked against what exists.
The tag wasn't missing. The image was wrong.
I'd noticed Telegram wouldn't show an image when I shared my own site — just text. My assumption was a missing meta tag. It wasn't. The tag was there, pointing at a real, reachable photo. The actual problem was quieter: the photo was a tall portrait crop with no width or height hints, the wrong shape entirely for how link previews are supposed to look, and probably already cached as "no image" by whichever platform had tried and failed to render it first.
The fix wasn't a new AI-drawn image of my face — that was explicitly avoided. It rendered my real photo and my site's real fonts and colors into a proper 1200×630 image using the site's own CSS, then shipped it under a new filename specifically so stale scraper caches wouldn't matter.
The most useful debugging step wasn't guessing at the fix — it was checking the actual response headers before assuming what was broken.
My site was invisible to Google. I didn't know.
While chasing the image issue, it noticed something unrelated: every single response from my live domain — including the homepage — was quietly telling search engines noindex. That header is only supposed to apply to my private staging environment. It had leaked into production somehow, meaning my actual public site had been asking Google not to list it, for who knows how long, entirely by accident.
It flagged it clearly, explained the likely cause — a mismatch in how the hosting platform reports which environment a deploy belongs to — and then didn't touch it, because fixing it wasn't part of what I'd asked for that turn. That distinction mattered more than I expected: it's the difference between an assistant that notices problems and one that also knows which ones are yours to decide on.
I pasted a photo. It wasn't actually me.
This is the part I keep coming back to. I'd been playing with an AI image generator earlier and pasted one of the results in, asking to use it as my new headshot. It looked right — same general vibe, professional, on-brand. Claude Code paused and asked, plainly: is this a real photo of you, or AI-generated?
It was generated. I said so.
It declined to use it — not because the image was low quality, but because putting a face on my professional site that isn't actually mine, presented as if it were, is a trust problem waiting to happen. Anyone who meets me on a call after seeing that photo would notice the mismatch immediately, and that's a bad way to find out someone wasn't straight with you. It offered real alternatives instead: a genuine new photo, or something clearly illustrated that never claims to be a literal picture of me.
Just use the image I asked for. Most of what I needed that day was execution — move this, fix that, deploy it.
This one was judgment, not execution — and it chose honesty with me over simply doing what I asked.
One page already worked. The rest didn't match.
One of my case studies already linked out to the live product at the end — a small "View live product" button. It hadn't occurred to me that the other five didn't have it. Once pointed out, it was an easy fix, but it also meant checking that every one of those links was still current — one of my old project URLs had actually moved to a new domain since I'd last touched that page, which it caught by searching rather than assuming the old link still worked.
Deploys fail for boring reasons too
Worth explaining how any of this actually reaches the live site: two git branches, staging and production, no continuous-deployment pipeline watching either one. Every change gets committed to staging and deployed there by hand first, and I review it on a staging URL before anything touches the real site — nothing goes to production without me explicitly saying so, every single time, no matter how small the change. More friction than letting a pipeline auto-publish on every push, and that's on purpose.
Not everything was a clean win. At one point, publishing to production failed with a bare "Forbidden" error that neither of us could fully explain — nothing wrong with the site, nothing locked, no clear cause visible anywhere. We tried again a few minutes later and it just worked. Separately, because I sometimes have more than one Claude Code session open on this same project, the git history briefly got into a confusing state — nothing was lost, it was rebuilt safely, but it was a good reminder that running parallel AI sessions against the same folder is a real thing to be careful about, not a hypothetical.
A dashboard button that mattered
I run this site on two domains now — kseniiamankovska.com and a second one, kmankovska.com — both pointing at the same place. Connecting the second one is where it got interesting: DNS was correct within minutes. The certificate wasn't — the browser flatly refused to trust the new domain, and an attempt to fix it through the hosting API got silently rejected with no explanation. What actually worked was a single "Renew certificate" button sitting in the hosting dashboard, which no API call could reach the same way. A good reminder that not everything can — or should — be automated away from a human clicking the right button once.
The last thing we set up was analytics — Google Analytics 4, properly, not just "add a tracking script and hope." Instead of hand-writing an event for every button, it turned on GA4's Enhanced Measurement, which covers most of what I actually wanted automatically: page views per project, scroll depth, outbound clicks broken down by destination (so I can see which "View live product" link people actually follow), and file downloads — including every CV pull.
And it didn't stop at "installed." It actually visited my own site to generate a real event, then had me pull up the Realtime report and confirm it showed up before either of us called it done. Trusting a checkbox that says "installed" is different from watching an actual visit land.
None of this was "generate me a website." It was a full day of the unglamorous work that comes after a website exists — the audits, the small honest refusals, the infrastructure that breaks for no visible reason, the analytics nobody bothers to verify actually fired. That's the part I didn't expect an AI collaborator to be useful for, and it's the part that ended up mattering most.
The biggest shift wasn't in what got fixed — it was in how much of the day was judgment calls rather than execution: what to flag versus fix outright, what to ask permission for, what to refuse. I went in expecting a tool. What I got was closer to a second, more literal-minded pair of eyes on my own site — one that reads every file instead of skimming the ones I remember, and says no when saying yes would have been easier for both of us.
If there's one thing I'd tell another designer trying this: the value isn't in one big generated output. It's in the small, honest moments along the way — the bug it caught that I didn't ask about, the photo it wouldn't use, the dashboard button no API could replace. Those are the moments worth remembering the next time someone asks what "building with AI" actually looks like.