Skip to content

Interview: become unified and fully independent of core#1880

Open
JGStyle wants to merge 1 commit into
mainfrom
1705-interview-move-to-become-a-fully-independent-course-phase-microservice
Open

Interview: become unified and fully independent of core#1880
JGStyle wants to merge 1 commit into
mainfrom
1705-interview-move-to-become-a-fully-independent-course-phase-microservice

Conversation

@JGStyle

@JGStyle JGStyle commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

✨ What is the change?

make interview cpm fully indepdent of core and unified:

  • reviews (revierwer + score) are now stored in the interview db
  • the score info is now transferred to the next phase via REST (as standard in other phases, such as assessment), the core graph record has been updated accordingly
  • client side aggregation updated to work with the rest api but still provide to the client

at the same time, core now no longer has a special case for aggregating the participations data from the database for interview: same codebase for all now.

📌 Reason for the change / Link to issue

fixes #1705

🧪 How to Test

ensure the interview phase works exactly as expected before, including passing the score to the next phase

🖼️ Screenshots (if UI changes are included)

no UI changes, only work behind the scenes

✅ PR Checklist

  • Tested locally or on the dev environment
  • Code is clean, readable, and documented
  • Tests added or updated (if needed)
  • Screenshots attached for UI changes (if any)
  • Documentation updated (if relevant)

Summary by CodeRabbit

  • New Features

    • Added interview reviews with scores, score levels, interviewer details, and interview answers.
    • Reviews now save automatically when edited, while pass/fail decisions remain separate.
    • Added interview review APIs and included review data in privacy exports.
    • Matching participants can display and sort by interview score.
  • Bug Fixes

    • Interview scores now consistently load and refresh across interview and matching views.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds independent interview-review persistence and APIs, updates interview clients to load and save reviews separately from pass status, and resolves participation outputs for matching and interview-score display.

Changes

Interview review backend

Layer / File(s) Summary
Interview review storage and API
servers/interview/database_dumps/base.sql, servers/interview/db/..., servers/interview/interviewReview/..., servers/interview/docs/...
Adds the interview_review table, SQLC accessors, DTO conversions, score-level derivation, authenticated review endpoints, OpenAPI definitions, and service tests.

Interview review client state and editing

Layer / File(s) Summary
Client review synchronization and editing
clients/interview_component/src/interview/...
Loads reviews into Zustand, reads scores from review records, persists review fields through the interview API, and keeps pass-status updates separate.

Resolved participation retrieval and matching display

Layer / File(s) Summary
Resolved participation data flow
clients/matching_component/src/matching/..., servers/core/coursePhaseType/initializeTypes.go, servers/core/db/migration/0026_interview_rest_provided_outputs.up.sql
Fetches configured resolution endpoints, merges resolved values into participation data, and displays interview scores in matching tables.

Metadata and privacy integration

Layer / File(s) Summary
Output routing and privacy export
servers/core/db/query/course_phase_participation.sql, servers/core/db/sqlc/course_phase_participation.sql.go, servers/interview/main.go, servers/interview/privacy/...
Removes Interview-specific predecessor metadata handling, registers the review module, and exports interview reviews in privacy data.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant InterviewDataShell
  participant InterviewReviewAPI
  participant InterviewReviewService
  participant PostgreSQL
  participant InterviewCard
  InterviewDataShell->>InterviewReviewAPI: GET interview reviews
  InterviewReviewAPI->>InterviewReviewService: load course-phase reviews
  InterviewReviewService->>PostgreSQL: query interview_review
  PostgreSQL-->>InterviewReviewService: review rows
  InterviewReviewService-->>InterviewDataShell: InterviewReview[]
  InterviewDataShell->>InterviewCard: store reviews
  InterviewCard->>InterviewReviewAPI: PUT edited review
  InterviewReviewAPI->>InterviewReviewService: upsert review
  InterviewReviewService->>PostgreSQL: write interview_review
Loading

Possibly related PRs

Suggested labels: Component: Interview

