Career Bridge is a Bangladesh-focused job discovery and hiring platform with a GitHub-style dark UI and a real backend foundation. It supports job search, salary insights, job seeker authentication, employer job posting, CV applications, saved jobs, employer application review, and basic admin moderation.
The frontend now changes navigation, dashboards, and job actions by role:
- Public Visitor: sees landing content, public job search, salary insight preview, login/register actions, and public job details. Public visitors cannot apply, save jobs, post jobs, view applicants, or access admin tools.
- Job Seeker: sees a dedicated dashboard with profile completion, profile editing, saved jobs, applied jobs, and application status tracking. Job Seekers can apply and save jobs, but cannot post jobs or see employer/admin tools.
- Employer: sees a hiring dashboard with company profile editing, job posting, owned job management, applicant review, application status updates, private employer notes, and protected CV download. Employers do not see Apply or Save job actions.
- Admin: sees platform stats, users, companies, jobs, applications, shortlist queue, reports, company verification, user activation/deactivation, job moderation, and salary insight management.
The backend still enforces authorization. The frontend only hides controls to make the experience clearer.
- Frontend: static HTML, CSS, and JavaScript in
index.html,styles/, andscripts/ - Backend: Node.js + Express in
backend/src - Database: PostgreSQL with Prisma ORM
- Auth: bcrypt-hashed passwords and JWT access tokens
- Uploads: multer-validated CV upload metadata stored in PostgreSQL, files stored under
backend/uploads/ - Security: Helmet, CORS allowlist, rate limiting, request logging, validation, centralized errors, role checks, and ownership checks
- Tests: Vitest + Supertest health check by default, optional database integration suite
- CI: GitHub Actions backend workflow runs dependency install, Prisma generate, and tests from
backend/
From the repository root:
docker compose up -d db
cd backend
npm install
cp .env.example .env
npm run prisma:generate
npm run prisma:migrate
npm run prisma:seed
npm run devOpen:
- App:
http://localhost:4000 - API health:
http://localhost:4000/api/health
If Docker is not installed, create a local PostgreSQL database yourself and set DATABASE_URL in backend/.env.
If login/register shows a database error, open http://localhost:4000/api/health. It should return "database":"connected". If it returns "database":"unavailable", start PostgreSQL and run migrations/seed data before trying the demo accounts.
Homebrew PostgreSQL fallback:
brew install postgresql@16
brew services start postgresql@16
export PATH="$(brew --prefix postgresql@16)/bin:$PATH"
createdb career_bridge
psql -d postgres -c "CREATE USER career_bridge WITH PASSWORD 'career_bridge_password';"
psql -d postgres -c "ALTER DATABASE career_bridge OWNER TO career_bridge;"
cd backend
npm run prisma:migrate
npm run prisma:seed
npm run devbackend/.env.example contains the required local configuration:
DATABASE_URL: PostgreSQL connection stringJWT_SECRET: secret used to sign access tokensJWT_EXPIRES_IN: token lifetime, default8hPASSWORD_RESET_TOKEN_MINUTES: password reset verification-code lifetimeFRONTEND_URL: deployed frontend URLALLOWED_ORIGINS: comma-separated CORS allowlist, or*for local developmentRATE_LIMIT_WINDOW_MS,RATE_LIMIT_MAX,AUTH_RATE_LIMIT_MAXMAX_CV_UPLOAD_MB: default5SMTP_HOST,SMTP_PORT,SMTP_SECURE,SMTP_USER,SMTP_PASS,SMTP_REQUIRE_TLS,SMTP_IGNORE_TLS,EMAIL_FROM: email settings used to send password reset verification codes.SMTP_HOSTenables SMTP;SMTP_USERandSMTP_PASSare optional for local relays.
Never commit real .env files.
Seeded local accounts all use demo1234:
- Admin:
admin@careerbridge.com - Employer:
employer@careerbridge.com - Job seeker:
employee@careerbridge.com
Passwords are stored as bcrypt hashes in the database.
Run these from backend/:
npm run dev # start Express with nodemon
npm start # start Express with node
npm test # run quick API tests
npm run prisma:generate # generate Prisma client
npm run prisma:migrate # apply checked-in migrations
npm run prisma:migrate:dev # create new migrations while developing schema changes
npm run prisma:seed # seed demo data
npm run db:reset # reset DB and rerun migrations/seedOptional database integration tests:
RUN_DB_TESTS=true TEST_DATABASE_URL="postgresql://career_bridge:career_bridge_password@localhost:5432/career_bridge_test?schema=public" npm testUse a separate test database because the integration suite truncates tables.
Auth:
POST /api/auth/registerPOST /api/auth/loginPOST /api/auth/logoutPOST /api/auth/forgot-passwordPOST /api/auth/reset-passwordGET /api/auth/me
Jobs:
GET /api/jobs?q=&location=&jobType=&workplaceType=&experienceLevel=&salaryMin=&salaryMax=&companyId=&status=&page=&limit=&sort=GET /api/jobs/:idPOST /api/jobsemployer onlyPATCH /api/jobs/:idowning employer or adminPATCH /api/jobs/:id/statusGET /api/jobs/:id/applications
Applications and CVs:
POST /api/applicationsjob seeker only, multipartcvFileGET /api/applications/meGET /api/applicationsemployer/adminGET /api/employer/applicationsPATCH /api/applications/:id/statusPATCH /api/applications/:id/noteGET /api/applications/:id/resumeGET /api/applications/:id/cvlegacy alias
Profiles, saved jobs, companies, salary insights, and admin:
GET/PATCH /api/profile/meGET /api/profile/:userIdGET /api/saved-jobs/mePOST /api/saved-jobs/:jobIdDELETE /api/saved-jobs/:jobIdGET /api/companiesGET /api/companies/:idGET/PATCH /api/employer/companyGET /api/employer/dashboardGET /api/salariesGET /api/salary-insightsGET /api/admin/statsGET/PATCH /api/admin/usersGET /api/admin/companiesPATCH /api/admin/companies/:id/verifyGET /api/admin/jobsPATCH /api/admin/jobs/:id/statusGET /api/admin/applicationsGET /api/admin/reportsPOST /api/reportsPATCH /api/admin/reports/:id/statusPOST/PATCH/DELETE /api/admin/salary-insights
JOB_SEEKER: can update their profile, save jobs, apply to open jobs, view their own application statuses, and download their own submitted resumeEMPLOYER: can create draft jobs, manage only jobs owned by their companies, view only applicants for their jobs, update application status and private notes, and download owned applicant resumesADMIN: can view platform-wide stats, users, companies, jobs, applications, reports, verify/unverify companies, deactivate users, and moderate jobs
Duplicate applications are blocked by a database unique constraint on jobId + applicantUserId.
Companies must be verified by an admin before their jobs can be published as public OPEN listings. Unverified employer-created listings are saved as drafts and cannot be opened until verification.
Reports can be submitted by signed-in users for suspicious jobs, companies, or users. Admins can track reports as OPEN, REVIEWING, RESOLVED, or DISMISSED.
Password reset uses hashed one-time verification codes. With SMTP_HOST configured, Career Bridge emails a 6-digit code to the account email. The code is not shown in the browser. For isolated local demos only, SHOW_DEVELOPMENT_RESET_CODE=true can expose the code outside production.
CV uploads accept only .pdf, .doc, and .docx with matching MIME types. File size defaults to 5 MB. Stored filenames are generated safely, resume metadata is saved on the Application record, and raw upload folders are not publicly served. Future production storage should move to S3, Supabase Storage, Firebase Storage, or Cloudinary.
Uploaded files are ignored by git except backend/uploads/.gitkeep.
The Apply modal also includes an optional browser-side CV Builder. Job Seekers can upload an existing CV or fill the builder form, preview it, and attach a generated career-bridge-cv.pdf to the same application upload endpoint.
- Seed the database and start
npm run dev. - Public visitor can view jobs and salary insights but cannot apply without login.
- Job Seeker can login/register.
- Job Seeker can save a job.
- Job Seeker can apply to a job with a PDF/DOC/DOCX CV.
- After applying, the job button changes to Applied immediately and still shows Applied after refresh.
- Duplicate applications are blocked with a friendly already-applied message.
- Job Seeker can apply with the optional CV Builder generated PDF.
- Job Seeker can see application status in the dashboard.
- Employer can login/register with company creation.
- Employer can post a job.
- Employer can view only own applicants.
- Employer can update application status and save private notes.
- Employer does not see Apply or Save buttons.
- Admin can login.
- Admin can see platform stats.
- Admin can filter applications, understand the Shortlisted queue, update statuses, and download CVs when authorized.
- Admin can manage users, verify companies, moderate jobs, update report statuses, and manage salary insights.
- Forgot Password sends a verification code by email when SMTP is configured, then resets the password after code verification.
- Unauthorized users cannot access restricted actions.
- App still uses the GitHub dark UI and every button has a visible label.
- Confirm
backend/uploads/,.env, andnode_modules/remain untracked.
- Set a production
DATABASE_URL, strongJWT_SECRET, and strictALLOWED_ORIGINS. - Run
npm ci,npm run prisma:generate, andnpx prisma migrate deploy. - Use persistent object storage for CVs before production traffic.
- Keep
NODE_ENV=productionso stack traces are hidden. - Do not expose
backend/uploads/as a public static directory. - GitHub Pages can host only the static frontend. It cannot run Express, Prisma, PostgreSQL, file uploads, or JWT-protected API routes.
- Deploy the backend separately on a Node-capable host such as Render, Railway, Fly.io, DigitalOcean App Platform, Heroku-compatible platforms, or a VPS.
- After deploying the backend, set the frontend API base URL with the
career-bridge-api-basemeta tag inindex.html, for example<meta name="career-bridge-api-base" content="https://your-api.example.com" />, and add the frontend origin toALLOWED_ORIGINS.