Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: 2
updates:
# Frontend npm dependencies
- package-ecosystem: "npm"
directory: "/frontend"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
Expand All @@ -22,4 +22,4 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
interval: "monthly"
12 changes: 6 additions & 6 deletions .github/workflows/azure-deploy-frontend-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ name: Frontend - Build and Deploy on Azure

on:
push:
branches: [ development ]
branches: [development]
paths:
- 'frontend/**'
- '.github/workflows/azure-deploy-frontend-dev.yml'
- "**"
- ".github/workflows/azure-deploy-frontend-dev.yml"
workflow_dispatch:

env:
Expand Down Expand Up @@ -52,8 +52,8 @@ jobs:
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: ./frontend
file: ./frontend/Dockerfile
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Expand Down Expand Up @@ -83,4 +83,4 @@ jobs:
environmentVariables: |
NOTION_API_KEY=${{ secrets.NOTION_API_KEY }}
NOTION_DATABASE_ID=${{ secrets.NOTION_DATABASE_ID }}
MONGODB_URI=${{ secrets.MONGODB_URI }}
MONGODB_URI=${{ secrets.MONGODB_URI }}
13 changes: 6 additions & 7 deletions .github/workflows/lint-checker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,23 @@ name: Frontend Lint Checker
on:
pull_request:
paths:
- 'frontend/**'
- "**"

jobs:
verify:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./frontend

working-directory: .
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: './frontend/package-lock.json'
node-version: "20"
cache: "npm"
cache-dependency-path: "./package-lock.json"

- name: Install dependencies
run: npm ci
Expand All @@ -35,4 +34,4 @@ jobs:
run: npx prettier --check .

- name: Build
run: npm run build
run: npm run build
21 changes: 12 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*

# MonoRepo Specific
/packages/*/node_modules/
**/dist/
**/build/
# Next.js
.next/
out/
.vercel/

# Env files
.env*.local
.env.*.local

# OS-specific
.DS_Store
Expand All @@ -33,8 +37,6 @@ coverage/
*.sqlite

# Miscellaneous
.env
.env.local
*.local
*.lock
*.bak
Expand Down Expand Up @@ -62,7 +64,8 @@ desktop.ini
# Lock file for pnpm
pnpm-lock.yaml

/repo-to-text/

# Typescript build info
frontend/tsconfig.tsbuildinfo
tsconfig.tsbuildinfo

# Docker
Dockerfile.*.env
File renamed without changes.
File renamed without changes.
File renamed without changes.
126 changes: 104 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,151 @@
# MAC Job Board
# MPloy Job Board

Hey there! 👋

This is a modern, intelligent job board platform that automatically aggregates job listings, providing users with a streamlined experience to search, filter, and discover relevant opportunities. The platform updates daily with fresh listings through our smart AI robots.

## Features 🚀

- Jobs update automatically every single day from various sources (automatically deduplicated)
- We use AI to help fix, sort and summarise the listings
- You can filter for exactly what you want (e.g. Big Tech Intern Roles for Interational students)
- You can filter for exactly what you want (e.g. Big Tech Intern Roles for International students)
- Works perfectly on phone or laptop
- Server-side rendering (where possible) with Next.js 15 App Router
- Multiple filters can be applied at once, including a text search filter
- Desktop/mobile responsive UI: list/details on desktop, modal on mobile
- State persists in URL: search, filters, pagination (`/jobs?q=dev&location=sydney&page=2`)
- Direct job links supported (`/jobs/[id]`)
- Parallel data fetching for faster loads
- Real-time job search with debouncing
- Data refreshed daily via Go scraper (not open source)
- Around 1k jobs, each ~4kB

## Tech Stack

## Frontend
### Frontend

- Next.js 15: Utilizing the App Router for server-side rendering and optimized client-side navigation
- React 19: For building the interactive user interface components
- TypeScript: Ensuring type safety across the codebase
- Mantine UI: For consistent, accessible UI components
- Tailwind CSS: For utility-first styling and responsive design

## Backend
### Backend (Data Layer)

- Server Actions: Answers search and feedback requests
- Server Actions: Handle search and feedback requests
- MongoDB: Stores job listings and related metadata
- GoLang: Powers our web robots (this part is not open source)

## Getting Started

### Prerequisites

- Node.js 20+
- Java 17
- Go 1.21+
- Docker & Docker Compose
- Redis
- MongoDB (local or cloud, set MONGODB_URI)

### Local Development

