Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/JobvistaBackendApplication.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/JobvistaBackendApplication.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/JobvistaBackendApplication.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -27,6 +27,4 @@
 			admin.setEmail("admin@admin.com");
 			admin.setHasAccess(true);
-//			admin.setName("admin");
-//			admin.setSurname("admin");
 			admin.setPassword(new BCryptPasswordEncoder().encode("admin"));
 			userRepository.save(admin);
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/config/GoogleOAuth2Properties.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/config/GoogleOAuth2Properties.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/config/GoogleOAuth2Properties.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -0,0 +1,28 @@
+package mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties(prefix = "spring.security.oauth2.client.registration.google")
+public class GoogleOAuth2Properties {
+
+    private String clientId;
+    private String clientSecret;
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getClientSecret() {
+        return clientSecret;
+    }
+
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+}
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/config/SecurityConfiguration.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/config/SecurityConfiguration.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/config/SecurityConfiguration.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -33,8 +33,10 @@
                         .requestMatchers(
                                 "/api/auth/**",
+                                "/oauth2/**",
                                 "/api/job-advertisements/**",
                                 "/api/applications/**",
                                 "/api/recruiter/**",
-                                "/api/job-seeker/**"
+                                "/api/job-seeker/**",
+                                "/uploads/**"
                         ).permitAll()
                         .requestMatchers("/api/admin/**").hasAnyAuthority(Role.ROLE_ADMIN.name())
@@ -46,13 +48,21 @@
                         .requestMatchers("/api/job-advertisements/edit/{id}").hasAnyAuthority(Role.ROLE_RECRUITER.name())
                         .requestMatchers("/api/job-advertisements/delete/{id}").hasAnyAuthority(Role.ROLE_RECRUITER.name())
-                        .requestMatchers("/api/applications/{id}/update").hasAnyAuthority(Role.ROLE_RECRUITER.name())
+                        .requestMatchers("/api/applications/{id}/update").hasAnyAuthority(Role.ROLE_JOBSEEKER.name())
+                        .requestMatchers("/api/applications/update").hasAnyAuthority(Role.ROLE_RECRUITER.name())
+                        .requestMatchers("/uploads/applications/**").hasAnyAuthority(Role.ROLE_RECRUITER.name())
                         .requestMatchers("/api/job-advertisements/{advertisement_id}/applications").hasAnyAuthority(Role.ROLE_RECRUITER.name())
+                        .requestMatchers("/api/job-advertisements/{advertisement_id}/applications/filtered").hasAnyAuthority(Role.ROLE_RECRUITER.name())
                         .requestMatchers("/api/applications/submit").hasAnyAuthority(Role.ROLE_JOBSEEKER.name())
                         .requestMatchers("/api/my-applications/{id}").hasAnyAuthority(Role.ROLE_JOBSEEKER.name())
-                        .anyRequest().authenticated())
+                        .requestMatchers("/api/my-applications/{id}/filtered").hasAnyAuthority(Role.ROLE_JOBSEEKER.name())
+                .anyRequest().authenticated())
                 .sessionManagement(manager -> manager.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                 .authenticationProvider(authenticationProvider()).addFilterBefore(
-                        jwtAuthFilter, UsernamePasswordAuthenticationFilter.class
-                );
+                        jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
+                .oauth2Login(oauth2 -> oauth2
+                        .defaultSuccessUrl("/api/auth/google", true)
+                )
+        ;
+
         return http.build();
     }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/config/WebConfig.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/config/WebConfig.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/config/WebConfig.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -0,0 +1,14 @@
+package mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+        registry.addResourceHandler("/uploads/**")
+                .addResourceLocations("file:D:/Finki-Projects/Internet-tehnologii/jobvista/jobvista-backend/uploads/");
+    }
+}
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/controllers/ApplicationController.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/controllers/ApplicationController.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/controllers/ApplicationController.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -30,4 +30,10 @@
     }
 
