NeatNest is a full-stack job posting app with a React frontend and an Express backend. It uses Kafka for asynchronous job event processing, PostgreSQL for persistence, and email notifications for newly posted jobs.
- Google sign-in (frontend)
- Recruiter flow to post jobs
- Job seeker flow to browse jobs
- Express REST API for jobs and users
- Kafka producer/consumer for job events
- PostgreSQL storage for users/jobs
- Email notifications via Nodemailer when new jobs are processed
- Frontend: React, Vite, Tailwind CSS, React Router
- Backend: Node.js, Express, KafkaJS, pg
- Database: PostgreSQL
- Messaging: Apache Kafka (with Zookeeper via Docker Compose)
- Auth UI: Google OAuth (
@react-oauth/google)
.
├── client/ # React + Vite frontend
├── server/ # Express API + Kafka producer/consumer
├── database/ # SQL setup/seed scripts
├── docker-compose.yml # Kafka + Zookeeper local services
├── package.json # Root workspace scripts
└── README.md
- Node.js 18+
- npm 9+
- PostgreSQL (local or remote)
- Docker + Docker Compose (for Kafka/Zookeeper)
- Google OAuth Client ID (for frontend login)
- Gmail app password (or working SMTP creds) for email notifications
Create server/.env with:
PORT=8000
DB_USER=your_db_user
DB_HOST=localhost
DB_DATABASE=neatnest
DB_PASSWORD=your_db_password
DB_PORT=5432
KAFKA_BROKERS=localhost:9092
EMAIL_USER=your_email@gmail.com
EMAIL_PASS=your_app_password
NOTIFICATION_TO=recipient@example.comCreate client/.env with:
VITE_GOOGLE_CLIENT_ID=your_google_oauth_client_idFrom the repo root:
npm install
npm run install-client
npm run install-serverOr use the helper script:
npm run install-all- Create a PostgreSQL database (example:
neatnest). - Run SQL scripts from
database/.
Example:
psql -U <user> -d neatnest -f database/setup.sql
psql -U <user> -d neatnest -f database/seed.sqlNote: The SQL scripts in database/ and some server controllers are not fully in sync in this branch. Review table definitions before seeding/running if you hit schema errors.
Start Kafka and Zookeeper:
docker compose up -dStop them:
docker compose downBackend:
npm run dev-serverFrontend:
npm run dev-clientnpm run dev- Frontend:
http://localhost:3000 - Backend API:
http://localhost:8000
Vite proxies /api/* requests from the frontend to the backend.
GET /- API welcome message
POST /api/jobs- Sends a job payload to Kafka (then consumer stores it in PostgreSQL)GET /api/jobs- Returns all jobs from PostgreSQLGET /api/jobs/:id- Returns a job by ID
GET /api/users- Returns all usersGET /api/users/:id- Returns a user by IDPOST /api/users- Creates a user and emits a Kafka user eventDELETE /api/users/:id- Deletes a user
{
"description": "Deep clean 2-bedroom apartment",
"deadline": "2026-03-01T16:00:00.000Z",
"budget": 150,
"createdBy": "Alex"
}- Frontend submits a job to
POST /api/jobs - Backend producer publishes the message to Kafka topic
jobs - Kafka consumer reads the message
- Consumer inserts job into PostgreSQL
- Consumer sends an email notification
server/app.jsdefinesPOST /api/jobsdirectly and also mountsserver/routes/jobs.js; the direct route handles the request first.server/kafka/producer.jscurrently sends all messages to thejobstopic even when a different topic name is passed.database/setup.sql,database/seed.sql, and controller queries reference different schemas in places.server/models/db.jslogs database connection environment values on startup (including presence of secrets), which may not be desirable outside local development.
A basic GitHub Actions workflow exists at .github/workflows/ci.yml and currently runs a placeholder step.
- Create a feature branch
- Make your changes
- Test locally (frontend, backend, Kafka, DB)
- Open a pull request
No license is currently specified in this repository.