Codex 5.3 Refactor Note: Canonical refactor plan: docs/CODEX-5.3-REFACTOR-PLAN.md. This document is retained for historical and implementation context during the refactor.
Project Context (Full)
Last updated: 2026-04-26
This is the full, high‑signal context for OfferReview. It’s meant to be used by Codex or engineers for fast onboarding, troubleshooting, and safe modifications.
1) Project summary
- Product: OfferReview (HR/manager hiring workflow system).
- Stack: Next.js 16.1.4 (App Router), Prisma ORM, Node 20.x.
- Email: Resend API.
- AI: OpenAI for resume analysis.
- Storage: Local uploads directory + optional S3 (presigned) support.
- Preferred DB: PostgreSQL (both local and VPS).
2) Current repository state
- Default branch:
main. - Primary working tree on this machine:
/srv/apps/offerreview/prod. - Workspace sibling trees:
/srv/apps/offerreview/prod_hotfix_manager,/srv/apps/offerreview/prod_deploy_smo_hotfix. - Current
prodHEAD:4b9615c(feat: ground resume extraction and add evidence-based skills). - Recent prior commits:
0f793bafeat: expand SMO analytics and interview workflowb70b127feat: enrich employer context with web search951b112feat: expand review workflow and resume insights
- Build script:
prisma generate && NEXT_DISABLE_TURBOPACK=1 NEXT_FORCE_WEBPACK=1 next build. prodcurrently has local uncommitted changes focused on candidate deep-dive flows, manager-review magic links, position job descriptions, candidate detail/dashboard/settings updates, and related Prisma migrations.prod_hotfix_manageralso has local changes.prod_deploy_smo_hotfixis currently clean.
2a) Current local workstream snapshot (2026-04-26)
- Shipped in recent commits:
- grounded resume extraction with evidence-based skills and stricter resume-only evidence (
4b9615c) - SMO compare analytics and richer SMO interview workflow (
0f793ba) - employer-context enrichment through OpenAI web search (
b70b127)
- grounded resume extraction with evidence-based skills and stricter resume-only evidence (
- Current dirty worktree themes:
- candidate deep-dive workflow:
- new models:
CandidateDeepDiveQuestion,CandidateDeepDiveQuestionSet,CandidateDeepDiveInvite,CandidateDeepDiveResponse - new public route:
/candidate-deep-dive/[token] - new candidate tab:
src/app/(app)/candidates/[id]/_tabs/CandidateDeepDiveTab.tsx - new SMO-owned question-bank surface:
/admin/deep-dive-questions
- new models:
- manager-review magic-link workflow:
- new model:
ManagerReviewAccessLink - new public route:
/manager-review/[token] - manager assignment now generates and emails a review link
- new model:
- position/job-description flow:
- positions now carry active job descriptions
- candidate creation requires a selected position with an active job description
- new route:
/api/positions/[id]/job-description
- candidate detail expansion:
- tabs now include
RadarandDeep Dive - candidate detail defaults SMO into deep-dive when response data exists
- tabs now include
- dashboard/settings/admin cleanup continues across the dirty worktree
- candidate deep-dive workflow:
- Evaluation upload workflow still uses manual form entry and the evaluation prefill route remains intentionally disabled.
3) Top‑level structure
/ (repo root)
src/ Next.js app + API routes
prisma/ Prisma schema + migrations + seed
scripts/ Release helpers
docs/ Canonical docs + historical delivery docs
uploads/ Local file storage target (dev/prod if UPLOADS_DIR unset)
4) Key routes (App Router)
App pages
/login,/request-access,/forgot-password/dashboard/notifications,/settings/candidates,/candidates/[id]/upload-resume/manager-review/[token]/candidate-deep-dive/[token]/admin/access-requests/admin/roles,/admin/users,/admin/organization/admin/deep-dive-questions(SMO-only)/admin/templates/admin/audit,/admin/notifications
API endpoints (selected)
- Auth:
/api/auth/login,/api/auth/logout,/api/auth/me - Access requests:
/api/access-requests,/api/access-requests/[id] - Candidates:
/api/candidates,/api/candidates/[id] - Candidate deep dive:
/api/candidate-deep-dive/[token],/api/candidates/[id]/deep-dive/resend - Candidate auxiliary:
/api/candidates/[id]/evaluation-prefill(currently disabled) - Manager review links:
/api/manager-review-links/[token] - Documents:
/api/documents,/api/documents/[docId] - Uploads:
/api/uploads/local,/api/uploads/presign - Analytics:
/api/analytics/smo-strength,/api/analytics/smo-compare - Deep-dive question-bank data:
/api/deep-dive/question-bank(SMO-only) - Templates:
/api/templates,/api/templates/[id] - Settings:
/api/settings,/api/settings/notification-rules - Admin outbox:
/api/admin/outbox - Health:
/api/health/openai
5) Environment variables (required/optional)
Required for app startup
DATABASE_URL(Postgres for local/VPS)JWT_SECRET
Email (Resend)
RESEND_API_KEYRESEND_FROM_EMAIL(orRESEND_FROM)APP_NAME(optional, default “OfferReview”)
OpenAI (resume analysis)
OPENAI_API_KEYOPENAI_MODEL(optional; defaultgpt-4o-mini)
Misc
NEXT_PUBLIC_APP_URL(used for invite links)JOB_SECRET(for/api/jobs/outbox-dispatch)OUTBOX_BATCH_SIZE(optional)UPLOADS_DIR(optional; defaults to<repo>/uploads)
6) Prisma models (overview)
Models:
User,Permission,RolePermission,InAppNotification,Outbox,OutboxLog,SystemSettings,NotificationRule,AuditLog,AccessRequest,Candidate,Department,Position,CandidateDocument,HrScreening,ManagerReview,EvaluationTemplate,AuthToken,ManagerReviewAccessLink,CandidateDeepDiveQuestion,CandidateDeepDiveQuestionSet,CandidateDeepDiveQuestionSetItem,CandidateDeepDiveInvite,CandidateDeepDiveResponse,Decision.
Enums (current values):
Role: ADMIN | HR | MANAGER | SMO
UserStatus: ACTIVE | DISABLED | PENDING_INVITE
RequestedRole: HR | MANAGER | SMO | ADMIN
AccessRequestStatus: PENDING | APPROVED | REJECTED
CandidateStatus: NEW | HR_SCREENED | MANAGER_EVAL_PENDING | MANAGER_REVIEWED | CANDIDATE_DEEP_DIVE_PENDING | TO_SMO | APPROVED | REJECTED | KIV | COMPLETED
DecisionType: APPROVED | REJECTED | KIV
DocumentCategory: RESUME | PORTFOLIO | CERT | OTHER | SCREENING_NOTES | EVALUATION | SMO_INTERVIEW | DECISION | OFFER
DocumentStatus: AVAILABLE | PENDING_SCAN
AuditEventType: (see schema for full list; includes login, candidate, template, access request, outbox)
NotificationChannel: EMAIL | IN_APP | BOTH
OutboxStatus: QUEUED | SENT | FAILED | RETRYING
OutboxProvider: RESEND | IN_APP
TemplateStatus: DRAFT | PUBLISHED | ARCHIVED
HrScreeningMode: QUICK
HrOutcome: PASS | KIV | REJECT
ManagerReviewMode: QUICK
ManagerRecommendation: PROCEED | KIV | REJECT
AuthTokenType: INVITE | RESET_PASSWORD
7) Seeds
package.json:
- Seed command:
node prisma/seed.js
prisma/seed.js creates or updates:
admin@example.com/admin123(ADMIN)hr@example.com/hr123(HR)manager@example.com/manager123(MANAGER)smo@example.com/smo123(SMO)
Additional scripts in scripts/:
seed-settings.tsseed-permissions.tsseed-demo.ts
8) File uploads
- Local storage helpers:
src/lib/storage/local.ts(usesuploads/by default). - S3 support exists via
src/lib/storage/s3.ts(needs AWS envs + @aws-sdk deps). - Upload routes:
/api/uploads/local,/api/uploads/presign. - Current local validation allows evaluation/job-description documents in
PDF,DOC,DOCX,XLS, andXLSX.
9) AI resume analysis
src/lib/ai/resumeAnalysis.tsextracts text from PDF/DOC/DOCX, calls OpenAI.- Writes results into
CandidateDocumentAI fields and updates candidate snapshot fields. - Requires
OPENAI_API_KEY. - Current local behavior also stores structured employment history, evidence-based skills, peer-comparison context, and resume-derived fallback contact/address fields in
aiStructuredJson.
9a) AI evaluation analysis
src/lib/ai/evaluationAnalysis.tscontains active parsing logic for evaluation documents, including spreadsheet (XLS/XLSX) extraction and verbatim recommendation-note handling.- Current local product behavior does not expose live AI evaluation prefill:
src/app/api/candidates/[id]/evaluation-prefill/route.tsis disabledsrc/app/api/candidates/[id]/documents/route.tsno longer kicks off evaluation analysis on upload
- Treat HR and manager evaluation forms as manual-entry flows until that pipeline is re-enabled end-to-end.
9b) AI deep-dive analysis
src/lib/ai/deepDiveAnalysis.tsanalyzes candidate questionnaire answers for depth, specificity, personality signals, suggested SMO follow-ups, and possible AI-assisted writing risk.- Candidate deep-dive responses are visible only to SMO in the current candidate detail UX.
10) Email
- Resend client:
src/lib/notifications/resend.ts. - Helper templates:
src/lib/notifications/email.ts. /api/users/[id]/resend-setupsends invite email (best effort; logs failures).- Manager assignment emails a manager-review magic link.
- Manager
PROCEEDreview can trigger a candidate deep-dive questionnaire email.
11) Build + runtime notes
- Build uses Webpack (Turbopack disabled in build script).
- On low‑resource servers, Turbopack may panic; keep
NEXT_DISABLE_TURBOPACK=1. - If you see
@prisma/client-xxxxmissing module errors, Prisma client wasn’t generated after install/build.
12) Local dev workflow
# from repo root
npm install
npx prisma generate
npx prisma migrate deploy
npm run dev
13) VPS deployment (Postgres)
Assumes Ubuntu, app in /var/www/offerreview, PM2 process offerreview.
Steps:
cd /var/www/offerreviewgit pull origin main- Ensure
.envexists (DATABASE_URL + JWT_SECRET + Resend keys). npm installnpx prisma generatenpx prisma migrate deploynpm run buildpm2 delete offerreviewexport $(grep -v '^#' .env | xargs)pm2 start npm --name offerreview -- startpm2 save
14) VPS Postgres permissions
If permission denied for schema public:
ALTER DATABASE offerreview OWNER TO offerreview_user;
ALTER SCHEMA public OWNER TO offerreview_user;
GRANT ALL ON SCHEMA public TO offerreview_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO offerreview_user;
15) Logs
Local
tail -n 200 /tmp/next-dev.log
VPS (PM2)
pm2 logs offerreview --lines 50 --nostream/root/.pm2/logs/offerreview-out.log/root/.pm2/logs/offerreview-error.log
16) Nginx + Adminer (VPS)
Adminer installed for DB inspection.
- Path:
/adminer/ - Needs php-fpm socket:
/run/php/php8.3-fpm.sock
If 404 on /adminer/, ensure:
location /adminer/ {
alias /usr/share/adminer/;
index adminer.php;
include snippets/fastcgi-php.conf;
fastcgi_param SCRIPT_FILENAME /usr/share/adminer/adminer.php;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
17) Common failure patterns
- 500 on login (local):
.env.localpointing to remote MySQL. - Prisma errors on VPS:
.envmissing or not loaded by PM2. - Missing
@prisma/client-xxx: Prisma client not generated after install. - Turbopack panics on VPS: keep Webpack build flags.
- Confusing evaluation behavior: older docs may mention AI prefill, but the current local worktree uses manual evaluation entry and a disabled prefill endpoint.
- Manager access surprises: actively edited candidate routes now assume assignment-based manager access rather than department-wide access.
- OpenAI request errors on newer models: use
src/lib/ai/openaiTokenLimits.tshelpers for token/temperature compatibility. - User-flow mismatches worth remembering: see
docs/ROLE-FLOW-CHECK-2026-04-26.mdfor current issues such as manager dashboard claimability vs access rules, settings visibility vs admin-only APIs, and HR user-detail access mismatch.
18) Docs in repo
W1-LOGIN-IMPLEMENTATION.md,W2-*,W3-*,W4-*,W6-*,W9-*,W10-*,W11-*,W12-*contain detailed implementation notes.AGENTS.mdis the bootstrap entry point.docs/PROJECT_CONTEXT.mdis the short current-state summary and should be updated alongside meaningful local workflow changes.docs/ROLE-FLOW-CHECK-2026-04-26.mdstores the current role-flow audit and observed UX/permission mismatches.
If you need this to include extra details (e.g., full API contract, UI screenshots, or complete schema), specify the scope and I’ll expand it.