+    @PostMapping("/my-applications/{id}/filtered")
+    public ResponseEntity<?> filterApplicationsByJobSeekerId(@PathVariable Long id, @RequestBody String status) {
+        List<ApplicationDetailsDTO> applicationList = applicationService.filterByJobSeekerId(id, status);
+        return new ResponseEntity<>(applicationList, HttpStatus.OK);
+    }
+
     @GetMapping("/job-advertisements/{advertisement_id}/applications")
     public ResponseEntity<?> findAllApplicationsByJobAdvertisementId(@PathVariable("advertisement_id") Long advertisementId) {
@@ -36,8 +42,20 @@
     }
 
-    @PostMapping("/applications/{id}/update")
+    @PostMapping("/job-advertisements/{advertisement_id}/applications/filtered")
+    public ResponseEntity<?> filterApplicationsByJobAdvertisementId(@PathVariable("advertisement_id") Long advertisementId, @RequestBody String status) {
+        List<ApplicationDetailsDTO> applicationList = applicationService.filterByJobAdvertisementId(advertisementId, status);
+         return new ResponseEntity<>(applicationList, HttpStatus.OK);
+    }
+
+    @PostMapping("/applications/{id}/update/NOT-IN-USE")
     public ResponseEntity<?> updateApplicationStatus(@PathVariable("id") Long applicaitonId, @RequestBody ApplicationStatusDTO appStatusDTO) {
         ApplicationStatusDTO applicationStatusDTO = applicationService.updateApplicationStatus(applicaitonId,appStatusDTO.getStatus());
         return new ResponseEntity<>(applicationStatusDTO, HttpStatus.OK);
+    }
+
+    @PostMapping("/applications/update")
+    public ResponseEntity<?> updateApplications(@RequestBody List<ApplicationStatusDTO> changes) {
+       List<ApplicationStatusDTO> updatedApplications = applicationService.updateApplications(changes);
+       return new ResponseEntity<>(updatedApplications, HttpStatus.OK);
     }
 
@@ -66,3 +84,18 @@
         return new ResponseEntity<>(applicationDetailsDTO, HttpStatus.OK);
     }
+
+    @PostMapping("/applications/{id}/update")
+    public ResponseEntity<ApplicationDetailsDTO> updateApplication(
+            @PathVariable("id") Long applicationId,
+            @RequestParam("additionalFiles") MultipartFile[] additionalFiles) {
+        ApplicationDetailsDTO applicationDetailsDTO = applicationService.updateApplication(applicationId, additionalFiles);
+        return new ResponseEntity<>(applicationDetailsDTO, HttpStatus.OK);
+    }
+
+    @GetMapping("/applications/{id}/download-additional-files")
+    public ResponseEntity<List<String>> getAdditionalFilesUrls(@PathVariable("id") Long applicationId) {
+        List<String> fileUrls = applicationService.loadAdditionalFilesAsUrls(applicationId);
+        return ResponseEntity.ok(fileUrls);
+    }
+
 }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/controllers/AuthController.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/controllers/AuthController.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/controllers/AuthController.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -7,8 +7,14 @@
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.users.mappers.JobSeekerMapper;
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.users.mappers.RecruiterMapper;
+
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.service.intef.AuthService;
+
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+
 
 @RestController
@@ -42,3 +48,8 @@
         return ResponseEntity.ok(authenticationService.refreshToken(refreshTokenRequest));
     }
+
+    @PostMapping("/google")
+    public ResponseEntity<?> googleSignIn(@RequestBody Map<String, String> token) {
+        return ResponseEntity.ok(authenticationService.googleSignIn(token));
+    }
 }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/models/applications/Application.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/models/applications/Application.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/models/applications/Application.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -9,8 +9,7 @@
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.job_advertisements.JobAdvertisement;
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.users.JobSeeker;
-import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.users.User;
 
 import java.time.LocalDateTime;
-import java.util.HashMap;
+import java.util.ArrayList;
 import java.util.List;
 
@@ -45,4 +44,9 @@
     private ApplicationStatus status;
 