Suggested reviewers: Mtze, mathildeshagl, rappm

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main change: Interview becoming independent of Core.
Description check ✅ Passed The PR description includes the required sections and covers change, reason, testing, screenshots, and checklist.
Linked Issues check ✅ Passed The changes move interview reviews out of restricted data into interview storage, matching issue #1705.
Out of Scope Changes check ✅ Passed The additional core, client, and matching updates support the interview-data migration and do not appear unrelated.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 1705-interview-move-to-become-a-fully-independent-course-phase-microservice

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the Migration Pull Requests that introduce a database migration label Jul 9, 2026
@JGStyle JGStyle changed the title Interview: Interview: become unified and fully independent of core Jul 9, 2026
@JGStyle JGStyle marked this pull request as ready for review July 9, 2026 21:33
@JGStyle JGStyle requested a review from a team July 9, 2026 21:33
…reviewer) into db; adjust client side fetching
@JGStyle JGStyle force-pushed the 1705-interview-move-to-become-a-fully-independent-course-phase-microservice branch from d2efb69 to 5d13796 Compare July 9, 2026 21:34
@JGStyle

JGStyle commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

rebased on main

@JGStyle

JGStyle commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
servers/interview/db/migration/0002_interview_review.up.sql (1)

6-6: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Consider a CHECK constraint on score for defense in depth.

main.go validates score range (1–5) at the application layer via errScoreOutOfRange, but a database-level CHECK (score IS NULL OR (score >= 1 AND score <= 5)) would guard against invalid data from direct SQL access or future code paths that bypass service validation.

