Skip to content

Latest commit

 

History

History
358 lines (262 loc) · 6.12 KB

File metadata and controls

358 lines (262 loc) · 6.12 KB

ApplyBoard

ApplyBoard is a full-stack job application tracker that helps users organize job opportunities, applications, interview stages, notes, and follow-ups in one place.

The app includes custom authentication using JWTs stored in HTTP-only cookies, a React/TypeScript frontend, an Express/TypeScript backend, and Firestore for persistent data storage.

Features

  • User registration and login
  • JWT authentication with HTTP-only cookies
  • Protected backend routes
  • Auth state management with React Context
  • Create job applications
  • View applications for the logged-in user
  • Update existing applications
  • Delete applications
  • Store application data in Firestore
  • Responsive login and signup pages

Tech Stack

Frontend

  • React
  • TypeScript
  • React Router
  • Context API
  • CSS

Backend

  • Node.js
  • Express
  • TypeScript
  • JWT
  • bcrypt
  • cookie-parser
  • CORS
  • Firebase Admin SDK

Database

  • Firebase Firestore

Project Structure

project-root/
  client/
    src/
      pages/
        Login.tsx
        Signup.tsx
        Home.tsx
      AuthProvider.tsx
      App.tsx

  server/
    src/
      server.ts
      firebase.ts
      controller/
        user.ts
        application.ts
      middleware/
        authenticateToken.ts
        getJWTSecret.ts
      types/
        types.ts
        express.d.ts
    serviceAccountKey.json
    .env
    package.json
    tsconfig.json

Authentication Flow

This project uses JWT authentication with HTTP-only cookies.

When a user logs in:

User submits email/password
        ↓
Express verifies credentials
        ↓
Express creates a JWT
        ↓
JWT is sent to the browser as an HTTP-only cookie
        ↓
Browser automatically includes the cookie on future requests
        ↓
Protected routes verify the JWT before allowing access

The frontend does not directly read the JWT. Instead, it checks whether the user is authenticated by calling the backend /me route.

Environment Variables

Create a .env file inside the server/ folder:

PORT=3000
JWT_SECRET=your_long_random_secret_here

Firebase Setup

This project uses Firestore through the Firebase Admin SDK.

  1. Create a Firebase project.
  2. Enable Firestore.
  3. Go to Project Settings → Service accounts → Generate new private key.
  4. Download the service account JSON file.
  5. Place it inside the server/ folder as serviceAccountKey.json.
  6. Add the file to .gitignore.
.env
serviceAccountKey.json

Do not commit your service account key to GitHub.

Backend Setup

From the server/ folder:

npm install

Start the backend:

npm run dev

The backend runs on:

http://localhost:3000

Frontend Setup

From the client/ folder:

npm install

Start the frontend:

npm run dev

The frontend runs on:

http://localhost:5173

API Routes

Auth Routes

POST /users/register
POST /users/login
GET  /me
POST /logout

Application Routes

GET    /applications
POST   /applications
PUT    /applications/:id
DELETE /applications/:id

User Routes

Register

POST /users/register

Example body:

{
  "email": "user@example.com",
  "passwordOne": "password123",
  "passwordTwo": "password123"
}

Login

POST /users/login

Example body:

{
  "email": "user@example.com",
  "password": "password123"
}

On successful login, the server sets an HTTP-only cookie containing the JWT.

Check Current User

GET /me

This route checks the JWT cookie and returns the authenticated user.

Logout

POST /logout

This clears the JWT cookie.

Application Routes

All application routes require authentication.

Get Applications

GET /applications

Returns all applications owned by the logged-in user.

Create Application

POST /applications

Example body:

{
  "company": "AcuityMD",
  "role": "Software Engineer",
  "status": "Applied",
  "jobUrl": "https://example.com/job",
  "location": "Remote",
  "salaryRange": "$100k - $130k",
  "notes": "Frontend/full-stack role"
}

The backend automatically attaches the logged-in user’s ID to the application.

Update Application

PUT /applications/:id

Updates a specific application if it belongs to the logged-in user.

Delete Application

DELETE /applications/:id

Deletes a specific application if it belongs to the logged-in user.

Firestore Data Model

users

{
  email: string;
  password: string; // hashed password
  createdAt: Date;
}

applications

{
  userId: string;
  company: string;
  role: string;
  status: string;
  jobUrl: string;
  location: string;
  salaryRange: string;
  notes: string;
  createdAt: Date;
  updatedAt: Date;
}

Auth Context

The frontend uses an AuthProvider to store the current user and authentication loading state.

The app checks authentication by calling:

GET /me

If the cookie is valid, the backend returns the user and the context stores it.

This allows components to access auth state with:

const { user, loading, checkAuth, logout } = useAuth();

Security Notes

  • Passwords are hashed with bcrypt before being stored.
  • JWTs are stored in HTTP-only cookies.
  • Protected routes verify the JWT before accessing user data.
  • Application routes only return, update, or delete documents owned by the authenticated user.
  • Firestore access is handled through the backend using the Firebase Admin SDK.
  • The service account key should never be committed to version control.

Future Improvements

  • Add application status filters
  • Add search by company or role
  • Add interview dates and reminders
  • Add notes history per application
  • Add dashboard analytics
  • Add AI-generated interview prep from job descriptions
  • Add refresh tokens or longer-lived session handling
  • Add form validation and user-facing error messages
  • Add unit and integration tests
  • Add deployment instructions

Current Status

This project is currently in development. The core authentication and Firestore-backed application CRUD flow are being implemented.