A clean, production-ready Express.js REST API — serving job listings, accommodation data, form submissions, and CV delivery via email attachment.
- ✨ Features
- 🗂️ Project Structure
- 🔌 API Reference
- 📬 Email & CV Delivery
- ⚙️ Environment Variables
- 🚀 Getting Started
- ☁️ Deployment
- 🛡️ Security
- 🤝 Contributing
- 📄 License
| Feature | Details |
|---|---|
| 🗃️ Job Listings API | Full CRUD-ready routes for browsing and filtering jobs |
| 🏠 Accommodation API | Verified PG, hostel, and apartment listings with filtering |
| 📄 CV Email Delivery | Resumes uploaded as base64 are emailed as attachments via Resend |
| 📝 Form Submissions | Job posting, room listing, general enquiry — all validated and stored |
| 📧 Newsletter Subscriptions | Email collection with duplicate detection |
| 🏥 Health Check Endpoint | /api/health for uptime monitoring |
| 🔒 Input Validation | Server-side required-field validation on all POST routes |
| 🌐 CORS Configured | Open CORS for frontend clients on any domain |
| 📝 Request Logging | Timestamped logs for every inbound request |
| 🚀 Render-ready | Zero-config deployment to Render.com |
backend/
├── server.js ← Express app entry point, middleware, route mounting
│
├── routes/
│ ├── jobs.js ← GET /api/jobs, GET /api/jobs/:id
│ ├── accommodation.js ← GET /api/accommodation, GET /api/accommodation/:id
│ └── contact.js ← POST routes: job, room, general, apply, enquire, resume, newsletter
│
├── data/
│ ├── jobs.js ← Static seed data — 15+ job listings
│ ├── accommodation.js ← Static seed data — accommodation listings
│ └── submissions.js ← In-memory store for form submissions
│
├── create-preset.js ← Dev utility script
├── .env.example ← Environment variable template
├── .env ← Your local secrets (git-ignored)
├── package.json
└── README.md
Base URL: https://good-jobs-backend.onrender.com/api
GET /api/healthResponse:
{
"status": "ok",
"service": "Good Jobs API",
"version": "1.0.0",
"timestamp": "2025-06-03T01:30:00.000Z",
"environment": "production"
}GET /api/jobsQuery Parameters:
| Parameter | Type | Description |
|---|---|---|
q |
string |
Search by title, company, area, or skills |
city |
string |
Filter by city (e.g. Ahmedabad) |
industry |
string |
Filter by industry (e.g. IT & Technology) |
type |
string |
Filter by job type (Full-time, Part-time, Contract) |
salary |
number |
Minimum monthly salary in ₹ (e.g. 20000) |
Example Request:
GET /api/jobs?city=Ahmedabad&type=Full-time&salary=20000Example Response:
{
"success": true,
"count": 8,
"data": [
{
"id": 1,
"title": "Frontend Developer",
"company": "TechCorp India",
"city": "Ahmedabad",
"area": "Navrangpura",
"industry": "IT & Technology",
"type": "Full-time",
"salaryMin": 25000,
"salaryDisplay": "₹25,000 – ₹35,000/mo",
"skills": ["React", "JavaScript", "CSS"],
"posted": "2 days ago",
"openings": 2,
"desc": "...",
"requirements": ["..."],
"benefits": ["..."],
"logo": "TC",
"logoColor": "#0d9488"
}
]
}GET /api/jobs/:idExample Request:
GET /api/jobs/1Response: Same job object as above, wrapped in { "success": true, "data": { ... } }
Error (404):
{ "success": false, "message": "Job not found" }GET /api/accommodationQuery Parameters:
| Parameter | Type | Description |
|---|---|---|
q |
string |
Search by name or area |
city |
string |
Filter by city |
type |
string |
PG, Hostel, or Apartment |
gender |
string |
Male, Female, or Any |
price |
number |
Maximum monthly rent in ₹ |
Example Response:
{
"success": true,
"count": 10,
"data": [
{
"id": 1,
"name": "Sunrise PG",
"city": "Ahmedabad",
"area": "Satellite",
"type": "PG",
"gender": "Female",
"price": 7500,
"distance": "1.2 km from Crossword",
"amenities": ["WiFi", "AC", "Meals", "Laundry"],
"rating": 4.6,
"ownerName": "Priya Shah",
"ownerPhone": "+91 98765 43210"
}
]
}GET /api/accommodation/:idPOST /api/contact/job
Content-Type: application/jsonRequired Body Fields:
| Field | Type | Description |
|---|---|---|
companyName |
string |
Company name |
companyEmail |
string |
Contact email |
jobTitle |
string |
Job title |
jobCity |
string |
Job location city |
jobIndustry |
string |
Industry category |
jobType |
string |
Full-time / Part-time / Contract |
jobDesc |
string |
Role description |
Success Response (201):
{
"success": true,
"message": "Job listing submitted! Our team will review and publish it within 24 hours.",
"data": { "id": "uuid", "createdAt": "2025-06-03T..." }
}POST /api/contact/room
Content-Type: application/jsonRequired Body Fields: propName, ownerName, ownerPhone, propType, propGender, propCity, propPrice, propAddress
POST /api/contact/general
Content-Type: application/jsonRequired Body Fields: genName, genEmail, genSubject, genMessage
POST /api/contact/resume
Content-Type: application/jsonRequired Body Fields:
| Field | Type | Description |
|---|---|---|
applicantName |
string |
Full name of the applicant |
applicantEmail |
string |
Applicant's email |
applicantPhone |
string |
Phone number (optional) |
coverNote |
string |
Cover letter text (optional) |
jobId |
number |
Target job ID |
jobTitle |
string |
Target job title |
fileName |
string |
Original filename of the CV |
fileSize |
string |
Human-readable size (e.g. "245 KB") |
fileBase64 |
string |
Base64-encoded PDF/Word file content |
Note: Maximum file size is 5 MB (enforced server-side). The CV is emailed as an attachment via the Resend API.
POST /api/contact/enquire
Content-Type: application/jsonRequired Body Fields: enquirerName, enquirerEmail, accId, accName
Optional: enquirerPhone, message
POST /api/newsletter
Content-Type: application/jsonBody:
{ "email": "user@example.com" }All error responses follow this shape:
{
"success": false,
"message": "Descriptive error message here"
}| Status | Meaning |
|---|---|
400 |
Bad Request — missing or invalid fields |
404 |
Not Found — resource doesn't exist |
500 |
Internal Server Error — unexpected failure |
The /api/contact/resume endpoint handles CV delivery without storing any files:
Applicant uploads PDF/Word on frontend
↓
File converted to base64 in the browser
↓
POST /api/contact/resume (JSON payload with base64 string)
↓
Server validates fields & file size (≤ 5 MB)
↓
Resend API called → email sent with CV as attachment
↓
201 success returned to frontend
Email includes:
- Job title and ID
- Applicant name, email, and phone
- Cover note / message
- Attached CV (PDF or Word)
Configure the destination inbox via NOTIFICATION_EMAIL in your .env.
Copy .env.example to .env and fill in your values:
cp .env.example .env| Variable | Required | Description |
|---|---|---|
PORT |
No | Server port (default: 3000). Render sets this automatically. |
NODE_ENV |
No | development or production |
RESEND_API_KEY |
Yes (for email) | Your Resend API key |
NOTIFICATION_EMAIL |
Yes (for email) | Where CV application emails are delivered |
CLOUDINARY_CLOUD_NAME |
Optional | Cloudinary cloud name (for future file hosting) |
CLOUDINARY_API_KEY |
Optional | Cloudinary API key |
CLOUDINARY_API_SECRET |
Optional | Cloudinary API secret |
⚠️ Never commit your.envfile. It is listed in.gitignoreby default.
- Node.js
>= 18.0.0 - npm
>= 9.0.0 - A Resend account and API key (for email features)
# 1. Clone the repository
git clone https://github.com/raunak0400/Good-Jobs-Frontend.git
cd Good-Jobs-Frontend/backend
# 2. Install dependencies
npm install
# 3. Set up environment variables
cp .env.example .env
# Edit .env and fill in your RESEND_API_KEY and NOTIFICATION_EMAIL
# 4. Start the development server (with auto-reload)
npm run dev
# — OR — start in production mode
npm startThe server will start at http://localhost:3000
🚀 Good Jobs API running on http://localhost:3000
Health check: http://localhost:3000/api/health
Jobs: http://localhost:3000/api/jobs
Accommodation:http://localhost:3000/api/accommodation
# Health check
curl http://localhost:3000/api/health
# Get all jobs
curl http://localhost:3000/api/jobs
# Get job #1
curl http://localhost:3000/api/jobs/1
# Filter jobs
curl "http://localhost:3000/api/jobs?type=Full-time&salary=20000"- Push your code to GitHub
- Go to render.com → New Web Service
- Connect your GitHub repository
- Set the following:
| Setting | Value |
|---|---|
| Root Directory | backend |
| Build Command | npm install |
| Start Command | npm start |
| Node Version | 18 |
- Add your environment variables in the Render dashboard
- Click Deploy — your API will be live in minutes
Render automatically sets the
PORTenvironment variable.
# Install Railway CLI
npm i -g @railway/cli
railway login
railway init
railway up- No secrets in code — all credentials via environment variables
- File size enforcement — base64 payloads over 7 MB (≈ 5 MB file) are rejected before processing
- Input validation — all POST endpoints validate required fields before any logic runs
- No file storage — CVs are never written to disk; they go straight from memory to email
- CORS — currently open (
*) for flexibility with the static frontend; restrict to your frontend domain in production
To report a vulnerability, see SECURITY.md.
We welcome contributions! Please read CONTRIBUTING.md first.
# Fork and clone
git clone https://github.com/YOUR_USERNAME/Good-Jobs-Frontend.git
# Create a feature branch
git checkout -b feat/your-feature
# Make changes, then commit
git commit -m "feat: describe your change"
# Push and open a PR
git push origin feat/your-featureThis project is licensed under the MIT License — see LICENSE for details.
Good Jobs Backend API · Built with Express.js · Deployed on Render · Email by Resend
Empowering North-East India's Workforce — One API Call at a Time