Skip to content

feat: Phase 2 — AI chat platform with recruiter assistant#21

Merged
praeducer merged 72 commits intomainfrom
feat/phase2-implementation
Mar 8, 2026
Merged

feat: Phase 2 — AI chat platform with recruiter assistant#21
praeducer merged 72 commits intomainfrom
feat/phase2-implementation

Conversation

@praeducer
Copy link
Owner

@praeducer praeducer commented Mar 4, 2026

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

  • Chat-first homepage (/) — AI career assistant powered by Claude Sonnet via Vercel AI SDK 6 + @assistant-ui/react, with streaming responses and tool-calling
  • Tailored resume generation — Chat tool that generates role-specific resume variants on demand
  • Job search tools (/tools) — Content generators for cover letters, LinkedIn messages, elevator pitches, STAR answers, and more (noindex)
  • Resume page (/resume) — Static rendered resume with section navigation, back-to-top, and PDF/DOCX/MD download links
  • Security hardening — CORS origin validation, Upstash Redis rate limiting, prompt injection defenses, CSP/HSTS/XFO headers
  • Prompt caching — Anthropic cache control on system prompts for cost reduction
  • Conversation pruningpruneMessages() strips old tool results to prevent 400 errors in long conversations

Architecture

  • Runtime: Next.js 16.1 (App Router, server-rendered) on Vercel
  • AI: @anthropic-ai/sdk for pipeline, Vercel AI SDK 6 (ai + @ai-sdk/anthropic) for chat streaming
  • Chat UI: @assistant-ui/react + @assistant-ui/react-ai-sdk with useChat + useAISDKRuntime (bypasses unstable thread list runtime)
  • Rate limiting: @upstash/redis + @upstash/ratelimit via Vercel KV integration
  • Resume export: Pandoc + Typst pipeline producing PDF, DOCX, and MD

Key fixes during QA

  • Fixed multi-turn conversation TypeError by replacing useChatRuntime with direct useChat + useAISDKRuntime
  • Added remark-gfm for proper markdown table rendering
  • Changed "Tailored resume" chip to pre-fill composer instead of sending a wasted turn
  • Gated HSTS smoke check by localhost detection
  • Refactored proxy/tool-calling tests to import production contracts instead of duplicating logic
  • Multiple rounds of accessibility, mobile UX, SEO metadata, and security header improvements

Test coverage

  • 406 unit/component tests passing (Vitest + Testing Library)
  • Playwright E2E smoke tests with multi-browser matrix support
  • Post-deploy smoke script (npm run smoke) covering homepage, resume, downloads, HTTPS redirect, security headers, and chat API validation

Pre-merge checklist

  • All unit/component tests pass (npm test)
  • Full release check passes (npm run check)
  • Docs validated (npm run validate:docs)
  • Preview deployment tested
  • Fund Anthropic API credits (see .claude/plans/human-tasks.md)
  • Test chat on preview URL with funded API key
  • Tag main as v1.0.0 before merge (Phase 1 milestone)
  • Merge to main and verify production deploy

Post-deploy

  • Run production QA plan (.claude/plans/production-qa-plan.md)
  • Monitor Anthropic API costs, Vercel functions, and Upstash Redis dashboard for 48 hours
  • See .claude/plans/human-tasks.md for full post-deploy checklist

Test plan

  • npm run check — full release gate (lint, format, tests, build, validation)
  • npm test — 406 tests pass
  • Browser QA on preview URL (chat flow, resume page, tools page, mobile, accessibility)
  • Post-deploy smoke test on production (npm run smoke)

🤖 Generated with Claude Code

@praeducer
Copy link
Owner Author

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 /resume.

What's implemented

Routes:

Route Type Status
/ Chat homepage (client component) ✅ Renders with mode toggle + quick actions
/resume Resume page (static server component) ✅ Full extraction from original homepage
/api/chat POST handler (Fluid Compute) ✅ Mode switching, rate limiting, streaming

Architecture:

  • @assistant-ui/react primitives (ThreadPrimitive, MessagePrimitive, ComposerPrimitive, ActionBarPrimitive) — NOT the pre-built <Thread /> component
  • AssistantChatTransport with body: { mode } for mode-aware API calls
  • lib/agent/context.ts loads career data + 5 knowledge base JSONs, assembles system prompts via template injection ({{CAREER_DATA}}, {{PLATFORM_CONSTRAINTS}}, etc.)
  • Upstash rate limiting with graceful fallback (returns success: true when env vars not configured)

