feat: Phase 2 — AI chat platform with recruiter assistant#21
feat: Phase 2 — AI chat platform with recruiter assistant#21
Conversation
Sprint 1 Status: Complete ✅Sprint 1 establishes the foundational architecture for Phase 2. All code builds, passes TypeScript, and all 315 existing tests pass. This is a working skeleton — the chat UI renders, the API route accepts requests, and the resume page is fully functional at What's implementedRoutes:
Architecture:
Key AI SDK 6 patterns (for future contributors):
What needs live testingThe chat functionality requires How to continue contributingThis is a long-lived feature branch. Push commits here and the PR updates automatically: git checkout feat/phase2-implementation
# make changes
git add <files> && git commit -m "feat: ..."
git push origin feat/phase2-implementationSprint 2+ work items are tracked in References
|
Recommended Next StepsImmediate (Sprint 1 cleanup)
Sprint 2 (Recruiter Complete + Resume Gen)
Sprint 3 (Job Tools Core)
DevOps (Plan 2C — can happen anytime)
Human steps (before production deploy)
|
praeducer
left a comment
There was a problem hiding this comment.
Detailed Code Review: Phase 2 Sprint 1 Implementation
Excellent work on laying the foundation for Phase 2. The shift from a purely static site to a mixed-rendering architecture with Next.js App Router and the Vercel AI SDK is implemented cleanly.
I have thoroughly reviewed the changes on feat/phase2-implementation and compared them against docs/technical-design-document.md and the Phase 2 plans. Here is the feedback:
What's Great
- Clean Route Restructure: Moving the resume to
/resumeand setting up the chat on/was executed perfectly, maintaining existing layout structures. - Context Loader Design:
lib/agent/context.tsdoes a fantastic job concatenating knowledge base JSON files and utilizing gray-matter to parse system prompts.stripEmptyis an elegant way to reduce token usage for the LLM system prompt. - Component Architecture: Utilizing
@assistant-ui/reactprimitives rather than fighting a monolithic component gives you maximum flexibility for the complex custom UI in 'Tools Mode'.
Areas for Improvement / Critical Issues
-
Rate Limiting Fail-Open Risk (CRITICAL)
Inapp/api/chat/route.ts, the rate limiter initialization includes acatchblock that defaults to{ success: true }. While this is great for local development where Upstash env vars are absent, in production if the Redis connection fails or times out, the API will fail open. This risks unbound requests to the Anthropic API and potentially massive billing spikes.
Recommendation: UseNODE_ENV === 'development'to determine if it should fail open. In production, fail-closed or implement a simple in-memory fallback. (I've created Issue #25 for this). -
Missing maxDuration in API Route
app/api/chat/route.tsdoes not export amaxDurationconfig. Vercel Pro defaults to 15s. The Claude Sonnet model can easily take longer than 15s to stream a complete response, which will result in Vercel aggressively terminating the function mid-stream with a 504 Gateway Timeout.
Recommendation: Addexport const maxDuration = 60;to the route. -
Error Handling for LLM API
There's notry/catchwrapping thestreamText()call. If Anthropic returns a 529 (Overloaded) or 400 error, it will throw an unhandled exception. Consider returning a graceful fallback response to the user so the chat UI doesn't crash opaquely. -
Vercel Build Target (
process.cwd())
Inlib/agent/context.ts, you useprocess.cwd()to locatelib/prompts/.... This usually works via Vercel's NFT (Node File Trace), but sometimes Markdown files are not automatically bundled into the serverless function output.
Recommendation: Consider addinglib/prompts/**/*to theoutputFileTracingIncludesinnext.config.tsto guarantee the files are available at runtime.
Next Steps
Once these issues are patched, the underlying codebase for the chat agent will be extremely robust. I will be following up with a meta-plan analyzing the 4 main Phase 2 plans from multiple stakeholder perspectives to guide the rest of the implementation.
Route restructure: chat homepage at /, resume moved to /resume. Backend: /api/chat with mode switching (chat/tools), career context loader, system prompts for recruiter Q&A and job search tools. Frontend: assistant-ui primitives (Thread, Composer, ActionBar), mode toggle, quick action chips, bidirectional navigation. All 315 tests pass, build succeeds, TypeScript clean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply validated suggestions from multi-stakeholder code review: - Add `export const maxDuration = 60` to chat API route (explicit Vercel Fluid Compute timeout for streaming responses) - Wrap streamText() in try/catch with user-friendly error messages for Anthropic API failures (529 overloaded, auth errors, etc.) - Add console.warn logging when Upstash rate limiter falls back to no-op (observable in Vercel function logs for debugging) - Add outputFileTracingIncludes to next.config.ts ensuring Vercel bundles prompt templates and data files for the chat API route - Add Anthropic API spending limits to human-steps as defense-in-depth - Add API smoke test (POST empty body → 400) to Plan 2C - Add "Frame Tools mode" UX item to Plan 2B for Sprint 2 - Document assessment of all review items in meta-improvement plan (SEO concern rejected — Next.js pre-renders client components) Addresses GitHub Issue #25. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
0aa54ba to
357dbea
Compare
Code Review Fixes Applied (357dbea)Reviewed Gemini Pro 3.1's multi-stakeholder code review with independent web research. Applied validated fixes, rejected incorrect claims. Applied ✅
Rejected ❌
Full assessment: |
- Add /tools route for Paul's personal job search tools (noindex) - ChatHome accepts mode prop instead of URL params — simpler, no Suspense needed - Remove ModeToggle from header — recruiters see only "Ask About Paul" chat - Update Plan 2B with finalized design decisions: - Single unified UI for recruiters/HMs at / - Tailored resume generation as inline chat feature (Sprint 2) - Welcome message: elegant, memorable, focused on target audience - Chat always present — content generation happens in thread - Delete meta-improvement plan (all Gemini feedback addressed, Issue #25 closed) - Fix next.config.ts comment, clean up blank lines Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SectionNav and BackToTop were copied to app/resume/components/ during Sprint 1. ModeToggle was replaced by route-based mode switching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Chat mode now shows Paul's name, title, career summary, and CTA. Tools mode keeps existing description. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New prompt template for tailored resume generation with G9/G10 grounding rules and tailoring strategy. PromptMode now supports "chat" | "tools" | "resume-generator". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two tools for chat mode: generate_tailored_resume (calls Opus for JD-optimized resumes) and get_resume_links (returns download URLs). Bumps maxDuration to 120s for tool execution. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New "Tailored resume" chip in chat mode prompts users to share a job description for AI-generated resume customization. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Install @testing-library/react, @testing-library/jest-dom, jsdom. Configure vitest to use jsdom for .tsx tests and add @ path alias. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- context.test.ts: career context loading, system prompt modes, stripEmpty - quick-actions.test.tsx: chip counts, click handlers, tailored resume chip - chat-home.test.tsx: welcome message content per mode, UI elements - chat-api.test.ts: input validation (400 responses) - vitest.config.ts: include .tsx tests, add @ path alias Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove static export config (framework: null, outputDirectory: out, deploymentEnabled: false). Add API cache headers with noindex. Update CSP to allow Vercel Analytics scripts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 2 uses server rendering, not static export. The build output is now .next/ instead of out/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Homepage now checks for "AI Career Assistant" (chat page title). New checks: /resume page content and /api/chat 400 validation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Check .next/BUILD_ID instead of out/index.html. Remove HTML content marker checks (covered by other tests). Update tests to match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CLAUDE.md: update phase status, tech stack, routes, file org - README.md: chat-first platform description, routes table, updated tech stack and architecture diagram - TDD: update agent architecture with tool-calling, Sprint 2 status Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mark completed items in phase2a (tools, tests), phase2b (welcome, tailored resume, cleanup, tests), phase2c (all done). Update backlog and human-steps-phase2 with confirmed status. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Archive phase2a/2b/2c plans (all complete) - Create remaining-work.md with pre-merge checklist and backlog - Update TDD: model routing table, roadmap status, references - Fix CONTRIBUTING.md: stale "static export" and co-author line Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 2 Complete — Phase 2 Ready for MergeSprint 2 has been implemented on top of the Sprint 1 work. The branch now has 19 commits and 337 tests (up from 315). Sprint 2 Changes (13 commits)Core Features:
Testing:
Infrastructure:
Documentation:
Cleanup:
Pre-Merge Blockers
What's NOT blocking merge (backlog)
|
Add try-catch around request.json() for deterministic 400 on malformed JSON. Add message count limit (50) and body size limit (100KB/413). Expand test suite from 3 to 10 cases covering invalid JSON, null body, array body, oversized payloads, and message count overflow. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add providerOptions.anthropic.cacheControl to streamText() and generateText() calls. The system prompt (~90K tokens of career data) is cached with 5-min ephemeral TTL, reducing costs ~90% after first turn in a conversation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update docs/devops.md, TDD, and .claude/commands/ to reflect server-rendered architecture (no more output: 'export' or out/). Remove legacy out/ test block from pipeline.test.ts (always skipped on Phase 2 anyway). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CHANGELOG follows Keep a Changelog format with SemVer. Documents Phase 1 (v1.0.0) and Phase 2 (unreleased) milestones. SECURITY.md provides responsible disclosure instructions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11 smoke tests covering page rendering (homepage, resume, tools), navigation, API validation (400 on bad input), and chat interaction with mocked streaming responses. Uses Chromium headless with dev server on port 3001. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Increase tailored resume maxOutputTokens from 4096 to 8192 — full 2-page resume with certs/skills was hitting the token limit, causing truncated markdown and missing download links - Add min-h-[44px] to quick action chips on mobile (WCAG touch target minimum). Desktop retains compact sizing via sm:min-h-0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Archive chrome-qa-plan.md (executed, both issues fixed) - Replace remaining-work.md with human-tasks.md (manual actions only) - Update backlog.md with all AI-driven tasks (absorbed version bump) - Keep data-model-and-knowledge-base.md separate (human data entry) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge & Deploy Guide for Phase 2This PR is ready to merge. CI passes, 406 tests green, TypeScript clean, data validated. What this changesPhase 2 transforms paulprae.com from a static resume site into an AI-powered career platform:
62 commits, 76 files changed, +10,151 / -3,523 lines. Pre-Merge Steps
What Happens on Merge
Required Environment Variables (already set on Vercel)
Post-Deploy ChecklistAfter the production deploy is live:
Full UAT checklist: Rollback PlanIf something breaks in production:
Risk Assessment
|
8-phase plan targeting paulprae.com production URL after merging Phase 2 to main. Covers deploy verification, chat streaming, tool- calling, security headers, SEO with production URLs, mobile layout, console errors, and a hiring manager impression test. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
VERCEL_OIDC_TOKEN is auto-injected by Vercel runtime but does not mean the AI Gateway is configured for this project. The previous check `AI_GATEWAY_API_KEY || VERCEL_OIDC_TOKEN` caused all Vercel deployments to route through the gateway, which silently failed — producing 200 responses with empty event streams (empty chat bubbles). Now only uses AI Gateway when AI_GATEWAY_API_KEY is explicitly set. Falls back to direct @ai-sdk/anthropic with ANTHROPIC_API_KEY (which IS configured in Vercel env vars). Also enhances stream error logging to capture full error details. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces generic checklist with 12 phases organized by real stakeholder personas: recruiter quick-screen, AI/ML hiring manager deep dive, business executive impact evaluation, and engineering peer reviews across 5 disciplines (AI/ML, data, cloud, cybersecurity, app dev). Adds tailored resume generation, job search tools, multi-turn conversation quality, and accessibility spot checks. Removes trivial already-verified items. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…list Rewrites human-tasks.md with: - Critical blocker: Anthropic API credits (root cause of empty chat) - Pre-merge checklist aligned to production QA plan - Detailed DNS setup guide with DreamHost-specific steps - Current DNS state audit (apex working, www not yet pointed) - Vercel + Google best practices for canonicalization - Step-by-step www CNAME + redirect configuration - Post-deploy monitoring checklist - SEO verification tasks Research sources: Vercel docs (domain setup, redirects, duplicate content avoidance), Google Search Central (canonicalization), DreamHost KB (DNS records, DNS Only mode). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…t runtime Replace useChatRuntime (which uses unstable_useRemoteThreadListRuntime) with direct useChat + useAISDKRuntime. The thread list runtime reassigns thread IDs on initialization, causing useChat to destroy and recreate the Chat instance. The stale sendMessage reference then fails with "Cannot read properties of undefined (reading 'state')" on the second message. Also updates docs to reflect current state: AI Gateway not active (direct Anthropic SDK), Upstash Redis rate limiting confirmed in all Vercel environments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Strengthen release confidence by aligning tests to production contracts, expanding UI/E2E QA coverage, and refreshing runbooks/prompts so Claude Code can execute prioritized fixes immediately. Made-with: Cursor
…ontracts P0 fixes: - Enable remark-gfm for markdown tables in chat responses (was rendering as raw pipe text) - Add pruneMessages() to strip old tool results before model call, preventing 400 errors on long conversations with resume generation - Increase body limit from 100KB to 256KB for legitimate tool result payloads - Change "Tailored resume" chip to pre-fill composer instead of sending unusable placeholder message UX improvements: - Add "New chat" button in header to clear conversation without page reload - Add tooltip on PDF download button for mobile users - Reduce empty state top whitespace (upper-center instead of dead center) - Add no-emoji rule to tools mode system prompt for consistency Infrastructure: - Gate HSTS check in smoke test by environment (skip on localhost) - Refactor proxy.test.ts to import production constants instead of duplicating - Update QuickActions tests for prefill behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Archive v2-qa-baseline-evidence.md to plans/archived/ - Delete qa-execute-v2 command (consolidated into qa-comprehensive) - Update backlog.md reconciliation date - Mark PR description review as done in human-tasks.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Latest status (2026-03-08)QA summaryAll automated checks pass. Multiple rounds of browser QA completed with fixes for:
Artifact cleanup
Before merging
|
Remove .claude/prompts/ from .gitignore so reusable prompts like comprehensive-qa-review.md are committed and available to all users. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mark pre-merge items complete (API funded, v1.0.0 tagged, chat tested). Replace post-deploy section with ordered step-by-step runbook that interleaves human actions with Claude Code automated checks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Phase 2 transforms paulprae.com from a static resume site into an AI-powered career platform. The chat-first homepage lets recruiters, hiring managers, and engineering peers interact with an AI assistant grounded in Paul's structured career data.
What's new
/) — AI career assistant powered by Claude Sonnet via Vercel AI SDK 6 +@assistant-ui/react, with streaming responses and tool-calling/tools) — Content generators for cover letters, LinkedIn messages, elevator pitches, STAR answers, and more (noindex)/resume) — Static rendered resume with section navigation, back-to-top, and PDF/DOCX/MD download linkspruneMessages()strips old tool results to prevent 400 errors in long conversationsArchitecture
@anthropic-ai/sdkfor pipeline, Vercel AI SDK 6 (ai+@ai-sdk/anthropic) for chat streaming@assistant-ui/react+@assistant-ui/react-ai-sdkwithuseChat+useAISDKRuntime(bypasses unstable thread list runtime)@upstash/redis+@upstash/ratelimitvia Vercel KV integrationKey fixes during QA
useChatRuntimewith directuseChat+useAISDKRuntimeremark-gfmfor proper markdown table renderingTest coverage
npm run smoke) covering homepage, resume, downloads, HTTPS redirect, security headers, and chat API validationPre-merge checklist
npm test)npm run check)npm run validate:docs).claude/plans/human-tasks.md)mainasv1.0.0before merge (Phase 1 milestone)mainand verify production deployPost-deploy
.claude/plans/production-qa-plan.md).claude/plans/human-tasks.mdfor full post-deploy checklistTest plan
npm run check— full release gate (lint, format, tests, build, validation)npm test— 406 tests passnpm run smoke)🤖 Generated with Claude Code