+    private String response;
+
+    @ElementCollection
+    private List<String> additionalFilePaths;
+
     public Application(JobSeeker jobSeeker, JobAdvertisement jobAdvertisement, List<String> answers, String message) {
         this.jobSeeker = jobSeeker;
@@ -53,4 +57,6 @@
         submittedOn = LocalDateTime.now();
         this.status = ApplicationStatus.PROPOSED;
+        this.response = "";
+        this.additionalFilePaths = new ArrayList<>();
     }
 
@@ -72,5 +78,7 @@
                 application.getMessage(),
                 application.getSubmittedOn(),
-                application.getStatus().name()
+                application.getStatus().name(),
+                application.getResponse(),
+                application.getAdditionalFilePaths()
         );
     }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/models/applications/DTO/ApplicationDetailsDTO.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/models/applications/DTO/ApplicationDetailsDTO.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/models/applications/DTO/ApplicationDetailsDTO.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -29,3 +29,5 @@
     private LocalDateTime submittedOn;
     private String status;
+    private String response;
+    private List<String> additionalFileNames;
 }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/models/applications/DTO/ApplicationStatusDTO.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/models/applications/DTO/ApplicationStatusDTO.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/models/applications/DTO/ApplicationStatusDTO.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -9,3 +9,4 @@
     Long id;
     String status;
+    String response;
 }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/repositories/JobSeekerRepository.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/repositories/JobSeekerRepository.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/repositories/JobSeekerRepository.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -4,4 +4,7 @@
 import org.springframework.data.jpa.repository.JpaRepository;
 
+import java.util.Optional;
+
 public interface JobSeekerRepository extends JpaRepository<JobSeeker, Long> {
+    Optional<JobSeeker> findByEmail(String email);
 }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/impl/ApplicationServiceImpl.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/impl/ApplicationServiceImpl.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/impl/ApplicationServiceImpl.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -6,4 +6,5 @@
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.users.JobSeeker;
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.repositories.JobSeekerRepository;
+import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.service.intef.EmailSenderService;
 import org.springframework.core.io.Resource;
 import org.springframework.core.io.UrlResource;
@@ -19,6 +20,9 @@
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
 
 import java.io.IOException;
+import java.net.MalformedURLException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -39,4 +43,7 @@
 
     @Autowired
