Index: backend/src/main/java/com/shifterwebapp/shifter/Validate.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/Validate.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/Validate.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -3,4 +3,5 @@
 import com.shifterwebapp.shifter.auth.CustomAuthDetails;
 import com.shifterwebapp.shifter.course.CourseRepository;
+import com.shifterwebapp.shifter.exception.BadRequestException;
 import com.shifterwebapp.shifter.exception.ResourceNotFoundException;
 import com.shifterwebapp.shifter.exception.UnauthorizedException;
@@ -37,4 +38,15 @@
     }
 
+    public Long extractUserId(Authentication authentication) {
+        validateUserIsAuthenticated(authentication);
+
+        Object detailsObj = authentication.getDetails();
+        if (!(detailsObj instanceof CustomAuthDetails details)) {
+            throw new BadRequestException("Invalid authentication details");
+        }
+        return details.getUserId();
+    }
+
+
     public void validateUserIsAdmin(Authentication authentication) {
         validateUserIsAuthenticated(authentication);
Index: backend/src/main/java/com/shifterwebapp/shifter/auth/AuthController.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/auth/AuthController.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/auth/AuthController.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -6,9 +6,7 @@
 import lombok.RequiredArgsConstructor;
 import org.springframework.http.ResponseEntity;
-import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
-import java.util.Map;
 
 @RequiredArgsConstructor
Index: backend/src/main/java/com/shifterwebapp/shifter/course/CourseController.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/course/CourseController.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/course/CourseController.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -5,14 +5,12 @@
 import com.shifterwebapp.shifter.auth.CustomAuthDetails;
 import com.shifterwebapp.shifter.course.dto.CourseDtoDetail;
+import com.shifterwebapp.shifter.course.dto.CourseDtoFull;
 import com.shifterwebapp.shifter.course.dto.CourseDtoPreview;
 import com.shifterwebapp.shifter.course.service.CourseService;
 import com.shifterwebapp.shifter.enrollment.service.EnrollmentService;
-import com.shifterwebapp.shifter.enums.Difficulty;
 import com.shifterwebapp.shifter.exception.ErrorResponse;
-import com.shifterwebapp.shifter.exception.ResourceNotFoundException;
 import com.shifterwebapp.shifter.upload.S3Service;
 import com.shifterwebapp.shifter.upload.S3UploadResponse;
 import lombok.RequiredArgsConstructor;
-import org.springframework.data.jpa.domain.Specification;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.core.Authentication;
@@ -136,4 +134,14 @@
     }
 
+    @GetMapping("/{courseId}/enrolled")
+    public ResponseEntity<?> getEnrolledCourseById(
+            @PathVariable("courseId") Long courseId,
+            Authentication authentication) {
+        Long userId = validate.extractUserId(authentication);
+
+        CourseDtoFull courseDtoFull = courseService.getEnrolledCourseById(courseId, userId);
+        return ResponseEntity.ok(courseDtoFull);
+    }
+
     @GetMapping("/{courseId}")
     public ResponseEntity<?> getCourseById(@PathVariable("courseId") Long courseId) {
@@ -178,5 +186,4 @@
 
             Course finalCourse = courseService.updateCourseWithImagesAndFiles(courseId, s3UploadResponse);
-            System.out.println("Final course: " + finalCourse);
 
             return ResponseEntity.ok(null);
Index: backend/src/main/java/com/shifterwebapp/shifter/course/CourseRepository.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/course/CourseRepository.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/course/CourseRepository.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -23,9 +23,21 @@
 
     @Query("select c from Course c where c.price >= :floorPrice and c.price <= :ceilPrice")
-    List<Course> findCoursesByPriceRange(@Param("floorPrice") Float floorPrice,@Param("ceilPrice") Float ceilPrice);
+    List<Course> findCoursesByPriceRange(@Param("floorPrice") Float floorPrice, @Param("ceilPrice") Float ceilPrice);
 
     List<Course> findCoursesBySkillsGainedIn(List<String> searchSkills);
 
     List<Course> findCoursesByDifficultyIn(List<Difficulty> searchDifficulties);
+
+    @Query("""
+                SELECT CASE WHEN COUNT(cl) > 0 THEN TRUE ELSE FALSE END
+                FROM Course c
+                JOIN c.courseContents cc
+                JOIN cc.courseLectures cl
+                WHERE c.id = :courseId
+                  AND cl.contentFileName = :fileName
+            """)
+    Boolean lectureFileExistsInCourse(@Param("courseId") Long courseId,
+                                      @Param("fileName") String fileName);
+
 
     @Query("select distinct c.topicsCovered from Course c")
Index: backend/src/main/java/com/shifterwebapp/shifter/course/service/CourseService.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/course/service/CourseService.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/course/service/CourseService.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -6,12 +6,13 @@
 import com.shifterwebapp.shifter.course.*;
 import com.shifterwebapp.shifter.course.dto.CourseDtoDetail;
+import com.shifterwebapp.shifter.course.dto.CourseDtoFull;
 import com.shifterwebapp.shifter.course.dto.CourseDtoPreview;
 import com.shifterwebapp.shifter.course.mapper.CourseMapperDetail;
+import com.shifterwebapp.shifter.course.mapper.CourseMapperFull;
 import com.shifterwebapp.shifter.course.mapper.CourseMapperPreview;
 import com.shifterwebapp.shifter.coursecontent.CourseContent;
-import com.shifterwebapp.shifter.coursecontent.CourseContentRepository;
 import com.shifterwebapp.shifter.courselecture.CourseLecture;
-import com.shifterwebapp.shifter.courselecture.CourseLectureRepository;
 import com.shifterwebapp.shifter.enrollment.service.EnrollmentService;
+import com.shifterwebapp.shifter.exception.AccessDeniedException;
 import com.shifterwebapp.shifter.upload.MetaInfo;
 import com.shifterwebapp.shifter.upload.S3UploadResponse;
@@ -19,11 +20,8 @@
 import com.shifterwebapp.shifter.user.service.UserService;
 import lombok.RequiredArgsConstructor;
-import org.springframework.data.jpa.domain.Specification;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
 
 @Service
@@ -34,4 +32,5 @@
     private final CourseMapperPreview courseMapperPreview;
     private final CourseMapperDetail courseMapperDetail;
+    private final CourseMapperFull courseMapperFull;
     private final UserService userService;
     private final Validate validate;
@@ -69,5 +68,5 @@
         for (S3UploadResponse s3UploadResponse : s3UploadResponses) {
             if ("COURSE_IMAGE".equals(s3UploadResponse.getType())) {
-                course.setImageUrl(s3UploadResponse.getUrl());
+                course.setImageUrl(s3UploadResponse.getFileName());
                 continue;
             }
@@ -86,5 +85,5 @@
                         CourseLecture courseLecture = courseContent.getCourseLectures().get(lectureIndex);
 
-                        courseLecture.setContentStoragePath(s3UploadResponse.getUrl());
+                        courseLecture.setContentFileName(s3UploadResponse.getFileName());
                     } else {
                         // handle invalid lecture index
@@ -101,4 +100,22 @@
 
     @Override
+    public Boolean lectureFileExistsInCourse(Long courseId, String fileName) {
+        return courseRepository.lectureFileExistsInCourse(courseId, fileName);
+    }
+
+    @Override
+    public CourseDtoFull getEnrolledCourseById(Long courseId, Long userId) {
+        validate.validateCourseExists(courseId);
+
+        boolean isUserEnrolled = enrollmentService.isUserEnrolledInCourse(userId, courseId);
+        if (!isUserEnrolled) {
+            throw new AccessDeniedException("User with ID " + userId + " is not enrolled in course with ID " + courseId + " and is therefore not authorized to access the full course with its content!");
+        }
+
+        Course course = courseRepository.findById(courseId).orElseThrow();
+        return courseMapperFull.toDto(course);
+    }
+
+    @Override
     public List<CourseDtoPreview> getAllCourses(List<Long> courseIds) {
         List<Course> courses = courseIds != null && !courseIds.isEmpty() ?
Index: backend/src/main/java/com/shifterwebapp/shifter/course/service/ImplCourseService.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/course/service/ImplCourseService.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/course/service/ImplCourseService.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -4,7 +4,7 @@
 import com.shifterwebapp.shifter.course.Course;
 import com.shifterwebapp.shifter.course.dto.CourseDtoDetail;
+import com.shifterwebapp.shifter.course.dto.CourseDtoFull;
 import com.shifterwebapp.shifter.course.dto.CourseDtoPreview;
 import com.shifterwebapp.shifter.upload.S3UploadResponse;
-import org.springframework.data.jpa.domain.Specification;
 
 import java.util.List;
@@ -15,4 +15,8 @@
 
     Course updateCourseWithImagesAndFiles(Long courseId, List<S3UploadResponse> s3UploadResponses);
+
+    Boolean lectureFileExistsInCourse(Long courseId, String storagePath);
+
+    CourseDtoFull getEnrolledCourseById(Long courseId, Long userId);
 
 //    List<CourseDtoPreview> getAllCourses(Specification<Course> specification);
Index: backend/src/main/java/com/shifterwebapp/shifter/courselecture/CourseLecture.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/courselecture/CourseLecture.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/courselecture/CourseLecture.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -30,5 +30,6 @@
     private String contentText;
 
-    private String contentStoragePath;
+    @Column(columnDefinition = "text")
+    private String contentFileName;
 
     @Enumerated(EnumType.STRING)
Index: backend/src/main/java/com/shifterwebapp/shifter/courselecture/CourseLectureDtoFull.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/courselecture/CourseLectureDtoFull.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/courselecture/CourseLectureDtoFull.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -23,5 +23,5 @@
     private String contentText;
 
-    private String contentStoragePath;
+    private String contentFileName;
 
     private ContentType contentType;
Index: backend/src/main/java/com/shifterwebapp/shifter/courselecture/CourseLectureRepository.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/courselecture/CourseLectureRepository.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/courselecture/CourseLectureRepository.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -2,5 +2,10 @@
 
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 
 public interface CourseLectureRepository extends JpaRepository<CourseLecture, Long> {
+
+    @Query("select cl.contentType from CourseLecture cl where cl.id = :lectureId and cl.contentFileName = :fileName and cl.courseContent.course.id = :courseId")
+    String getContentType(@Param("fileName") String fileName,@Param("courseId") Long courseId, @Param("lectureId") Long lectureId);
 }
Index: backend/src/main/java/com/shifterwebapp/shifter/courselecture/service/CourseLectureService.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/courselecture/service/CourseLectureService.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/courselecture/service/CourseLectureService.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,4 +1,20 @@
 package com.shifterwebapp.shifter.courselecture.service;
 
+import com.shifterwebapp.shifter.Validate;
+import com.shifterwebapp.shifter.courselecture.CourseLectureRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
 public class CourseLectureService implements ImplCourseLectureService{
+
+    private final Validate validate;
+    private final CourseLectureRepository courseLectureRepository;
+
+    @Override
+    public String getContentType(String fileName, Long courseId, Long lectureId) {
+        validate.validateCourseExists(courseId);
+        return courseLectureRepository.getContentType(fileName, courseId, lectureId);
+    }
 }
Index: backend/src/main/java/com/shifterwebapp/shifter/courselecture/service/ImplCourseLectureService.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/courselecture/service/ImplCourseLectureService.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/courselecture/service/ImplCourseLectureService.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -2,3 +2,4 @@
 
 public interface ImplCourseLectureService {
+    String getContentType(String fileName, Long courseId, Long lectureId);
 }
Index: backend/src/main/java/com/shifterwebapp/shifter/enrollment/EnrollmentController.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/enrollment/EnrollmentController.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/enrollment/EnrollmentController.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -22,8 +22,5 @@
     @PostMapping("/create/{courseId}")
     public ResponseEntity<?> enrollUserInCourse(@PathVariable Long courseId, Authentication authentication) {
-        validate.validateUserIsAuthenticated(authentication);
-
-        CustomAuthDetails details = (CustomAuthDetails) authentication.getDetails();
-        Long userId = details.getUserId();
+        Long userId = validate.extractUserId(authentication);
 
         EnrollmentDto enrollmentDto = enrollmentService.enrollUser(courseId, userId);
@@ -36,11 +33,5 @@
     @GetMapping("/user")
     public ResponseEntity<?> getEnrollmentsByUser(Authentication authentication) {
-        validate.validateUserIsAuthenticated(authentication);
-
-        Object detailsObj = authentication.getDetails();
-        if (!(detailsObj instanceof CustomAuthDetails details)) {
-            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid authentication details"));
-        }
-        Long userId = details.getUserId();
+        Long userId = validate.extractUserId(authentication);
 
         List<EnrollmentDto> enrollmentDtos = enrollmentService.getEnrollmentsByUser(userId);
Index: backend/src/main/java/com/shifterwebapp/shifter/enrollment/service/EnrollmentService.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/enrollment/service/EnrollmentService.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/enrollment/service/EnrollmentService.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -13,5 +13,4 @@
 import com.shifterwebapp.shifter.exception.PaymentNotCompleteException;
 import com.shifterwebapp.shifter.payment.Payment;
-import com.shifterwebapp.shifter.payment.PaymentRepository;
 import com.shifterwebapp.shifter.payment.service.PaymentService;
 import com.shifterwebapp.shifter.user.service.UserService;
Index: backend/src/main/java/com/shifterwebapp/shifter/exception/AccessDeniedException.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/exception/AccessDeniedException.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ backend/src/main/java/com/shifterwebapp/shifter/exception/AccessDeniedException.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,7 @@
+package com.shifterwebapp.shifter.exception;
+
+public class AccessDeniedException extends RuntimeException {
+    public AccessDeniedException(String message) {
+        super(message);
+    }
+}
Index: backend/src/main/java/com/shifterwebapp/shifter/exception/BadRequestException.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/exception/BadRequestException.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ backend/src/main/java/com/shifterwebapp/shifter/exception/BadRequestException.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,7 @@
+package com.shifterwebapp.shifter.exception;
+
+public class BadRequestException extends RuntimeException {
+    public BadRequestException(String message) {
+        super(message);
+    }
+}
Index: backend/src/main/java/com/shifterwebapp/shifter/exception/GlobalExceptionHandler.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/exception/GlobalExceptionHandler.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/exception/GlobalExceptionHandler.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -10,7 +10,31 @@
 public class GlobalExceptionHandler {
 
+    @ExceptionHandler(BadRequestException.class)
+    public ResponseEntity<ErrorResponse> handleBadRequestException(BadRequestException ex) {
+        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ErrorResponse(ex.getMessage()));
+    }
+
+    @ExceptionHandler(UnauthorizedException.class)
+    public ResponseEntity<ErrorResponse> handleUnauthorizedException(UnauthorizedException ex) {
+        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new ErrorResponse(ex.getMessage()));
+    }
+
+    @ExceptionHandler(ResourceNotFoundException.class)
+    public ResponseEntity<ErrorResponse> handleNotFoundException(ResourceNotFoundException ex) {
+        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse(ex.getMessage()));
+    }
+
+    @ExceptionHandler(ResourceAlreadyExistsException.class)
+    public ResponseEntity<ErrorResponse> handleAlreadyExistsException(ResourceAlreadyExistsException ex) {
+        return ResponseEntity.status(HttpStatus.CONFLICT).body(new ErrorResponse(ex.getMessage()));
+    }
+
+    @ExceptionHandler(AccessDeniedException.class)
+    public ResponseEntity<ErrorResponse> handleAccessDeniedException(AccessDeniedException ex) {
+        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResponse(ex.getMessage()));
+    }
+
     @ExceptionHandler(RuntimeException.class)
     public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException ex) {
-        // You can customize based on exception message or type
         return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ErrorResponse(ex.getMessage()));
     }
