A full-stack course enrollment system rebuilt from a legacy Servlet/JSP codebase into a modern Spring Boot application โ role-based access for students and admins, real database-backed enrollment, and a complete migration story from raw JDBC to Spring Data JPA.
Course Management Portal is a web application that lets students browse and enroll in courses, and lets admins create, edit, and manage the course catalog. It started as a Java Servlet + JSP + raw JDBC project, and I rebuilt it end-to-end in Spring Boot โ swapping hand-written SQL for Spring Data JPA, a custom session filter for Spring Security, and JSP templates for Thymeleaf โ while keeping every original feature intact.
The original app worked, but every new feature meant touching a DAO class, a servlet, a JSP, and often web.xml. Manual JDBC connection handling and hand-wired dependencies made the codebase fragile and slow to extend โ and it wasn't a stack most modern Java teams actually hire for.
A full migration to Spring Boot: Spring Data JPA repositories replaced ~500 lines of DAO code with five-line interfaces, Spring Security handled dual-role authentication (student/admin) out of the box, and Thymeleaf brought server-side templating in line with how the framework actually expects it.
One login screen, two roles โ Spring Security checks the Admin table first, then falls back to Students, using BCrypt-hashed passwords.
Admins can add, edit, and remove courses with fee, duration, trainer, and category fields โ all validated server-side.
Students browse active courses and enroll with one click; duplicate enrollments are blocked at the database level.
Each student has a "My Courses" view pulling only their own enrollments via a scoped repository query.
Four related MySQL tables โ Admins, Students, Courses, Enrollments โ mapped with JPA @ManyToOne relationships.
Live on Render with a custom domain and CNAME routing, connected to a managed MySQL instance.
A standard Spring MVC layered architecture โ each layer has exactly one job, which is the whole point of the migration.
| Full Stack Java | โน15,000 |
| Python for DS | โน12,000 |
| Web Design | โน8,000 |
Hibernate's ddl-auto=validate rejected the app on startup because fees was a Java double but the column was DECIMAL(10,2) in MySQL, and a timestamp field was typed as String instead of LocalDateTime.
Admins and Students live in separate tables with different identifying fields (username vs. email). Spring Security's default login only understands a single "username" field.
โ Solved with a customUserDetailsService that checks the Admin table first, then falls back to Student lookup by email.
Direct copy-pasting old JSP templates into the new templates/ folder produced broken pages โ Thymeleaf doesn't understand <% %> scriptlets or JSP's pageContext expressions at all.
th:each, th:field, @{...}) rather than translating line-by-line.