Key AI SDK 6 patterns (for future contributors):

  • maxOutputTokens not maxTokens (renamed in v6)
  • toUIMessageStreamResponse() not toDataStreamResponse() (renamed in v6)
  • await convertToModelMessages(messages) to convert UIMessage[] → model format
  • useChatRuntime({ transport }) not useChatRuntime({ api }) — must create AssistantChatTransport explicitly

What needs live testing

The chat functionality requires ANTHROPIC_API_KEY to test end-to-end. Build and TypeScript verification confirm the wiring is correct, but streaming responses haven't been tested against the real API yet.

How to continue contributing

This 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-implementation

Sprint 2+ work items are tracked in docs/phase2-redesign-plan.md (Implementation Status section) and the individual plan files in .claude/plans/phase2{a,b,c}-*.md.

References

  • Authoritative plan: docs/phase2-redesign-plan.md
  • Backend plan: .claude/plans/phase2a-backend-agent-api.md
  • Frontend plan: .claude/plans/phase2b-frontend-chat.md
  • DevOps plan: .claude/plans/phase2c-devops-docs.md
  • Human steps: .claude/plans/human-steps-phase2.md

@praeducer
Copy link
Owner Author

Recommended Next Steps

Immediate (Sprint 1 cleanup)

  1. Set ANTHROPIC_API_KEY and test live chat end-to-end (npm run dev → send a message)
  2. Delete dead componentsapp/components/SectionNav.tsx and app/components/BackToTop.tsx (moved to app/resume/components/)
  3. Write unit tests for lib/agent/context.ts, app/api/chat/route.ts, and app/components/ChatHome.tsx

Sprint 2 (Recruiter Complete + Resume Gen)

  1. Agent toolsget_resume_links, get_platform_constraints, generate_resume via AI SDK 6 tool-calling
  2. /api/resume route — Opus 4.6 tailored resume generation with maxDuration: 300
  3. resume-generator.system.md — system prompt for tailored resume generation
  4. Welcome message — pre-populated assistant message summarizing Paul's value proposition (user story R1)

Sprint 3 (Job Tools Core)

  1. Platform-aware copy-to-clipboard — strip markdown for LinkedIn, preserve for email
  2. Character count display — real-time count from platform-constraints.json
  3. Content generation templates — cover letters, LinkedIn messages, emails, follow-ups (user stories P1-P7)

DevOps (Plan 2C — can happen anytime)

  1. vercel.json — CSP headers, /api/* cache-control
  2. CI validation — verify /, /resume, /api/chat routes in build output
  3. Sitemap — add /resume to public/sitemap.xml
  4. Documentation — update CLAUDE.md, README.md for Phase 2 conventions

Human steps (before production deploy)

  1. Upgrade to Vercel Pro ($20/mo) for Fluid Compute
  2. Provision Upstash Redis and add env vars to Vercel
  3. Add ANTHROPIC_API_KEY to Vercel Production + Preview environments

Copy link
Owner Author

@praeducer praeducer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  1. Clean Route Restructure: Moving the resume to /resume and setting up the chat on / was executed perfectly, maintaining existing layout structures.
  2. Context Loader Design: lib/agent/context.ts does a fantastic job concatenating knowledge base JSON files and utilizing gray-matter to parse system prompts. stripEmpty is an elegant way to reduce token usage for the LLM system prompt.
  3. Component Architecture: Utilizing @assistant-ui/react primitives rather than fighting a monolithic component gives you maximum flexibility for the complex custom UI in 'Tools Mode'.

Areas for Improvement / Critical Issues

  1. Rate Limiting Fail-Open Risk (CRITICAL)
    In app/api/chat/route.ts, the rate limiter initialization includes a catch block 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: Use NODE_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).

  2. Missing maxDuration in API Route
    app/api/chat/route.ts does not export a maxDuration config. 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: Add export const maxDuration = 60; to the route.

  3. Error Handling for LLM API
    There's no try/catch wrapping the streamText() 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.

  4. Vercel Build Target (process.cwd())
    In lib/agent/context.ts, you use process.cwd() to locate lib/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 adding lib/prompts/**/* to the outputFileTracingIncludes in next.config.ts to 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.