Index: backend/src/main/java/com/shifterwebapp/shifter/upload/S3Controller.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/upload/S3Controller.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ backend/src/main/java/com/shifterwebapp/shifter/upload/S3Controller.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,60 @@
+package com.shifterwebapp.shifter.upload;
+
+import com.shifterwebapp.shifter.Validate;
+import com.shifterwebapp.shifter.course.service.CourseService;
+import com.shifterwebapp.shifter.courselecture.service.CourseLectureService;
+import com.shifterwebapp.shifter.enrollment.service.EnrollmentService;
+import com.shifterwebapp.shifter.exception.AccessDeniedException;
+import com.shifterwebapp.shifter.exception.ResourceNotFoundException;
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.core.Authentication;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+@RestController
+@RequestMapping("${api.base.path}/s3")
+@RequiredArgsConstructor
+public class S3Controller {
+
+    private final S3Service s3Service;
+    private final EnrollmentService enrollmentService;
+    private final CourseService courseService;
+    private final CourseLectureService courseLectureService;
+    private final Validate validate;
+
+    @GetMapping("/presigned-url")
+    public Map<String, String> getPresignedUrl(
+            @RequestParam Long courseId,
+            @RequestParam Long lectureId,
+            @RequestParam String fileName,
+            @RequestParam int expirySeconds,
+            Authentication authentication
+    ) {
+        Long userId = validate.extractUserId(authentication);
+
+        if (!enrollmentService.isUserEnrolledInCourse(userId, courseId)) {
+            throw new AccessDeniedException("You do not have access to this course content.");
+        }
+
+        System.out.println(fileName);
+        System.out.println(courseId);
+        String contentType = courseLectureService.getContentType(fileName, courseId, lectureId);
+        if (contentType == null) {
+            throw new ResourceNotFoundException("Content type not found for the specified file.");
+        }
+
+        String key = "private/courseContent/" + contentType.toLowerCase() + "/course" + courseId + "_" + fileName;
+        System.out.println(key);
+
+        if (!courseService.lectureFileExistsInCourse(courseId, fileName)) {
+            throw new ResourceNotFoundException("File does not exist in the course.");
+        }
+
+        String url = s3Service.generatePresignedGetUrl(key, expirySeconds).toString();
+        return Map.of("url", url);
+    }
+}
Index: backend/src/main/java/com/shifterwebapp/shifter/upload/S3Service.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/upload/S3Service.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/upload/S3Service.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,5 +1,4 @@
 package com.shifterwebapp.shifter.upload;
 
-import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.RequiredArgsConstructor;
@@ -13,9 +12,14 @@
 import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
+import software.amazon.awssdk.services.s3.presigner.S3Presigner;
+import software.amazon.awssdk.services.s3.model.GetObjectRequest;
+import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
+import java.time.Duration;
+
 
 import java.io.IOException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 @Service
@@ -34,4 +38,27 @@
     @Value("${aws.s3.bucket-name}")
     private String bucketName;
+
+    public URL generatePresignedGetUrl(String key, int expirySeconds) {
+        S3Presigner presigner = S3Presigner.builder()
+                .region(Region.of(region))
+                .credentialsProvider(StaticCredentialsProvider.create(
+                        AwsBasicCredentials.create(accessKey, secretKey)
+                ))
+                .build();
+
+        GetObjectRequest getObjectRequest = GetObjectRequest.builder()
+                .bucket(bucketName)
+                .key(key)
+                .build();
+
+        GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder()
+                .signatureDuration(Duration.ofSeconds(expirySeconds))
+                .getObjectRequest(getObjectRequest)
+                .build();
+
+        URL url = presigner.presignGetObject(presignRequest).url();
+        presigner.close();
+        return url;
+    }
 
     public List<S3UploadResponse> uploadCourseImageAndFiles(
@@ -88,5 +115,5 @@
 
             MetaInfo meta = new ObjectMapper().readValue(metaJson, MetaInfo.class);
-            responses.add(new S3UploadResponse("COURSE_LECTURE", key, meta));
+            responses.add(new S3UploadResponse("COURSE_LECTURE", file.getOriginalFilename(), meta));
         }
 
Index: backend/src/main/java/com/shifterwebapp/shifter/upload/S3UploadResponse.java
===================================================================
--- backend/src/main/java/com/shifterwebapp/shifter/upload/S3UploadResponse.java	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ backend/src/main/java/com/shifterwebapp/shifter/upload/S3UploadResponse.java	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -8,5 +8,5 @@
 public class S3UploadResponse {
     public String type;
-    public String url;
+    public String fileName;
     public MetaInfo meta;
 }
Index: frontend/src/App.tsx
===================================================================
--- frontend/src/App.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/App.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -9,5 +9,4 @@
 import CourseDetails from "./pages/CourseDetails.tsx";
 import {ToastContainer} from 'react-toastify';
-import 'react-toastify/dist/ReactToastify.css';
 import AppLoader from "./AppLoader.tsx";
 import Profile from "./pages/Profile.tsx";
@@ -20,8 +19,14 @@
 import Admin from "./admin/Admin.tsx";
 import AdminAddCourse from "./admin/pages/AdminAddCourse.tsx";