+    private EmailSenderService emailSenderService;
+
+    @Autowired
     public ApplicationServiceImpl(@Value("${file.upload-dir}") String uploadDir, UserRepository userRepository, ApplicationRepository applicationRepository, JobAdvertisementRepository jobAdvertisementRepository,
                                   JobSeekerRepository jobSeekerRepository) {
@@ -95,4 +102,38 @@
 
     @Override
+    public ApplicationDetailsDTO updateApplication(Long applicationId, MultipartFile[] additionalFiles) {
+        Application application = applicationRepository.findById(applicationId).orElse(null);
+        if(application== null) {
+            throw new RuntimeException("Application not found.");
+        }
+
+        for (MultipartFile additionalFile : additionalFiles) {
+            if (additionalFile.isEmpty()) {
+                throw new RuntimeException("Failed to store empty file.");
+            }
+        }
+
+        Path filesPath = this.fileStorageLocation.resolve(String.valueOf(application.getId())).resolve("additional_files");
+        for(MultipartFile additionalFile: additionalFiles) {
+            Path targetLocation = filesPath.resolve(additionalFile.getOriginalFilename());
+
+            try {
+                Files.createDirectories(filesPath);
+                Files.copy(additionalFile.getInputStream(), targetLocation);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            String relativePath = Paths.get("uploads","applications",String.valueOf(application.getId()),
+                    "additional_files", additionalFile.getOriginalFilename()).toString();
+            List<String> currentAdditionalFilePaths = application.getAdditionalFilePaths();
+            currentAdditionalFilePaths.add(relativePath);
+            application.setAdditionalFilePaths(currentAdditionalFilePaths);
+            application = applicationRepository.save(application);
+        }
+        return Application.mapToApplicationDetailsDTO(application);
+    }
+
+    @Override
     public List<ApplicationDetailsDTO> findAllByJobAdvertisementId(Long jobId) {
         List<Application> applications =  applicationRepository.findAllByJobAdvertisementId(jobId);
@@ -101,7 +142,32 @@
 
     @Override
+    public List<ApplicationDetailsDTO> filterByJobAdvertisementId(Long jobId, String status) {
+        List<Application> applications =  applicationRepository.findAllByJobAdvertisementId(jobId);
+        String statusTrimmed = status.subSequence(0, status.length()-1).toString();
+
+        if(statusTrimmed.equals("ALL")) {
+            applications =  applicationRepository.findAllByJobAdvertisementId(jobId);
+        } else {
+            applications = applications.stream().filter(application -> application.getStatus().name().equals(statusTrimmed)).toList();
+        }
+        return applications.stream().map(Application::mapToApplicationDetailsDTO).toList();
+    }
+
+    @Override
     public List<ApplicationDetailsDTO> findAllByJobSeekerId(Long jobSeekerId) {
        List<Application> applications = applicationRepository.findAllByJobSeekerId(jobSeekerId);
        return applications.stream().map(Application::mapToApplicationDetailsDTO).toList();
+    }
+
+    @Override
+    public List<ApplicationDetailsDTO> filterByJobSeekerId(Long jobSeekerId, String status) {
+        List<Application> applications = applicationRepository.findAllByJobSeekerId(jobSeekerId);
+        String statusTrimmed = status.subSequence(0, status.length()-1).toString();
+        if(statusTrimmed.equals("ALL")) {
+            applications =  applicationRepository.findAllByJobSeekerId(jobSeekerId);
+        } else {
+            applications = applications.stream().filter(application -> application.getStatus().name().equals(statusTrimmed)).toList();
+        }
+        return applications.stream().map(Application::mapToApplicationDetailsDTO).toList();
     }
 
@@ -126,4 +192,92 @@
     }
 
+    public List<String> loadAdditionalFilesAsUrls(Long applicationId) {
+        Application application = applicationRepository.findById(applicationId)
+                .orElseThrow(() -> new IllegalArgumentException("Application not found"));
+
+        List<String> fileUrls = new ArrayList<>();
+        List<String> relativeFilePaths = application.getAdditionalFilePaths();
+
+        for (String relativeFilePath : relativeFilePaths) {
+            //TO DO: refactor
+            Path filePath = Paths.get(fileStorageLocation.getParent().getParent().toString(), relativeFilePath).normalize();
+            String relativePath = filePath.toString().replace("\\", "/").replaceFirst("^.+uploads", "uploads");
+
+            String fileUrl = ServletUriComponentsBuilder.fromCurrentContextPath()
+                    .path("/")
+                    .path(relativePath)
+                    .toUriString();
+            fileUrls.add(fileUrl);
+        }
+
+        return fileUrls;
+    }
+
+   /* @Override
+    public List<Resource> loadAdditionalFilesAsZippedResource(Long applicationId) {
+        Application application = applicationRepository.findById(applicationId).
+                orElseThrow(() -> new IllegalArgumentException("Application not found"));
+
+        List<Resource> resources = new ArrayList<>();
+
+        List<String> relativeFilePaths = application.getAdditionalFilePaths();
+        for(String relativeFilePath: relativeFilePaths) {
+            Path filePath = fileStorageLocation.getParent().getParent().resolve(relativeFilePath).normalize();
+
+            try {
+                Resource resource = new UrlResource(filePath.toUri());
+                if (resource.exists()) {
+                    resources.add(resource);
+                }
+            } catch (MalformedURLException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return resources;
+    }*/
+
+    @Override
+    public List<ApplicationStatusDTO> updateApplications(List<ApplicationStatusDTO> updates) {
+        List<ApplicationStatusDTO> updatedApplications = new ArrayList<>();
+
+        for(ApplicationStatusDTO applicationStatusDTO : updates) {
+            Application application = applicationRepository.findById(applicationStatusDTO.getId()).orElse(null);
+            if(application != null) {
+                application.setStatus(ApplicationStatus.valueOf(applicationStatusDTO.getStatus()));
+                application.setResponse(applicationStatusDTO.getResponse());
+                applicationRepository.save(application);
+                updatedApplications.add(applicationStatusDTO);
+
+                //email notification
+                String email = application.getJobSeeker().getEmail();
+                String subject = application.getJobAdvertisement().getRecruiter().getName() + ": " + application.getJobAdvertisement().getTitle() + " - STATUS UPDATE";
+                String text = "Dear " + application.getJobSeeker().getName() + ",\n\n";
+
+                switch (applicationStatusDTO.getStatus()) {
+                    case "ACCEPTED":
+                        text += "Great news! Your application has been accepted.\n\n";
+                        break;
+                    case "DENIED":
+                        text += "We regret to inform you that your application has been denied. We appreciate your interest and effort.\n\n";
+                        break;
+                    case "PROPOSED":
+                        text += "Your application status has been updated to 'Proposed'. We're considering your application for the next phase.\n\n";
+                        break;
+                    case "UNDER_REVIEW":
+                        text += "Your application is currently under review.\n\n";
+                        break;
+                }
+
+
+                if(!applicationStatusDTO.getResponse().isEmpty()) {
+                    text += "Response: " + applicationStatusDTO.getResponse() + "\n\n";
+                }
+               text += "Thank you.";
+           emailSenderService.sendEmail(email, subject, text);
+            }
+        }
+        return updatedApplications;
+    }
+
     @Override
     public ApplicationStatusDTO updateApplicationStatus(Long id, String status) {
@@ -132,5 +286,5 @@
        application.setStatus(ApplicationStatus.valueOf(status));
        applicationRepository.save(application);
-       return new ApplicationStatusDTO(id, status);
+       return new ApplicationStatusDTO(id, status, "");
     }
 }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/impl/AuthServiceImpl.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/impl/AuthServiceImpl.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/impl/AuthServiceImpl.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -1,5 +1,12 @@
 package mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.service.impl;
 
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
+import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.json.jackson2.JacksonFactory;
 import lombok.RequiredArgsConstructor;
+import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.config.GoogleOAuth2Properties;
+import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.controllers.AuthController;
+import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.enumerations.Role;
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.users.DTO.SignInDTO;
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.users.DTO.JwtAuthResponse;
@@ -12,12 +19,30 @@
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.repositories.UserRepository;
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.service.intef.AuthService;
+import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.service.intef.JobSeekerService;
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.service.intef.JwtService;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
+import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
+import org.springframework.security.oauth2.core.user.OAuth2User;
 import org.springframework.stereotype.Service;
-
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
 import java.time.LocalDateTime;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
 
 @Service
@@ -30,5 +55,7 @@
     private final AuthenticationManager authenticationManager;
     private final UserRepository userRepository;
+    private final JobSeekerService jobSeekerService;
     private final JwtService jwtService;
+    private final GoogleOAuth2Properties googleOAuth2Properties;
 
     @Override
@@ -56,9 +83,9 @@
         return new JwtAuthResponse(user.getId(), user.getEmail(), user.getName(), user.getRole().name(), user.isHasAccess(), jwt, refreshJwt);
     }