```bash
# Start all services
# Start with Docker (includes dev server)
docker compose -f docker-compose.dev.yml up
# Alternative if Make is installed
make dev

# Frontend only
cd frontend
# Or run frontend directly
npm install
npm run dev

# Backend only
cd backend
./gradlew bootRun
```

## Development Guidelines

### Git Workflow
### Naming & File Structuring Conventions

- Everything uses kebab-case `product-card.ts` unless there's an agreed standard e.g. `useCustomHook` for hooks
- Group related components in feature directories (e.g. `components/layout/search/filter/` contains all components used for search filtering)
- Most UI components are 50-150 lines of code. Keep pages thin, move complex logic to components
- Use layouts for shared UI across routes

### State Management & Data Passing Patterns

- Begin with simple props passing - max 2 levels of components
- When stateful logic needs to be reused, move it to custom hooks
- When props drilling becomes cumbersome or state needs to be widely available, use Context (e.g. the global filter state of jobs should be context)
- Pre-fetch the data in the next job page
- Load the essential data first and display the page, while other job listings and details are being loaded
- Implement parallel data fetching when possible

### Next / React Features

- Intercepting Routes: Use intercepting routes for modal-like experiences
- Lazy Loading: use when we can defer the loading of heavy components
- Error Boundaries: define error.tsx files to catch errors to prevent the entire site from breaking
- Add `<Suspense/>` boundaries for loading state
- Use useMemo for expensive calculations (e.g. filtered results)
- Use useRef to maintain filter input values

## Frontend Structure

```
├── next.config.ts # Next.js configuration, API routes, environment
├── src
│ ├── app
│ │ ├── error.tsx # Global error boundary UI
│ │ ├── jobs
│ │ │ ├── [id] # Dynamic route for individual job pages
│ │ │ │ ├── @modal # Intercepted route - shows job details as modal on mobile
│ │ │ │ ├── page.tsx # Individual job page UI
│ │ │ ├── error.tsx # Job section error boundary
│ │ │ ├── layout.tsx # Job section layout wrapper (includes JobsProvider)
│ │ │ ├── loading.tsx # Job section loading state
│ │ │ ├── page.tsx # Main jobs listing page
│ │ ├── layout.tsx # Root layout with nav and theme providers
│ │ ├── page.tsx # Home page (redirects to /jobs)
│ ├── components
│ │ ├── jobs
│ │ │ ├── details
│ │ │ │ ├── job-card.tsx # Individual job preview card
│ │ │ │ ├── job-details.tsx # Full job details view
│ │ │ │ ├── job-list.tsx # Container for job cards with virtualization
│ │ │ ├── filters
│ │ │ │ ├── dropdown-filter.tsx # Reusable filter dropdown
│ │ │ │ ├── dropdown-sort.tsx # Sort options dropdown
│ │ │ │ ├── filter-section.tsx # Container for all filters
│ │ │ ├── search
│ │ │ │ └── search-bar.tsx # Search input with suggestions
│ │ │ ├── layout
│ │ │ │ └── logo.tsx # Site logo component
│ │ │ │ └── nav-bar.tsx # Navigation bar
│ ├── context
│ │ ├── jobs
│ │ │ └── filter-context.tsx # Job state and actions context
│ │ │ └── jobs-provider.tsx # Provider wrapper with initial state
│ ├── hooks
│ │ ├── use-job-filters.ts # Filter logic and state management
│ │ ├── use-job-search.ts # Search functionality and API calls
│ │ ├── use-pagination.ts # Pagination state and navigation
│ │ ├── use-url-state.ts # URL parameters sync with app state
│ ├── lib
│ │ ├── theme.ts # Theme configuration
│ ├── types
│ │ └── api.ts # API response/request types
│ │ └── filters.ts # Filter option types
│ │ └── job.ts # Job data types
├── tailwind.config.ts # Tailwind CSS configuration
```

## Git Workflow

#### Branch Structure

- `main` - Production branch
- `dev` - Development branch
- Feature branches follow the pattern:
```
<component>/<developer>/<feature-name>
Examples:
- backend/edwn/redis-caching
- frontend/sarah/job-filters
- ui/edwn/dark-mode
- jobs/sarah/advanced-filters
```

## License
This project is licensed under the MIT License.

This project is licensed under the MIT License.
3 changes: 0 additions & 3 deletions backend/.gitattributes

This file was deleted.

42 changes: 0 additions & 42 deletions backend/.gitignore

This file was deleted.

7 changes: 0 additions & 7 deletions backend/Dockerfile.dev

This file was deleted.

Loading
Loading