+import CourseLearn from "./pages/CourseLearn.tsx";
+import NavbarLearn from "./layout/NavbarLearn.tsx";
 
 function LayoutWrapper() {
     const location = useLocation();
-    const hideLayout = location.pathname === "/login" || location.pathname === "/register"; // You can add more paths like || location.pathname === "/signup"
+    const isLearn = location.pathname.startsWith("/learn");
+    const hideLayout =
+        location.pathname === "/login" ||
+        location.pathname === "/register" ||
+        isLearn;
     const {user, authChecked} = useAuthContext();
 
@@ -32,8 +37,8 @@
         return (
             <>
-                <AdminNavbar />
+                <AdminNavbar/>
                 <Routes>
-                    <Route path="/" element={<Admin />}/>
-                    <Route path="/add-course" element={<AdminAddCourse />}/>
+                    <Route path="/" element={<Admin/>}/>
+                    <Route path="/add-course" element={<AdminAddCourse/>}/>
                     <Route path="/analytics" element={<p>Analytics</p>}/>
                 </Routes>
@@ -46,4 +51,5 @@
         <>
             {!hideLayout && <Navbar/>}
+            {isLearn && <NavbarLearn/>}
             <Routes>
                 <Route path="/login" element={
@@ -73,9 +79,16 @@
                     </UserOnlyRoute>
                 }/>
-                <Route path="/dashboard" element={
+
+                <Route path="/learn" element={
                     <UserOnlyRoute>
                         <Dashboard/>
                     </UserOnlyRoute>
                 }/>
+                <Route path="/learn/:courseId/:courseTitle" element={
+                    <UserOnlyRoute>
+                        <CourseLearn/>
+                    </UserOnlyRoute>
+                }/>
+
             </Routes>
             {!hideLayout && <Footer/>}
Index: frontend/src/AppLoader.tsx
===================================================================
--- frontend/src/AppLoader.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/AppLoader.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -5,4 +5,6 @@
 } from "./api/courseApi.ts";
 import {useEffect} from "react";
+import {fetchUserEnrollmentsApi} from "./api/enrollmentApi.ts";
+import {getFromSessionStorage, saveToSessionStorage} from "./utils/useSessionStorage.ts";
 
 function AppLoader() {
@@ -11,4 +13,6 @@
         recommendedCourses,
         setRecommendedCourses,
+        enrollments,
+        setEnrollments
     } = useCourseStorage();
 
@@ -19,10 +23,23 @@
             // Recommended Courses
             try {
-                const recommendedStored = JSON.parse(sessionStorage.getItem("recommendedCourses") || "null");
+                const recommendedStored = getFromSessionStorage<typeof recommendedCourses>("recommendedCourses");
                 if (recommendedStored) {
-                    setRecommendedCourses(JSON.parse(recommendedStored));
+                    setRecommendedCourses(recommendedStored);
                 } else {
                     const recommended = await fetchRecommendedCoursesApi(accessToken || "");
                     setRecommendedCourses(recommended);
+                }
+            } catch (err) {
+                console.error("Failed to fetch recommended courses:", err);
+            }
+
+            // Enrollments
+            try {
+                const userEnrollmentsStored = getFromSessionStorage<typeof enrollments>("enrollments");
+                if (userEnrollmentsStored) {
+                    setEnrollments(userEnrollmentsStored);
+                } else {
+                    const userEnrollments = await fetchUserEnrollmentsApi(accessToken || "");
+                    setEnrollments(userEnrollments);
                 }
             } catch (err) {
@@ -36,6 +53,10 @@
 
     useEffect(() => {
-        sessionStorage.setItem("recommendedCourses", JSON.stringify(recommendedCourses));
+        saveToSessionStorage("recommendedCourses", recommendedCourses);
     }, [recommendedCourses]);
+
+    useEffect(() => {
+        saveToSessionStorage("enrollments", enrollments);
+    }, [enrollments]);
 
 
Index: frontend/src/admin/components/AdminAddCourseContent.tsx
===================================================================
--- frontend/src/admin/components/AdminAddCourseContent.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/admin/components/AdminAddCourseContent.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,5 +1,5 @@
 import type {Dispatch, SetStateAction} from "react";
 import AdminAddCourseInput from "./AdminAddCourseInput.tsx";
-import type {ContentType} from "../../types/ContentType.tsx";
+import type {ContentType} from "../../models/types/ContentType.tsx";
 import AdminAddCourseInputSelect from "./AdminAddCourseInputSelect.tsx";
 import AdminAddCourseInputTextArea from "./AdminAddCourseInputTextArea.tsx";
@@ -360,5 +360,5 @@
                                                     position: item.courseLectures.length + 1,
                                                     contentText: "",
-                                                    contentStoragePath: "",
+                                                    contentFileName: "",
                                                     contentType: "TEXT",
                                                     description: "",
Index: frontend/src/admin/components/AdminAddCourseInfo.tsx
===================================================================
--- frontend/src/admin/components/AdminAddCourseInfo.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/admin/components/AdminAddCourseInfo.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,4 +1,4 @@
 import AdminAddCourseInput from "./AdminAddCourseInput.tsx";
-import type {Difficulty} from "../../types/Difficulty.tsx";
+import type {Difficulty} from "../../models/types/Difficulty.tsx";
 import AdminAddCourseInputWithPills from "./AdminAddCourseInputWithPills.tsx";
 import AdminAddCourseInputTextArea from "./AdminAddCourseInputTextArea.tsx";
Index: frontend/src/admin/pages/AdminAddCourse.tsx
===================================================================
--- frontend/src/admin/pages/AdminAddCourse.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/admin/pages/AdminAddCourse.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -4,5 +4,5 @@
 import {createCourseApi, uploadCourseFilesApi} from "../api/addCourse.ts";
 import {useAuthContext} from "../../context/AuthContext.tsx";
-import type {ContentType} from "../../types/ContentType.tsx";
+import type {ContentType} from "../../models/types/ContentType.tsx";
 import AdminAddCourseInfo from "../components/AdminAddCourseInfo.tsx";
 import AdminAddCourseContent from "../components/AdminAddCourseContent.tsx";
@@ -35,5 +35,5 @@
     const courseCard = (
         <CourseCard card={{
-            id: 0, // temporary since new course has no ID yet
+            id: 0, // temporary since new javaObjects has no ID yet
             imageUrl: courseImage ? URL.createObjectURL(courseImage) : "",
             color: course.color,
@@ -52,12 +52,24 @@
 
     const handleAddCourse = async () => {
+        const countFileOrVideoLectures = course.courseContents
+            .flatMap(content => content.courseLectures)
+            .filter(lecture => lecture.contentType === "FILE" || lecture.contentType === "VIDEO" || lecture.contentType === "QUIZ" || lecture.contentType === "TOOL")
+            .length;
+
+        if (!courseImage) {
+            setError("Please upload a course image");
+            return;
+        }
+        if (!course.titleShort || !course.title || !course.difficulty ||
+            !course.descriptionShort || !course.description || !course.descriptionLong ||
+            course.whatWillBeLearned.length === 0 || course.skillsGained.length === 0 || course.topicsCovered.length === 0) {
+            setError("Please fill in all course details");
+            return;
+        }
         if (
-            !courseImage ||
-            !course.titleShort || !course.title || !course.difficulty || !course.durationMinutes ||
-            !course.descriptionShort || !course.description || !course.descriptionLong ||
-            course.whatWillBeLearned.length === 0 || course.skillsGained.length === 0 || course.topicsCovered.length === 0 ||
-            course.courseContents.length === 0
+            course.courseContents.length === 0 || course.courseContents.some(content => content.title.length === 0) ||
+            course.courseContents.some(content => content.courseLectures.length === 0) || courseLectureFiles.length < countFileOrVideoLectures
         ) {
-            setError("Please fill in all fields");
+            setError("Please add at least one content with lectures and upload files for all file/video/quiz/tool lectures");
             return;
         }
@@ -81,5 +93,5 @@
             const courseId = await createCourseApi(JSON.stringify(course), accessToken || "");
             if (!courseId) {
-                throw new Error("Failed to create course.");
+                throw new Error("Failed to create javaObjects.");
             }
 
@@ -88,10 +100,10 @@
                 navigate('/')
             } catch (err) {
-                console.error("Error uploading course image and lecture files:", err);
-                setError("An error occurred while uploading course image and lecture files. Please try again or contact support.");
+                console.error("Error uploading javaObjects image and lecture files:", err);
+                setError("An error occurred while uploading javaObjects image and lecture files. Please try again or contact support.");
             }
         } catch (err) {
-            console.error("Error creating course:", err);
-            setError("An error occurred while creating the course. Please try again or contact support.");
+            console.error("Error creating javaObjects:", err);
+            setError("An error occurred while creating the javaObjects. Please try again or contact support.");
         } finally {
             setLoading(false);
Index: frontend/src/admin/types/CourseEntity.tsx
===================================================================
--- frontend/src/admin/types/CourseEntity.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/admin/types/CourseEntity.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,3 +1,3 @@
-import type {Difficulty} from "../../types/Difficulty.tsx";
+import type {Difficulty} from "../../models/types/Difficulty.tsx";
 import type {CourseContentEntity} from "./CourseContentEntity.tsx";
 
Index: frontend/src/admin/types/CourseLectureEntity.tsx
===================================================================
--- frontend/src/admin/types/CourseLectureEntity.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/admin/types/CourseLectureEntity.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,3 +1,3 @@
-import type {ContentType} from "../../types/ContentType.tsx";
+import type {ContentType} from "../../models/types/ContentType.tsx";
 
 export interface CourseLectureEntity {
@@ -7,5 +7,5 @@
     position: number;
     contentText: string;
-    contentStoragePath: string;
+    contentFileName: string;
     contentType: ContentType;
 }
Index: ontend/src/api/auth.ts
===================================================================
--- frontend/src/api/auth.ts	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,49 +1,0 @@
-import axios from "axios";
-import type {UserRegister} from "../types/UserRegister.tsx";
-import type {User} from "../types/User.tsx";
-
-const backendUrl = import.meta.env.VITE_BACKEND_URL;
-
-export const refreshAccessTokenApi = async (): Promise<{user: User, accessToken: string}> => {
-    const res = await axios.post(`${backendUrl}/api/auth/refresh`,
-        {},
-        {withCredentials: true}
-    );
-
-    return res.data;
-}
-
-export const registerApi = async (user: UserRegister): Promise<{user: User, accessToken: string}> => {
-    const res = await axios.post(`${backendUrl}/api/auth/register`,
-        user,
-        { withCredentials: true }
-    );
-
-    return res.data;
-}
-
-export const loginApi = async (email: string, password: string): Promise<{user: User, accessToken: string}> => {
-    const res = await axios.post(`${backendUrl}/api/auth/authenticate`,
-        {email, password},
-        {withCredentials: true}
-    );
-
-    return res.data;
-}
-
-export const logoutApi = async (): Promise<void> => {
-    await axios.post(`${backendUrl}/api/auth/logout`,
-        {},
-        {withCredentials: true}
-    );
-}
-
-export const checkEmailExistsApi = async (email: string): Promise<boolean> => {
-    const res = await axios.get(`${backendUrl}/api/auth/check-email`, {
-        params: {
-            email: email,
-        },
-    });
-
-    return res.data;
-}
Index: frontend/src/api/authApi.ts
===================================================================
--- frontend/src/api/authApi.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/api/authApi.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,51 @@
+import axios from "axios";
+import type {UserRegister} from "../models/javaObjects/UserRegister.tsx";
+import type {User} from "../models/javaObjects/User.tsx";
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
+const backendUrl = import.meta.env.VITE_BACKEND_URL;
+
+export const refreshAccessTokenApi = async (): Promise<{user: User, accessToken: string}> => {
+    const res = await axios.post(`${backendUrl}/api/auth/refresh`,
+        {},
+        {withCredentials: true}
+    );
+
+    return res.data;
+}
+
+export const registerApi = async (user: UserRegister): Promise<{user: User, accessToken: string}> => {
+    const res = await axios.post(`${backendUrl}/api/auth/register`,
+        user,
+        { withCredentials: true }
+    );
+
+    return res.data;
+}
+
+export const loginApi = async (email: string, password: string): Promise<{user: User, accessToken: string}> => {
+    const res = await axios.post(`${backendUrl}/api/auth/authenticate`,
+        {email, password},
+        {withCredentials: true}
+    );
+
+    return res.data;
+}
+
+export const logoutApi = async (): Promise<void> => {
+    await axios.post(`${backendUrl}/api/auth/logout`,
+        {},
+        {withCredentials: true}
+    );
+}
+
+export const checkEmailExistsApi = async (email: string): Promise<boolean> => {
+    const res = await axios.get(`${backendUrl}/api/auth/check-email`, {
+        params: {
+            email: email,
+        },
+    });
+
+    return res.data;
+}
Index: frontend/src/api/courseApi.ts
===================================================================
--- frontend/src/api/courseApi.ts	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/api/courseApi.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,6 +1,9 @@
 import axios from "axios";
-import type {CoursePreview} from "../types/CoursePreview.tsx";
-import type {CourseDetail} from "../types/CourseDetail.tsx";
+import type {CoursePreview} from "../models/javaObjects/CoursePreview.tsx";
+import type {CourseDetail} from "../models/javaObjects/CourseDetail.tsx";
+import type {CourseFull} from "../models/javaObjects/CourseFull.tsx";
 
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
 const backendUrl = import.meta.env.VITE_BACKEND_URL;
 
@@ -24,5 +27,5 @@
         {
             signal,
-            headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined
+            headers: accessToken ? {Authorization: `Bearer ${accessToken}`} : undefined
 
         }
@@ -55,6 +58,17 @@
     const res = await axios.get(
         `${backendUrl}/api/courses/${courseId}`,
-        { signal }
+        {signal}
     );
+
+    return res.data;
+}
+
+export const fetchCourseFullApi = async (courseId: number, accessToken: string): Promise<CourseFull> => {
+    const res = await axios.get(
+        `${backendUrl}/api/courses/${courseId}/enrolled`, {
+            headers: {
+                Authorization: `Bearer ${accessToken}`
+            }
+        });
 
     return res.data;
Index: frontend/src/api/enrollmentApi.ts
===================================================================
--- frontend/src/api/enrollmentApi.ts	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/api/enrollmentApi.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,9 +1,11 @@
 import axios from "axios";
-import type {Enrollment} from "../types/Enrollment.tsx";
+import type {Enrollment} from "../models/javaObjects/Enrollment.tsx";
 
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
 const backendUrl = import.meta.env.VITE_BACKEND_URL;
 
-export const enrollUserApi = async (courseId: number, accessToken: string): Promise<void> => {
-    await axios.post(
+export const enrollUserApi = async (courseId: number, accessToken: string): Promise<Enrollment> => {
+    const res = await axios.post(
         `${backendUrl}/api/enrollments/create/${courseId}`,
         {},
@@ -15,4 +17,5 @@
     )
 
+    return res.data;
 }
 
Index: frontend/src/api/s3Api.ts
===================================================================
--- frontend/src/api/s3Api.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/api/s3Api.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,17 @@
+import axios from "axios";
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
+const backendUrl = import.meta.env.VITE_BACKEND_URL;
+
+export const fetchPresignedUrlApi = async (accessToken: string, courseId: number, lectureId: number, fileName: string, expirySeconds: number): Promise<string> => {
+    const res = await axios.get(
+        `${backendUrl}/api/s3/presigned-url?courseId=${courseId}&lectureId=${lectureId}&fileName=${fileName}&expirySeconds=${expirySeconds}`,
+        {
+            headers: accessToken ? {Authorization: `Bearer ${accessToken}`} : undefined
+
+        }
+    )
+
+    return res.data.url;
+}
Index: frontend/src/api/userApi.ts
===================================================================
--- frontend/src/api/userApi.ts	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/api/userApi.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,4 +1,6 @@
 import axios from "axios";
 
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
 const backendUrl = import.meta.env.VITE_BACKEND_URL;
 
Index: frontend/src/components/CourseCard.tsx
===================================================================
--- frontend/src/components/CourseCard.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/CourseCard.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -3,6 +3,6 @@
 import {hexToRgb} from "../utils/hexToRGB.ts";
 import {slugify} from "../utils/slug.ts";
-import { Link } from "react-router-dom";
-import type {CoursePreview} from "../types/CoursePreview.tsx";
+import {Link, useNavigate} from "react-router-dom";
+import type {CoursePreview} from "../models/javaObjects/CoursePreview.tsx";
 import HeartOutline from "../assets/icons/HeartOutline.tsx";
 import HeartFill from "../assets/icons/HeartFill.tsx";
@@ -20,9 +20,11 @@
     const bgColor = "bg-[var(--card-color)]";
     const shadowColor = `rgba(${hexToRgb(card.color)}, 0.6)`;
+    const navigate = useNavigate();
 
     const handleToggleFavoriteCourse = () => {
         setUser(prevUser => {
             if (!prevUser) {
-                showInfoToast("Please log in to save favorite courses.");
+                navigate("/login");
+                // showInfoToast("Please log in to save favorite courses.");
                 return prevUser; // Exit early
             }
@@ -55,5 +57,5 @@
                     });
 
-                    console.error("Error toggling course favorite status:", error);
+                    console.error("Error toggling javaObjects favorite status:", error);
                 });
         }
@@ -74,5 +76,5 @@
 
             {/*TITLE AND TOPICS LEARNED*/}
-            <div className="flex flex-col gap-2 items-start text-left h-full">
+            <div className="flex flex-col gap-2 items-start text-left justify-between h-full">
                 {/*Title*/}
                 <h3 className="font-semibold text-xl">{card.titleShort}</h3>
Index: frontend/src/components/CourseDetailsInfo.tsx
===================================================================
--- frontend/src/components/CourseDetailsInfo.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/CourseDetailsInfo.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,6 +1,17 @@
-import {Check, ChevronDown, ChevronUp, ClipboardList, File, Text, TvMinimalPlay} from "lucide-react"
+import {
+    Check,
+    ChevronDown,
+    ChevronUp,
+    ClipboardList,
+    File,
+    ListChecks,
+    Text,
+    TvMinimalPlay
+} from "lucide-react"
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
 import ShifterArrow from "../../public/Shifter-Arrow.png";
 import {useState} from "react";
-import type {CourseDetail} from "../types/CourseDetail.tsx";
+import type {CourseDetail} from "../models/javaObjects/CourseDetail.tsx";
 
 function CourseDetailsInfo({ course }: { course: CourseDetail | null}) {
@@ -76,5 +87,5 @@
                                     { isOpen &&
                                         (
-                                            <div className="border-t-1 border-black/20 py-4 text-black/80">
+                                            <div className="border-t-1 border-black/20 py-4 text-black">
                                                 {content.courseLectures.map((lecture, lectureIndex) => {
                                                     return (
@@ -82,10 +93,15 @@
                                                             key={lectureIndex}
                                                             className="flex justify-between px-6 py-2">
-                                                            <div className="flex gap-4">
-                                                                {lecture.contentType === "VIDEO" && <TvMinimalPlay size={20} strokeWidth={1.5} />}
-                                                                {lecture.contentType === "TEXT" && <Text size={20} strokeWidth={1.5} />}
-                                                                {lecture.contentType === "FILE" && <File size={20} strokeWidth={1.5} />}
-                                                                {lecture.contentType === "QUIZ" && <ClipboardList size={20} strokeWidth={1.5} />}
-                                                                <h4>{lecture.title}</h4>
+                                                            <div className="flex items-start gap-2">
+                                                                {lecture.contentType === "VIDEO" && <TvMinimalPlay size={20} strokeWidth={1.5} className="shrink-0"/>}
+                                                                {lecture.contentType === "TEXT" && <Text size={20} strokeWidth={1.5} className="shrink-0"/>}
+                                                                {lecture.contentType === "FILE" && <File size={20} strokeWidth={1.5} className="shrink-0" />}
+                                                                {lecture.contentType === "QUIZ" && <ListChecks size={20} strokeWidth={1.5} className="shrink-0"/>}
+                                                                {lecture.contentType === "TOOL" && <ClipboardList size={20} strokeWidth={1.5} className="shrink-0"/>}
+
+                                                                <div className="flex flex-col gap-2">
+                                                                    <h4 className="font-medium">{lecture.title}</h4>
+                                                                    <p className="opacity-80">{lecture.description}</p>
+                                                                </div>
                                                             </div>
                                                             <span>{lecture.durationMinutes}min</span>
Index: frontend/src/components/CoursesCarouselHome.tsx
===================================================================
--- frontend/src/components/CoursesCarouselHome.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/CoursesCarouselHome.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -11,5 +11,4 @@
 function CoursesCarouselHome() {
     const {recommendedCourses} = useCourseStorage();
-    console.log(recommendedCourses)
 
     return (
@@ -34,5 +33,5 @@
                 {recommendedCourses && recommendedCourses.length > 0 ? (
                     recommendedCourses.length <= 3 ? (
-                        <div className="flex gap-4 justify-center items-center">
+                        <div className="flex gap-12 justify-evenly items-center">
                             {recommendedCourses.map((course, index) => (
                                 <div key={index} className="max-w-1/3">
Index: frontend/src/components/CoursesFilters.tsx
===================================================================
--- frontend/src/components/CoursesFilters.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/CoursesFilters.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -2,5 +2,5 @@
 import Checkbox from "@mui/material/Checkbox";
 import {durationToQueryMapper, priceToQueryMapper} from "../utils/mapper.ts";
-import type {FilterParams} from "../types/FilterParams.tsx";
+import type {FilterParams} from "../models/FilterParams.tsx";
 import {useAuthContext} from "../context/AuthContext.tsx";
 
Index: frontend/src/components/CoursesGrid.tsx
===================================================================
--- frontend/src/components/CoursesGrid.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/CoursesGrid.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,7 +1,7 @@
-import type {CoursePreview} from "../types/CoursePreview.tsx";
+import type {CoursePreview} from "../models/javaObjects/CoursePreview.tsx";
 import CourseCard from "./CourseCard.tsx";
 import {InputAdornment, TextField} from '@mui/material';
 import {Search} from 'lucide-react';
-import type {FilterParams} from "../types/FilterParams.tsx";
+import type {FilterParams} from "../models/FilterParams.tsx";
 import React from "react";
 import {X} from 'lucide-react';
Index: ontend/src/components/CustomStepper.tsx
===================================================================
--- frontend/src/components/CustomStepper.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,81 +1,0 @@
-import {StepConnector, stepConnectorClasses, type StepIconProps, styled} from "@mui/material";
-import Check from "@mui/icons-material/Check";
-
-const CustomStepperConnector = styled(StepConnector)(() => ({
-    [`&.${stepConnectorClasses.alternativeLabel}`]: {
-        top: 10,
-        left: 'calc(-50% + 16px)',
-        right: 'calc(50% + 16px)',
-    },
-    [`&.${stepConnectorClasses.completed}`]: {
-        [`& .${stepConnectorClasses.line}`]: {
-            borderColor: 'var(--color-shifter)',
-            opacity: 0.2
-        },
-    },
-    [`&.${stepConnectorClasses.active}`]: {
-        [`& .${stepConnectorClasses.line}`]: {
-            borderColor: 'var(--color-shifter)',
-            opacity: 0.2
-        },
-    },
-    [`& .${stepConnectorClasses.line}`]: {
-        borderColor: '#BBB',
-        borderWidth: 2,
-        borderRadius: 2,
-        transition: 'border-color 0.4s ease-in-out, opacity 0.4s ease-in-out',
-    },
-}));
-const CustomStepperStepIconRoot = styled('div')<{ ownerState: { active?: boolean; completed?: boolean } }>(
-    ({ ownerState }) => ({
-        color: '#eaeaf0',
-        display: 'flex',
-        position: 'relative',       // <-- needed for absolute positioning inside
-        height: 22,
-        alignItems: 'center',
-        transition: 'color 0.3s ease-in-out',
-
-        // CHECKMARK
-        '& .CustomStepperStepIcon-completedIcon': {
-            color: 'var(--color-shifter)',
-            zIndex: 2,                // on top
-            fontSize: 30,
-            position: 'absolute',     // overlay on circle
-            opacity: ownerState.completed ? 1 : 0,
-            pointerEvents: ownerState.completed ? 'auto' : 'none',  // ignore clicks when hidden
-            transition: 'opacity 0.5s ease-in-out',
-            left: '50%',
-            top: '50%',
-            transform: ownerState.completed
-                ? 'translate(-50%, -50%) scale(1)'
-                : 'translate(-50%, -50%) scale(0.8)',
-            transitionProperty: 'opacity, transform',
-        },
-
-        // CIRCLE
-        '& .CustomStepperStepIcon-circle': {
-            width: 16,
-            height: 16,
-            borderRadius: '50%',
-            backgroundColor: ownerState.active ? 'var(--color-shifter)' : '#BBB',
-            transition: 'background-color 0.4s ease-in-out, transform 0.4s ease-in-out, opacity 0.5s ease-in-out',
-            transform: ownerState.active ? 'scale(1.2)' : 'scale(1)',
-            opacity: ownerState.completed ? 0 : 1,
-            pointerEvents: ownerState.completed ? 'none' : 'auto',  // ignore clicks when hidden
-        },
-    }),
-);
-
-function CustomStepperStepIcon(props: StepIconProps) {
-    const { active, completed, className } = props;
-
-    return (
-        <CustomStepperStepIconRoot ownerState={{ active, completed }} className={className}>
-            <Check className="CustomStepperStepIcon-completedIcon" />
-            <div className="CustomStepperStepIcon-circle" />
-        </CustomStepperStepIconRoot>
-    );
-}
-
-
-export { CustomStepperConnector, CustomStepperStepIcon };
Index: frontend/src/components/DashboardCourses.tsx
===================================================================
--- frontend/src/components/DashboardCourses.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/DashboardCourses.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,8 +1,11 @@
 import React, {useEffect, useState} from "react";
 import {fetchCoursesApi, fetchEnrolledCoursesApi} from "../api/courseApi.ts";
-import type {CoursePreview} from "../types/CoursePreview.tsx";
+import type {CoursePreview} from "../models/javaObjects/CoursePreview.tsx";
 import {useAuthContext} from "../context/AuthContext.tsx";
 import {useCourseStorage} from "../context/CourseStorage.ts";
 import StarFilled from "../assets/icons/StarFilled.tsx";
+import {Sparkle} from "lucide-react";
+import {Link} from "react-router-dom";
+import {toUrlFormat} from "../utils/toUrlFormat.ts";
 
 function DashboardCourses() {
@@ -55,5 +58,6 @@
 
         switch (selectedTab) {
-            case "all": return (
+            case "all":
+                return (
                     <>
                         {
@@ -64,5 +68,6 @@
                     </>
                 );
-            case "active": return (
+            case "active":
+                return (
                     <>
                         {
@@ -73,5 +78,6 @@
                     </>
                 );
-            case "completed": return (
+            case "completed":
+                return (
                     <>
                         {
@@ -82,5 +88,6 @@
                     </>
                 );
-            case "favorites": return (
+            case "favorites":
+                return (
                     <>
                         {
@@ -117,50 +124,66 @@
 
     return (
-        <aside
-            style={{"--card-color": course.color} as React.CSSProperties}
-            className="flex gap-8 items-center p-4 border-1 border-black/40 rounded-xl"
-        >
-            {/*IMAGE*/}
-            <div className="overflow-clip rounded-lg w-1/3">
-                <img src={course.imageUrl} alt={course.title}
-                     className="aspect-video object-cover"/>
-            </div>
-
-            {/*INFO*/}
-            <div className="flex flex-col gap-4 w-2/3">
-                {/*TITLE AND TOPICS COVERED*/}
-                <div className="flex flex-col gap-0">
-                    <h3 className="text-xl font-bold">{course.titleShort}</h3>
-
-                    <p className="text-black/60">{
-                        course.topicsCovered.map(item =>
-                            item
-                                .toLowerCase()
-                                .replace(/_/g, " ")
-                                .replace(/\b\w/g, c => c.toUpperCase())
-                        )
-                            .join(" • ")
-                    }</p>
+        <aside>
+            <Link
+                style={{"--card-color": course.color} as React.CSSProperties}
+                className="hover:shadow-md transition-all duration-300 ease-in-out
+                flex gap-8 items-center p-4 border-1 border-black/40 rounded-xl"
+                to={`/learn/${course.id}/${toUrlFormat(course.titleShort)}`}>
+                {/*IMAGE*/}
+                <div className="overflow-clip rounded-lg w-1/3">
+                    <img src={course.imageUrl} alt={course.title}
+                         className="aspect-video object-cover"/>
                 </div>
 
-                {/*Info*/}
-                <div className="flex flex-wrap gap-2 whitespace-nowrap">
-                    <div className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
-                        <StarFilled className="w-4 h-4 text-gold"/> {course.rating / course.ratingCount}
+                {/*INFO*/}
+                <div className="flex flex-col gap-4 w-2/3">
+                    {/*TITLE AND TOPICS COVERED*/}
+                    <div className="flex flex-col gap-0">
+                        <h3 className="text-xl font-bold">{course.titleShort}</h3>
+
+                        <p className="text-black/60">{
+                            course.topicsCovered.map(item =>
+                                item
+                                    .toLowerCase()
+                                    .replace(/_/g, " ")
+                                    .replace(/\b\w/g, c => c.toUpperCase())
+                            )
+                                .join(" • ")
+                        }</p>
                     </div>
-                    <div className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
-                        {course.ratingCount} reviews
-                    </div>
-                    <div className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
-                        {(course.durationMinutes / 60).toFixed(1)} hours
-                    </div>
-                    <div className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
-                        {course.courseContentCount} modules
-                    </div>
-                    <div className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
-                        {course.difficulty.charAt(0) + course.difficulty.slice(1).toLowerCase()}
+
+                    {/*Info*/}
+                    <div className="flex flex-wrap gap-2 whitespace-nowrap">
+                        {
+                            course.ratingCount > 10 ? (
+                                <>
+                                    <div
+                                        className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
+                                        <StarFilled className="w-4 h-4 text-gold"/> {course.rating / course.ratingCount}
+                                    </div>
+                                    <div
+                                        className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
+                                        {course.ratingCount} reviews
+                                    </div>
+                                </>
+                            ) : (
+                                <div
+                                    className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
+                                    <Sparkle className="w-4 h-4 text-gold"/> New
+                                </div>
+                            )
+                        }
+                        <div className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
+                            {(course.durationMinutes / 60).toFixed(1)} hours
+                        </div>
+                        <div className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
+                            {course.courseContentCount} modules
+                        </div>
+                        <div className="flex items-center gap-1 px-2 border-1 border-black/20 rounded-sm text-black/60">
+                            {course.difficulty.charAt(0) + course.difficulty.slice(1).toLowerCase()}
+                        </div>
                     </div>
                 </div>
-            </div>
+            </Link>
         </aside>
     )
Index: frontend/src/components/HeroCourseDetails.tsx
===================================================================
--- frontend/src/components/HeroCourseDetails.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/HeroCourseDetails.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,5 +1,7 @@
-import type {CourseDetail} from "../types/CourseDetail.tsx";
+import type {CourseDetail} from "../models/javaObjects/CourseDetail.tsx";
 import React from "react";
 import {useCourseStorage} from "../context/CourseStorage.ts";
+import { Link } from "react-router-dom";
+import {toUrlFormat} from "../utils/toUrlFormat.ts";
 
 function HeroCourseDetails({course, enrollUser}: { course: CourseDetail | null, enrollUser: () => Promise<void> }) {
@@ -21,5 +23,5 @@
             description: course?.ratingCount && course.ratingCount > 10
                 ? 'Rated highly by learners for its practical insights and actionable strategies.'
-                : 'New to the platform, this course is growing quickly. Be among the first learners to benefit from its insights.'
+                : 'New to the platform, this javaObjects is growing quickly. Be among the first learners to benefit from its insights.'
         }
         ,
@@ -27,5 +29,4 @@
 
     const bgColor = "bg-[var(--card-color)]";
-
 
     return (
@@ -47,18 +48,21 @@
                                     <div className="w-8 loader"></div>
                                 ) : (
-                                    <button className={`
-                                ${bgColor}
-                                hover:shadow-lg hover:shadow-deep-green/50 transition-all duration-300 ease-in-out cursor-pointer
-                                shadow-md shadow-deep-green/30 text-white font-medium text-xl border-3 border-white/50 rounded-full px-14 py-2
-                            `}
-                                    >Start Learning Now</button>
+                                    <Link
+                                        to={`/learn/${course?.id}/${toUrlFormat(course?.titleShort || "")}`}
+                                        className={`
+                                            ${bgColor}
+                                            hover:shadow-lg hover:shadow-deep-green/50 transition-all duration-300 ease-in-out cursor-pointer
+                                            shadow-md shadow-deep-green/30 text-white font-medium text-xl border-3 border-white/50 rounded-full px-14 py-2
+                                        `}
+                                    >Go To Course</Link>
                                 )
                             }
                         </div>
                         :
-                        <div className="flex mt-12 gap-4 items-center bg-gray/60 backdrop-blur-lg border-3 border-black/5 px-2 py-1 w-fit rounded-full">
-                    <span className="font-semibold text-xl px-8">{
-                        course?.price && course.price > 0 ? `$${course?.price}` : 'Free'
-                    }</span>
+                        <div
+                            className="flex mt-12 gap-4 items-center bg-gray/60 backdrop-blur-lg border-3 border-black/5 px-2 py-1 w-fit rounded-full">
+                            <span className="font-semibold text-xl px-8">
+                                {course?.price && course.price > 0 ? `$${course?.price}` : 'Free'}
+                            </span>
                             {
                                 isLoading ? (
@@ -66,13 +70,13 @@
                                 ) : (
                                     <button className={`
-                                ${bgColor}
-                                hover:shadow-lg hover:shadow-deep-green/50 transition-all duration-300 ease-in-out cursor-pointer
-                                shadow-md shadow-deep-green/30 text-white font-medium text-xl border-3 border-white/50 rounded-full px-14 py-2
-                            `}
+                                                ${bgColor}
+                                                hover:shadow-lg hover:shadow-deep-green/50 transition-all duration-300 ease-in-out cursor-pointer
+                                                shadow-md shadow-deep-green/30 text-white font-medium text-xl border-3 border-white/50 rounded-full px-14 py-2
+                                            `}
                                             onClick={() => {
                                                 setIsLoading(true)
                                                 enrollUser()
                                                     .catch((error) => {
-                                                        console.error("Error enrolling user in course:", error);
+                                                        console.error("Error enrolling user in javaObjects:", error);
                                                     })
                                                     .finally(() => {
Index: frontend/src/components/HeroHome.tsx
===================================================================
--- frontend/src/components/HeroHome.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/HeroHome.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -44,5 +44,5 @@
                         className="absolute bottom-5 flex gap-2 bg-gray/20 backdrop-blur-lg p-1 rounded-full border-3 border-black/5 text-md">
                         <Link
-                            to="/"
+                            to="/free-consultation"
                             className="hover:shadow-lg hover:shadow-shifter/50 transition-all duration-200 ease-in-out cursor-pointer
                         rounded-full text-white px-8 py-3 bg-shifter border-3 border-white/50 font-semibold
Index: frontend/src/components/ProfileModalAddSkills&Interests.tsx
===================================================================
--- frontend/src/components/ProfileModalAddSkills&Interests.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/ProfileModalAddSkills&Interests.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -32,5 +32,5 @@
                 })
                 .catch(err => {
-                    console.error("Failed to fetch course skills", err);
+                    console.error("Failed to fetch javaObjects skills", err);
                 })
                 .finally(() => setComponentRenderLoading(false));
@@ -42,5 +42,5 @@
                 })
                 .catch(err => {
-                    console.error("Failed to fetch course topics", err);
+                    console.error("Failed to fetch javaObjects topics", err);
                 })
                 .finally(() => setComponentRenderLoading(false));
Index: frontend/src/components/inputs/RegisterInput.tsx
===================================================================
--- frontend/src/components/inputs/RegisterInput.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/inputs/RegisterInput.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,5 +1,5 @@
 import {Eye, EyeOff} from "lucide-react";
 import React from "react";
-import type { UserRegister } from "../../types/UserRegister.tsx";
+import type { UserRegister } from "../../models/javaObjects/UserRegister.tsx";
 
 type UserStrFields = 'email' | 'password' | 'passwordConfirmation' | 'name' | 'workPosition' | 'companyType';
Index: frontend/src/components/inputs/RegisterSelect.tsx
===================================================================
--- frontend/src/components/inputs/RegisterSelect.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/inputs/RegisterSelect.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,4 +1,4 @@
-import type {UserRegister} from "../../types/UserRegister.tsx";
-import type {SelectProps} from "../../types/SelectProps.tsx";
+import type {UserRegister} from "../../models/javaObjects/UserRegister.tsx";
+import type {SelectProps} from "../../models/SelectProps.tsx";
 import {toEnumFormat} from "../../utils/toEnumFormat.ts";
 
Index: frontend/src/components/inputs/RegisterSlider.tsx
===================================================================
--- frontend/src/components/inputs/RegisterSlider.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/inputs/RegisterSlider.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,5 +1,5 @@
 import React from "react";
-import type {UserRegister} from "../../types/UserRegister.tsx";
-import type {SliderProps} from "../../types/SliderProps.tsx";
+import type {UserRegister} from "../../models/javaObjects/UserRegister.tsx";
+import type {SliderProps} from "../../models/SliderProps.tsx";
 
 function RegisterSlider(sliderProps: SliderProps) {
Index: frontend/src/components/learn/CourseContentSideNav.tsx
===================================================================
--- frontend/src/components/learn/CourseContentSideNav.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/components/learn/CourseContentSideNav.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,79 @@
+import type {CourseContentFull} from "../../models/javaObjects/CourseContentFull.tsx";
+import {useState} from "react";
+import {ChevronDown, ClipboardList, File, ListChecks, Text, TvMinimalPlay} from "lucide-react";
+import type {CourseLectureFull} from "../../models/javaObjects/CourseLectureFull.tsx";
+
+function CourseContentSideNav({ setActiveLecture, courseContents }: {
+    setActiveLecture: (lecture: CourseLectureFull) => void,
+    courseContents: CourseContentFull[]
+}) {
+    const [openIndices, setOpenIndices] = useState<number[]>([]);
+
+    const toggleAccordion = (index: number) => {
+        if (openIndices.includes(index)) {
+            setOpenIndices(openIndices.filter(i => i !== index));
+        } else {
+            setOpenIndices([...openIndices, index]);
+        }
+    }
+
+    return (
+        <aside className="sticky top-0 right-0 min-w-28/100 h-screen overflow-y-auto border-l-1 border-black/20">
+            {
+                courseContents && courseContents.map((content, index) => {
+                    const isOpen = openIndices.includes(index);
+
+                    return (
+                    <div
+                        key={index}
+                        className="flex flex-col border-t-2 border-black/20">
+                        {/*Content*/}
+                        <button
+                            onClick={() => toggleAccordion(index)}
+                            className="py-4 px-4 bg-black/5 flex flex-col items-start gap-2 cursor-pointer">
+                            <div className="flex items-start gap-2 justify-between w-full">
+                                <h3 className="text-left font-bold">Module {index+1}: {content.title}</h3>
+                                <ChevronDown height={20}
+                                className={`${isOpen && "-rotate-180"} transition-all duration-500 ease-out`}/>
+                            </div>
+
+                            <span className="text-xs text-black text-light">
+                                0 / {content.courseLectures.length} | {content.courseLectures.reduce((acc, lecture) => acc + lecture.durationMinutes, 0)}min
+                            </span>
+                        </button>
+
+                        {/*Lecture*/}
+                        {isOpen && content.courseLectures.map((lecture, lectureIndex) => {
+                            return (
+                                <button
+                                    key={lectureIndex}
+                                    onClick={() => setActiveLecture(lecture)}
+                                    className="hover:bg-shifter/5 cursor-pointer
+                                    py-4 px-4 flex gap-2 items-start">
+                                    <input
+                                        type={"checkbox"}
+                                        className="w-4 aspect-square"
+                                    />
+
+                                    <div className="flex flex-col gap-2 text-left">
+                                        <h4 className="leading-tight text-sm">{lecture.title}</h4>
+                                        <span className="flex items-center gap-2 text-xs opacity-80">
+                                            {lecture.contentType === "VIDEO" && <TvMinimalPlay size={16} strokeWidth={1.5} />}
+                                            {lecture.contentType === "TEXT" && <Text size={16} strokeWidth={1.5} />}
+                                            {lecture.contentType === "FILE" && <File size={16} strokeWidth={1.5} />}
+                                            {lecture.contentType === "QUIZ" && <ListChecks size={16} strokeWidth={1.5} />}
+                                            {lecture.contentType === "TOOL" && <ClipboardList size={16} strokeWidth={1.5} />}
+                                            {lecture.durationMinutes}min
+                                        </span>
+                                    </div>
+                                </button>
+                            )
+                        })}
+                    </div>
+                )})
+            }
+        </aside>
+    )
+}
+
+export default CourseContentSideNav;
Index: frontend/src/components/registerSteps/CustomStepper.tsx
===================================================================
--- frontend/src/components/registerSteps/CustomStepper.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/components/registerSteps/CustomStepper.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,81 @@
+import {StepConnector, stepConnectorClasses, type StepIconProps, styled} from "@mui/material";
+import Check from "@mui/icons-material/Check";
+
+const CustomStepperConnector = styled(StepConnector)(() => ({
+    [`&.${stepConnectorClasses.alternativeLabel}`]: {
+        top: 10,
+        left: 'calc(-50% + 16px)',
+        right: 'calc(50% + 16px)',
+    },
+    [`&.${stepConnectorClasses.completed}`]: {
+        [`& .${stepConnectorClasses.line}`]: {
+            borderColor: 'var(--color-shifter)',
+            opacity: 0.2
+        },
+    },
+    [`&.${stepConnectorClasses.active}`]: {
+        [`& .${stepConnectorClasses.line}`]: {
+            borderColor: 'var(--color-shifter)',
+            opacity: 0.2
+        },
+    },
+    [`& .${stepConnectorClasses.line}`]: {
+        borderColor: '#BBB',
+        borderWidth: 2,
+        borderRadius: 2,
+        transition: 'border-color 0.4s ease-in-out, opacity 0.4s ease-in-out',
+    },
+}));
+const CustomStepperStepIconRoot = styled('div')<{ ownerState: { active?: boolean; completed?: boolean } }>(
+    ({ ownerState }) => ({
+        color: '#eaeaf0',
+        display: 'flex',
+        position: 'relative',       // <-- needed for absolute positioning inside
+        height: 22,
+        alignItems: 'center',
+        transition: 'color 0.3s ease-in-out',
+
+        // CHECKMARK
+        '& .CustomStepperStepIcon-completedIcon': {
+            color: 'var(--color-shifter)',
+            zIndex: 2,                // on top
+            fontSize: 30,
+            position: 'absolute',     // overlay on circle
+            opacity: ownerState.completed ? 1 : 0,
+            pointerEvents: ownerState.completed ? 'auto' : 'none',  // ignore clicks when hidden
+            transition: 'opacity 0.5s ease-in-out',
+            left: '50%',
+            top: '50%',
+            transform: ownerState.completed
+                ? 'translate(-50%, -50%) scale(1)'
+                : 'translate(-50%, -50%) scale(0.8)',
+            transitionProperty: 'opacity, transform',
+        },
+
+        // CIRCLE
+        '& .CustomStepperStepIcon-circle': {
+            width: 16,
+            height: 16,
+            borderRadius: '50%',
+            backgroundColor: ownerState.active ? 'var(--color-shifter)' : '#BBB',
+            transition: 'background-color 0.4s ease-in-out, transform 0.4s ease-in-out, opacity 0.5s ease-in-out',
+            transform: ownerState.active ? 'scale(1.2)' : 'scale(1)',
+            opacity: ownerState.completed ? 0 : 1,
+            pointerEvents: ownerState.completed ? 'none' : 'auto',  // ignore clicks when hidden
+        },
+    }),
+);
+
+function CustomStepperStepIcon(props: StepIconProps) {
+    const { active, completed, className } = props;
+
+    return (
+        <CustomStepperStepIconRoot ownerState={{ active, completed }} className={className}>
+            <Check className="CustomStepperStepIcon-completedIcon" />
+            <div className="CustomStepperStepIcon-circle" />
+        </CustomStepperStepIconRoot>
+    );
+}
+
+
+export { CustomStepperConnector, CustomStepperStepIcon };
Index: frontend/src/components/registerSteps/RegisterStepFour.tsx
===================================================================
--- frontend/src/components/registerSteps/RegisterStepFour.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/registerSteps/RegisterStepFour.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,4 +1,4 @@
 import React, {useEffect} from "react";
-import type {UserRegister} from "../../types/UserRegister.tsx";
+import type {UserRegister} from "../../models/javaObjects/UserRegister.tsx";
 import RegisterSlider from "../inputs/RegisterSlider.tsx";
 import {fetchCoursesSkillsApi} from "../../api/courseApi.ts";
Index: frontend/src/components/registerSteps/RegisterStepOne.tsx
===================================================================
--- frontend/src/components/registerSteps/RegisterStepOne.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/registerSteps/RegisterStepOne.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,4 +1,4 @@
 import React, {useEffect} from "react";
-import type {UserRegister} from "../../types/UserRegister.tsx";
+import type {UserRegister} from "../../models/javaObjects/UserRegister.tsx";
 import RegisterInput from "../inputs/RegisterInput.tsx";
 import {isValidEmail, hasUppercase, hasDigit, hasSpecialChar} from "../../utils/validation.ts";
Index: frontend/src/components/registerSteps/RegisterStepThree.tsx
===================================================================
--- frontend/src/components/registerSteps/RegisterStepThree.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/registerSteps/RegisterStepThree.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,4 +1,4 @@
 import React, {useEffect} from "react";
-import type {UserRegister} from "../../types/UserRegister.tsx";
+import type {UserRegister} from "../../models/javaObjects/UserRegister.tsx";
 import RegisterSlider from "../inputs/RegisterSlider.tsx";
 import {fetchCoursesTopicsApi} from "../../api/courseApi.ts";
@@ -17,5 +17,5 @@
                 setInterests(topicsData);
             } catch (err) {
-                console.error("Failed to fetch course topics (user interests)", err);
+                console.error("Failed to fetch javaObjects topics (user interests)", err);
             }
         };
Index: frontend/src/components/registerSteps/RegisterStepTwo.tsx
===================================================================
--- frontend/src/components/registerSteps/RegisterStepTwo.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/components/registerSteps/RegisterStepTwo.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,4 +1,4 @@
 import React, {useEffect} from "react";
-import type {UserRegister} from "../../types/UserRegister.tsx";
+import type {UserRegister} from "../../models/javaObjects/UserRegister.tsx";
 import RegisterInput from "../inputs/RegisterInput.tsx";
 import RegisterSelect from "../inputs/RegisterSelect.tsx";
Index: frontend/src/components/skeletons/CourseLearnSkeleton.tsx
===================================================================
--- frontend/src/components/skeletons/CourseLearnSkeleton.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/components/skeletons/CourseLearnSkeleton.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,55 @@
+
+function CourseLearnSkeleton() {
+    return (
+        <main className="flex ">
+            <div className="flex flex-col w-full">
+                {/* Video player skeleton */}
+                <div className="w-full h-96 bg-gray-300 animate-pulse"></div>
+
+                <div className="flex flex-col gap-4 flex-grow py-vertical-md px-horizontal-sm text-left text-black-text">
+                    {/* Title skeleton */}
+                    <div className="h-10 bg-gray-300 rounded w-3/4 animate-pulse"></div>
+
+                    {/* Content text skeleton */}
+                    <div className="flex flex-col gap-3">
+                        <div className="h-6 bg-gray-300 rounded w-full animate-pulse"></div>
+                        <div className="h-6 bg-gray-300 rounded w-98/100 animate-pulse"></div>
+                        <div className="h-6 bg-gray-300 rounded w-full animate-pulse"></div>
+                        <div className="h-6 bg-gray-300 rounded w-95/100 animate-pulse"></div>
+                        <div className="h-6 bg-gray-300 rounded w-4/5 animate-pulse"></div>
+                    </div>
+
+                    {/* File download section skeleton */}
+                    <div className="flex justify-between w-full gap-20 items-center py-12">
+                        <div className="h-6 bg-gray-300 rounded w-120 animate-pulse"></div>
+                        <div className="h-12 bg-gray-300 rounded-md w-36 animate-pulse"></div>
+                    </div>
+                </div>
+            </div>
+
+            {/* CourseContentSideNav skeleton */}
+            <div className="w-28/100 flex flex-col gap-4 p-6 bg-gray-50">
+                {/* Side nav header skeleton */}
+                <div className="h-8 bg-gray-300 rounded w-3/4 animate-pulse"></div>
+
+                {/* Course content sections skeleton */}
+                {[...Array(4)].map((_, sectionIndex) => (
+                    <div key={sectionIndex} className="flex flex-col gap-2">
+                        {/* Section title skeleton */}
+                        <div className="h-6 bg-gray-300 rounded w-2/3 animate-pulse"></div>
+
+                        {/* Lectures skeleton */}
+                        {[...Array(4)].map((_, lectureIndex) => (
+                            <div key={lectureIndex} className="flex items-center gap-3 p-2">
+                                <div className="w-4 h-4 bg-gray-300 rounded-full animate-pulse"></div>
+                                <div className="h-5 bg-gray-300 rounded w-full animate-pulse"></div>
+                            </div>
+                        ))}
+                    </div>
+                ))}
+            </div>
+        </main>
+    );
+}
+
+export default CourseLearnSkeleton;
Index: frontend/src/context/AuthContext.tsx
===================================================================
--- frontend/src/context/AuthContext.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/context/AuthContext.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -7,7 +7,7 @@
     type SetStateAction,
 } from "react";
-import type {User} from "../types/User.tsx";
-import type {UserRegister} from "../types/UserRegister.tsx";
-import {loginApi, logoutApi, refreshAccessTokenApi, registerApi} from "../api/auth.ts";
+import type {User} from "../models/javaObjects/User.tsx";
+import type {UserRegister} from "../models/javaObjects/UserRegister.tsx";
+import {loginApi, logoutApi, refreshAccessTokenApi, registerApi} from "../api/authApi.ts";
 import {useNavigate} from "react-router-dom";
 
@@ -70,5 +70,5 @@
                 setAccessToken(null);
                 setUser(null);
-                navigate("/courses");
+                navigate("/");
             })
             .catch(err => {
Index: frontend/src/context/CourseStorage.ts
===================================================================
--- frontend/src/context/CourseStorage.ts	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/context/CourseStorage.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,5 +1,5 @@
 import { create } from "zustand";
-import type {CoursePreview} from "../types/CoursePreview.tsx";
-import type {Enrollment} from "../types/Enrollment.tsx";
+import type {CoursePreview} from "../models/javaObjects/CoursePreview.tsx";
+import type {Enrollment} from "../models/javaObjects/Enrollment.tsx";
 
 
Index: frontend/src/global.css
===================================================================
--- frontend/src/global.css	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/global.css	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -26,4 +26,5 @@
     --color-bright-gray: #DDDDDD;
     --color-gray: #E5E7EBFF;
+    --color-black-text: #333333;
 
 
@@ -79,5 +80,5 @@
 :root {
     --color-white: #F8F8F8;
-    --color-black: #111;
+    --color-black: #202024;
 
     font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
Index: frontend/src/hooks/useEnrollUserInCourse.tsx
===================================================================
--- frontend/src/hooks/useEnrollUserInCourse.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/hooks/useEnrollUserInCourse.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,38 @@
+import { useNavigate } from "react-router-dom";
+import { enrollUserApi } from "../api/enrollmentApi.ts";
+import { useAuthContext } from "../context/AuthContext.tsx";
+import { useCourseStorage } from "../context/CourseStorage.ts";
+import { showInfoToast } from "../utils/showInfoToast.ts";
+import { slugify } from "../utils/slug.ts";
+import type { Enrollment } from "../models/javaObjects/Enrollment.tsx";
+import {fetchRecommendedCoursesApi} from "../api/courseApi.ts";
+
+export function useEnrollUserInCourse(courseId: number, courseTitleShort: string | undefined) {
+    const { user, accessToken } = useAuthContext();
+    const navigate = useNavigate();
+    const { enrollments, setEnrollments, allCourses, setAllCourses, setRecommendedCourses } = useCourseStorage();
+
+    async function enroll() {
+        if (!user) {
+            showInfoToast("Please log in to enroll in the javaObjects.");
+        }
+
+        try {
+            const enrollment: Enrollment = await enrollUserApi(courseId, accessToken || "");
+
+            setAllCourses(allCourses?.filter(course => course.id !== courseId) || [])
+            setEnrollments([...(enrollments ?? []), enrollment]);
+
+            const recommendedCourses = await fetchRecommendedCoursesApi(accessToken || "");
+            setRecommendedCourses(recommendedCourses);
+
+            navigate(`/learn/${courseId}/${slugify(courseTitleShort || "")}`);
+            console.log("User enrolled in javaObjects successfully");
+        } catch (error) {
+            console.error("Error enrolling user in javaObjects:", error);
+            throw error;
+        }
+    }
+
+    return { enroll };
+}
Index: frontend/src/layout/Navbar.tsx
===================================================================
--- frontend/src/layout/Navbar.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/layout/Navbar.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,3 +1,5 @@
 import {Link} from "react-router-dom";
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
 import logo from "../../public/Shifter-S2W-White-Transparent.png"
 import {useAuthContext} from "../context/AuthContext.tsx";
@@ -32,5 +34,5 @@
                 {user ? (
                     <>
-                        <NavbarLink to="/dashboard" label="Dashboard"/>
+                        <NavbarLink to="/learn" label="Dashboard"/>
                         <div className="flex gap-4 items-center">
                             <Link
Index: frontend/src/layout/NavbarLearn.tsx
===================================================================
--- frontend/src/layout/NavbarLearn.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/layout/NavbarLearn.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,36 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
+import logo from "../../public/Shifter-S2W-White-Transparent.png";
+import {Link, useLocation} from "react-router-dom";
+import {fromUrlFormat} from "../utils/toUrlFormat.ts";
+import NavbarLink from "../components/NavbarLink.tsx";
+
+function NavbarLearn() {
+    const location = useLocation();
+    const courseId = location.pathname.split("/")[2] || "";
+    const courseTitleEncoded = location.pathname.split("/")[3] || "";
+    const courseTitle = fromUrlFormat(courseTitleEncoded)
+
+    return (
+        <nav className="flex justify-between items-center bg-black w-full py-2 px-8 border-b-2 border-white/60">
+            <div className="flex gap-4 items-center text-xl text-white ">
+                <Link to="/learn">
+                    <img src={logo} alt="Shifter Logo" className="h-12"/>
+                </Link>
+                <div className="w-[1px] bg-white/40 self-stretch my-2"/>
+                {
+                    courseTitle && <Link to={`/courses/${courseId}/${courseTitleEncoded}`}>{courseTitle}</Link>
+                }
+            </div>
+
+            <div className="flex gap-4">
+                <NavbarLink className="w-fit text-white"
+                            to={"/learn"} label={"Dashboard"}/>
+                <NavbarLink className="w-fit text-white"
+                            to={"/"} label={"Return Home"}/>
+            </div>
+        </nav>
+    )
+}
+
+export default NavbarLearn;
Index: frontend/src/models/FilterParams.tsx
===================================================================
--- frontend/src/models/FilterParams.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/FilterParams.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,10 @@
+
+export interface FilterParams {
+    showOnlyFavoriteCourses?: boolean;
+    search?: string[];
+    difficulty?: string[];
+    price?: string[];
+    duration?: string[];
+    skill?: string[];
+    topic?: string[];
+}
Index: frontend/src/models/FilterRange.tsx
===================================================================
--- frontend/src/models/FilterRange.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/FilterRange.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,4 @@
+export interface FilterRange {
+    floor: number;
+    ceil: number;
+}
Index: frontend/src/models/SelectProps.tsx
===================================================================
--- frontend/src/models/SelectProps.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/SelectProps.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,11 @@
+import React from "react";
+import type {UserRegister} from "./javaObjects/UserRegister.tsx";
+
+export interface SelectProps {
+    label: string;
+    name: keyof UserRegister;
+    id: string;
+    options?: string[];
+    setUser: React.Dispatch<React.SetStateAction<UserRegister>>;
+    user: UserRegister;
+}
Index: frontend/src/models/SliderProps.tsx
===================================================================
--- frontend/src/models/SliderProps.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/SliderProps.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,12 @@
+import React from "react";
+import type {UserRegister} from "./javaObjects/UserRegister.tsx";
+
+type UserArrayFields = 'interests' | 'desiredSkills';
+export interface SliderProps {
+    label: string;
+    name: UserArrayFields;
+    id: string;
+    options?: string[];
+    setUser: React.Dispatch<React.SetStateAction<UserRegister>>;
+    user: UserRegister;
+}
Index: frontend/src/models/javaObjects/CourseContentFull.tsx
===================================================================
--- frontend/src/models/javaObjects/CourseContentFull.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/javaObjects/CourseContentFull.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,7 @@
+import type {CourseLectureFull} from "./CourseLectureFull.tsx";
+
+export interface CourseContentFull {
+    title: string;
+    position: number;
+    courseLectures: CourseLectureFull[];
+}
Index: frontend/src/models/javaObjects/CourseContentPreview.tsx
===================================================================
--- frontend/src/models/javaObjects/CourseContentPreview.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/javaObjects/CourseContentPreview.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,7 @@
+import type {CourseLecturePreview} from "./CourseLecturePreview.tsx";
+
+export interface CourseContentPreview {
+    title: string;
+    position: number;
+    courseLectures: CourseLecturePreview[];
+}
Index: frontend/src/models/javaObjects/CourseDetail.tsx
===================================================================
--- frontend/src/models/javaObjects/CourseDetail.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/javaObjects/CourseDetail.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,10 @@
+import type {CoursePreview} from "./CoursePreview.tsx";
+import type {CourseContentPreview} from "./CourseContentPreview.tsx";
+
+export interface CourseDetail extends CoursePreview {
+    descriptionShort: string;
+    description: string;
+    descriptionLong: string;
+    whatWillBeLearned: string[];
+    courseContents: CourseContentPreview[];
+}
Index: frontend/src/models/javaObjects/CourseFull.tsx
===================================================================
--- frontend/src/models/javaObjects/CourseFull.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/javaObjects/CourseFull.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,22 @@
+import type {Difficulty} from "../types/Difficulty.tsx";
+import type {CourseContentFull} from "./CourseContentFull.tsx";
+
+export interface CourseFull {
+    id: number,
+    imageUrl: string;
+    color: string;
+    titleShort: string;
+    title: string;
+    difficulty: Difficulty;
+    durationMinutes: number;
+    price: number;
+    rating: number;
+    ratingCount: number;
+    descriptionShort: string;
+    description: string;
+    descriptionLong: string;
+    whatWillBeLearned: string[];
+    skillsGained: string[];
+    topicsCovered: string[];
+    courseContents: CourseContentFull[];
+}
Index: frontend/src/models/javaObjects/CourseLectureFull.tsx
===================================================================
--- frontend/src/models/javaObjects/CourseLectureFull.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/javaObjects/CourseLectureFull.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,12 @@
+import type {ContentType} from "../types/ContentType.tsx";
+
+export interface CourseLectureFull {
+    id: number;
+    title: string;
+    description: string;
+    durationMinutes: number;
+    position: number;
+    contentText: string;
+    contentFileName: string;
+    contentType: ContentType;
+}
Index: frontend/src/models/javaObjects/CourseLecturePreview.tsx
===================================================================
--- frontend/src/models/javaObjects/CourseLecturePreview.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/javaObjects/CourseLecturePreview.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,9 @@
+import type {ContentType} from "../types/ContentType.tsx";
+
+export interface CourseLecturePreview {
+    title: string;
+    description: string;
+    durationMinutes: number;
+    position: number;
+    contentType: ContentType;
+}
Index: frontend/src/models/javaObjects/CoursePreview.tsx
===================================================================
--- frontend/src/models/javaObjects/CoursePreview.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/javaObjects/CoursePreview.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,18 @@
+import type {Difficulty} from "../types/Difficulty.tsx";
+
+export interface CoursePreview {
+    id: number,
+    imageUrl: string;
+    color: string;
+    titleShort: string;
+    title: string;
+    difficulty: Difficulty;
+    durationMinutes: number;
+    price: number;
+    rating: number;
+    ratingCount: number;
+    skillsGained: string[];
+    topicsCovered: string[];
+    courseContentCount: number;
+}
+
Index: frontend/src/models/javaObjects/Enrollment.tsx
===================================================================
--- frontend/src/models/javaObjects/Enrollment.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/javaObjects/Enrollment.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,7 @@
+
+export interface Enrollment {
+    enrollmentStatus: "PENDING" | "ACTIVE" | "COMPLETED";
+    percentCompleted: number;
+    date: Date;
+    courseId: number;
+}
Index: frontend/src/models/javaObjects/User.tsx
===================================================================
--- frontend/src/models/javaObjects/User.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/javaObjects/User.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,13 @@
+export interface User {
+    id: number,
+    email: string;
+    name: string;
+    companyType: string;
+    workPosition: string;
+    interests: string[];
+    skills: string[];
+    desiredSkills: string[];
+    points: number;
+    favoriteCourses: number[];
+    isAdmin: boolean;
+}
Index: frontend/src/models/javaObjects/UserRegister.tsx
===================================================================
--- frontend/src/models/javaObjects/UserRegister.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/javaObjects/UserRegister.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,10 @@
+export interface UserRegister {
+    email: string;
+    password: string;
+    passwordConfirmation: string;
+    name: string;
+    workPosition: string;
+    companyType: string;
+    interests: string[];
+    desiredSkills: string[];
+}
Index: frontend/src/models/types/ContentType.tsx
===================================================================
--- frontend/src/models/types/ContentType.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/types/ContentType.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,1 @@
+export type ContentType = "VIDEO" | "TEXT" | "FILE" | "QUIZ" | "TOOL";
Index: frontend/src/models/types/Difficulty.tsx
===================================================================
--- frontend/src/models/types/Difficulty.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/models/types/Difficulty.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,1 @@
+export type Difficulty = "BEGINNER" | "INTERMEDIATE" | "ADVANCED" | "EXPERT";
Index: frontend/src/pages/CourseDetails.tsx
===================================================================
--- frontend/src/pages/CourseDetails.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/pages/CourseDetails.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -5,36 +5,36 @@
 import CourseDetailsInfo from "../components/CourseDetailsInfo.tsx";
 import CoursesCarouselCourseDetails from "../components/CoursesCarouselCourseDetails.tsx";
-import type {CourseDetail} from "../types/CourseDetail.tsx";
-import {enrollUserApi} from "../api/enrollmentApi.ts";
+import type {CourseDetail} from "../models/javaObjects/CourseDetail.tsx";
 import {useAuthContext} from "../context/AuthContext.tsx";
-import {showInfoToast} from "../utils/showInfoToast.ts";
-import {useCourseStorage} from "../context/CourseStorage.ts";
 import HeroCourseDetailsSkeleton from "../components/skeletons/HeroCourseDetailsSkeleton.tsx";
 import CourseDetailsInfoSkeleton from "../components/skeletons/CourseDetailsInfoSkeleton.tsx";
+import {useEnrollUserInCourse} from "../hooks/useEnrollUserInCourse.tsx";
 
 function CourseDetails() {
-    const { user, accessToken, loading: authLoading } = useAuthContext();
-    const { enrollments, setEnrollments } = useCourseStorage();
+    const { loading: authLoading } = useAuthContext();
     const [loading, setLoading] = useState<boolean>(true);
     const { courseId } = useParams<{ courseId: string; courseTitle: string }>();
-    const [course, setCourse] = useState<CourseDetail | null>(null);
+    const [course, setCourse] = useState<CourseDetail>({
+        color: "",
+        courseContentCount: 0,
+        courseContents: [],
+        description: "",
+        descriptionLong: "",
+        descriptionShort: "",
+        difficulty: "BEGINNER",
+        durationMinutes: 0,
+        id: 0,
+        imageUrl: "",
+        price: 0,
+        rating: 0,
+        ratingCount: 0,
+        skillsGained: [],
+        title: "",
+        titleShort: "",
+        topicsCovered: [],
+        whatWillBeLearned: []
+    });
 
-    const handleBuyCourse = () => {
-        if (!user) {
-            showInfoToast("Please log in to enroll in the course.");
-            return Promise.reject("No user logged in");
-        }
-
-        return enrollUserApi(Number(courseId), accessToken || "")
-            .then(() => {
-                if (enrollments) {
-                    setEnrollments(enrollments.filter((enrollment) => enrollment.courseId !== Number(courseId)));
-                }
-                console.log("User enrolled in course successfully");
-            })
-            .catch((error) => {
-                console.error("Error enrolling user in course:", error);
-            })
-    }
+    const { enroll } = useEnrollUserInCourse(Number(courseId), course?.titleShort);
 
     useEffect(() => {
@@ -46,5 +46,5 @@
             })
             .catch(err => {
-                console.error("Error fetching course details: ", err);
+                console.error("Error fetching javaObjects details: ", err);
             })
             .finally(() => {
@@ -64,5 +64,5 @@
                     </> :
                     <>
-                        <HeroCourseDetails course={course} enrollUser={handleBuyCourse}/>
+                        <HeroCourseDetails course={course} enrollUser={enroll}/>
                         <CourseDetailsInfo course={course}/>
                         <CoursesCarouselCourseDetails/>
Index: frontend/src/pages/CourseLearn.tsx
===================================================================
--- frontend/src/pages/CourseLearn.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/pages/CourseLearn.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,138 @@
+import {useEffect, useState} from "react";
+import type {CourseFull} from "../models/javaObjects/CourseFull.tsx";
+import {useParams} from "react-router-dom";
+import {fetchCourseFullApi} from "../api/courseApi.ts";
+import {useAuthContext} from "../context/AuthContext.tsx";
+import CourseContentSideNav from "../components/learn/CourseContentSideNav.tsx";
+import type {CourseLectureFull} from "../models/javaObjects/CourseLectureFull.tsx";
+import {fetchPresignedUrlApi} from "../api/s3Api.ts";
+import CourseLearnSkeleton from "../components/skeletons/CourseLearnSkeleton.tsx";
+
+function CourseLearn() {
+    const {courseId} = useParams<{ courseId: string }>();
+    const [course, setCourse] = useState<CourseFull | null>(null);
+    const [activeLecture, setActiveLecture] = useState<CourseLectureFull>({
+        id: -1,
+        contentFileName: "",
+        contentText: "",
+        contentType: "TEXT",
+        description: "",
+        durationMinutes: 0,
+        position: 0,
+        title: ""
+    });
+    const [loading, setLoading] = useState(true);
+    const [isDownloading, setIsDownloading] = useState(false);
+    const [videoUrl, setVideoUrl] = useState<string>("");
+    const {accessToken} = useAuthContext();
+
+    useEffect(() => {
+        setLoading(true);
+        fetchCourseFullApi(Number(courseId), accessToken || "")
+            .then(resCourse => {
+                setCourse(resCourse)
+                setActiveLecture(resCourse?.courseContents[0]?.courseLectures[0]);
+            })
+            .catch(err => {
+                console.error("Error fetching full course api: ", err)
+            })
+            .finally(() => {
+                setLoading(false);
+            });
+    }, [courseId, accessToken]);
+
+    useEffect(() => {
+        if (activeLecture.contentType === "VIDEO") {
+            getPresignedUrl(60 * 60)
+                .then(url => {
+                    setVideoUrl(url || "")
+                })
+                .catch(err => {
+                    console.error("Error fetching video URL: ", err);
+                });
+        } else {
+            setVideoUrl("");
+        }
+    }, [activeLecture]);
+
+
+    const getPresignedUrl = async (expirySeconds: number): Promise<string | undefined> => {
+        const encodedFileName = encodeURIComponent(activeLecture.contentFileName);
+        try {
+            const url = await fetchPresignedUrlApi(accessToken || "", Number(courseId) || -1, Number(activeLecture.id), encodedFileName, expirySeconds);
+            console.log("Presigned URL: ", url);
+            return url;
+        } catch (err) {
+            console.error("Error fetching presigned URL: ", err);
+        }
+    };
+
+
+    const triggerDownload = (url: string, filename: string) => {
+        const a = document.createElement("a");
+        a.href = url;
+        a.download = filename;
+        document.body.appendChild(a);
+        a.click();
+        document.body.removeChild(a);
+    };
+
+    if (loading) {
+        return (
+            <CourseLearnSkeleton />
+        );
+    }
+
+    return (
+        <main className="flex ">
+            <div className="flex flex-col">
+                {
+                    activeLecture.contentType === "VIDEO" && (
+                        <video
+                            src={videoUrl}
+                            controls
+                            controlsList="nodownload"
+                            preload="metadata"
+                        />
+                    )
+                }
+                <div
+                    className="flex flex-col gap-4 flex-grow py-vertical-md px-horizontal-sm text-left text-black-text">
+                    <h1 className="text-4xl font-semibold">{activeLecture?.title}</h1>
+                    <p className="text-lg leading-loose">{activeLecture?.contentText}</p>
+                    {
+                        (activeLecture?.contentType === "FILE" || activeLecture.contentType === "TOOL") && (
+                            <div className="flex justify-between w-full gap-20 items-center py-12">
+                                <p className="text-lg font-medium">
+                                    {activeLecture.contentFileName}
+                                </p>
+                                <button
+                                    disabled={isDownloading}
+                                    onClick={async () => {
+                                        setIsDownloading(true);
+                                        const url = await getPresignedUrl(60 * 5)
+                                        if (url) {
+                                            triggerDownload(url, activeLecture.contentFileName);
+                                        }
+                                        setIsDownloading(false);
+                                    }}
+                                    className={`disabled:cursor-not-allowed disabled:opacity-40 hover:shadow-lg transition-all duration-300 ease-in-out cursor-pointer
+                                    bg-shifter text-white text-lg px-8 py-2 rounded-md shadow-md border-2 border-white/40 shadow-shifter/40`}
+                                >
+                                    {
+                                        isDownloading ? "Downloading..." : "Download File"
+                                    }
+                                </button>
+                            </div>
+                        )
+                    }
+                </div>
+            </div>
+            <CourseContentSideNav
+                setActiveLecture={setActiveLecture}
+                courseContents={course?.courseContents}/>
+        </main>
+    )
+}
+
+export default CourseLearn;
Index: frontend/src/pages/Courses.tsx
===================================================================
--- frontend/src/pages/Courses.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/pages/Courses.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -2,13 +2,14 @@
 import CoursesFilters from "../components/CoursesFilters.tsx";
 import CoursesGrid from "../components/CoursesGrid.tsx";
-import type {FilterParams} from "../types/FilterParams.tsx";
+import type {FilterParams} from "../models/FilterParams.tsx";
 import {fetchCoursesApi} from "../api/courseApi.ts";
 import ShifterRocket from "../../public/Rocket-Blue-Fire.png"
 import {useCourseStorage} from "../context/CourseStorage.ts";
-import type {CoursePreview} from "../types/CoursePreview.tsx";
+import type {CoursePreview} from "../models/javaObjects/CoursePreview.tsx";
 import {useAuthContext} from "../context/AuthContext.tsx";
 import {useLocation, useNavigate} from "react-router-dom";
 import CoursesFiltersSkeleton from "../components/skeletons/CoursesFiltersSkeleton.tsx";
 import CoursesGridSkeleton from "../components/skeletons/CoursesGridSkeleton.tsx";
+import {getFromSessionStorage, saveToSessionStorage} from "../utils/useSessionStorage.ts";
 
 function getInitialFiltersFromSearch(locationSearch: string): FilterParams {
@@ -59,7 +60,7 @@
     // Effect to initialize courses
     useEffect(() => {
-        const storedCourses = sessionStorage.getItem("allCourses");
+        const storedCourses = getFromSessionStorage<typeof allCourses>("allCourses");
         if (storedCourses) {
-            setAllCourses(JSON.parse(storedCourses));
+            setAllCourses(storedCourses);
             return;
         }
@@ -67,7 +68,6 @@
         setLoading(true);
         fetchCoursesApi(accessToken || "")
-            .then(courses => {
-                setAllCourses(courses);
-                sessionStorage.setItem("allCourses", JSON.stringify(courses));
+            .then(resCourses => {
+                setAllCourses(resCourses);
             })
             .catch(err => {
@@ -76,4 +76,8 @@
             .finally(() => setLoading(false));
     }, [authLoading])
+    
+    useEffect(() => {
+        saveToSessionStorage("allCourses", allCourses);
+    }, [allCourses])
 
     // Effect to filter courses based on filters and favorites
Index: frontend/src/pages/Register.tsx
===================================================================
--- frontend/src/pages/Register.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/pages/Register.tsx	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -8,8 +8,8 @@
     Box,
 } from "@mui/material";
-import {CustomStepperConnector, CustomStepperStepIcon} from "../components/CustomStepper";
+import {CustomStepperConnector, CustomStepperStepIcon} from "../components/registerSteps/CustomStepper.tsx";
 import {Link, useNavigate} from "react-router-dom";
 import {motion, AnimatePresence} from "framer-motion";
-import type {UserRegister} from "../types/UserRegister.tsx";
+import type {UserRegister} from "../models/javaObjects/UserRegister.tsx";
 import RegisterStepOne from "../components/registerSteps/RegisterStepOne.tsx";
 import RegisterStepTwo from "../components/registerSteps/RegisterStepTwo.tsx";
@@ -18,5 +18,5 @@
 import {useAuthContext} from "../context/AuthContext.tsx";
 import {isValidEmail} from "../utils/validation.ts";
-import {checkEmailExistsApi} from "../api/auth.ts";
+import {checkEmailExistsApi} from "../api/authApi.ts";
 
 function Register() {
Index: ontend/src/types/ContentType.tsx
===================================================================
--- frontend/src/types/ContentType.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,1 +1,0 @@
-export type ContentType = "VIDEO" | "TEXT" | "FILE" | "QUIZ" | "TOOL";
Index: ontend/src/types/CourseContentPreview.tsx
===================================================================
--- frontend/src/types/CourseContentPreview.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,7 +1,0 @@
-import type {CourseLecturePreview} from "./CourseLecturePreview.tsx";
-
-export interface CourseContentPreview {
-    title: string;
-    position: number;
-    courseLectures: CourseLecturePreview[];
-}
Index: ontend/src/types/CourseDetail.tsx
===================================================================
--- frontend/src/types/CourseDetail.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,10 +1,0 @@
-import type {CoursePreview} from "./CoursePreview.tsx";
-import type {CourseContentPreview} from "./CourseContentPreview.tsx";
-
-export interface CourseDetail extends CoursePreview {
-    descriptionShort: string;
-    description: string;
-    descriptionLong: string;
-    whatWillBeLearned: string[];
-    courseContents: CourseContentPreview[];
-}
Index: ontend/src/types/CourseLecturePreview.tsx
===================================================================
--- frontend/src/types/CourseLecturePreview.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,9 +1,0 @@
-import type {ContentType} from "./ContentType.tsx";
-
-export interface CourseLecturePreview {
-    title: string;
-    description: string;
-    durationMinutes: number;
-    position: number;
-    contentType: ContentType;
-}
Index: ontend/src/types/CoursePreview.tsx
===================================================================
--- frontend/src/types/CoursePreview.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,18 +1,0 @@
-import type {Difficulty} from "./Difficulty.tsx";
-
-export interface CoursePreview {
-    id: number,
-    imageUrl: string;
-    color: string;
-    titleShort: string;
-    title: string;
-    difficulty: Difficulty;
-    durationMinutes: number;
-    price: number;
-    rating: number;
-    ratingCount: number;
-    skillsGained: string[];
-    topicsCovered: string[];
-    courseContentCount: number;
-}
-
Index: ontend/src/types/Difficulty.tsx
===================================================================
--- frontend/src/types/Difficulty.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,1 +1,0 @@
-export type Difficulty = "BEGINNER" | "INTERMEDIATE" | "ADVANCED" | "EXPERT";
Index: ontend/src/types/Enrollment.tsx
===================================================================
--- frontend/src/types/Enrollment.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,7 +1,0 @@
-
-export interface Enrollment {
-    enrollmentStatus: "PENDING" | "ACTIVE" | "COMPLETED";
-    percentCompleted: number;
-    date: Date;
-    courseId: number;
-}
Index: ontend/src/types/FilterParams.tsx
===================================================================
--- frontend/src/types/FilterParams.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,10 +1,0 @@
-
-export interface FilterParams {
-    showOnlyFavoriteCourses?: boolean;
-    search?: string[];
-    difficulty?: string[];
-    price?: string[];
-    duration?: string[];
-    skill?: string[];
-    topic?: string[];
-}
Index: ontend/src/types/FilterRange.tsx
===================================================================
--- frontend/src/types/FilterRange.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,4 +1,0 @@
-export interface FilterRange {
-    floor: number;
-    ceil: number;
-}
Index: ontend/src/types/SelectProps.tsx
===================================================================
--- frontend/src/types/SelectProps.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,11 +1,0 @@
-import React from "react";
-import type {UserRegister} from "./UserRegister.tsx";
-
-export interface SelectProps {
-    label: string;
-    name: keyof UserRegister;
-    id: string;
-    options?: string[];
-    setUser: React.Dispatch<React.SetStateAction<UserRegister>>;
-    user: UserRegister;
-}
Index: ontend/src/types/SliderProps.tsx
===================================================================
--- frontend/src/types/SliderProps.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,12 +1,0 @@
-import React from "react";
-import type {UserRegister} from "./UserRegister.tsx";
-
-type UserArrayFields = 'interests' | 'desiredSkills';
-export interface SliderProps {
-    label: string;
-    name: UserArrayFields;
-    id: string;
-    options?: string[];
-    setUser: React.Dispatch<React.SetStateAction<UserRegister>>;
-    user: UserRegister;
-}
Index: ontend/src/types/User.tsx
===================================================================
--- frontend/src/types/User.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,13 +1,0 @@
-export interface User {
-    id: number,
-    email: string;
-    name: string;
-    companyType: string;
-    workPosition: string;
-    interests: string[];
-    skills: string[];
-    desiredSkills: string[];
-    points: number;
-    favoriteCourses: number[];
-    isAdmin: boolean;
-}
Index: ontend/src/types/UserRegister.tsx
===================================================================
--- frontend/src/types/UserRegister.tsx	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ 	(revision )
@@ -1,10 +1,0 @@
-export interface UserRegister {
-    email: string;
-    password: string;
-    passwordConfirmation: string;
-    name: string;
-    workPosition: string;
-    companyType: string;
-    interests: string[];
-    desiredSkills: string[];
-}
Index: frontend/src/utils/toUrlFormat.ts
===================================================================
--- frontend/src/utils/toUrlFormat.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/utils/toUrlFormat.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,14 @@
+export function toUrlFormat(title: string): string {
+    return title
+        .toLowerCase()
+        .trim() // Trim leading and trailing spaces
+        .replace(/\s+/g, "-") // Replace spaces with hyphens
+        .replace(/-+/g, "-"); // Replace multiple hyphens with a single hyphen
+}
+
+export function fromUrlFormat(url: string): string {
+    return url
+        .toLowerCase()
+        .replace(/-/g, " ") // Replace hyphens with spaces
+        .replace(/\b\w/g, c => c.toUpperCase()); // Capitalize the first letter of each word
+}
Index: frontend/src/utils/useSessionStorage.ts
===================================================================
--- frontend/src/utils/useSessionStorage.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
+++ frontend/src/utils/useSessionStorage.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -0,0 +1,21 @@
+export function getFromSessionStorage<T>(key: string): T | null {
+    try {
+        const item = sessionStorage.getItem(key);
+        if (!item) return null;
+
+        return JSON.parse(item) as T;
+    } catch (error) {
+        console.error(`Failed to load or parse sessionStorage key "${key}":`, error);
+        sessionStorage.removeItem(key); // Remove corrupted data
+        return null;
+    }
+}
+
+export function saveToSessionStorage<T>(key: string, value: T): void {
+    try {
+        sessionStorage.setItem(key, JSON.stringify(value));
+    } catch (error) {
+        console.error(`Failed to save "${key}" to sessionStorage:`, error);
+    }
+}
+
Index: frontend/src/vite-env.d.ts
===================================================================
--- frontend/src/vite-env.d.ts	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/src/vite-env.d.ts	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -1,1 +1,1 @@
-/// <reference types="vite/client" />
+/// <reference models="vite/client" />
Index: frontend/tailwind.config.js
===================================================================
--- frontend/tailwind.config.js	(revision b195962b09cc87b68efe01f35cd5b386de7aaf63)
+++ frontend/tailwind.config.js	(revision 68246e68f7e45c676b93f2b5f19b16c190925da0)
@@ -32,4 +32,5 @@
                 'bright-gray': '#DDDDDD',
                 gray: '#E5E7EB',
+                'black-text': '#333333',
             },
             boxShadow: {