-    
+
     public JwtAuthResponse refreshToken(RefreshTokenRequest refreshTokenRequest) {
         String userEmail = jwtService.extractUsername(refreshTokenRequest.getToken());
         User user = userRepository.findByEmail(userEmail).orElseThrow();
-        if(jwtService.isTokenValid(refreshTokenRequest.getToken(), user)) {
+        if (jwtService.isTokenValid(refreshTokenRequest.getToken(), user)) {
             String jwt = jwtService.generateToken(user);
 
@@ -67,3 +94,157 @@
         return null;
     }
+
+    @Override
+    public JwtAuthResponse googleSignIn(Map<String, String> token) {
+        OAuth2AuthenticationToken authentication = getAuthentication(token.get("tokenId"));
+
+        OAuth2User oAuth2User = authentication.getPrincipal();
+        String email = oAuth2User.getAttribute("email");
+
+        JobSeeker jobSeeker = jobSeekerRepository.findByEmail(email)
+                .orElseGet(() -> {
+                    JobSeeker newJobSeeker = new JobSeeker();
+                    newJobSeeker.setEmail(email);
+                    newJobSeeker.setFirstName(oAuth2User.getAttribute("given_name"));
+                    newJobSeeker.setLastName(oAuth2User.getAttribute("family_name"));
+                    newJobSeeker.setPassword("");
+                    newJobSeeker.setRole(Role.ROLE_JOBSEEKER);
+                    newJobSeeker.setHasAccess(true);
+                    jobSeekerRepository.save(newJobSeeker);
+
+                    String googleProfilePicUrl = oAuth2User.getAttribute("picture");
+                    submitGoogleProfilePic(newJobSeeker.getId(), googleProfilePicUrl);
+
+                    return newJobSeeker;
+                });
+
+        String jwt = jwtService.generateToken(jobSeeker);
+
+        return new JwtAuthResponse(
+                jobSeeker.getId(),
+                jobSeeker.getEmail(),
+                jobSeeker.getFirstName() + " " + jobSeeker.getLastName(),
+                jobSeeker.getRole().name(),
+                jobSeeker.isHasAccess(),
+                jwt,
+                null
+        );
+    }
+
+    public OAuth2AuthenticationToken getAuthentication(String tokenId) {
+        try {
+            GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new JacksonFactory())
+                    .setAudience(Collections.singletonList(googleOAuth2Properties.getClientId()))
+                    .build();
+
+            GoogleIdToken idToken = verifier.verify(tokenId);
+            if (idToken != null) {
+                GoogleIdToken.Payload payload = idToken.getPayload();
+
+                String userId = payload.getSubject();
+                String email = payload.getEmail();
+                boolean emailVerified = Boolean.TRUE.equals(payload.getEmailVerified());
+                String name = (String) payload.get("name");
+                String pictureUrl = (String) payload.get("picture");
+                String familyName = Optional.ofNullable((String) payload.get("family_name")).orElse("");
+                String givenName = (String) payload.get("given_name");
+
+                Map<String, Object> attributes = Map.of(
+                        "sub", userId,
+                        "email", email,
+                        "email_verified", emailVerified,
+                        "name", name,
+                        "picture", pictureUrl,
+                        "family_name", familyName,
+                        "given_name", givenName
+                );
+
+                OAuth2User oAuth2User = new DefaultOAuth2User(
+                        Collections.singleton(new SimpleGrantedAuthority("ROLE_JOBSEEKER")),
+                        attributes,
+                        "sub"
+                );
+
+                return new OAuth2AuthenticationToken(oAuth2User, oAuth2User.getAuthorities(), "google");
+            } else {
+                throw new IllegalArgumentException("Invalid ID token");
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to verify token", e);
+        }
+    }
+
+    public void submitGoogleProfilePic(Long jobSeekerId, String googleProfilePicUrl) {
+        try {
+            URL url = new URL(googleProfilePicUrl);
+            BufferedImage image = ImageIO.read(url);
+
+            // Convert BufferedImage to byte array
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ImageIO.write(image, "jpg", baos);
+            byte[] imageBytes = baos.toByteArray();
+
+            // Convert byte array to MultipartFile
+            MultipartFile multipartFile = new InMemoryMultipartFile("profilePicFile", "google-profile-pic.jpg", "image/jpeg", imageBytes);
+
+            jobSeekerService.submitProfilePic(jobSeekerId, multipartFile);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    class InMemoryMultipartFile implements MultipartFile {
+
+        private final String name;
+        private final String originalFilename;
+        private final String contentType;
+        private final byte[] content;
+
+        public InMemoryMultipartFile(String name, String originalFilename, String contentType, byte[] content) {
+            this.name = name;
+            this.originalFilename = originalFilename;
+            this.contentType = contentType;
+            this.content = content;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String getOriginalFilename() {
+            return originalFilename;
+        }
+
+        @Override
+        public String getContentType() {
+            return contentType;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return content.length == 0;
+        }
+
+        @Override
+        public long getSize() {
+            return content.length;
+        }
+
+        @Override
+        public byte[] getBytes() throws IOException {
+            return content;
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return new ByteArrayInputStream(content);
+        }
+
+        @Override
+        public void transferTo(java.io.File dest) throws IOException {
+            throw new UnsupportedOperationException("This method is not implemented");
+        }
+    }
 }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/impl/EmailSenderServiceImpl.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/impl/EmailSenderServiceImpl.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/impl/EmailSenderServiceImpl.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -0,0 +1,33 @@
+package mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.service.impl;
+
+import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.service.intef.EmailSenderService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.stereotype.Service;
+
+@Service
+public class EmailSenderServiceImpl implements EmailSenderService {
+
+    @Autowired
+    private JavaMailSender mailSender;
+
+    @Value("${custom.mail.sender.email}")
+    private String senderEmail;
+
+    @Value("${custom.mail.sender.name}")
+    private String senderName;
+
+    @Override
+    public void sendEmail(String to, String subject, String text) {
+        SimpleMailMessage message = new SimpleMailMessage();
+        message.setTo(to);
+        message.setSubject(subject);
+        message.setText(text);
+
+        message.setFrom(String.format("%s <%s>", senderName, senderEmail));
+
+        mailSender.send(message);
+    }
+}
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/intef/ApplicationService.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/intef/ApplicationService.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/intef/ApplicationService.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -7,4 +7,5 @@
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.applications.DTO.ApplicationStatusDTO;
 import org.springframework.core.io.Resource;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
@@ -12,7 +13,12 @@
 public interface ApplicationService {
     ApplicationDetailsDTO submitApplication(ApplicationDTO applicationDTO);
+    ApplicationDetailsDTO updateApplication(Long applicationId, MultipartFile[] additionalFiles);
     List<ApplicationDetailsDTO> findAllByJobAdvertisementId(Long jobId);
+    List<ApplicationDetailsDTO> filterByJobAdvertisementId(Long jobId, String status);
     List<ApplicationDetailsDTO> findAllByJobSeekerId(Long jobSeekerId);
+    List<ApplicationDetailsDTO> filterByJobSeekerId(Long jobSeekerId, String status);
     Resource loadResumeAsResource(Long applicationId);
+    List<String> loadAdditionalFilesAsUrls(Long applicationId);
     ApplicationStatusDTO updateApplicationStatus(Long id, String status);
+    List<ApplicationStatusDTO> updateApplications(List<ApplicationStatusDTO> updates);
 }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/intef/AuthService.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/intef/AuthService.java	(revision 0f0add0e646bd880b8213e381f57f621bc0e6861)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/intef/AuthService.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -7,4 +7,7 @@
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.users.Recruiter;
 import mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.models.users.User;
+import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
+
+import java.util.Map;
 
 public interface AuthService {
@@ -13,3 +16,7 @@
     JwtAuthResponse signIn(SignInDTO signInDTO);
     JwtAuthResponse refreshToken(RefreshTokenRequest refreshTokenRequest);
+
+    JwtAuthResponse googleSignIn(Map<String, String> token);
+    OAuth2AuthenticationToken getAuthentication(String tokenId);
+    void submitGoogleProfilePic(Long jobSeekerId, String googleProfilePicUrl);
 }
Index: jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/intef/EmailSenderService.java
===================================================================
--- jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/intef/EmailSenderService.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
+++ jobvista-backend/src/main/java/mk/ukim/finki/predmeti/internettehnologii/jobvistabackend/service/intef/EmailSenderService.java	(revision 4d97b633e131eca76d6c290321725684fc1d5970)
@@ -0,0 +1,5 @@
+package mk.ukim.finki.predmeti.internettehnologii.jobvistabackend.service.intef;
+
+public interface EmailSenderService {
+    void sendEmail(String to, String subject, String text);
+}
