Back to Projects
Live

Kevin Lam Portfolio

A 30-schema content graph modeling an enterprise cybersecurity sales career as a queryable knowledge base

Solo EngineerSoloAug 2022 – Jan 2025
Next.jsTypeScriptTailwindCSSSanity

Overview

Role

Solo Engineer

Team

Solo

Timeline

Aug 2022 – Jan 2025

Stack

4 technologies

8 live case studies documenting $12.3M+ in deal value, filterable by role (AE/AM/CSM), deal size, and industry

The Problem

Situation

Kevin Lam is a B2B enterprise Account Executive with $140M+ in career ARR, a FIDO Alliance member, Forbes-featured, who sells FIDO2/WebAuthn/Zero Trust solutions to CISOs and VPs of IT across healthcare, government, financial services, education, and manufacturing. He had no digital presence — no portfolio, no case studies, no way to express the relational complexity of his career: accounts with multiple stakeholders, deals with compliance mappings across five regulatory frameworks (HIPAA, FedRAMP, CMMC, NIST, SOC 2), and quantified outcomes that should cross-reference each other. I built kevintlam.com from scratch as a 30-schema content graph where every concept in Kevin's sales career — accounts, deals, stakeholders, compliance frameworks, buyer personas, sales plays, impact metrics — is a first-class document type with typed references to related concepts.

My Goal

Build Kevin a headless CMS architecture from scratch that models his entire sales career relationally — enabling queries like 'show all healthcare deals above $1M with HIPAA compliance where the CISO was a champion' — while giving Kevin a Salesforce-like editing interface he can maintain independently, daily, without developer support.

My Approach

1

Designed a 30-schema content graph in Sanity v5 (7,469 lines of TypeScript) where every concept in Kevin's sales career — accounts, stakeholders, deals, compliance frameworks, buyer personas, impact metrics — is a first-class document type with typed relational references, enabling GROQ queries that traverse the full graph

2

Built 8 live case study pages with full STAR narratives, Recharts data visualizations driven by chartDataset schema, stakeholder maps with role enums (champion/blocker/influencer/economic buyer/technical buyer), deal timelines, and compliance framework mappings across HIPAA, FedRAMP, CMMC, NIST, and SOC 2

3

Implemented ISR revalidation pipeline: Sanity webhook fires to /api/revalidate on publish, HMAC-validates the signature, extracts document type and slug, calls revalidateTag() to rebuild only affected pages — a case study update rebuilds that page only, not the entire site

4

Built a dual-purpose interviewAnswer schema with an isPublic boolean — true renders on the About page as a public FAQ, false stays private STAR prep in Studio only. One document, two rendering paths, zero content duplication

5

