Skip to content

feat: import candidate brief from LinkedIn profile (#48)#52

Merged
ogarciarevett merged 2 commits into
mainfrom
feat/onboarding-linkedin-import
May 29, 2026
Merged

feat: import candidate brief from LinkedIn profile (#48)#52
ogarciarevett merged 2 commits into
mainfrom
feat/onboarding-linkedin-import

Conversation

@ogarciarevett

Copy link
Copy Markdown
Collaborator

Closes #48.

Adds an optional "Import from LinkedIn" path for generating config/candidate-brief.md, alongside the existing CV upload. Uses LinkedIn's self-serve "Save to PDF" export (no scraping, no auth, ToS-safe) fed through the existing parse → LLM pipeline with a LinkedIn-tuned prompt — the issue's recommended first cut.

⚠️ Stacked on #51 (feat/onboarding-cli-install-buttons). This PR targets that branch and should be merged after #51. Once #51 merges to main, GitHub will auto-retarget this PR to main. The diff below shows only the #48 changes.

What's in it

  • src/lib/brief-prompt.ts (new) — single shared buildBriefPrompt(text, source, maxChars) with a 'cv' | 'linkedin' source. Consolidates the prompt that was duplicated in setup-brief.ts and ui/plugins/brief.ts; the 3-paragraph output contract is identical across sources so a LinkedIn-sourced brief is comparable to a CV-sourced one.
  • ui/plugins/brief.ts + _shared.tsPOST /api/cv accepts an optional, allowlist-validated source (defaults to cv).
  • ui/src/lib/api/index.tscv.upload input gains optional source.
  • ui/src/Onboarding.tsx — optional "Import from LinkedIn" affordance in the CV-upload step (collapsed; expands to the Save-to-PDF steps + a PDF picker).
  • ui/src/Profile.tsx — matching "From LinkedIn" toggle on the Profile tab.
  • src/setup-brief.ts--linkedin <file> flag + basename-scoped filename auto-detect.
  • Docs — README onboarding step 2, the setup-brief CLI block, and the Profile-tab description.

Commits

  1. feat: the LinkedIn import implementation
  2. fix: code-review findings (busy-state try/finally, mutually-exclusive Profile panels, basename-only auto-detect, an integration test asserting source=linkedin reaches /api/cv, tightened CV no-leak assertion)

Security

Local-only dev-server middleware. The source field is allowlist-validated before any LLM call; no new path/SSRF/injection surface; document-in-prompt posture unchanged from the existing CV path (self-owned input, local-only).

Test plan

  • pnpm run lint, pnpm run typecheck, pnpm run lint:ui-patterns — green
  • pnpm test420 pass (new tests/brief-prompt.test.ts + Onboarding.test.tsx LinkedIn cases)
  • pnpm run build + pnpm run ui:build — green; bundle within budget (LinkedIn UI lives in lazy chunks)
  • Manual: onboarding step 2 → "Import from LinkedIn" → upload a LinkedIn "Save to PDF" → brief generated; same via Profile tab; pnpm run setup-brief --linkedin ~/profile.pdf

🤖 Generated with Claude Code

ogarciarevett and others added 2 commits May 28, 2026 21:41
Adds an optional LinkedIn-import path alongside CV upload for generating
config/candidate-brief.md, using LinkedIn's self-serve "Save to PDF"
export (no scraping/auth, ToS-safe) through the existing parse → LLM
pipeline with a LinkedIn-tuned prompt.

- src/lib/brief-prompt.ts: single shared buildBriefPrompt(text, source,
  maxChars) with a 'cv' | 'linkedin' source. Consolidates the prompt that
  was duplicated in setup-brief.ts and ui/plugins/brief.ts; the output
  contract (3 paragraphs) is identical across sources so quality matches.
- ui/plugins/brief.ts + _shared.ts: /api/cv accepts an optional, allowlist-
  validated `source`; defaults to 'cv'.
- ui/src/lib/api/index.ts: cv.upload input gains optional `source`.
- ui/src/Onboarding.tsx: optional "Import from LinkedIn" affordance in the
  CV-upload step (collapsed; reveals Save-to-PDF steps + PDF picker).
- ui/src/Profile.tsx: matching "From LinkedIn" toggle on the Profile tab.
- src/setup-brief.ts: `--linkedin <file>` flag + filename auto-detect.
- Tests (brief-prompt.test.ts, Onboarding.test.tsx) + README docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Profile.tsx: wrap summarizeFile in try/finally so a throw in
  fileToBase64/fileToText can't leave `busy` stuck and disable the tab
  (HIGH). Make the "Paste text" / "From LinkedIn" panels mutually
  exclusive — opening one closes the other (MEDIUM).
- setup-brief.ts: match the LinkedIn filename auto-detect on basename
  only, so a "linkedin"-named directory can't silently flip a real CV to
  the LinkedIn prompt (MEDIUM).
- Onboarding.test.tsx: add an integration test asserting source=linkedin
  actually reaches POST /api/cv (regression guard for the upload wiring)
  (MEDIUM).
- brief-prompt.test.ts: tighten the CV "no-leak" assertion to check the
  exact LinkedIn copy instead of a broad /LinkedIn/i glob (LOW).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ogarciarevett ogarciarevett requested a review from FranRom May 28, 2026 20:15
@ogarciarevett ogarciarevett self-assigned this May 28, 2026
Base automatically changed from feat/onboarding-cli-install-buttons to main May 28, 2026 22:07
@ogarciarevett ogarciarevett merged commit b48c4cc into main May 29, 2026
@ogarciarevett ogarciarevett deleted the feat/onboarding-linkedin-import branch May 29, 2026 18:38
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.

Feature: import profile from LinkedIn instead

2 participants