← All Posts

Setting Up an AI-Built Portfolio on a New Machine

5 min readMarch 5, 2026
setupdevopstursovercelclaude-codeguide

Setting Up an AI-Built Portfolio on a New Machine

Setting Up an AI-Built Portfolio on a New Machine
Setting Up an AI-Built Portfolio on a New Machine

I built this entire site through Claude Code — no traditional IDE, no manual coding. But what happens when I need to work from a different machine? Here's the full setup guide, including every gotcha I discovered.

What You Need

Before anything else, make sure you have:

  • Node.js 20+ — the runtime
  • Git — version control
  • npm — package manager (comes with Node)

Everything else gets installed by the setup script.

The CLI Toolchain

This project depends on four CLI tools beyond Node:

ToolPurposeInstall
ghGitHub CLI for auth and repo managementbrew install gh or cli.github.com
vercelDeployment CLInpm install -g vercel
tursoDatabase CLI for cloud SQLitecurl -sSfL https://get.tur.so/install.sh | bash
claudeClaude Code for AI-assisted developmentnpm install -g @anthropic-ai/claude-code

Each needs authentication:

gh auth login          # GitHub
vercel login           # Vercel
turso auth login       # Turso
# Claude Code authenticates on first run

Clone and Configure

git clone https://github.com/carlfung1003/ai-journey.git ~/ai-journey
cd ~/ai-journey
npm install
npx prisma generate

The Git Email Gotcha

This one cost me hours. Vercel's GitHub integration rejects deploys if the git author email doesn't match the Vercel team. My work email gets blocked. The fix:

git config user.email "carlfung1003@users.noreply.github.com"
git config user.name "carlfung1003"

Set this per-repo (not global) if you use different emails for different projects.

Database Credentials

The site uses Turso (cloud SQLite). You need three environment variables in .env:

TURSO_DATABASE_URL=libsql://your-db.turso.io
TURSO_AUTH_TOKEN=your-token-here
ADMIN_PASSWORD=your-admin-password

Get the credentials from Turso CLI:

turso db show ai-journey --url    # Database URL
turso db tokens create ai-journey  # Auth token

The ADMIN_PASSWORD is whatever you choose — it protects the admin API endpoints for managing content.

Verify Everything Works

# Build the site
npx next build

# Start dev server
npm run dev

# Test the admin API
curl -s http://localhost:3000/api/admin/posts \
  -H "Authorization: Bearer your-password" | head -c 200

If the build succeeds and the API returns posts, you're good.

Claude Code Skills

The site was built with these Claude Code skills. Install them in a Claude Code session:

SkillWhat It Does
senior-frontendReact/Next.js patterns, component architecture
frontend-designVisual design, animations, CSS
vercel-react-best-practicesSSG optimization, performance
senior-fullstackPrisma, API routes, data architecture
senior-backendCRUD endpoints, auth patterns
git-commit-helperCommit message generation

Find and install with /find-skills <name> inside Claude Code.

Deploy Pipeline

The deploy pipeline is simple:

  1. Make changes locally (via Claude Code or manually)
  2. git push origin main
  3. Vercel auto-deploys via GitHub integration
  4. Site is live in ~45 seconds

No CI/CD config needed — Vercel handles it.

Content Sanitization

This is critical. The site is public but content often originates from work context. Every piece of content must be sanitized before publishing.

What to Remove

  • Company names and project codenames
  • Team member names
  • Internal IDs (Confluence pages, Google Sheets, Slack channels)
  • Internal URLs

What to Replace With

Use generic terms: "my company", "a major finance platform", "the product", or role-based references like "the engineering lead" instead of names.

What's Safe to Keep

Claude Code, MCP, Atlassian MCP, Glean MCP, Confluence (as a generic tool), model names (Opus/Sonnet/Haiku), desk CLI.

Audit Before Every Push

grep -ri "your-company\|your-project\|internal-terms" src/lib/constants.ts

If it returns matches, fix them before pushing.

Admin API Quirks

A few things that aren't obvious:

  • Dev server must be running (npm run dev) to use the admin API
  • PUT expects published as string "true", not boolean — the endpoint does data.published === "true"
  • PUT requires the id field (a cuid like cmm6o...), not the slug
  • POST creates with published: false by default — follow up with a PUT to publish

Four Gotchas That Will Save You Time

1. Vercel Build Cache Serves Stale CSS

You push a visual overhaul. Vercel says "Ready." But the site looks exactly the same. The build cache is serving old CSS bundles.

Fix: Push an empty commit to force a clean rebuild:

git commit --allow-empty -m "Force rebuild: clear Vercel cache"
git push origin main

Verify by comparing the deployed CSS file size against your local .next/static/chunks/*.css.

2. Prisma orderBy Doesn't Work with Turso

Prisma's orderBy clause is silently ignored by the Turso (libSQL) adapter. Your blog posts will show in database insert order instead of date order.

Fix: Always sort in JavaScript after fetching:

function sortPostsByDate(posts: PostData[]): PostData[] {
  return posts.sort((a, b) => {
    const da = a.publishedAt ? new Date(a.publishedAt).getTime() : 0;
    const db = b.publishedAt ? new Date(b.publishedAt).getTime() : 0;
    return db - da;
  });
}

3. Keep Both Data Sources in Sync

The site uses a DB-first pattern with static fallback. When adding content, you must update both:

  • The Turso database (via admin API POST)
  • The SAMPLE_* arrays in src/lib/constants.ts

If you only update one, the site works but the fallback data is stale. If Turso goes down, visitors see outdated content.

4. Sanitize Everything

Run the audit grep before every content commit. It takes 2 seconds and prevents accidentally publishing internal references to a public site.

The Setup Script

All of the above is automated in setup.sh at the repo root. On a fresh machine:

git clone https://github.com/carlfung1003/ai-journey.git
cd ai-journey
bash setup.sh

It checks prerequisites, installs CLI tools, authenticates services, configures git, creates .env, and runs a verification build. Takes about 5 minutes.

What's Different from a "Normal" Dev Setup

The biggest difference: there's no IDE in this workflow. No VS Code, no WebStorm. The entire development loop — reading code, writing components, debugging, committing — happens through Claude Code in the terminal.

This means the setup is actually simpler than most projects. No editor extensions to install, no linter configs to sync, no debugger to attach. Just a terminal, Claude Code, and the CLI tools.

The tradeoff is that your development speed depends on prompt quality. Clear, specific prompts produce better code faster. Vague prompts produce vague code. The skills help by giving Claude Code domain expertise, but the developer's clarity of thought is still the bottleneck — same as it's always been.