Proxied PostHog analytics through kevintlam.com/ingest/* via 3 Next.js rewrite rules to bypass ad-blockers that block 30–50% of technical visitors when analytics load from third-party domains

6

Built a React Three Fiber 3D world (17 components, 2,076 lines) with CMS-driven zone overlays — the zoneNarrative Sanity schema drives both the 2D site and 3D world; content editors update zone text without touching Three.js code

7

Pair programmed with Kevin throughout, teaching Sanity Studio and GROQ by connecting to his MIS/SQL background — enabling him to maintain all 30 schema types independently and speak credibly about the architecture in interviews

The Outcome

8 live case studies documenting $12.3M+ in deal value, filterable by role (AE/AM/CSM), deal size, and industry

30 Sanity schema types across 8 business domains — Kevin edits content like a Salesforce record, independently, without developer dependencies

3x recruiter outreach within the first month of launch; site ranks on first page of Google for 'Kevin Lam sales' and related searches

PageSpeed 98 | 292 TypeScript files | ~54K lines | $0/month hosting (Vercel + Sanity free tiers)


Project Roadmap

MVP, stretch goals, and future vision

Project Roadmap

Development phases and milestones

100%
1/1 complete
1

Portfolio Website

MVP

Personal portfolio website for Kevin Lam

Website Launch

Complete portfolio website with project showcases

Completed
In Progress
Planned

Interview Questions

Common questions, answered in STAR format

Q1

Tell me about a time you helped someone learn a new skill.

SSituation
A junior developer on a previous project struggled with React hooks and state management. They kept creating bugs with stale closures and unnecessary re-renders, slowing down the team.
TTask
Help them understand React's mental model deeply enough to write clean, bug-free components without constant code review corrections.
AActions
  • Identified their specific knowledge gaps through code review patterns—they understood class components but not functional component lifecycle
  • Created a mini curriculum progressing from useState to useEffect to custom hooks
  • Pair programmed on real features rather than toy examples, letting them drive while I asked guiding questions
  • Drew diagrams showing how React's reconciliation works and when closures capture values
  • Assigned progressively harder tasks with immediate feedback loops
  • Documented common patterns in a team wiki so they could reference it later
RResult
Within three weeks, they were shipping features independently with minimal review feedback. Their code quality improved enough that they started catching similar issues in others' PRs. They later told me it was the first time someone explained 'why' instead of just 'what'.

Key Takeaway: Teaching technical concepts works best when you identify existing mental models and build bridges from there—this developer understood class lifecycles, so connecting hooks to that foundation accelerated learning dramatically.

Q2

Describe a project where the process was as important as the outcome.

SSituation
A startup I consulted for needed their MVP shipped fast, but the two junior devs on the team would need to maintain it after I left. Shipping quickly meant nothing if they couldn't iterate on it.
TTask
Deliver a working product while ensuring the team could understand, debug, and extend the codebase independently after my engagement ended.
AActions
  • Chose technologies they had some familiarity with rather than optimal-but-unfamiliar alternatives
  • Wrote extensive inline comments explaining non-obvious decisions
  • Created architecture decision records (ADRs) documenting why we chose certain patterns
  • Conducted code walkthroughs for every major feature before merging
  • Built debugging guides showing how to trace issues through the system
  • Intentionally left some 'stretch tasks' undone so they could practice extending the codebase while I was still available for questions
RResult
The MVP launched on time. More importantly, six months later the team had added three major features without external help. The CTO mentioned that previous consultants' code had been 'black boxes' they eventually rewrote, but ours they actually built on.

Key Takeaway: A codebase that the team can't maintain is technical debt from day one. The 'right' architecture is the one your team can actually work with—not the theoretically optimal one.

Q3

How do you adapt your communication style for different audiences?

SSituation
During a sprint planning meeting, a product manager, a designer, and two backend engineers were debating a feature's scope. Each group was talking past the others—PM focused on user metrics, designer on UX flows, engineers on data model constraints.
TTask
Bridge the communication gap so the team could align on a realistic scope that satisfied all stakeholders' core concerns.
AActions
  • Listened first to understand each group's actual constraints and priorities, not just their stated positions
  • Reframed the PM's metrics goals in terms of specific user behaviors the engineers could reason about
  • Translated the designer's UX concerns into data requirements that revealed the engineering complexity
  • Created a simple diagram showing how user actions mapped to backend operations, making tradeoffs visible
  • Proposed a phased approach that delivered the PM's key metric while deferring designer polish and engineering complexity
  • Followed up individually to ensure each stakeholder felt heard and understood the rationale
RResult
The team aligned on a scope in that meeting instead of the usual 2-3 follow-up discussions. The PM later asked me to facilitate other cross-functional discussions because 'you actually make people understand each other.'

Key Takeaway: Communication isn't about dumbing things down—it's about finding the translation layer between different mental models. Engineers think in systems, designers in flows, PMs in metrics. Good facilitation makes those perspectives compatible.

Technical Decisions

Why I chose X over Y

Kevin wanted to speak credibly about technology in tech sales interviews. Learning the current industry standard—not a simplified alternative—gave him relevant talking points. Plus, TypeScript's static typing connected well to his C/C++ background from San Jose State, making it easier to learn than dynamic JavaScript.

We evaluated both for Kevin's specific needs. Tina CMS has excellent visual editing and Git-backed content, but Sanity won on: (1) Cross-references—Kevin's case studies needed to link to skills, companies, and testimonials; (2) Reverse lookups—showing which case studies use which skills; (3) Better account management for a single-user portfolio; (4) Growth potential if Kevin's site expands; (5) Metrics dashboards in Sanity Studio. Tina's visual editing was appealing, but Sanity's structured content model better served Kevin's interconnected portfolio content.

GROQ's syntax resembles SQL, which Kevin learned in his MIS database courses at San Jose State. Queries like *[_type == 'caseStudy'] felt familiar compared to his old SELECT * FROM case_studies memories. For a personal portfolio with a non-developer maintaining it, teaching something that connected to his existing mental model made more sense than GraphQL—which I'd use for a developer like Sean who would benefit from the industry-standard transferable skill.

Used driver-navigator with Kevin driving most of the time. Started each session reviewing what we'd built previously, explained the goal for the session, then coded together with lots of 'what do you think should happen here?' questions. Ended with Kevin summarizing key concepts. This kept him active rather than passive.

Created explicit bridges to his San Jose State background: 'Remember classes in C++? Components are similar—encapsulated, reusable units.' Avoided jargon when possible, and when I used it, immediately explained it. Focused on concepts over syntax—once Kevin understood the 'why', the 'how' followed more easily.

Built progressively simpler documentation as we went—not technical docs, but 'how to do X' guides written for Kevin specifically. Had him make real updates during our sessions so the process became familiar. Sanity Studio's intuitive interface made this easier than expected—Kevin could navigate the content structure visually and GROQ queries he'd written made sense to him because of the SQL parallels. Kept the codebase simple enough that Kevin could read and understand it.


Key Trade-offs

Every decision has costs

Sanity CMS over a Postgres relational database

Gained

  • +Content editors get Sanity Studio — a visual UI they can use without SQL
  • +GROQ traverses references natively: one query joins accounts, stakeholders, and compliance frameworks
  • +Real-time collaborative editing out of the box
  • +30 schema types deployed without migrations or downtime

Gave Up

  • GROQ is niche; a developer joining the project must learn it
  • Free tier limits (100k API requests/month) require monitoring
  • No raw SQL for ad-hoc analytical queries

Why Worth It

Kevin needs to update content daily without touching code. Sanity Studio gives him a Salesforce-like interface he already understands; Postgres would require a custom admin UI or technical help for every update.

30 typed schema types over a flat document/text model

Gained

  • +Every concept — account, stakeholder, deal, compliance framework, buyer persona — is queryable and filterable in Studio
  • +Cross-references enable portfolio views like 'all HIPAA deals with champion CISOs'
  • +Type safety across 7,469 lines of schema TypeScript catches errors at author time, not runtime

Gave Up

  • Significantly higher upfront modeling effort vs. a blog CMS
  • Schema changes require careful migration planning
  • Kevin must understand the document graph to use Studio effectively

Why Worth It

Kevin's career story is inherently relational. Flat text hides the complexity that makes him impressive; typed references expose it as queryable, filterable data — exactly what enterprise hiring managers want to see.

ISR with selective revalidation over full SSG or pure SSR

Gained

  • +Sanity webhook fires to /api/revalidate on publish → HMAC-validated → revalidateTag() rebuilds only affected pages
  • +A case study update rebuilds that page only, not the entire site
  • +Kevin sees changes live within seconds, not after a 2-minute full rebuild

Gave Up

  • Webhook infrastructure adds operational complexity
  • HMAC signature validation logic must be maintained
  • Stale-while-revalidate window means very briefly stale responses

Why Worth It

Kevin updates content daily. Full rebuilds would mean 90-second lag on every save. Selective ISR turns Sanity Studio into a real-time publishing tool without sacrificing static performance.

Dual analytics (GA4 + PostHog) with PostHog proxied through kevintlam.com/ingest/*

Gained

  • +PostHog proxied via 3 Next.js rewrite rules bypasses ad-blockers that block 30–50% of technical visitors
  • +GA4 for SEO and search console integration; PostHog for session replay and funnel analysis
  • +Kevin sees which case studies recruiters actually read, not just which pages they land on

Gave Up

  • Dual analytics means reconciling two data sources
  • Proxy rewrites must be updated if PostHog changes their ingestion endpoint
  • Small performance overhead from two analytics payloads

Why Worth It

Kevin's audience is enterprise tech buyers and security-conscious recruiters — exactly the people most likely to run ad-blockers. Unproxied analytics would be invisible for 30–50% of his most important visitors.

Heavy client bundle (Three.js + D3 + Recharts + GSAP) vs. lightweight static site

Gained

  • +3D world, animated data visualizations, and scroll-driven transitions make the site impossible to forget at a glance
  • +Differentiates Kevin from 99% of sales portfolios which are PDFs or LinkedIn pages
  • +Visual complexity signals technical depth to engineering-adjacent hiring managers

Gave Up

  • Lighthouse performance score is lower than a typical Next.js site
  • Mobile experience is notably slower due to Three.js rendering overhead
  • Longer initial load on slower connections

Why Worth It

Kevin is not applying for Lighthouse score jobs. He is competing for enterprise sales roles where standing out in 10 seconds matters more than a 98 performance score. The bundle is a deliberate product decision, not a failure.

React Three Fiber over vanilla Three.js

Gained

  • +17 Three.js components integrate cleanly into Next.js component tree without imperative scene management
  • +CMS-driven zone overlays: zoneNarrative Sanity schema drives both 2D site and 3D world — content editors update zone text without touching Three.js code
  • +React's reconciler handles disposal and re-renders when CMS content changes

Gave Up

  • R3F abstraction adds a learning curve on top of already-complex Three.js concepts
  • Debugging requires understanding both React and Three.js mental models simultaneously
  • Bundle includes both React and Three.js runtimes

Why Worth It

The CMS-driven zone overlay requirement made this decision clear: vanilla Three.js would need manual DOM reconciliation to sync with Sanity content. R3F's declarative model meant a Sanity schema change propagates to the 3D world through normal React re-rendering — no imperative scene surgery.

Challenges & Solutions

The hardest problems I solved

1Kevin had MIS background from San Jose State but years of gap—modern JavaScript ecosystem was overwhelming

Approach

Started with concepts he knew from his MIS coursework (HTML/CSS, basic programming logic) and built bridges to modern equivalents

Solution

Drew parallels: 'TypeScript interfaces are like the structs you learned in C', 'npm is like package managers you might remember'. Pair programmed everything so he saw concepts in context rather than abstract tutorials

Lesson: Rusty developers aren't beginners—they have mental models to build on. Honor their existing knowledge while updating it.

2No existing brand guidelines or professional photos to work with

Approach

Conducted a mini brand workshop, teaching Kevin about personal branding for tech while gathering design direction

Solution

Created a simple but professional design system together. Used high-quality stock imagery strategically while planning for future professional photos

Lesson: Constraints drive creativity. Limited assets forced us to focus on typography, whitespace, and content quality.

3Balancing Kevin's learning pace with getting a polished product launched

Approach

Identified which parts were best for learning vs. where I should lead to maintain quality and momentum

Solution

Kevin drove on components and content areas where mistakes were recoverable; I led on architecture and critical path items while explaining decisions

Lesson: Mentorship on real projects requires intentional task allocation—not everything is equally suited for learning.

4Presenting Kevin's sales metrics impressively without coming across as boastful

Approach

Drew on Kevin's sales training—he understood the difference between bragging and demonstrating value

Solution

Framed achievements in terms of business impact with specific numbers, letting metrics speak for themselves. Used testimonials to add third-party validation

Lesson: Sales professionals often have better instincts about self-presentation than developers—leverage their expertise.

What I Learned

  • A content schema is a domain model first; the CMS is an implementation detail. Modeling Kevin's career as distinct concepts (account, stakeholder, compliance framework) unlocked query power that flat text fields never could
  • Dual-purpose content (isPublic boolean) eliminates drift between private interview prep and public-facing copy — the same STAR answer serves both audiences without duplication
  • Pair programming with a non-developer while building their product accelerates both quality and ownership: Kevin maintains all content independently and can discuss the architecture in interviews because he built it alongside me
  • ISR selective revalidation is worth the webhook complexity — per-page cache invalidation on Sanity publish means Kevin sees changes in seconds without full rebuilds
  • Heavy client bundles are a deliberate product decision, not a failure: Three.js + D3 + Recharts + GSAP make the site unmemorable at a glance impossible, which matters more than Lighthouse scores in enterprise sales hiring

Future Plans

  • +Mobile-optimized 3D experience — the Three.js world is currently notably slower on mobile due to the heavy client bundle
  • +Private /interview-prep dashboard with full-text search and filtering across all STAR answers by category and case study reference
  • +Automated weekly SEO digest: GA4 data → email report showing which case studies and compliance keywords are driving inbound traffic
  • +Expand compliance mapping to include EU AI Act and emerging frameworks as Kevin's territory evolves