Project context: Swift Hire is a FAST-NUCES SE2004 Team 1 project, not a solo project. Contributor roles and the evidence-backed portfolio boundary are recorded in ATTRIBUTION.md.
A dual-driven HR automation platform. Candidates upload CVs; employers type hiring prompts. The system auto-matches, ranks, schedules interviews, and sends reminders — no external AI API.
| Layer | Technology |
|---|---|
| Backend | Java 17, Spring Boot 3.2 |
| Auth | Spring Security + JWT (jjwt 0.12) |
| ORM | Spring Data JPA + Hibernate |
| Database | MySQL 8 |
| CV Parsing | Apache PDFBox 3 |
| JavaMail / Gmail SMTP | |
| Scheduler | Spring @Scheduled |
| Frontend | React 18 + Vite |
| Charts | Chart.js + react-chartjs-2 |
swift-hire/
├── backend/ # Spring Boot (Maven)
│ ├── pom.xml
│ └── src/main/java/com/swifthire/
│ ├── auth/ # JWT, login, signup, password reset
│ ├── user/model/ # User, Candidate, Employer, Role, AccountStatus
│ ├── user/repository/ # UserRepository, CandidateRepository, EmployerRepository
│ ├── candidate/ # CV upload, PDFBox parser, preferences, matching
│ ├── employer/ # Employer profile CRUD
│ ├── job/ # HiringPrompt, JobPosting, PromptEngine, ATS scoring
│ ├── scheduling/ # InterviewWindow, InterviewSlot, ScheduleService
│ ├── automation/ # EmailService (SMTP), ReminderScheduler (cron),
│ │ # NotificationLog entity + repo (NFR 3.7.3)
│ ├── review/ # Review model, rate candidate/employer
│ ├── analytics/ # Candidate + Employer analytics APIs
│ ├── admin/ # Manage users (ban/block), system reports
│ ├── dictionary/ # KnownSkillsDictionary (seed table)
│ ├── config/ # SecurityConfig, CorsConfig, RateLimitInterceptor
│ └── common/ # ApiResponse<T>, GlobalExceptionHandler
└── frontend/ # React + Vite
└── src/
├── api/ # axios instance + per-module API files
├── context/AuthContext.jsx # JWT storage, login/logout
├── components/common/ # ProtectedRoute, StarRating
├── pages/auth/ # Login, Signup, ResetPassword, VerifyEmail
├── pages/shared/ # MyInterviews (role-aware: candidate + employer)
├── pages/candidate/ # Dashboard, Profile, JobPostings, Analytics, RateEmployer
├── pages/employer/ # Dashboard, HiringPrompt, RecommendedCandidates,
│ # AutoSchedule, RateCandidate, EmployerProfile, Analytics
└── pages/admin/ # AdminDashboard, ManageUsers (+ Audit Log), SystemReports
No extra config needed for testing. Gmail SMTP credentials and DB defaults are already set in
application.properties. All tables are auto-created on first run (ddl-auto=update).
Verification email links will work on any device, any network (phone, teammate's laptop, etc.).
Prerequisites: Sign up free at ngrok.com → install → authenticate once:
# macOS
brew install ngrok
ngrok config add-authtoken <your-token>
# Windows — download from ngrok.com/download, then:
ngrok config add-authtoken <your-token>Then just run the launcher script (starts ngrok + backend automatically):
# macOS
bash start-ngrok.sh
# Windows — double-click start-ngrok.bat, or:
start-ngrok.batStart frontend normally in a separate terminal: npm run dev
1. Start MySQL
brew services start mysql
mysql -u root -e "CREATE DATABASE IF NOT EXISTS swift_hire;"2. Seed Demo Data + Admin Account (run once after DB is created)
mysql -u root swift_hire < ~/Desktop/swift-hire/seed.sql
# Login: admin@swifthire.com / Admin@12343. Start Backend
Maven on macOS defaults to the Homebrew JDK. The
JAVA_HOMEprefix forces Java 17 — don't skip it.
cd ~/Desktop/swift-hire/backend
JAVA_HOME=/opt/homebrew/opt/openjdk@17 mvn spring-boot:run
# API live at http://localhost:80804. Start Frontend
cd ~/Desktop/swift-hire/frontend
npm install # first time only
npm run dev
# UI live at http://localhost:51731. Start MySQL
Open MySQL Workbench or MySQL Shell and run:
CREATE DATABASE IF NOT EXISTS swift_hire;Or if MySQL is in your PATH:
mysql -u root -e "CREATE DATABASE IF NOT EXISTS swift_hire;"2. Seed Demo Data + Admin Account (run once after DB is created)
mysql -u root swift_hire < seed.sql
rem Login: admin@swifthire.com / Admin@12343. Start Backend
Open Command Prompt or PowerShell in the backend folder, then:
set JAVA_HOME=C:\Program Files\Java\jdk-17
mvn spring-boot:runIf
mvnis not recognized, download Maven and add it to your PATH. Adjust theJAVA_HOMEpath to wherever Java 17 is installed on your machine.
4. Start Frontend
cd frontend
npm install
npm run devcurl -s http://localhost:8080/api/auth/login \
-X POST -H "Content-Type: application/json" \
-d "{\"email\":\"test@test.com\",\"password\":\"test\"}"
# Expected: {"success":false,"message":"Invalid email or password."}| Member | Roll # | Module |
|---|---|---|
| Saad Mehmood | 24L-3050 | BE1: Core/Auth + Admin + DB Schema |
| [BE2 member] | — | BE2: Candidate Module (PDFBox, preferences, matching) |
| [BE3 member] | — | BE3: Employer Module (Prompt Engine, ATS, JobPostings) |
| [BE4 member] | — | BE4: Automation (Auto-Schedule, Cron, Email, Reviews) |
| [FE1 member] | — | FE1: Candidate-facing UI |
| [FE2 member] | — | FE2: Employer + Admin UI |
| UC | Name |
|---|---|
| UC-01 | Login (JWT, lockout after 5 failures, role-based redirect) |
| UC-02 | Process Hiring Prompt (Regex NLP, ATS scoring, job posting saved) |
| UC-03 | View Recommended Candidates (ranked by ATS score, profile view) |
| UC-04 | Auto-Schedule Batch (45-min slots, Jitsi Meet links, emails both parties) |
| UC-05 | Rate Candidate (1–5 stars, gated behind COMPLETED slot) |
| UC-06 | Sign Up (password strength via @Pattern, role: CANDIDATE or EMPLOYER) |
| UC-07 | Log Out (JWT cleared client-side, redirect) |
| UC-08 | Manage Candidate Profile |
| UC-09 | Upload CV (PDFBox PDF parsing, skills extracted to DB) |
| UC-10 | Set Preferences (location, shift, job type) |
| UC-11 | View Job Postings (ranked feed for candidate) |
| UC-12 | Rate Employer (1–5 stars, gated behind COMPLETED slot) |
| UC-13 | Manage Users (admin: view, filter, ban/block/activate + audit log) |
| UC-14 | View System Reports + CSV Export |
| UC-15 | Send Interview Reminders (cron 7d/3d/1d, logged to DB) |
| UC-16 | View Hiring Analytics (5+ Chart.js charts) |
| UC-17 | Manage Employer Profile |
| NFR | Implementation |
|---|---|
| Prompt parse ≤3s | Regex + in-memory dictionary lookup |
| CV parse ≤5s | PDFBox + word-boundary matching |
| BCrypt password hashing | BCryptPasswordEncoder bean |
| JWT + configurable expiry | jwt.expiry-ms in properties |
| Email verification on signup (NFR 3.4.4) | UUID token, 24h expiry, blocks login until verified |
| Rate limiting (NFR 3.6.6) | Per-IP sliding window: 10 req/min on login, 100 req/min elsewhere → 429 |
| Strong password (NFR 3.8.2) | @Pattern regex on SignupRequest |
| Account lockout after 5 failures (NFR 3.8.4) | failedLoginAttempts counter, admin can re-activate |
| Audit logs for admin actions (NFR 3.8.5) | Every approve/block/deactivate logged to audit_logs |
| Email retry ×3 (NFR 3.7.2) | @Retryable(maxAttempts=3) on EmailService |
| Notification DB log (NFR 3.7.3) | NotificationLog entity — SENT/FAILED per reminder |
| No duplicate reminders (NFR 3.7.5) | reminderSent7d/3d/1d flags on InterviewSlot |
| Archive deleted jobs (NFR 3.9.5) | Soft-delete → ARCHIVED status |
- Maven on macOS: always
JAVA_HOME=/opt/homebrew/opt/openjdk@17 mvn <cmd>— Homebrew defaults to latest JDK - PDFBox 3.x API: use
Loader.loadPDF(byte[])—PDDocument.load(InputStream)was removed - CV parsing regex: use
Pattern.find()notString.matches()— multi-line PDF text requires substring search - Stale JWT: after a backend restart, log out and back in — old tokens cause 403s without a
messagefield Map.of()with mixed types: useLinkedHashMapwith explicitput()—Map.of()infers a complex intersection type incompatible withMap<String, Object>- Jitsi Meet links:
https://meet.jit.si/swift-hire-<12-char-uid>— no API key needed; DB column still namedcalendlyLink - Cross-device testing (phone/other machine on same WiFi): the email verification link uses
localhostby default, which only works on the same machine. To test across devices: find your LAN IP (ipconfigon Windows,ifconfig | grep 192on macOS), then start the backend withFRONTEND_URL=http://192.168.x.x:5173. Vite already exposes on LAN viahost: trueinvite.config.js.