praeducer and others added 2 commits March 4, 2026 16:14
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>
@praeducer praeducer force-pushed the feat/phase2-implementation branch from 0aa54ba to 357dbea Compare March 4, 2026 21:20
@praeducer
Copy link
Owner Author

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 ✅

Fix Detail
maxDuration = 60 Explicit Vercel Fluid Compute timeout (research: default is 300s with FC enabled, not 15s as claimed)
Error handling try/catch around streamText() with user-friendly messages for 529 overloaded, auth errors, etc.
Rate limiter logging console.warn in catch block — Redis failures now observable in Vercel logs
outputFileTracingIncludes Safety net ensuring Vercel bundles .md templates and .json data files
Anthropic spend limits Added to human-steps as defense-in-depth
API smoke test Added POST-empty-body→400 check to Plan 2C
Frame Tools mode Added UX item to Plan 2B for Sprint 2

Rejected ❌

Claim Why
"Client-side chat hurts SEO" Incorrect. Next.js pre-renders Client Components to HTML on the server. Crawlers receive full HTML.
"Change to fail-closed rate limiting" Overstated. Failing closed kills the entire API during Redis outage — worse for a portfolio site. Kept fail-open with logging + Anthropic spending cap as backstop.

Full assessment: .claude/plans/phase2-meta-improvement-plan.md
Addresses: Issue #25

praeducer and others added 16 commits March 4, 2026 16:38
- 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>
@praeducer
Copy link
Owner Author

Sprint 2 Complete — Phase 2 Ready for Merge

Sprint 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:

  • Welcome message — recruiter-focused value proposition with Paul's name, title, career summary, and CTA for tailored resumes
  • Tool-calling — two AI SDK 6 tools in chat mode: generate_tailored_resume (JD → tailored resume markdown) and get_resume_links (download URLs)
  • Resume generator prompt — new resume-generator.system.md with G9/G10 grounding rules and tailoring strategy
  • Quick action chip — "Tailored resume" chip added to chat mode (5 chips total)

Testing:

  • Installed @testing-library/react + jsdom for component testing
  • New tests: context.test.ts, quick-actions.test.tsx, chat-home.test.tsx, chat-api.test.ts
  • 337 tests passing (22 new)

Infrastructure:

  • vercel.json — removed static export config (framework: null, outputDirectory: out), added API cache headers + CSP for Vercel Analytics
  • CI — validates .next/BUILD_ID instead of out/index.html
  • Smoke tests — added /resume page check and /api/chat validation check
  • Release check — updated for .next/ build output
  • Sitemap — added /resume route

Documentation:

  • CLAUDE.md, README.md, TDD — fully updated for Phase 2
  • CONTRIBUTING.md — fixed stale "static export" references
  • Completed Phase 2 plans archived; consolidated remaining work in remaining-work.md

Cleanup:

  • Deleted dead components: SectionNav.tsx, BackToTop.tsx, ModeToggle.tsx from app/components/

Pre-Merge Blockers

  • Upstash Redis — provision free DB, add env vars to Vercel (rate limiting uses no-op fallback without it)
  • Live e2e testnpm run dev with API key, verify chat + tool-calling + resume page
  • npm run check — full release checklist
  • Remove DRAFT status and merge

What's NOT blocking merge (backlog)

  • Platform-aware copy-to-clipboard for tools mode
  • Character count display for tools mode
  • AI Gateway integration
  • Block-level prompt caching optimization

praeducer and others added 5 commits March 4, 2026 21:34
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>
@praeducer
Copy link
Owner Author

Merge & Deploy Guide for Phase 2

This PR is ready to merge. CI passes, 406 tests green, TypeScript clean, data validated.

What this changes

Phase 2 transforms paulprae.com from a static resume site into an AI-powered career platform:

  • / (homepage): AI chat assistant for recruiter Q&A — streams responses grounded in structured career data via Claude Sonnet 4.6
  • /resume: Static resume page with section navigation, PDF/DOCX download
  • /tools: Job search content tools (cover letters, LinkedIn messages, etc.) — intentionally noindexed
  • /api/chat: Streaming chat endpoint with tool-calling (tailored resume generation, resume download links)

62 commits, 76 files changed, +10,151 / -3,523 lines.

