fix(experiences): persist interview submissions with review status - #1641
Conversation
Form only updated React state, so reload wiped cards despite the moderation success copy. Add a backend resource, save on submit, reload via client key, and surface pending/approved/rejected. Co-authored-by: Cursor <cursoragent@cursor.com>
Add idempotent creates, restrict status updates to MODERATOR_EMAILS, and load approved experiences into the Common tab. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Reject blank or missing keys so retries cannot bypass the unique partial index and create duplicate submissions. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Warning Review limit reached
Next review available in: 50 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe PR adds persisted interview-experience submissions, validation, idempotency, moderator authorization, API routes, retrieval states, and frontend integration with pending, approved, and rejected statuses. ChangesInterview experience workflow
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Contributor
participant InterviewExperiences
participant interviewExperienceRoutes
participant createInterviewExperience
participant InterviewExperience
Contributor->>InterviewExperiences: Submit experience
InterviewExperiences->>interviewExperienceRoutes: POST with client and idempotency keys
interviewExperienceRoutes->>createInterviewExperience: Validate and authorize
createInterviewExperience->>InterviewExperience: Find or create submission
InterviewExperience-->>createInterviewExperience: Pending document
createInterviewExperience-->>InterviewExperiences: Normalized response
InterviewExperiences-->>Contributor: Show pending status
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Allowlist status updates and validate ObjectIds before Mongo writes, and add double-submit CSRF middleware on mutating experience routes. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
backend/tests/interviewExperienceController.unit.test.js (1)
126-154: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTest duplicate-key recovery after create.
This test covers the pre-create lookup only. Add a test where the first
findOnereturnsnull,InterviewExperience.createrejects with{ code: 11000 }, and the recovery lookup returns the saved submission. This protects the concurrent retry path.🤖 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 `@backend/tests/interviewExperienceController.unit.test.js` around lines 126 - 154, Add a test alongside the existing duplicate-key test for the concurrent retry path: configure the first InterviewExperience.findOne call to return null, make InterviewExperience.create reject with an error whose code is 11000, then configure the recovery lookup to return the saved submission. Assert the controller responds with status 200 and the recovered experience, and verify create was attempted and the recovery findOne lookup occurred.
🤖 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 `@backend/controllers/interviewExperienceController.js`:
- Around line 48-50: Update the submission creation logic in the interview
experience controller so anonymous requests without a non-empty
payload.clientKey return HTTP 400 before persistence; authenticated requests
identified by req.user._id and anonymous requests with clientKey must continue
to work. Add a unit test covering anonymous creation without clientKey and
asserting the 400 response.
In `@frontend/src/pages/InterviewExperiences/InterviewExperiences.jsx`:
- Around line 29-40: Update getOrCreateClientKey so every generated client key
uses cryptographic randomness via crypto.randomUUID() or
crypto.getRandomValues(), removing the Math.random() and timestamp-only
fallbacks. If Web Crypto is unavailable or storage access fails, return a
disabled/absent key rather than enabling anonymous submission retrieval through
GET /mine.
---
Nitpick comments:
In `@backend/tests/interviewExperienceController.unit.test.js`:
- Around line 126-154: Add a test alongside the existing duplicate-key test for
the concurrent retry path: configure the first InterviewExperience.findOne call
to return null, make InterviewExperience.create reject with an error whose code
is 11000, then configure the recovery lookup to return the saved submission.
Assert the controller responds with status 200 and the recovered experience, and
verify create was attempted and the recovery findOne lookup occurred.
🪄 Autofix
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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 472864c4-4e80-4d21-9da8-3da12c8040c8
📒 Files selected for processing (11)
backend/.env.examplebackend/Input_validators/ValidateInterviewExperience.jsbackend/controllers/interviewExperienceController.jsbackend/middlewares/authMiddleware.jsbackend/models/InterviewExperience.jsbackend/routes/interviewExperienceRoutes.jsbackend/server.jsbackend/tests/interviewExperienceController.unit.test.jsbackend/tests/requireModerator.unit.test.jsfrontend/src/pages/InterviewExperiences/InterviewExperiences.jsxfrontend/src/utils/apiPaths.js
Require clientKey for unauthenticated creates and generate keys only with Web Crypto so /mine cannot be enumerated via weak anon keys. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@frontend/src/pages/InterviewExperiences/InterviewExperiences.jsx`:
- Around line 47-48: Update the client-key retrieval logic around
CLIENT_KEY_STORAGE to validate stored values before returning them, accepting
only UUID or 32-hex Web Crypto formats. Remove invalid legacy anon- or
timestamp/random-based values instead of sending them to /mine, and apply
equivalent rejection or migration in the /mine backend path.
- Around line 542-548: Remove the unconditional clientKey guard from the
submission flow around the create request so authenticated users can submit
without Web Crypto support. Continue including clientKey when available, and
send the request without it when unavailable so the API enforces the requirement
only for anonymous submissions; preserve the existing submitting-state and API
error handling.
🪄 Autofix
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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 7a48dfa3-40ea-4bc3-9d84-9660ee6b0ca6
📒 Files selected for processing (3)
backend/controllers/interviewExperienceController.jsbackend/tests/interviewExperienceController.unit.test.jsfrontend/src/pages/InterviewExperiences/InterviewExperiences.jsx
🚧 Files skipped from review as they are similar to previous changes (2)
- backend/tests/interviewExperienceController.unit.test.js
- backend/controllers/interviewExperienceController.js
Only UUID/hex crypto keys are accepted for anonymous identity, and authenticated submits no longer require a clientKey on the client. Co-authored-by: Cursor <cursoragent@cursor.com>
Pull Request Description
Related Issue
Closes #935
Summary
Interview experience submit only wrote to React state, so a refresh dropped the card even though the UI said it was up for review. Added
/api/interview-experiences(create, mine, approved, status update), wired the form to POST with an idempotency key, and show pending/approved/rejected on cards.Type of Change
How Has This Been Tested?
vitest run tests/interviewExperienceController.unit.test.js(pass)vitest run tests/requireModerator.unit.test.js(pass)Checklist
Made with Cursor
Looks good to me. Ready to merge.