🛡️ Optional CHECK constraint
-    score integer,
+    score integer CHECK (score IS NULL OR (score >= 1 AND score <= 5)),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@servers/interview/db/migration/0002_interview_review.up.sql` at line 6, Add a
database-level CHECK constraint to the interview review table’s score column,
allowing NULL values while restricting non-NULL scores to the inclusive range
1–5; update the migration in a reversible manner if applicable.
servers/interview/interviewReview/router.go (1)

24-27: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Return generic error message for 500 responses.

handleError returns err.Error() directly to the client for all status codes. For 500 errors, service-layer messages wrap database errors (e.g., "failed to upsert interview review: ERROR: duplicate key..."), exposing schema and constraint details. Return a generic message for server errors while keeping the detailed log.

🔒 Suggested fix
 func handleError(c *gin.Context, statusCode int, err error) {
 	log.Error(err)
+	if statusCode >= 500 {
+		c.JSON(statusCode, gin.H{"error": "internal server error"})
+		return
+	}
 	c.JSON(statusCode, gin.H{"error": err.Error()})
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@servers/interview/interviewReview/router.go` around lines 24 - 27, Update
handleError to continue logging the original err, but return a generic user-safe
message such as “internal server error” when statusCode is 500 or another
server-error status; preserve err.Error() for client-error responses.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@clients/interview_component/src/interview/network/hooks/useUpdateInterviewReview.ts`:
- Around line 10-19: Guard against an undefined coursePhaseID in
useUpdateInterviewReview before invoking updateInterviewReview; throw a clear
error instead of substituting an empty string, and ensure onSuccess only
invalidates the query using a valid coursePhaseID.

In `@clients/matching_component/src/matching/network/resolveParticipations.ts`:
- Around line 69-88: Add a finite per-request timeout to the axios.get call
within the resolutions mapping in resolveParticipations, using the request
configuration alongside headers. Preserve the existing error handling so
timed-out requests are logged and return an empty valuesByParticipation result.

In
`@clients/matching_component/src/matching/pages/MatchingParticipantsPage/MatchingParticipantsPage.tsx`:
- Around line 36-43: Update the extraData mapping in MatchingParticipantsPage so
stringValue is empty when prevData.score is either null or undefined, matching
the table’s N/A handling; only convert the score to String when it is non-null.

In `@servers/interview/interviewReview/interviewReviewDTO/interviewReview.go`:
- Around line 104-113: Update decodeInterviewAnswers to log a warning when
json.Unmarshal fails, including the unmarshal error and enough context to
identify the corrupted interview_answers data, before returning the empty slice.

---

Nitpick comments:
In `@servers/interview/db/migration/0002_interview_review.up.sql`:
- Line 6: Add a database-level CHECK constraint to the interview review table’s
score column, allowing NULL values while restricting non-NULL scores to the
inclusive range 1–5; update the migration in a reversible manner if applicable.

In `@servers/interview/interviewReview/router.go`:
- Around line 24-27: Update handleError to continue logging the original err,
but return a generic user-safe message such as “internal server error” when
statusCode is 500 or another server-error status; preserve err.Error() for
client-error responses.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1c8dd264-e8b7-4bfb-a08f-01695c49607f

📥 Commits

Reviewing files that changed from the base of the PR and between ad5a465 and 5d13796.

📒 Files selected for processing (34)
  • clients/interview_component/src/interview/components/InterviewCard.tsx
  • clients/interview_component/src/interview/components/StudentCard.tsx
  • clients/interview_component/src/interview/hooks/useSorting.tsx
  • clients/interview_component/src/interview/interfaces/InterviewReview.ts
  • clients/interview_component/src/interview/network/hooks/useUpdateInterviewReview.ts
  • clients/interview_component/src/interview/network/mutations/updateInterviewReview.ts
  • clients/interview_component/src/interview/network/queries/getInterviewReviews.ts
  • clients/interview_component/src/interview/pages/InterviewDataShell.tsx
  • clients/interview_component/src/interview/zustand/useParticipationStore.tsx
  • clients/matching_component/src/matching/MatchingOverviewPage.tsx
  • clients/matching_component/src/matching/network/getResolvedCoursePhaseParticipations.ts
  • clients/matching_component/src/matching/network/resolveParticipations.ts
  • clients/matching_component/src/matching/pages/MatchingParticipantsPage/MatchingParticipantsPage.tsx
  • servers/core/coursePhaseType/initializeTypes.go
  • servers/core/db/migration/0026_interview_rest_provided_outputs.up.sql
  • servers/core/db/query/course_phase_participation.sql
  • servers/core/db/sqlc/course_phase_participation.sql.go
  • servers/interview/database_dumps/base.sql
  • servers/interview/db/migration/0002_interview_review.up.sql
  • servers/interview/db/query/interview_review.sql
  • servers/interview/db/query/privacy.sql
  • servers/interview/db/sqlc/interview_review.sql.go
  • servers/interview/db/sqlc/models.go
  • servers/interview/db/sqlc/privacy.sql.go
  • servers/interview/docs/docs.go
  • servers/interview/docs/swagger.json
  • servers/interview/docs/swagger.yaml
  • servers/interview/interviewReview/interviewReviewDTO/interviewReview.go
  • servers/interview/interviewReview/main.go
  • servers/interview/interviewReview/router.go
  • servers/interview/interviewReview/service.go
  • servers/interview/interviewReview/service_test.go
  • servers/interview/main.go
  • servers/interview/privacy/service.go

Comment on lines +10 to +19
export const useUpdateInterviewReview = (coursePhaseID: string | undefined) => {
const queryClient = useQueryClient()

return useMutation({
mutationFn: ({ courseParticipationID, review }: UpdateInterviewReviewVariables) =>
updateInterviewReview(coursePhaseID ?? '', courseParticipationID, review),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['interviewReviews', coursePhaseID] })
},
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Guard against undefined coursePhaseID in the mutation.

coursePhaseID ?? '' produces a malformed URL (interview/api/course_phase//interview-review/...) when coursePhaseID is undefined, and onSuccess invalidates ['interviewReviews', undefined] which won't match any active query. Consider throwing early when coursePhaseID is undefined so the caller gets a clear error instead of a silent 404.

💚 Suggested guard
 export const useUpdateInterviewReview = (coursePhaseID: string | undefined) => {
   const queryClient = useQueryClient()
 
   return useMutation({
     mutationFn: ({ courseParticipationID, review }: UpdateInterviewReviewVariables) => {
+      if (!coursePhaseID) {
+        throw new Error('coursePhaseID is required')
+      }
       return updateInterviewReview(coursePhaseID, courseParticipationID, review)
     },
     onSuccess: () => {
       queryClient.invalidateQueries({ queryKey: ['interviewReviews', coursePhaseID] })
     },
   })
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const useUpdateInterviewReview = (coursePhaseID: string | undefined) => {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({ courseParticipationID, review }: UpdateInterviewReviewVariables) =>
updateInterviewReview(coursePhaseID ?? '', courseParticipationID, review),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['interviewReviews', coursePhaseID] })
},
})
export const useUpdateInterviewReview = (coursePhaseID: string | undefined) => {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({ courseParticipationID, review }: UpdateInterviewReviewVariables) => {
if (!coursePhaseID) {
throw new Error('coursePhaseID is required')
}
return updateInterviewReview(coursePhaseID, courseParticipationID, review)
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['interviewReviews', coursePhaseID] })
},
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@clients/interview_component/src/interview/network/hooks/useUpdateInterviewReview.ts`
around lines 10 - 19, Guard against an undefined coursePhaseID in
useUpdateInterviewReview before invoking updateInterviewReview; throw a clear
error instead of substituting an empty string, and ensure onSuccess only
invalidates the query using a valid coursePhaseID.