Pre-Merge Steps

  1. Tag the current main as Phase 1 milestone (preserves rollback point):

    git tag v1.0.0 main
    git push origin v1.0.0
  2. Merge this PR. Squash merge is fine — the commit history is clean but 62 commits is a lot for main. A merge commit also works if you want to preserve history.

What Happens on Merge

  • Vercel auto-deploys main to production (paulprae.com)
  • The new deployment includes serverless functions (/api/chat) and edge middleware (proxy.ts)
  • Static pages (/, /resume, /tools, /_not-found) are prerendered at build time
  • No database migration needed — all data is in committed JSON files

Required Environment Variables (already set on Vercel)

Variable Purpose Required?
ANTHROPIC_API_KEY Claude API for chat + tool-calling Yes
UPSTASH_REDIS_REST_URL Rate limiting (Redis) Optional (in-memory fallback)
UPSTASH_REDIS_REST_TOKEN Rate limiting (Redis) Optional (in-memory fallback)

Post-Deploy Checklist

After the production deploy is live:

  1. Smoke test chat: Go to paulprae.com, send "Quick overview" — verify streaming response mentions Arine, AWS, Microsoft
  2. Smoke test tool-calling: Click "Tailored resume", paste any JD, verify a tailored resume generates
  3. Verify downloads: Click resume download links (PDF, DOCX) — confirm they open
  4. Check security headers: DevTools > Network > response headers should show CSP, HSTS, X-Frame-Options
  5. Check Vercel Dashboard: Functions tab shows /api/chat executions; AI Gateway shows logged API calls
  6. Monitor costs: Watch Anthropic Console usage for the first few hours

Full UAT checklist: docs/uat-checklist.md

Rollback Plan

If something breaks in production:

  1. Quick rollback: Vercel Dashboard > Deployments > click the previous deployment > "Promote to Production"
  2. Full rollback: git revert --no-commit HEAD && git commit -m "revert: Phase 2" and push
  3. Tag rollback: Deploy from v1.0.0 tag if needed

Risk Assessment

Risk Mitigation
AI costs spike Rate limiting (20 req/min per IP), max token caps on all endpoints
Hallucinated content 10 grounding rules in system prompt, career data preprocessing, few-shot examples
Prompt injection XML-wrapped untrusted input, system prompt reveal prevention, security rules in all prompts
API key leak Server-side only, never sent to client, CSP blocks unauthorized connect-src

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>
@praeducer
Copy link
Owner Author

Latest status (2026-03-08)

QA summary

All automated checks pass. Multiple rounds of browser QA completed with fixes for:

  • Multi-turn chat buguseChatRuntimeuseChat + useAISDKRuntime migration
  • Markdown tables — Added remark-gfm plugin
  • Long conversation 400s — Added pruneMessages() + increased body limit to 256KB
  • Tailored resume UX — Pre-fills composer instead of sending placeholder message
  • Test contracts — Proxy and tool-calling tests now import production logic
  • Smoke test — HSTS check gated by localhost detection

Artifact cleanup

  • Archived v2-qa-baseline-evidence.md to plans/archived/
  • Consolidated claude-code-v2-execution-handoff.md learnings into comprehensive-qa-review.md
  • Deleted Phase 2-specific: qa-execute-v2.md command, claude-code-v2-execution-handoff.md prompt
  • Updated backlog.md and human-tasks.md

Before merging

  1. Fund Anthropic API credits at console.anthropic.com — chat returns empty bubbles without balance
  2. Tag current main as v1.0.0: git tag v1.0.0 && git push origin v1.0.0
  3. Test chat on preview URL with funded API key to confirm streaming works
  4. Merge to main — Vercel auto-deploys from main
  5. Post-deploy: run npm run smoke against production, follow .claude/plans/human-tasks.md post-deploy checklist

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>
@praeducer praeducer marked this pull request as ready for review March 8, 2026 17:16
@praeducer praeducer merged commit c9d47a3 into main Mar 8, 2026
4 checks passed
@praeducer praeducer deleted the feat/phase2-implementation branch March 8, 2026 17:18
praeducer added a commit that referenced this pull request Mar 8, 2026
Mark Phase 2 launch tasks complete (PRs #21, #26, #27). Replace
pre-merge checklist with current post-deploy verification items
for mobile skip-nav, CORS headers, and dashboard monitoring.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant