March 18, 2026
Building a Full-Stack Career Intelligence Dashboard in One Day with Claude Code and gstack
From zero to 64 commits, 7,500 lines of source code, and a production AWS deployment in a single sitting.
My niece is graduating from Vanderbilt and diving into climate tech, an industry where the job market is scattered across government portals, niche boards like Climatebase, random company career pages, and the usual aggregators. She’d need to check half a dozen sites daily just to stay on top of it.
I wanted to build her something that would do that automatically. Scrape all the sources, score every listing against her background, track her applications, and email her a daily digest. A personal career dashboard, built specifically for her.
I also wanted to build it in a day.
The tools
Claude Code is Anthropic’s CLI agent for software engineering, not autocomplete, more like a collaborator that lives in your terminal. I used it for everything: architecture, adapters, UI, Terraform, Lambda debugging, tests.
gstack is Garry Tan’s skill pack for Claude Code. It adds opinionated workflows for design systems, QA, code review, shipping, and more. I had 15 skills available. I used two of them well, and looking back, I should have used several more.
What got built
The app is a SvelteKit frontend with five main views: dashboard, application tracker, company directory, profile, and scrape history. Under that sits a scraper pipeline that pulls from six sources (JSearch, Climatebase, USAJobs, Adzuna, company career pages, WA State jobs), deduplicates, filters by location, and inserts into DuckDB. Three of those adapters use APIs directly; the other three use Playwright because the sites render everything client-side.
AI scoring happens through AWS Bedrock. Batch 5-10 jobs per API call, get back a 0-100 fit score and a one-line explanation for each. Daily email digest goes out via SES. The whole thing runs on Lambda with EventBridge scheduling, DuckDB syncing to S3 for persistence. Terraform handles everything, with shared modules so the same configs deploy locally (via robotocore/LocalStack) and to prod.
How the day went
Morning: foundation
First commit laid down the SvelteKit skeleton: routing, database schema, the first two adapters (JSearch and Climatebase), AI scoring, and a working dashboard.
The adapter pattern fell into place early, a TypeScript interface with Zod validation that every source implements:
interface SourceAdapter {
fetch(searchTerms: string[]): Promise<RawJob[]>
isHealthy(): Promise<boolean>
}
Once this existed, adding a new source was mechanical. Describe the API or page structure to Claude Code, get back a complete adapter with schema validation, error handling, and test fixtures. Each one took a few minutes.
Midday: infrastructure + email
AWS deployment (ECS Fargate initially), the SES email digest, USAJobs adapter for federal positions, and Playwright-based scraping for the JS-rendered career portals.
Afternoon: serverless migration
This is where it got interesting. ECS was overkill for a single-user app, so mid-afternoon I decided to migrate to Lambda. Claude Code rewrote the database layer for Lambda’s ephemeral filesystem, split into two Lambda functions (web + scraper), and wired up EventBridge for scheduling.
This phase generated 20+ commits. Playwright on Lambda was a real pain, it needed @sparticuz/chromium, specific sandbox flags, and eventually a singleton browser pattern to stop concurrent invocations from crashing each other. Having Claude Code in the loop made this bearable. I’d paste the error, it would diagnose and fix, and we’d move on. That Playwright-on-Lambda saga alone would’ve eaten a full day without it.
Late afternoon: local dev parity
Full local/prod parity via docker-compose and robotocore. Same Terraform modules deploy against robotocore locally and AWS in prod. Secrets flow from .env to Terraform to Secrets Manager to resolveSecrets(). I could test the entire pipeline locally without touching AWS.
Evening: polish + QA
Features were done, so I ran /qa. It launched the headless browser, tested every page, and found real issues: the scrape button needed a spinner and cooldown, toast notifications were missing, empty states looked bad. Each fix got a screenshot before and after.
I manually added the last two adapters (WA State and Adzuna) to close out the night.
Where gstack helped
Two skills earned their place:
/design-consultation ran before the first commit. It researched comparable tools (Linear, Raycast, Notion), had a conversation about the aesthetic I wanted (“industrial but warm, like opening this app should feel like sitting down at a clean desk with a warm coffee”), and produced DESIGN.md. Typography choices (Instrument Serif for display, DM Sans for body), a sage green and warm amber palette, score badge color system, spacing rules, layout grid, motion guidelines. Every visual decision for the rest of the day pointed back to this file.
/qa ran two or three times during the build. I can see 19 screenshots across three testing passes in .gstack/qa-reports/. The first pass at noon caught issues right after the initial feature push. A second pass mid-afternoon tested login flows, job detail pages, filtering, and all the core views. A third pass later tested with real scraped data. The QA findings commit at 12:01 PM added new TODOs for issues found during testing.
Where I should have used gstack more
Looking at the 15 skills that were available and the commit history, there are clear missed opportunities:
/design-review never ran. After 60+ commits of feature churn, infrastructure rewrites, and UX fixes, the UI almost certainly drifted from DESIGN.md. /design-review does an 80-item visual audit against the design system and fixes spacing, typography, and color inconsistencies with atomic commits. I should have run it after the serverless migration stabilized, probably around 9 PM when features were complete.
/review (the staff engineer code review) never ran. It looks for the stuff that passes CI but breaks in production: race conditions, missing env vars, bad retry logic. The in-memory digest cooldown bug that required a late fix (my second-to-last commit the next morning) is exactly the kind of thing /review catches. So are the missing Terraform env vars that caused production debugging.
/debug would have helped during the Playwright-on-Lambda saga. That was 11 consecutive fix commits over about 4 hours, clearly a trial-and-error pattern: add sandbox flags, change base images, revert actions, disable adapters, try different libraries. /debug enforces an investigation-before-fix discipline and stops after 3 failed attempts to force you to rethink. That structure could have shortened a 4-hour debugging session considerably.
/plan-eng-review should have run before the serverless migration. Moving from ECS/Fargate to Lambda touched the database layer, deployment pipeline, Terraform, and all the adapters simultaneously. An engineering review with architecture diagrams and edge case analysis might have surfaced the Playwright-on-Lambda compatibility issues before they turned into an afternoon of debugging.
/ship could have kept the branch workflow cleaner. The repo has two stale feature branches (feat/phase-2-deployment-email-adapters and feat/serverless-migration) that were started but never properly closed out. /ship handles the sync-main, run-tests, push, create-PR loop and would have kept things tidier.
/retro after the build would have been useful documentation. It analyzes commit history and produces a retrospective with metrics: fix ratio, hotspot files, test coverage trends, shipping streaks. After a 20-hour build session, that’s good data to have.
What I learned about the workflow
Adding a new adapter was almost entirely hands-off. “Add an Adzuna adapter” turned into a complete implementation with API client, Zod schema, error handling, and tests. I’d review it, maybe adjust something, and commit. That loop stayed fast all day.
Lambda debugging was where the model helped most. Instead of bouncing between CloudWatch, Stack Overflow, and my editor, I’d paste the error and Claude Code would figure it out. Though in hindsight, the /debug skill’s structured approach would have been better than the raw back-and-forth.
Terraform came out mostly right on the first pass. Lambda, EventBridge, S3, SES, Secrets Manager, IAM policies with correct resource relationships. IAM is never right the first time, but the iteration cycle was quick.
What still needed me: deciding to migrate from ECS to Lambda, choosing DuckDB over PostgreSQL, the design direction, which job boards to scrape, how to weight the scoring. Those were conversations, not things I could delegate.
A few technical decisions worth noting
I went with DuckDB over PostgreSQL because this is a single-user Lambda app. No connection pooling headaches, no managed database costs, instant cold starts, and DuckDB’s analytical query performance is great for this use case. It syncs to S3 for persistence.
Jobs show up on multiple boards, so there’s a two-tier dedup: exact URL match catches re-scrapes, fuzzy title+company match catches the same role posted to different sources.
The hardest bug was concurrent Lambda invocations each launching their own Chromium instance, then crashing with “Target page, context or browser has been closed.” Fixed it with a module-level singleton and a mutex-like promise chain.
The final tally
Empty directory at 11:27 AM, production app at 10:10 PM:
- 6 job source adapters (3 API, 3 Playwright)
- AI-powered fit scoring via Bedrock
- Kanban application tracker with drag-and-drop
- Company ecosystem view with hiring status
- Daily email digest via SES
- Full AWS infrastructure (Lambda, EventBridge, S3, SES, Bedrock, Secrets Manager)
- Local dev environment with cloud parity
- 117 tests (108 unit + 9 E2E)
- Dark/light mode design system
- 64 commits
The biggest lesson wasn’t about Claude Code. It was about gstack. I had 15 specialized skills available and used 2 of them. The skills I skipped, /design-review, /review, /debug, /plan-eng-review, would have caught bugs earlier, shortened the Lambda debugging saga, and kept the codebase cleaner. Next time I’ll treat them less like optional extras and more like checkpoints in the build.
Built with Claude Code and gstack on March 18, 2026.