A full-stack web application for managing job applications with user authentication, built as a learning project to demonstrate CRUD operations, authentication, and modern web development practices.
- π User Authentication - Secure signup/login with session-based authentication
- β Create Jobs - Add new job applications with company, title, status, date, and notes
- βοΈ Edit Jobs - Update application details with a modal interface
- ποΈ Delete Jobs - Remove job entries with confirmation
- π Filter by Status - View jobs by application status (Applied, Interviewing, Offer, Rejected, Accepted)
- π± Responsive Design - Works on desktop, tablet, and mobile devices
- π¨ Modern UI - Clean interface with Tailwind CSS and smooth animations
- π Private & Secure - Users can only view and manage their own jobs
- React - UI library
- Vite - Build tool and dev server
- Tailwind CSS - Utility-first CSS framework
- JavaScript (ES6+) - Modern JavaScript features
- Node.js - Runtime environment
- Express.js - Web framework
- PostgreSQL - Relational database
- Supabase - Database hosting
- bcrypt - Password hashing
- express-session - Session management
- validator - Input validation
- Vercel - Hosting platform (frontend + serverless backend)
- Node.js (v18 or higher)
- npm or yarn
- Supabase account (for database)
- Clone the repository
git clone https://github.com/yourusername/job-tracker.git
cd job-tracker- Install dependencies
# Install backend dependencies
cd server
npm install
# Install frontend dependencies
cd ../client
npm install-
Set up environment variables
Backend (
server/.env):
DATABASE_URL=your_supabase_connection_string
SESSION_SECRET=your_random_secret_here
PORT=8000
NODE_ENV=development
CLIENT_URL=http://localhost:5173Frontend (client/.env.development):
VITE_API_URL=http://localhost:8000-
Set up the database
Run this SQL in your Supabase SQL editor:
-- Create statuses table
CREATE TABLE statuses (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Insert status options
INSERT INTO statuses (name) VALUES
('Applied'),
('Interviewing'),
('Rejected'),
('Offer'),
('Accepted');
-- Create users table
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Create jobs table
CREATE TABLE jobs (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
company_name TEXT NOT NULL,
job_title TEXT NOT NULL,
status_id INTEGER REFERENCES statuses(id) ON DELETE RESTRICT,
application_date DATE NOT NULL,
notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);-
Start the development servers
Terminal 1 - Backend:
cd server
npm startTerminal 2 - Frontend:
cd client
npm run dev- Open your browser
http://localhost:5173
job-tracker/
βββ client/ # Frontend React application
β βββ src/
β β βββ components/ # React components
β β β βββ EditJobForm.jsx
β β β βββ Header.jsx
β β β βββ JobCard.jsx
β β β βββ JobForm.jsx
β β β βββ LoginForm.jsx
β β β βββ Modal.jsx
β β β βββ SignupForm.jsx
β β β βββ StatusFilter.jsx
β β βββ App.jsx
β β βββ main.jsx
β β βββ index.css
β βββ index.html
β βββ package.json
β βββ vite.config.js
β βββ tailwind.config.js
β
βββ server/ # Backend Express application
β βββ controllers/ # Route controllers
β β βββ authController.js
β β βββ jobsController.js
| | βββ meController.js
| | βββ statusesController.js
β βββ routes/ # API routes
β β βββ auth.js
β β βββ jobs.js
β β βββ me.js
β β βββ statuses.js
β βββ middleware/ # Custom middleware
β β βββ requireAuth.js
β βββ db.js # Database connection
β βββ server.js # Express app setup
β βββ package.json
β
βββ README.md
POST /api/auth/register- Create new user accountPOST /api/auth/login- Login userPOST /api/auth/logout- Logout user
GET /api/jobs- Get all jobs for authenticated userGET /api/jobs?status={id}- Filter jobs by statusPOST /api/jobs- Create new jobPUT /api/jobs/:id- Update jobDELETE /api/jobs/:id- Delete job
GET /api/auth/me- Get current user info
GET /api/statuses- Get all available statuses
- Gradient Header - Blue gradient with sticky positioning
- Status Badges - Color-coded status indicators (Applied, Interviewing, Offer, Rejected, Accepted)
- Hover Effects - Cards lift with shadow on hover
- Modal Interface - Smooth modal for editing jobs with backdrop blur
- Responsive Grid - Adapts from 1 column (mobile) to 3 columns (desktop)
- Form Validation - Client-side and server-side validation
- Loading States - Visual feedback during API calls
- Password hashing with bcrypt (10 salt rounds)
- Session-based authentication with HTTP-only cookies
- CSRF protection with SameSite cookies
- Input validation and sanitization
- SQL injection prevention with parameterized queries
- User data isolation (users can only access their own data)
Manual testing checklist:
- User signup with validation
- User login/logout
- Session persistence across page refresh
- Create job application
- Edit job application
- Delete job with confirmation
- Filter by status
- Responsive design on mobile/tablet/desktop
This project was built as a learning experience in full-stack development. Key concepts practiced:
- RESTful API design
- Database schema design and relationships
- User authentication and authorization
- Session management
- Frontend state management with React hooks
- Environment variable management
- Deployment to production
- Git version control
This is a personal learning project, but suggestions and feedback are welcome!
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Your Name
- GitHub: @AndyyyPhan
- LinkedIn: Andy Phan
- Built as part of a take-home assessment
- Inspired by modern job application tracking needs
- Thanks to the open-source community for excellent tools and libraries
β If you found this project helpful, please consider giving it a star!