feat(cv-sections): add best-effort bulk-create endpoint for education/experience - #174
Merged
Merged
Conversation
…/experience Closes #161. Pairs with the stateless LinkedIn-export-parse flow (#141): parse -> review client-side -> bulk-save many entries in one request instead of one create call per entry. - src/candidate_profile/BaseController.ts: new fnBulkCreate on createCrudController() (reused, not a dedicated bulk-only path) and a MAX_BULK_ITEMS=100 cap. Forces candidateId from the authenticated req.user._id onto every array item before validation, never trusting a client-supplied value nested inside items[] (verifyToken only forces req.body.candidateId at the top level) - same IDOR-safe pattern as every other write path, applied per item. Validates each item with the section's own Joi schema and calls the section's own service.handlerCreate per item; best-effort, one bad item never blocks the rest. - Bug found and fixed during implementation: utils/helper.ts's formatResponse() nulls out `data` whenever the response envelope's `success` is false. A naive envelope tied to summary.failed===0 would have silently dropped results/summary on every partial failure - the one case the response most needs to report. fnBulkCreate keeps the envelope success:true always; real per-item pass/fail lives in results[]/summary instead. - src/candidate_profile/education/education.controller.ts, src/candidate_profile/experience/experience.controller.ts: export the new fnBulkCreate alongside fnCreate/fnUpdate. - src/routers/api/v1/education.route.ts, src/routers/api/v1/experience.route.ts: new POST /bulk route + swagger docs. Scope limited to education/experience, matching what the LinkedIn-export parser currently produces. - src/locales/en.ts, src/locales/vi.ts: 2 new common.* i18n keys (bulkNoItems, bulkTooManyItems) for the new 400 rejection paths. - src/__tests__/candidate_profile/BaseController.test.ts: 5 new tests - reject missing/non-array items, reject >100 items, candidateId force (IDOR-safe), partial-failure results/summary, all-success summary. - agent-hub: seal node add-bulk-import-cv-sections (implementer + independent verifier subagent pass). npm test: 155 passed, 155 total (29/29 suites, independently re-run by the verifier subagent from scratch). npm run build: clean. Node: add-bulk-import-cv-sections (SEALED) Evidence: agent-hub/evidence/implementer/2026-09-28/add-bulk-import-cv-sections-plan.md, agent-hub/evidence/verifier/2026-09-28/add-bulk-import-cv-sections-seal.md Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
POST /api/v1/education/bulkandPOST /api/v1/experience/bulk(best-effort, up to 100 items per request), reusingcreateCrudController()'s newfnBulkCreate— per-itemcandidateIdis forced from the authenticated user (IDOR-safe, matching every other write path), each item validated with the section's own Joi schema, each item created via the section's ownservice.handlerCreate.utils/helper.ts'sformatResponse()nulls outdatawhenever the response envelope'ssuccessisfalse.fnBulkCreatekeeps the envelopesuccess: truealways so a partial failure doesn't silently dropresults/summaryfrom the response.BaseController.test.ts.Commits
Test plan
npm test— 155 passed, 155 total (29/29 suites), independently re-run by the verifier subagentnpm run build— cleanadd-bulk-import-cv-sectionsSEALED after independent verifier pass (evidence:agent-hub/evidence/implementer/2026-09-28/add-bulk-import-cv-sections-plan.md,agent-hub/evidence/verifier/2026-09-28/add-bulk-import-cv-sections-seal.md)Closes #161.
🤖 Generated with Claude Code