Handover workspace

ERS, Todo, OfferReview, and Docu in one view

Imported from live server docs, code structure, and deployment notes.

Apr 3, 2026, 12:38 PM

OfferReview

Project Context (Full)

Last updated: 2026-02-05

docs/PROJECT_CONTEXT_FULL.md

Updated Feb 19, 2026, 6:59 AM

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-02-05

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.
  • Latest known commit: 0a7cb7e (Resend email helpers + resend-setup sends email).
  • Build script: prisma generate && NEXT_DISABLE_TURBOPACK=1 NEXT_FORCE_WEBPACK=1 next build.

3) Top‑level structure

/ (repo root)
  src/               Next.js app + API routes
  prisma/            Prisma schema + migrations + seed
  scripts/           Seed helpers
  docs/              Project docs (W1…W12)
  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
  • /admin/access-requests
  • /admin/roles, /admin/users, /admin/organization
  • /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]
  • Documents: /api/documents, /api/documents/[docId]
  • Uploads: /api/uploads/local, /api/uploads/presign
  • 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_KEY
  • RESEND_FROM_EMAIL (or RESEND_FROM)
  • APP_NAME (optional, default “OfferReview”)

OpenAI (resume analysis)

  • OPENAI_API_KEY
  • OPENAI_MODEL (optional; default gpt-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, 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 | TO_SMO | APPROVED | REJECTED | KIV | COMPLETED
DecisionType: APPROVED | REJECTED | KIV
DocumentCategory: RESUME | PORTFOLIO | CERT | OTHER | SCREENING_NOTES | EVALUATION | 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.ts
  • seed-permissions.ts
  • seed-demo.ts

8) File uploads

  • Local storage helpers: src/lib/storage/local.ts (uses uploads/ 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.

9) AI resume analysis

  • src/lib/ai/resumeAnalysis.ts extracts text from PDF/DOC/DOCX, calls OpenAI.
  • Writes results into CandidateDocument AI fields and updates candidate snapshot fields.
  • Requires OPENAI_API_KEY.

10) Email

  • Resend client: src/lib/notifications/resend.ts.
  • Helper templates: src/lib/notifications/email.ts.
  • /api/users/[id]/resend-setup sends invite email (best effort; logs failures).

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-xxxx missing 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:

  1. cd /var/www/offerreview
  2. git pull origin main
  3. Ensure .env exists (DATABASE_URL + JWT_SECRET + Resend keys).
  4. npm install
  5. npx prisma generate
  6. npx prisma migrate deploy
  7. npm run build
  8. pm2 delete offerreview
  9. export $(grep -v '^#' .env | xargs)
  10. pm2 start npm --name offerreview -- start
  11. pm2 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.local pointing to remote MySQL.
  • Prisma errors on VPS: .env missing or not loaded by PM2.
  • Missing @prisma/client-xxx: Prisma client not generated after install.
  • Turbopack panics on VPS: keep Webpack build flags.

18) Docs in repo

  • W1-LOGIN-IMPLEMENTATION.md, W2-*, W3-*, W4-*, W6-*, W9-*, W10-*, W11-*, W12-* contain detailed implementation notes.

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.