← Blog

58 commits in 8 days — building a site that qualifies leads for me

10 min read
case-study ai portfolio astro build-in-public freelance

The problem: a portfolio site that does nothing

I build systems for clients — production rescues, MVPs, AI automation. But my own site was a static business card with a contact form. 80% of inquiries: “how much does an app cost” with zero context, $500 budgets for SaaS platforms, vague briefs.

Classic pattern: client writes, I ask about budget and timeline, they reply in 3 days, I ask follow-ups. After a week I have information I could’ve had in 10 minutes.

I decided to build a site that doesn’t just display a portfolio — but actively qualifies leads. The client talks to AI that collects full project context. I get a complete brief before writing my first email.

58 commits. 8 days. 5 integrations. Here’s what it actually looked like.

Days 1-2: From empty repo to working funnel (28 commits)

Foundation

First commit (1a99878) — Astro 6 with TypeScript, Tailwind CSS, Vercel. Why Astro? A portfolio site is 90% static content — it doesn’t need a React runtime on every page. But API endpoints (chat, payments, webhooks) need server-side rendering. Astro handles both natively.

Two-tier consultation system

Key commit (4657ef3). Two levels:

Free conversation — Claude Haiku classifies the query (project vs spam), then Sonnet handles qualification in 8 exchanges. Collects: problem, tech stack, budget, timeline, scale. Cost per session: pennies.

Premium consultation — 200 PLN (~$50) via Stripe. 25 exchanges with deep technical analysis. Sonnet at full power: architecture, recommendations, risks. The 200 PLN is deducted from project pricing.

Context continuity between tiers — the free session UUID is stored in Stripe Checkout metadata, the webhook links sessions in Supabase, Sonnet loads the free session summary into its system prompt. The client never repeats themselves.

5 commits to fix Stripe (reality vs plan)

No system works on the first deploy to production.

6ffbcf4  Fix checkout: use card only, add error details
69e7448  Fix Stripe on Vercel: use fetch HTTP client
5ad5dfa  Fix checkout URL: add process.env fallback for SITE_URL
661320f  Switch chat to query param route for Vercel compatibility
6e4c41b  Fix: trim STRIPE_PRICE_ID to remove trailing newline

A trailing newline in an environment variable — 30 seconds to fix once you find it, an hour to diagnose. Serverless is a different runtime than localhost. These things don’t appear in tutorials.

End of day 2

Working AI chat, Stripe payments, transactional emails (Resend), database (Supabase), contact form, JSON summaries. Complete MVP. Ugly, but functional.

Days 2-3: Prompt engineering (15 commits)

I wrote a separate deep-dive on this phase — because it turned out to be the hardest part of the project. Summary:

Identity crisis. The bot said “I build projects” — clients thought they were talking to me. Fix: third-person rule.

15 rules that conflicted. Every conversation bug = new rule. 15 rules = model loses track. Solution: trimmed to 10.

Gemini experiment. Haiku had poor Polish. Switched to Gemini 3 Flash — better language quality, but hallucinated experience (“Artur uses eBPF”). 4 commits to the trash. Full revert.

Breakthrough. A disclaimer saying “Technical findings will be verified by Artur” worked better than a list of 15 prohibitions. Context beats regulation.

Days 3-4: Architecture and cleanup

Silent Router

Commit a6d897f — new AI architecture. Haiku doesn’t run the conversation — it only classifies the first message (PROJECT/SPAM). Sonnet takes over from there. Result: better conversation quality, Haiku only as a cheap filter.

Visitor ID and chat history

Commits 2f08b79 and 2868c43. Visitor ID in localStorage, chat history visible on the consultation page. Client returns — sees their previous conversations. Zero logins, zero registrations. Every entry barrier is a potential lead walking away.

Privacy policy

Commit 911244f. GDPR requires disclosure about data processing and AI. Not a feature — a requirement. Two versions (PL + EN).

Days 5-8: Visual identity and funnel optimization

This is where the second phase began. The site works — now it needs to sell.

Visual redesign

Commit a56786f. Moved away from generic dark theme with cyan accents. New palette: dark background, warm brown, cream text. Typography: DM Serif Display for headings (architecture, solidity), Inter for body text.

Why brown? Because cyan says “generic tech startup.” Brown says “architect who builds solid systems.” Colors communicate positioning. If you don’t choose deliberately — you’re sending a random signal.

Copy rewrite

Commit 712188b. Every sentence on the site went through one filter: “does the client know what’s in it for them?”

Before: “Modern IT solutions for your business.”

After: “I stabilize systems, build MVPs, and automate processes.”

Zero adjectives. Verbs. Specifics. Nobody buys “modern solutions” — they buy someone who’ll solve their specific problem.

Homepage redesign

Commit 6cf0555. Asymmetric hero, solid CTAs, blueprint animations. Every homepage section has one job: drive traffic to /consultation. If a section doesn’t do that — it’s not on the page.

Funnel optimization

Commit b786ed2. Removed what didn’t convert:

Premium tier — nobody pays $50 to a stranger on the internet without talking to them first. Free diagnostics stays as the entry point. Premium can return later, once trust is built.

Tutoring services — diluted the positioning. The site should communicate one thing: “systems architect who solves problems.” Not “guy who teaches and builds and fixes and streams.”

Less = more. Every element on the site either drives toward a lead or actively blocks one.

Dark theme everywhere

Commit 652384d. Blog, portfolio, contact — all in dark theme with blueprint animations. Consistent visual identity. Seems cosmetic, but a client who goes from homepage to blog and sees a different design — loses trust.

Two contact paths — not one

The first version had a single funnel: homepage → AI diagnostics → lead. Simple, clean, elegant. And wrong.

