Skip to content

Commit 345c942

Browse files
committed
Add AI interview copilot flow across backend and frontend
1 parent 1851b38 commit 345c942

16 files changed

+721
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.thughari.jobtrackerpro.controller;
2+
3+
import com.thughari.jobtrackerpro.dto.*;
4+
import com.thughari.jobtrackerpro.service.InterviewService;
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.security.core.context.SecurityContextHolder;
7+
import org.springframework.web.bind.annotation.*;
8+
import org.springframework.web.multipart.MultipartFile;
9+
10+
import java.util.Map;
11+
import java.util.UUID;
12+
13+
@RestController
14+
@RequestMapping("/api/interviews")
15+
public class InterviewController {
16+
private final InterviewService interviewService;
17+
18+
public InterviewController(InterviewService interviewService) {
19+
this.interviewService = interviewService;
20+
}
21+
22+
@PostMapping("/start/{jobId}")
23+
public ResponseEntity<InterviewSessionStartResponse> startInterview(@PathVariable UUID jobId) {
24+
return ResponseEntity.ok(interviewService.startSession(jobId, getAuthenticatedEmail()));
25+
}
26+
27+
@GetMapping("/{sessionId}/questions")
28+
public ResponseEntity<InterviewQuestionsResponse> getQuestions(@PathVariable UUID sessionId) {
29+
return ResponseEntity.ok(interviewService.getQuestions(sessionId, getAuthenticatedEmail()));
30+
}
31+
32+
@PostMapping("/{sessionId}/answers")
33+
public ResponseEntity<InterviewAnswerResponse> submitAnswer(@PathVariable UUID sessionId, @RequestBody InterviewAnswerRequest request) {
34+
return ResponseEntity.ok(interviewService.submitAnswer(sessionId, getAuthenticatedEmail(), request));
35+
}
36+
37+
@GetMapping("/{sessionId}/report")
38+
public ResponseEntity<InterviewReportResponse> getReport(@PathVariable UUID sessionId) {
39+
return ResponseEntity.ok(interviewService.getReport(sessionId, getAuthenticatedEmail()));
40+
}
41+
42+
@PostMapping("/{sessionId}/resume")
43+
public ResponseEntity<Map<String, String>> uploadResume(@PathVariable UUID sessionId, @RequestParam("file") MultipartFile file) {
44+
interviewService.uploadResume(sessionId, getAuthenticatedEmail(), file);
45+
return ResponseEntity.ok(Map.of("status", "processed"));
46+
}
47+
48+
private String getAuthenticatedEmail() {
49+
return ((String) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).toLowerCase();
50+
}
51+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.thughari.jobtrackerpro.dto;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class InterviewAnswerRequest {
7+
private Integer questionIndex;
8+
private String answer;
9+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.thughari.jobtrackerpro.dto;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
6+
@Data
7+
@AllArgsConstructor
8+
public class InterviewAnswerResponse {
9+
private Integer score;
10+
private String feedback;
11+
private String improvementGap;
12+
private Integer nextQuestionIndex;
13+
private boolean completed;
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.thughari.jobtrackerpro.dto;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
6+
@Data
7+
@AllArgsConstructor
8+
public class InterviewQuestionDTO {
9+
private Integer index;
10+
private String question;
11+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.thughari.jobtrackerpro.dto;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
6+
import java.util.List;
7+
8+
@Data
9+
@AllArgsConstructor
10+
public class InterviewQuestionsResponse {
11+
private List<InterviewQuestionDTO> questions;
12+
private Integer currentIndex;
13+
private Integer totalQuestions;
14+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.thughari.jobtrackerpro.dto;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
6+
import java.util.List;
7+
8+
@Data
9+
@AllArgsConstructor
10+
public class InterviewReportResponse {
11+
private Integer overallScore;
12+
private Integer answeredQuestions;
13+
private Integer totalQuestions;
14+
private List<String> weakAreas;
15+
private List<String> improvementSuggestions;
16+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.thughari.jobtrackerpro.dto;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
6+
import java.util.UUID;
7+
8+
@Data
9+
@AllArgsConstructor
10+
public class InterviewSessionStartResponse {
11+
private UUID sessionId;
12+
private String status;
13+
private String message;
14+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.thughari.jobtrackerpro.entity;
2+
3+
import jakarta.persistence.*;
4+
import lombok.Data;
5+
6+
import java.time.LocalDateTime;
7+
import java.util.UUID;
8+
9+
@Data
10+
@Entity
11+
@Table(name = "interview_sessions", indexes = {
12+
@Index(name = "idx_interview_sessions_user_updated", columnList = "userEmail, updatedAt DESC")
13+
})
14+
public class InterviewSession {
15+
@Id
16+
@GeneratedValue(strategy = GenerationType.UUID)
17+
@Column(columnDefinition = "uuid")
18+
private UUID id;
19+
20+
@Column(nullable = false)
21+
private String userEmail;
22+
23+
@Column(nullable = false, columnDefinition = "uuid")
24+
private UUID jobId;
25+
26+
private String jobCompany;
27+
private String jobRole;
28+
29+
@Column(nullable = false)
30+
private String status;
31+
32+
private Integer currentQuestionIndex;
33+
private Integer totalQuestions;
34+
private Double overallScore;
35+
36+
@Lob
37+
@Column(columnDefinition = "TEXT")
38+
private String questionsJson;
39+
40+
@Lob
41+
@Column(columnDefinition = "TEXT")
42+
private String answersJson;
43+
44+
@Lob
45+
@Column(columnDefinition = "TEXT")
46+
private String weakAreasJson;
47+
48+
@Lob
49+
@Column(columnDefinition = "TEXT")
50+
private String improvementSuggestionsJson;
51+
52+
private String resumeFileName;
53+
private String resumeProcessingStatus;
54+
55+
@Column(nullable = false)
56+
private LocalDateTime createdAt;
57+
58+
@Column(nullable = false)
59+
private LocalDateTime updatedAt;
60+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.thughari.jobtrackerpro.repo;
2+
3+
import com.thughari.jobtrackerpro.entity.InterviewSession;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
import java.util.Optional;
7+
import java.util.UUID;
8+
9+
public interface InterviewSessionRepository extends JpaRepository<InterviewSession, UUID> {
10+
Optional<InterviewSession> findByIdAndUserEmail(UUID id, String userEmail);
11+
}

0 commit comments

Comments
 (0)