Comment on lines +69 to +88
const resolvedDtos = await Promise.all(
resolutions.map(async (resolution): Promise<ResolvedDto> => {
const valuesByParticipation: Record<string, unknown> = {}
try {
const response = await axios.get<Array<Record<string, unknown>>>(
buildResolutionURL(resolution),
{ headers: authHeaders() },
)
for (const item of response.data ?? []) {
const id = item.courseParticipationID
if (typeof id === 'string') {
valuesByParticipation[id] = item[resolution.dtoName]
}
}
} catch (err) {
console.error(`Failed to resolve "${resolution.dtoName}" from ${resolution.baseURL}`, err)
}
return { dtoName: resolution.dtoName, valuesByParticipation }
}),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add a timeout to the axios requests to prevent indefinite hangs.

axios.get has no default timeout. If a provider endpoint is slow or unresponsive, Promise.all will block indefinitely, preventing the matching page from ever loading. The error handler catches network/HTTP errors but cannot catch a request that simply hangs.

⏱️ Proposed fix: add per-request timeout
   const resolvedDtos = await Promise.all(
     resolutions.map(async (resolution): Promise<ResolvedDto> => {
       const valuesByParticipation: Record<string, unknown> = {}
       try {
         const response = await axios.get<Array<Record<string, unknown>>>(
           buildResolutionURL(resolution),
-          { headers: authHeaders() },
+          { headers: authHeaders(), timeout: 10_000 },
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const resolvedDtos = await Promise.all(
resolutions.map(async (resolution): Promise<ResolvedDto> => {
const valuesByParticipation: Record<string, unknown> = {}
try {
const response = await axios.get<Array<Record<string, unknown>>>(
buildResolutionURL(resolution),
{ headers: authHeaders() },
)
for (const item of response.data ?? []) {
const id = item.courseParticipationID
if (typeof id === 'string') {
valuesByParticipation[id] = item[resolution.dtoName]
}
}
} catch (err) {
console.error(`Failed to resolve "${resolution.dtoName}" from ${resolution.baseURL}`, err)
}
return { dtoName: resolution.dtoName, valuesByParticipation }
}),
)
const resolvedDtos = await Promise.all(
resolutions.map(async (resolution): Promise<ResolvedDto> => {
const valuesByParticipation: Record<string, unknown> = {}
try {
const response = await axios.get<Array<Record<string, unknown>>>(
buildResolutionURL(resolution),
{ headers: authHeaders(), timeout: 10_000 },
)
for (const item of response.data ?? []) {
const id = item.courseParticipationID
if (typeof id === 'string') {
valuesByParticipation[id] = item[resolution.dtoName]
}
}
} catch (err) {
console.error(`Failed to resolve "${resolution.dtoName}" from ${resolution.baseURL}`, err)
}
return { dtoName: resolution.dtoName, valuesByParticipation }
}),
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@clients/matching_component/src/matching/network/resolveParticipations.ts`
around lines 69 - 88, Add a finite per-request timeout to the axios.get call
within the resolutions mapping in resolveParticipations, using the request
configuration alongside headers. Preserve the existing error handling so
timed-out requests are logged and return an empty valuesByParticipation result.

Comment on lines +36 to +43
extraData: (participations ?? []).map((participation) => {
const score = participation.prevData?.score as number | undefined
return {
courseParticipationID: participation.courseParticipationID,
value: score ?? null,
stringValue: score !== undefined ? String(score) : '',
}
}),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Export stringValue renders "null" for missing scores.

When prevData.score is null (not undefined), the guard score !== undefined passes and String(null) yields the literal "null" in the exported/extra data, whereas the table cell correctly shows N/A. Align the two so exports show an empty string for absent scores.

🔧 Proposed fix
       extraData: (participations ?? []).map((participation) => {
         const score = participation.prevData?.score as number | undefined
         return {
           courseParticipationID: participation.courseParticipationID,
           value: score ?? null,
-          stringValue: score !== undefined ? String(score) : '',
+          stringValue: score != null ? String(score) : '',
         }
       }),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
extraData: (participations ?? []).map((participation) => {
const score = participation.prevData?.score as number | undefined
return {
courseParticipationID: participation.courseParticipationID,
value: score ?? null,
stringValue: score !== undefined ? String(score) : '',
}
}),
extraData: (participations ?? []).map((participation) => {
const score = participation.prevData?.score as number | undefined
return {
courseParticipationID: participation.courseParticipationID,
value: score ?? null,
stringValue: score != null ? String(score) : '',
}
}),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@clients/matching_component/src/matching/pages/MatchingParticipantsPage/MatchingParticipantsPage.tsx`
around lines 36 - 43, Update the extraData mapping in MatchingParticipantsPage
so stringValue is empty when prevData.score is either null or undefined,
matching the table’s N/A handling; only convert the score to String when it is
non-null.

Comment on lines +104 to +113
func decodeInterviewAnswers(raw []byte) []InterviewAnswer {
answers := make([]InterviewAnswer, 0)
if len(raw) == 0 {
return answers
}
if err := json.Unmarshal(raw, &answers); err != nil {
return make([]InterviewAnswer, 0)
}
return answers
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Log JSON unmarshal errors in decodeInterviewAnswers.

Corrupted interview_answers data is silently replaced with an empty slice, hiding data integrity issues. Add a log warning so corruption is diagnosable.

🛡️ Suggested fix
 func decodeInterviewAnswers(raw []byte) []InterviewAnswer {
 	answers := make([]InterviewAnswer, 0)
 	if len(raw) == 0 {
 		return answers
 	}
 	if err := json.Unmarshal(raw, &answers); err != nil {
+		log.Warn("failed to decode interview answers: ", err)
 		return make([]InterviewAnswer, 0)
 	}
 	return answers
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func decodeInterviewAnswers(raw []byte) []InterviewAnswer {
answers := make([]InterviewAnswer, 0)
if len(raw) == 0 {
return answers
}
if err := json.Unmarshal(raw, &answers); err != nil {
return make([]InterviewAnswer, 0)
}
return answers
}
func decodeInterviewAnswers(raw []byte) []InterviewAnswer {
answers := make([]InterviewAnswer, 0)
if len(raw) == 0 {
return answers
}
if err := json.Unmarshal(raw, &answers); err != nil {
log.Warn("failed to decode interview answers: ", err)
return make([]InterviewAnswer, 0)
}
return answers
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@servers/interview/interviewReview/interviewReviewDTO/interviewReview.go`
around lines 104 - 113, Update decodeInterviewAnswers to log a warning when
json.Unmarshal fails, including the unmarshal error and enough context to
identify the corrupted interview_answers data, before returning the empty slice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Migration Pull Requests that introduce a database migration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Interview: move to become a fully independent course phase microservice

1 participant