The problem: not everyone wants to talk to a bot. A CTO who knows what they need prefers sending a three-sentence email. A CEO in a rush doesn’t have time for 8 exchanges with AI. Someone on mobile doesn’t want to write an essay in a chat window.

The solution: two paths.

Primary path — AI diagnostics. The bot collects context, generates a brief, I get ready material for a quote. The recommended path, promoted on every page.

Side path — contact form. Classic fields: name, email, service, problem description. For those who prefer direct contact. The contact page isn’t a dead end — there’s a banner at the top saying “Recommended: Start diagnostics” pointing to AI. But it doesn’t force it.

The CTABanner on the homepage has a subtle link under the main button: “Prefer to write directly?” — the only element on the page that leads to /contact instead of /consultation. Sufficient for those looking for an alternative. Invisible to those following the main funnel.

Lesson: one funnel isn’t always the best funnel. Sometimes the best conversion comes from giving people a choice — as long as you clearly recommend the preferred path.

The compromise: technical authority vs non-technical audience

The hardest design decision. The site needs to simultaneously:

  1. Build authority among technical people — CTOs, lead devs, DevOps engineers. They want to see the stack, architecture, case studies with metrics. “Shaka Player replacing Bitmovin” tells them more than “I optimized video costs.”

  2. Be accessible to non-technical people — CEOs, founders, managers. They have a business problem (“system is falling apart”, “I want to automate processes”) but don’t know what a webhook or RBAC is.

Too technical on the homepage scares away the CEO. Too simple doesn’t build trust with the CTO.

The solution: simple entry → depth on demand.

Entry pages (homepage, consultation) speak business language. Hero: “Your IT is eating budget?” — not “I optimize CI/CD pipelines.” Situation cards: “I want to automate processes” — click, AI guides the conversation without requiring technical knowledge.

Depth pages (blog, portfolio, case studies) deliver full technical content. This is where “Stripe webhook desync”, “PostgreSQL race condition”, “Claude Haiku triage + Sonnet conversation” appear. Whoever got here is either technical or engaged enough that terminology won’t scare them off.

CTAs are always simple — whether you’re on a technical deep dive or the homepage. “Have a similar problem? Describe it to AI.” Zero barriers, zero jargon in buttons.

SocialProof on the homepage deliberately bridges both worlds. Business metric: “Payment bug fixed in 3 days.” Technical context underneath in fine print: “Stripe webhook desync, PostgreSQL race condition.” The CEO sees the result. The CTO sees that I know what I’m talking about.

What came out of it

A system that works 24/7:

  1. Client lands on the site
  2. Clicks “Start diagnostics”
  3. AI runs the conversation — collects problem, tech stack, budget, timeline
  4. Generates JSON with full context
  5. I get an email with the brief — client gets a summary
  6. First human interaction starts from full understanding of the problem, not “how can I help?”

Concrete numbers

ElementValue
Pages16+ (PL + EN)
API endpoints5
IntegrationsAnthropic, Stripe, Supabase, Resend, Vercel
AI models2 (Haiku router + Sonnet conversation)
LanguagesPL + EN
Commits58
Build time8 days
Monthly cost~$0 (free tiers) + pennies per AI conversation

4 lessons learned

1. Build for yourself what you build for clients

Freelancers build lead-gen systems for clients — but run a contact form from 2015 on their own site. Your site is your most important product. If you can’t sell yourself, how will you convince a client you can sell their product?

2. Ship the ugly version, iterate fast

5 commits debugging Stripe. A trailing newline in an env variable. A process.env fallback on Vercel. These problems don’t show up in the plan — they show up in production. Production tells you what’s actually broken. Plans tell you what looks good on paper.

3. AI is a business tool, not a feature

The bot doesn’t exist so the site can have “AI.” It exists because qualifying leads was eating hours of my week. Now it costs pennies per conversation. If your AI implementation doesn’t solve a specific business problem — it’s a demo, not a product.

4. Removing code > adding code

The premium tier and tutoring services sounded good in theory. In practice, they diluted the message. The most important commit in the project is b786ed2 — which removes hundreds of lines of code. Every element that doesn’t drive conversion actively hinders it.

Timeline (full git log)

Days 1-2 (March 14-15):
1a99878  Initial commit — arturmrowicki.pl
4657ef3  feat: two-tier consultation system
         + 5 Stripe fixes on Vercel
         + emails, sessions, forms, summaries

Days 2-3 (March 15):
c8c8bee  fix: bot identity — never impersonate Artur
003a9c0  fix: harden bot prompts
fe01dd1  feat: switch to Gemini ← experiment
00e293e  revert: back to Haiku   ← revert
a6477b4  refactor: 15 rules → 10 ← breakthrough
e9af61a  feat: urgent form + Telegram

Days 3-4 (March 16-17):
c3eeac6  feat: dual-model chat (Haiku triage + Sonnet)
a6d897f  refactor: silent router
2f08b79  feat: visitor ID + chat history
911244f  feat: privacy policy

Days 5-8 (March 19-22):
a56786f  feat: premium visual redesign
712188b  copy: brutal professional rewrite
6cf0555  feat: homepage redesign
b786ed2  refactor: remove premium tier + tutoring
652384d  feat: dark theme everywhere

58 commits. 4 of them trashed. The system that came out of it is better than if I’d nailed it on the first try — because I know why every decision is the way it is.


Want to see it in action? Talk to the bot — it’ll collect context on your problem in 5 minutes. I get a full brief, you get a summary by email.

Building a SaaS, automating processes, or rescuing a system? Describe your situation — free diagnostics, response within 48h.

Have a similar problem?

Describe it to AI — it gathers technical context, Artur delivers a quote in 48h.

Start diagnostics