The Problem

Job seekers often scatter applications, resumes, and follow‑up tasks across email, spreadsheets, and note‑taking apps. That fragmentation makes it hard to see progress, measure success rates, or reuse data for AI‑driven insights. A single, self‑hosted tool that stores everything locally and exposes the data to AI without sending it to third‑party services fills that gap.

What This Does

jobsync is a Next.js web app that centralises job‑application data, résumé files, and activity tracking. Core UI components live under src/components/ui/ (e.g., button.tsx, use-toast.ts, card.tsx) and are heavily reused—57 modules import button, 21 import card, etc. The AI layer resides in src/lib/ai/ and provides résumé review (src/lib/ai/prompts/job-match/) and job‑matching scoring. Persistence is handled by Prisma (prisma/ schema files) and a collection of action modules (src/actions/*.actions.ts) that wrap CRUD operations for jobs, companies, activities, tags, and automations.

How It Is Wired

Execution begins in the API routes; the most isolated entry is src/lib/scheduler/index.tsrunDueAutomations (line 8), which triggers a chain of 28 internal functions for scheduled automations. The primary user‑facing flow starts in src/app/api/automations/[id]/logs/route.ts (start at line 49) and quickly reaches the toast system (src/components/ui/use-toast.ts → dispatch → toast).

Key call‑graph hubs:

  • src/lib/utils.ts – exports cn, formatUrl, handleError, getTimestampedFileName, combineDateAndTime; imported by 39 files.
  • src/components/ui/use-toast.ts – defines the toast reducer and toast; used by 21 files, called 44 times.
  • src/utils/user.utils.tsgetCurrentUser is invoked from 108 locations, making it the widest user‑context blast radius.

Database interaction is concentrated in the action layer; for example, src/actions/profile.actions.ts (18 functions) reads/writes resumes and contacts, while src/actions/job.actions.ts (13 functions) handles job CRUD and detail retrieval. The AI endpoint (src/lib/ai/index.ts) calls the OpenAI/OpenRouter model once per request, and file I/O occurs only in src/lib/scraper/runner.ts (PDF generation) and PDF export logic (src/components/profile/resume-pdf/).

A circular import exists among src/components/profile/resume-pdf/generateResumePdf.tsx, src/models/job.model.ts, and src/components/profile/resume-pdf/ProfessionalTemplate.tsx; breaking it would reduce coupling. Several files (e.g., src/lib/scraper/runner.ts, large test suites) exceed 600 lines, increasing cognitive load.

How To Use It

# Clone the upstream repo (the fork you are reviewing)
git clone https://github.com/moses-y/jobsync
cd jobsync

# Build and run with Docker (Dockerfile + docker‑compose.yml are present)
docker compose up -d

# The app listens on http://localhost:3737
# Create an account, then configure AI keys in Settings (environment vars are read from .env.example)

Required env vars are documented in .env.example (e.g., AUTH_SECRET, NEXTAUTH_URL). No additional build scripts are needed; npm install is implicit in the Dockerfile.

Real‑World Use

A small consultancy hosts the container on a VPS, points NEXTAUTH_URL to the public host, and stores the PostgreSQL volume on encrypted storage. Recruiters import candidate resumes, run AI Resume Review to get structured feedback, then use AI Job Match to prioritize openings. All data stays on the VPS, satisfying privacy requirements.

Code Health & Issues

  • MEDIUM – Declare least‑privilege permissions for GITHUB_TOKEN.github/workflows/ci.yml
  • MEDIUM – Enable Dependabot or Renovate – repository lacks an update bot
  • MEDIUM – Pin Docker base image by digest – Dockerfile uses mutable node:20.18.0-alpine
  • MEDIUM – Add dependency‑vulnerability scan to PR workflow – .github/workflows/* missing a scan step
  • MEDIUM – Set persist-credentials: false on checkout – .github/workflows/ci.yml keeps token in .git/config
  • MEDIUM – Add non‑root USER to the image – Dockerfile runs as root
  • LOW – Set timeout-minutes on workflow jobs – .github/workflows/ci.yml lacks timeouts
  • LOW – Add repository convention files (.editorconfig, .gitattributes, formatter config) – missing in root

Additional static findings: high‑impact hub modules (button, use-toast), deep nesting in several UI components, duplicated test blocks, and an import cycle that should be refactored.

The Bottom Line

jobsync delivers a functional, self‑hosted job‑search dashboard with AI‑enhanced résumé review and matching, backed by a solid Next.js/Tailwind stack and comprehensive test coverage. The codebase is healthy overall but would benefit from reducing UI nesting, breaking a circular import, and tightening CI/CD security and Docker hygiene. It is well‑suited for teams that need full data control and are comfortable maintaining a Node/Next.js container.