Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/iDevRanjan/lws-ra-b4-assignment-five/llms.txt

Use this file to discover all available pages before exploring further.

LWS Job Portal is organized as a monorepo with the React frontend at the root and the Express backend nested inside a /backend subdirectory. This page documents every layer of that structure — from how React components are grouped by domain, through the service and routing layers, to the Express controllers and Sequelize models that power the API.

Monorepo Layout

lws-job-portal/
├── src/                    # React 19 frontend source
│   ├── components/         # Reusable UI components, grouped by domain
│   ├── pages/              # Page-level route components
│   ├── routes/             # React Router configuration & guards
│   ├── services/           # Axios instances, API modules, query options
│   ├── store/              # Custom Pub-Sub global state store
│   ├── hooks/              # Shared custom React hooks
│   ├── layouts/            # MainLayout shell component
│   ├── providers/          # QueryObjectProvider and other React providers
│   ├── context/            # Raw React context definitions (QueryObjectContext, authContext)
│   ├── data/               # Static option data for filters and forms
│   └── utils/              # Pure helper functions
├── public/                 # Static assets served by Vite
├── index.html              # Vite HTML entry point
├── vite.config.js          # Vite + Tailwind CSS configuration
├── package.json            # Frontend dependencies & npm scripts
└── backend/                # Express 5 backend
    ├── server.js           # App entry point, middleware, route registration
    ├── routes/             # Express route definitions per domain
    ├── controllers/        # Business logic handlers
    ├── models/             # Sequelize ORM models
    ├── middleware/         # Auth, file upload middleware
    ├── config/             # Database configuration
    └── uploads/            # Multer upload destination (resumes, images)
The frontend and backend are completely decoupled — they communicate exclusively over HTTP through the REST API. Vite’s dev server proxies nothing; the frontend reads VITE_API_BASE_URL from its environment file to locate the backend.

Frontend Structure

Pages — src/pages/

Page-level components map one-to-one with application routes. They are organized by feature area:
SubdirectoryContents
auth/Login, JobSeekerRegister, CompanyRegister
public/Home, JobDetails, CompanyProfile
jobSeeker/JobSeekerDashboard, JobSeekerApplications, JobSeekerProfile, EditJobSeekerProfile
company/CompanyDashboard, ManageJobs, Applicants, ApplicantProfile, CreateAndEditJob, CompanySettings
error/ErrorElement — rendered by React Router’s errorElement and the catch-all path: "*" route

Components — src/components/

UI components follow a domain-driven folder structure:
Job-related display and interaction components: JobCard, JobSearchAndFilter, ManageJobsTable, ApplyJobDialog, and the filter sidebar. These are used on both public and authenticated pages.
Company-specific components: CompanyInfo, ApplicantsCard, and CoverLetterModal for viewing an applicant’s cover letter inside a modal dialog.
Profile and resume components scoped to the USER role: JobSeekerExperience, JobSeekerSkills, and related profile section widgets.
Generic, role-agnostic components reused across the app: ApplyNowButton, Pagination, SearchInput, CompanyAvatar, and similar primitives.
Shell components: Header, Footer, RootFallback, and NavigationProgressBar. The Header renders a different navbar component (LoggedinJobSeekerNavbar from jobSeeker/ or LoggedinCompanyNavbar from company/) based on the authenticated user’s role, read from the custom store via useAuth. Note: MainLayout.jsx lives at src/layouts/MainLayout.jsx, not inside this subfolder.
Placeholder shimmer components displayed during data fetches: JobCardSkeleton, RecentJobsCardSkeleton, ApplicantsCardSkeleton. These replace spinners and prevent layout shift.

Routing — src/routes/

React Router v7’s Data API drives all navigation. The routing layer has three files:
FileRole
AppRoutes.jsxCreates the browser router with the full nested route tree and wraps it in RouterProvider
RoleBasedRoute.jsxAn outlet wrapper that accepts an allowedRole prop ("USER" or "COMPANY") and redirects unauthorized users; paired with roleBasedLoader
PublicRoutes.jsxAn outlet wrapper that redirects already-authenticated users away from login/register pages; paired with publicLoader
Route loaders (routerLoaders.js) prefetch data before the page renders. If a loader throws, React Router activates the nearest errorElement rather than crashing the full layout.

Services & Networking — src/services/

All backend communication is centralized here:
FilePurpose
axiosInstance.jsA pre-configured Axios instance that attaches the JWT Authorization header to every request automatically
authApi.jslogin, register API calls
jobApi.jsJob listing, detail, similar jobs, and recommendations
companyApi.jsCompany profile reads and updates
userApi.jsJob seeker profile reads and updates
queryOptions.jsReusable TanStack Query queryOptions objects (e.g., getAllJobsQueryOption) for consistent cache key management
mutationOptions.jsReusable mutationOptions for create/update/delete operations
routerLoaders.jsReact Router loader functions that call API modules and return data to page components
queryClient.jsGlobal QueryClient instance with default options shared across the app

State Management — src/store/

LWS Job Portal does not use Redux or Zustand. Instead it implements a lightweight Pub-Sub store on top of React’s built-in useSyncExternalStore:
src/store/
├── index.js          # Core store: subscribe/getSnapshot/emit primitives
└── actions/
    └── authActions.js  # setAuth, clearAuth action creators
