fix: resume pipeline (PDF parse, DOCX preview, downloads), inline job runner, Google OAuth, applicant emails#89
Merged
Conversation
…undling
The createRequire(import.meta.url) + require("pdf-parse") combo broke module
resolution inside the Next runtime (inline parse paths), so PDF resumes failed
to parse while DOCX (ESM mammoth) worked. A memoized dynamic import stays
external thanks to serverExternalPackages, which now also lists pdf-parse's
transitive deps (pdfjs-dist, @napi-rs/canvas). Adds a committed PDF fixture so
the extraction test always runs in CI.
…heap fallbacks Replaces openrouter/owl-alpha default and free/auto fallbacks with google/gemini-2.5-flash -> google/gemini-2.5-flash-lite -> openrouter/auto (slugs verified against the live OpenRouter model list). Tightens the resume parse prompt for stricter, deduplicated output.
…sition and clearer 404 Extracts the duplicated local-disk/ResumeFile resolution into src/lib/resume/storage-read.ts, reused by the serving route and the parser. The serving route now sends Content-Disposition (inline for embeddable types, attachment otherwise, ?download=1 to force) with RFC 5987 filenames, and the 404 explains the dev-vs-prod storage mismatch.
Word resumes now render inline: a new authenticated route /api/resumes/preview/<objectName> converts DOCX to sanitized HTML (mammoth + sanitize-html allowlist, CSP default-src 'none') and the admin applicant page embeds it in a sandboxed iframe. PDFs keep the native iframe. Adds getResumePreviewKind() and a committed DOCX fixture.
…very when no worker runs Adds a job dispatcher (src/server/jobs) with two modes via JOB_RUNNER: 'worker' enqueues to pg-boss as before; 'inline' (default on Vercel) runs parsing and email sends after the response with next/server after(), so serverless deployments work without worker processes. The email dispatch switch is extracted to a shared module used by both the worker and the inline path. Apply page gets maxDuration=60 for the inline LLM call.
…s with an organization Root cause of the broken Google login: AUTH_GOOGLE_ID/SECRET were set to empty strings while the real credentials lived in the legacy GOOGLE_CLIENT_* vars, making it easy to edit the wrong pair. The dev diagnostic now warns when both conventions are set with different values. Google sign-ins are also upserted into the User table with an organization attached (the Prisma adapter creates users without one, which broke org-scoped routes like parse-retry). Roles are never downgraded and existing org memberships are never reassigned. Adds an optional AUTH_ALLOWED_EMAIL_DOMAIN gate, unset by default.
…te limits Parallel after() callbacks fired one Resend request per admin simultaneously and tripped the requests-per-second limit (observed in smoke testing). The inline fan-out now sends sequentially inside a single after() task.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the full resume pipeline plus auth and notification delivery:
createRequire + require("pdf-parse")broke under the Next bundler (PDF resumes failed while DOCX worked). Replaced with a memoized dynamicimport()left external viaserverExternalPackages(now also listspdfjs-dist,@napi-rs/canvas). Committed PDF/DOCX fixtures so extraction tests always run in CI.google/gemini-2.5-flashwithgemini-2.5-flash-lite → openrouter/autofallbacks (slugs verified against the live model list); tightened the parse prompt.src/lib/resume/storage-read.ts), properContent-Disposition(inline for embeddable types, attachment with the real filename otherwise,?download=1to force), clearer 404 explaining dev/prod storage mismatches./api/resumes/preview/[...objectName]converts DOCX → sanitized HTML (mammoth + sanitize-html allowlist, CSPdefault-src 'none'), rendered in a sandboxed iframe on the applicant detail page. PDFs keep the native viewer.src/server/jobs/) withJOB_RUNNER=worker|inline. Inline (default on Vercel) runs resume parsing and email sends post-response vianext/serverafter()— no worker processes needed on Vercel. Worker mode keeps the existing pg-boss path. Admin fan-out sends sequentially to respect Resend rate limits.AUTH_GOOGLE_*set to empty strings while real credentials sat in legacyGOOGLE_CLIENT_*. Dev diagnostics now warn on conflicting pairs. Google sign-ins are upserted with an organization attached (Prisma adapter created them org-less, breaking org-scoped routes); roles never downgraded; optionalAUTH_ALLOWED_EMAIL_DOMAINgate.Verification
lint → typecheck → test (192 passed) → buildall green.pnpm build && pnpm startwithJOB_RUNNER=inline(no workers running):parsingStatus=COMPLETED, name/skills extracted by gemini-2.5-flash, match score computed — the previously broken path.Flagged risks / follow-ups
/api/resumes/*serves files unauthenticated (pre-existing; URLs are UUID-unguessable). Follow-up candidate.maxDuration(60s on apply page); Retry button is the recovery path if cut.AUTH_ALLOWED_EMAIL_DOMAINto restrict.EMAIL_FROM.🤖 Generated with Claude Code