Busy

Job Posting Platform

End-to-end recruitment platform with public job discovery, candidate self-service, and protected backoffice hiring workflows.

Role

Full-Stack Engineer

Timeline

2020

Platform

Web

Focus

Recruitment Workflow

Back to Case Studies

Overview

Built a hiring workflow system that combines a React/Vite frontend, candidate-facing application flows, recruiter backoffice tools, and a TypeScript Express.js backend.

Problem

Recruiting workflows were spread across manual tools, making job status, candidate progress, access control, and decision history difficult to manage consistently.

Solution

Delivered a structured job posting platform with public job pages, candidate accounts, application review workflows, RBAC, audit logs, file handling, notification foundations, and production-style CI/CD.

Role

Full-Stack Engineer

Timeline

2020

Stack

ReactViteTypeScriptAnt DesignReact RouterTanStack React QueryReact Hook FormZodNode.jsExpressPostgreSQLOpenAPIPM2GitHub Actions

Requirements

Functional & non-functional

Functional

  • Public job listing and job detail pages
  • Candidate registration, authentication, profile, inbox, and application tracking
  • Resume upload and application submission flow
  • Backoffice job posting management
  • Application review, stages, notes, interviews, offers, and rejection flow
  • User, role, permission, candidate, report, and audit management
  • Notification, inbox, background job, and file storage support

Non-functional

  • Typed API contract between frontend and backend
  • Permission-based access control for protected backoffice routes
  • Maintainable modular structure across frontend and backend
  • Production-style validation, CI/CD, deployment, and health checks

System Design

Architecture + data flow

Architecture

The system uses a React/Vite frontend with feature-first modules and a TypeScript Express.js backend with PostgreSQL, OpenAPI, RBAC, audit logging, file storage, notifications, and background jobs.

Key Decisions

  • Separated public, candidate, and backoffice surfaces to keep user flows clear.
  • Used OpenAPI-generated TypeScript types to keep frontend and backend contracts aligned.
  • Organized frontend and backend by feature modules instead of technical layers only.
  • Structured the Express.js backend into clear feature modules to reduce operational overhead while preserving maintainable boundaries.
  • Used RBAC and candidate ownership checks so UI permissions and backend authorization stay aligned.

Data Flow

  • Candidate → public job detail → apply form → resume upload → backend application record.
  • Recruiter → backoffice job posting form → API use case → PostgreSQL transaction → audit/outbox events.
  • Application update → backend workflow → candidate-visible update → inbox/notification flow.
  • Page → React Query hook → feature API module → typed API client → backend endpoint.
Job Posting Platform architecture diagram

Flow & Data

State flow and data model

Flow Steps

  • Candidate → public job detail → apply form → resume upload → backend application record.
  • Recruiter → backoffice job posting form → API use case → PostgreSQL transaction → audit/outbox events.
  • Application update → backend workflow → candidate-visible update → inbox/notification flow.
  • Page → React Query hook → feature API module → typed API client → backend endpoint.

Data Model

Entities

  • Job
  • JobPosting
  • Candidate
  • JobApplication
  • ApplicationStage
  • Interview
  • Offer
  • User
  • Role
  • Permission
  • File
  • InboxItem
  • AuditLog

Relationships

  • Job Posting exposes a public Job detail
  • Candidate has many Job Applications
  • Job Application belongs to Candidate and Job Posting
  • Application Stage records review progress
  • Interview and Offer belong to Job Application
  • User has Roles and Permissions for backoffice access
  • File metadata stores resume references
  • Audit Log records important backoffice mutations

Business Logic

Rules that drive decisions

  • Candidates can only manage and view their own applications.
  • Backoffice actions are gated by role and permission codes.
  • Job postings move through draft, published, unpublished, and closed states.
  • Application review actions update status history and candidate-visible progress.
  • Important mutations create audit history and can trigger notification or inbox work.
  • Resume files are accessed through controlled file metadata and authorization rules.

Demo

Available app and product links

Scope & Constraints

Project boundaries

Scope

  • Public job board
  • Candidate account and application tracking
  • Backoffice hiring operations
  • Job posting and application review workflow
  • Role, permission, user, candidate, report, and audit management
  • Backend API, file handling, notification foundation, and deployment workflow

Constraints

  • Multiple user surfaces with different authentication flows
  • Complex authorization rules across candidate and backoffice users
  • Contract consistency between frontend and backend
  • Production-style deployment and rollback requirements

Your Contribution

What I handled directly

  • Designed and implemented feature-first frontend modules for public, candidate, and backoffice surfaces.
  • Built backend modules for job postings, applications, candidates, auth, RBAC, files, notifications, inbox, reports, and audit logs.
  • Integrated OpenAPI-generated types and typed API clients between frontend and backend.
  • Implemented protected routes, permission gates, form validation, loading, empty, and error states.
  • Structured CI/CD workflows, release artifacts, health checks, and PM2 deployment behavior.
  • Documented product scope, architecture, API contract, and deployment standards.

Challenges → Solutions

Key problem solving

Challenge

Public, candidate, and backoffice users needed different flows without mixing access rules.

Solution

Separated route surfaces, auth providers, permission gates, and backend authorization checks by user type.

Challenge

Application review involved many state transitions, notes, interviews, offers, and candidate-visible updates.

Solution

Modeled the workflow around explicit application actions, status history, and feature-specific modules.

Challenge

Frontend and backend changes needed to stay aligned across many endpoints.

Solution

Used OpenAPI contracts and generated TypeScript types to keep API usage explicit and maintainable.

Trade-offs

Decisions and compromises

  • A single Express.js backend kept deployment and development simpler than splitting the system into separate services.
  • Feature-first frontend modules improved clarity but required consistent shared UI and API conventions.
  • Permission gates improve UX, while backend authorization remains the source of truth.

Lessons Learned

What we would repeat

  • Recruitment systems need clear state transitions because small ambiguity creates operational confusion.
  • OpenAPI contracts reduce integration drift when frontend and backend evolve together.
  • Separating candidate and backoffice auth surfaces reduces permission leakage risk.
  • Production-style deployment needs health checks and rollback behavior, even for portfolio-scale systems.

Edge Cases

Stability in production

  • Duplicate application attempts for the same job
  • Expired or invalid candidate verification flow
  • Unauthorized backoffice access to restricted modules
  • Resume upload failures or invalid file references
  • Application status changes while a reviewer is viewing stale data
  • Notification or background job failure after a successful main transaction
  • Health or deployment rollback when a release fails readiness checks

Impact

Results and outcomes

Centralized hiring flow
Workflow
RBAC + ownership rules
Access
OpenAPI typed integration
Contract

Gallery

Key screens

Job Posting Platform Public job discovery
Public job discovery

Key Takeaways

What mattered most

  • Web
  • Recruitment
  • Full-Stack
  • RBAC