useAuth.js (in src/hooks/) consumes the store via useSyncExternalStore, giving any component reactive access to the current user’s login state and role without prop drilling or a context re-render cascade.

Hooks — src/hooks/

HookPurpose
useAuth.jsExposes { isAuthenticated, user, role } from the custom Pub-Sub store
useDebounce.jsDelays a value update by a configurable ms interval; used in the job search input to throttle API calls
useQueryObject.jsSyncs filter state bidirectionally with URL query parameters
useApplications.jsEncapsulates TanStack Query logic for fetching and mutating job applications
useProfile.jsEncapsulates profile read and update query/mutation logic for job seekers

Providers, Context, Data & Utils

DirectoryContents
src/providers/QueryObjectProvider.jsx — wraps the Home page to provide query-param filter state to the search and filter components
src/context/Raw React context definitions consumed by providers
src/data/Static arrays/objects for dropdowns and filters: categoryOptionData.js, statusFiltersData.js, skill lists, salary ranges
src/utils/Pure helper functions: slugify.js, formatDate.js, getQueryParams.js, getDateDifferenceFromNow.js, applicationJobChecking.js

Backend Structure

Entry Point — backend/server.js

server.js is the single Express application entry point. It:
  1. Loads environment variables via dotenv
  2. Registers global middleware: CORS (open origin), Morgan request logger, JSON and URL-encoded body parsers
  3. Serves uploaded files as static assets from /uploads
  4. Mounts all route modules under /api/*
  5. Registers a global error handler that formats errors as JSON
  6. Calls sequelize.authenticate() and sequelize.sync() before binding to the port
app.use("/api/auth",         require("./routes/authRoutes"));
app.use("/api/jobs",         require("./routes/jobRoutes"));
app.use("/api/users",        require("./routes/userRoutes"));
app.use("/api/companies",    require("./routes/companyRoutes"));
app.use("/api/applications", require("./routes/applicationRoutes"));
app.use("/api/utils",        require("./routes/utilRoutes"));

Routes — backend/routes/

Each file defines the HTTP verbs and paths for one domain, then delegates to a controller:
Route FileMounted AtDomain
authRoutes.js/api/authRegistration and login
jobRoutes.js/api/jobsJob CRUD, search, pagination, recommendations
userRoutes.js/api/usersJob seeker profile management
companyRoutes.js/api/companiesCompany profile management
applicationRoutes.js/api/applicationsApply, withdraw, status updates
utilRoutes.js/api/utilsShared utility endpoints (e.g., option lists)

Controllers — backend/controllers/

Controllers contain the business logic for each domain. They receive validated request data from the route layer, interact with Sequelize models, and return JSON responses. Errors are passed to next(err) and caught by the global error handler in server.js.

Models — backend/models/

Sequelize ORM models map to SQLite tables. The four core models are:
ModelKey Fields
Userid, name, email, password (bcrypt), role: "USER"
Companyid, name, email, password (bcrypt), role: "COMPANY", description, socialLinks
Jobid, slug, title, category, type, workMode, salary, skills, companyId
Applicationid, jobId, userId, coverLetter, status
sequelize.sync({ force: false }) on server start creates tables if they do not exist without dropping existing data.

Middleware — backend/middleware/

FileExportsPurpose
auth.jsprotect, authorizeprotect verifies the JWT from the Authorization header and attaches req.user. authorize(...roles) ensures the authenticated user’s role is in the permitted list.
upload.jsMulter instanceHandles multipart/form-data for resume PDF uploads, saving files to uploads/resumes/
imageUpload.jsMulter instanceHandles image uploads (e.g., company logos)

Database Config — backend/config/database.js

Configures and exports the Sequelize instance pointing to an SQLite file on disk. No external database server is required — SQLite is bundled via the sqlite3 npm package.

Data Flow

The following diagram describes how a request travels through every layer of the stack, from user interaction to database and back:
Browser


React Component
  │  (user interaction triggers query or mutation)

TanStack React Query
  │  (cache check → stale? → re-fetch)

Axios (axiosInstance)
  │  (attaches JWT Authorization header)

HTTP Request  ──────────────────────────────────────►  Express 5 Router

                                                    protect / authorize
                                                         middleware

                                                          Controller

                                                       Sequelize ORM

                                                           SQLite DB

                                                        JSON Response
◄────────────────────────────────────────────────────────────┘

TanStack React Query
  │  (updates cache, triggers re-render)

React Component re-renders with fresh data

Two-Role System

The USER / COMPANY role distinction is enforced at every layer:
RoleBasedRoute.jsx wraps protected child routes and receives an allowedRole prop. Its paired roleBasedLoader reads the current user from the store; if the role does not match allowedRole, the loader redirects to /login. This means a company user navigating to /jobseeker-dashboard is immediately redirected before any page component renders.
// AppRoutes.jsx (simplified)
{
  element: <RoleBasedRoute allowedRole="USER" />,
  loader: roleBasedLoader,
  children: [
    { path: "jobseeker-dashboard", element: <JobSeekerDashboard /> },
    // ...
  ]
},
{
  element: <RoleBasedRoute allowedRole="COMPANY" />,
  loader: roleBasedLoader,
  children: [
    { path: "company-dashboard", element: <CompanyDashboard /> },
    // ...
  ]
}

Build docs developers (and LLMs) love