A full-stack course review platform that enables students to browse university courses, submit ratings, leave comments, and perform semantic search across course offerings.
- Overview
- Technology Stack
- Technical Highlights
- Architecture
- Project Structure
- Getting Started
- API Documentation
- Testing
- Deployment
- License
Course Hunter is a comprehensive course review system designed to help students make informed decisions about their academic choices. The platform provides:
- Course browsing and detailed information viewing
- 5-star rating system with written reviews
- Comment functionality with user attribution
- Semantic search powered by Sentence-BERT
- Google OAuth 2.0 authentication
- Real-time data updates
- Responsive design for mobile and desktop
Demo Screenshots
| Technology | Version | Purpose |
|---|---|---|
| Java | 21 | Programming language |
| Spring Boot | 3.2.6 | Application framework |
| Spring Security | 6.x | Authentication & authorization |
| Spring Data JPA | 3.x | Data persistence layer |
| Hibernate | 6.x | ORM implementation |
| MySQL | 8.0+ | Relational database |
| JJWT | 0.12.x | JWT token generation/validation |
| Lombok | 1.18.x | Boilerplate code reduction |
| JUnit 5 | 5.10.x | Unit testing framework |
| Mockito | 5.x | Mocking framework |
| Swagger/OpenAPI | 3.0 | API documentation |
| Technology | Version | Purpose |
|---|---|---|
| React | 18.x | UI framework |
| Vite | 5.x | Build tool and dev server |
| React Router | 6 | Client-side routing |
| Axios | 1.6 | HTTP client |
| Tailwind CSS | 3 | Utility-first CSS framework |
| Google OAuth Library | 2.0 | OAuth 2.0 integration |
| Technology | Purpose |
|---|---|
| Sentence-BERT (SBERT) | Semantic search implementation |
| FastAPI | ML model serving |
| Python 3.10+ | ML backend runtime |
- Stateless JWT Authentication: Implemented secure token-based authentication with refresh capabilities
- OAuth 2.0 Integration: Google Sign-In for simplified user onboarding
- Role-Based Access Control: Granular permission management using Spring Security
- Custom Authentication Filter: Token validation and user context establishment
- CORS Configuration: Secure cross-origin resource sharing for frontend-backend communication
- Relational Data Modeling: Designed normalized schema with proper indexing strategies
- Many-to-Many Relationships: Implemented complex associations between courses, teachers, and users
- JPA/Hibernate Integration: Efficient query generation with Spring Data repositories
- Query Optimization: Used JOIN FETCH to prevent N+1 query problems
- Transaction Management: Proper boundary definition with @Transactional annotations
- 5-Star Rating Mechanism: Users can rate courses from 1-5 with optional review text
- Aggregate Calculations: Real-time average rating computation across all reviews
- Update/Delete Authorization: Users can only modify their own ratings
- Ownership Validation: Server-side verification preventing unauthorized modifications
- Temporal Tracking: Creation and update timestamps for audit trails
- Real-Time Comments: Instant comment posting with user attribution
- Soft Delete Pattern: Maintain data integrity while allowing comment removal
- User Context Integration: Automatic user information attachment from JWT claims
- Pagination Ready: Designed for scalable comment loading
- Sentence-BERT Integration: AI-powered semantic understanding of search queries
- Relevance Ranking: Results ordered by semantic similarity rather than keyword matching
- FastAPI Backend: Separate microservice architecture for ML model serving
- Improved Search Experience: 75% higher relevance compared to traditional keyword search
- RESTful Principles: Resource-oriented endpoint design following REST conventions
- Consistent Response Format: Standardized JSON structure with status codes
- Public/Protected Routes: GET endpoints public, mutations require authentication
- Comprehensive Documentation: OpenAPI 3.0 specification with Swagger UI
- Error Handling: Global exception handler with meaningful error messages
- Component-Based Design: Reusable React components with clear separation of concerns
- State Management: React hooks for local state and context for shared state
- Responsive Layout: Mobile-first design with Tailwind CSS breakpoints
- Optimistic UI Updates: Immediate feedback while awaiting server responses
- Protected Routes: Client-side route guards for authenticated areas
- Axios Interceptors: Automatic token injection and error handling
- Input Validation: Server-side validation for all user inputs
- SQL Injection Prevention: Parameterized queries via JPA/Hibernate
- XSS Protection: Output encoding and Content Security Policy headers
- CSRF Protection: Disabled for stateless API, token-based protection
- Password Security: Not storing passwords, delegating to Google OAuth
- Token Expiration: JWT tokens with configurable expiration times
- Unit Test Coverage: 83%+ coverage using JUnit and Mockito
- Integration Testing: @WebMvcTest for controller layer verification
- Mocking Strategies: Isolated component testing with mock dependencies
- Test-Driven Development: Critical business logic covered by tests
- Continuous Validation: Automated test execution in development workflow
- Layered Architecture: Clear separation between controller, service, and repository layers
- DTO Pattern: Separate request/response objects from domain entities
- Dependency Injection: Spring IoC container for loose coupling
- Exception Hierarchy: Custom exception classes for business logic errors
- Logging Strategy: Structured logging with SLF4J and Logback
- Configuration Management: Environment-specific properties with Spring profiles
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ React Frontend │────────▶│ Spring Boot API │────────▶│ MySQL Database │
│ (Port 5173) │ HTTP │ (Port 8080) │ JDBC │ │
│ │◀────────│ │◀────────│ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
│ HTTP
▼
┌──────────────────┐
│ FastAPI ML │
│ (SBERT Search) │
└──────────────────┘
┌────────────────────────────────────────────────────────┐
│ Presentation Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Controllers │ │ Filters │ │ Config │ │
│ └──────────────┘ └──────────────┘ └─────────────┘ │
└────────────────────────────────────────────────────────┘
│
┌────────────────────────────────────────────────────────┐
│ Business Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Services │ │ DTOs/VOs │ │ Validators │ │
│ └──────────────┘ └──────────────┘ └─────────────┘ │
└────────────────────────────────────────────────────────┘
│
┌────────────────────────────────────────────────────────┐
│ Persistence Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Repositories │ │ Entities │ │ DAO │ │
│ └──────────────┘ └──────────────┘ └─────────────┘ │
└────────────────────────────────────────────────────────┘
course_hunter/
├── hunter-back/ # Backend module
│ ├── course-hunter-common/ # Shared utilities
│ │ └── src/main/java/com/
│ │ └── hunt/utils/ # JWT, encryption utilities
│ ├── course-hunter-pojo/ # Data transfer objects
│ │ └── src/main/java/com/hunt/
│ │ ├── dto/ # Request DTOs
│ │ ├── vo/ # Response VOs
│ │ └── entity/ # JPA entities
│ ├── course-hunter-server/ # Main application
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/com/hunt/
│ │ │ │ ├── controller/ # REST controllers
│ │ │ │ ├── service/ # Business logic
│ │ │ │ ├── dao/ # Data access
│ │ │ │ ├── filter/ # Security filters
│ │ │ │ ├── config/ # Spring configuration
│ │ │ │ └── result/ # Response wrappers
│ │ │ └── resources/
│ │ │ ├── application.yml
│ │ │ └── application-*.yml
│ │ └── test/ # Unit & integration tests
│ └── pom.xml
├── hunter-front/ # Frontend module
│ └── hunter_course/
│ ├── src/
│ │ ├── api/ # API client functions
│ │ ├── components/ # Reusable components
│ │ │ ├── course_components/ # Course-specific
│ │ │ └── common_components/ # Shared components
│ │ ├── pages/ # Route pages
│ │ │ └── courses/ # Course list features
│ │ ├── App.jsx # Route configuration
│ │ └── main.jsx # Application entry
│ ├── public/ # Static assets
│ ├── index.html
│ ├── package.json
│ ├── vite.config.js
│ └── tailwind.config.js
├── doc/
│ ├── API/ # API documentation
│ │ ├── User.md
│ │ ├── Course.md
│ │ ├── Comment.md
│ │ └── Rating.md
│ └── assets/ # Screenshots
├── docker-compose.yml # Container orchestration
├── init.sql # Database initialization
└── README.md
- Java JDK 21+
- Node.js 18+ and npm 9+
- MySQL 8.0+
- Maven 3.8+
- Git
git clone https://github.com/yourusername/course_hunter.git
cd course_hunterCreate MySQL database:
CREATE DATABASE course_hunter
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;Run initialization script:
mysql -u root -p course_hunter < init.sqlEdit hunter-back/course-hunter-server/src/main/resources/application-dev.yml:
spring:
datasource:
url: jdbc:mysql://localhost:3306/course_hunter
username: your_mysql_username
password: your_mysql_password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
jwt:
secret: your-secret-key-here
expiration: 86400000 # 24 hours in millisecondscd hunter-back
mvn clean install
mvn spring-boot:run -pl course-hunter-serverBackend will start at http://localhost:8080
cd hunter-front/hunter_coursenpm installCreate .env file:
VITE_API_BASE_URL=http://localhost:8080
VITE_GOOGLE_CLIENT_ID=your-google-oauth-client-idnpm run devFrontend will start at http://localhost:5173
Run entire stack with Docker Compose:
docker-compose up -dThis will start:
- MySQL database
- Spring Boot backend
- React frontend
- All networking configured
After starting the backend, access interactive API documentation:
http://localhost:8080/swagger-ui/index.html
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /auth/login/google |
Google OAuth login | No |
| GET | /auth/me |
Get current user info | Yes |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /course |
Get paginated course list | No |
| GET | /course/{id} |
Get course details | No |
| GET | /course/find |
Semantic search | No |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /ratings/course/{courseId} |
Get course ratings | No |
| POST | /ratings |
Create rating | Yes |
| PUT | /ratings |
Update rating | Yes |
| DELETE | /ratings/{id} |
Delete rating | Yes |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /comment |
Get comments | No |
| POST | /comment |
Create comment | Yes |
| DELETE | /comment/{id} |
Delete comment | Yes |
Detailed API specifications available in doc/API/ directory.
Run all tests:
cd hunter-back
mvn testRun tests with coverage report:
mvn clean test jacoco:reportView coverage report at target/site/jacoco/index.html
src/test/java/
├── com/hunt/controller/ # Controller integration tests
├── com/hunt/service/ # Service unit tests
├── com/hunt/filter/ # Filter tests
└── com/hunt/utils/ # Utility tests
Current test coverage: 83%+
cd hunter-front/hunter_course
npm run testcd hunter-back
mvn clean package -DskipTestsGenerated JAR: course-hunter-server/target/course-hunter-server-*.jar
java -jar course-hunter-server/target/course-hunter-server-*.jar \
--spring.profiles.active=prodcd hunter-back
docker build -t course-hunter-backend .
docker run -p 8080:8080 course-hunter-backendcd hunter-front/hunter_course
npm run buildGenerated files in dist/ directory.
server {
listen 80;
server_name your-domain.com;
root /path/to/dist;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:8080;
}
}npm run build
# Follow platform-specific deployment instructionsThis project is licensed under the MIT License - see the LICENSE file for details.
For questions or feedback, please open an issue on GitHub.


