Skip to content

[Feat] 크롬 익스텐션 공고 수집 API 추가#107

Merged
whc9999 merged 1 commit into
mainfrom
feat/chrome-extension-job-posting-ingest
Jun 25, 2026
Merged

[Feat] 크롬 익스텐션 공고 수집 API 추가#107
whc9999 merged 1 commit into
mainfrom
feat/chrome-extension-job-posting-ingest

Conversation

@whc9999

@whc9999 whc9999 commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

✨ 어떤 이유로 PR를 하셨나요?

  • feature 병합
  • 버그 수정(아래에 issue #를 남겨주세요)
  • 코드 개선
  • 코드 수정
  • 배포
  • 기타(아래에 자세한 내용 기입해주세요)

📋 세부 내용 - 왜 해당 PR이 필요한지 작업 내용을 자세하게 설명해주세요

  • 크롬 익스텐션이 크롤링한 공고 원문을 전달하는 ingest API 추가
  • 기존 채용 공고 ingest 로직을 재사용해 공고 저장 처리
  • 공고 저장 성공 시 모의 서류 지원을 자동 생성하도록 연계
  • sourceUrl, sourceSite를 응답에 포함해 프론트/익스텐션에서 원본 출처를 확인할 수 있도록 구성
  • 익스텐션 ingest 성공/저장 보류 케이스 단위 테스트 추가

📸 작업 화면 스크린샷

⚠️ PR하기 전에 확인해주세요

  • 로컬테스트를 진행하셨나요?
  • 머지할 브랜치를 확인하셨나요?
  • 관련 label을 선택하셨나요?

🚨 관련 이슈 번호 [#106 ]

Summary by CodeRabbit

  • New Features

    • Added a new endpoint to ingest job postings from a browser extension.
    • The response now includes ingestion status, source details, and related mock-apply data when available.
    • Added support for submitting extension-sourced job posting content with validation.
  • Bug Fixes

    • Improved handling so related follow-up data is created only when the posting is successfully saved.

- 크롬 익스텐션이 크롤링한 공고 원문을 전달하는 ingest API 추가
- 기존 채용 공고 ingest 로직을 재사용해 공고 저장 처리
- 공고 저장 성공 시 모의 서류 지원을 자동 생성하도록 연계
- sourceUrl, sourceSite를 응답에 포함해 프론트/익스텐션에서 원본 출처를 확인할 수 있도록 구성
- 익스텐션 ingest 성공/저장 보류 케이스 단위 테스트 추가
@whc9999 whc9999 self-assigned this Jun 25, 2026
@whc9999 whc9999 added the ✨ feat New feature or request label Jun 25, 2026
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new job posting extension ingestion endpoint, request and response DTOs, and a service that reuses base job-posting ingestion before optionally creating a mock apply. Tests cover the saved and unsaved service paths.

Changes

Job Posting Extension Ingest Flow

Layer / File(s) Summary
Request and response contracts
src/main/java/com/jobdri/jobdri_api/domain/jobposting/dto/request/JobPostingExtensionIngestRequest.java, src/main/java/com/jobdri/jobdri_api/domain/jobposting/dto/response/JobPostingExtensionIngestResponse.java
Adds the extension ingest request and response records, including rawText validation and the response factory that copies ingest status fields.
REST endpoint
src/main/java/com/jobdri/jobdri_api/domain/jobposting/controller/JobPostingExtensionController.java
Adds POST /api/job-postings/extension/ingest, resolves and validates the authenticated user, validates the request body, and wraps the service result in ApiResponse.
Ingest orchestration and tests
src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingExtensionIngestService.java, src/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingExtensionIngestServiceTest.java
Implements extension ingestion by calling the base ingest service, conditionally creating a mock apply from a saved job posting, and covers the saved and unsaved paths in Mockito tests.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant JobPostingExtensionController
  participant userService
  participant jobPostingExtensionIngestService
  participant jobPostingIngestService
  participant mockApplyService
  Client->>JobPostingExtensionController: POST /api/job-postings/extension/ingest
  JobPostingExtensionController->>userService: validateUser(user)
  JobPostingExtensionController->>jobPostingExtensionIngestService: ingest(user, request)
  jobPostingExtensionIngestService->>jobPostingIngestService: ingestAndCreate(request.rawText(), null)
  alt savedToDatabase and saved job posting exists
    jobPostingExtensionIngestService->>mockApplyService: createMockApplyFromJobPosting(user, jobPostingId)
  end
  jobPostingExtensionIngestService-->>JobPostingExtensionController: JobPostingExtensionIngestResponse
  JobPostingExtensionController-->>Client: ApiResponse.onSuccess(...)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I hop to the ingest with carrot-bright glee
A JSON nibble, then a mock apply for me
If the posting is saved, I do a little twirl
If not, I sniff the text and let it unfurl
Thump-thump—new job posts under the moon!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the new Chrome extension job collection API.
Description check ✅ Passed The description matches the template well and covers purpose, details, checks, and issue link; the screenshot section is the only empty part.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feat/chrome-extension-job-posting-ingest

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingExtensionIngestServiceTest.java (1)

48-120: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: add coverage for savedToDatabase=true but getSaved()==null.

The service guards on ingest.isSavedToDatabase() && ingest.getSaved() != null, but tests only exercise (true, non-null saved) and (false, null saved). A test for (true, null saved) would lock in that mock-apply creation is skipped when no saved entity is present.

🤖 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
`@src/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingExtensionIngestServiceTest.java`
around lines 48 - 120, Add a test in JobPostingExtensionIngestServiceTest to
cover the branch where JobPostingIngestResponse has savedToDatabase=true but
getSaved()==null, since JobPostingExtensionIngestService.ingest currently
requires both conditions before calling
MockApplyService.createMockApplyFromJobPosting. Reuse the existing setup pattern
from ingestCreatesMockApplyWhenJobPostingSaved, but return an ingest response
with null saved and verify createMockApplyFromJobPosting is never called. Also
assert the response keeps savedToDatabase true and mockApply null to lock in the
guard behavior.
🤖 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
`@src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingExtensionIngestService.java`:
- Around line 20-40: The ingest orchestration in
JobPostingExtensionIngestService.ingest currently performs two writes without a
shared transaction boundary, so make the whole flow transactional by adding a
transaction to the orchestrator and ensuring the downstream calls participate in
it. Review JobPostingIngestService.ingestAndCreate and
MockApplyService.createMockApplyFromJobPosting so they don’t opt out of the
caller’s transaction; in particular, remove the NOT_SUPPORTED behavior if
mock-apply creation should be atomic with the job posting save.

---

Nitpick comments:
In
`@src/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingExtensionIngestServiceTest.java`:
- Around line 48-120: Add a test in JobPostingExtensionIngestServiceTest to
cover the branch where JobPostingIngestResponse has savedToDatabase=true but
getSaved()==null, since JobPostingExtensionIngestService.ingest currently
requires both conditions before calling
MockApplyService.createMockApplyFromJobPosting. Reuse the existing setup pattern
from ingestCreatesMockApplyWhenJobPostingSaved, but return an ingest response
with null saved and verify createMockApplyFromJobPosting is never called. Also
assert the response keeps savedToDatabase true and mockApply null to lock in the
guard behavior.
🪄 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 Plus

Run ID: 98cd511c-b2f7-48ba-81b1-a4e1a9298286

📥 Commits

Reviewing files that changed from the base of the PR and between 7db47f6 and f4d9088.

📒 Files selected for processing (5)
  • src/main/java/com/jobdri/jobdri_api/domain/jobposting/controller/JobPostingExtensionController.java
  • src/main/java/com/jobdri/jobdri_api/domain/jobposting/dto/request/JobPostingExtensionIngestRequest.java
  • src/main/java/com/jobdri/jobdri_api/domain/jobposting/dto/response/JobPostingExtensionIngestResponse.java
  • src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingExtensionIngestService.java
  • src/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingExtensionIngestServiceTest.java

Comment on lines +20 to +40
public JobPostingExtensionIngestResponse ingest(User user, JobPostingExtensionIngestRequest request) {
JobPostingIngestResponse ingest = jobPostingIngestService.ingestAndCreate(
user,
new JobPostingIngestRequest(request.rawText(), null)
);

MockApplyCreateResponse mockApply = null;
if (ingest.isSavedToDatabase() && ingest.getSaved() != null) {
mockApply = mockApplyService.createMockApplyFromJobPosting(
user,
ingest.getSaved().getJobPostingId()
);
}

return JobPostingExtensionIngestResponse.of(
request.sourceUrl(),
request.sourceSite(),
ingest,
mockApply
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect JobPostingIngestService for `@Transactional` usage and ingestAndCreate signatures
fd JobPostingIngestService.java --exec sh -c 'echo "== {} =="; rg -nP -C3 "`@Transactional`|public .*ingestAndCreate" "{}"'
# Inspect MockApplyService.createMockApplyFromJobPosting transaction semantics
fd MockApplyService.java --exec sh -c 'echo "== {} =="; rg -nP -C3 "`@Transactional`|createMockApplyFromJobPosting" "{}"'

Repository: JobDri-Developer/BackEnd

Length of output: 3872


Atomicity risk: Two write operations have no common transaction boundary.

ingest() triggers a persistence action via jobPostingIngestService.ingestAndCreate(...) followed by mockApplyService.createMockApplyFromJobPosting(...).

Verification confirms that neither the orchestrator method nor the callee ingestAndCreate have a @Transactional annotation. Furthermore, createMockApplyFromJobPosting is explicitly annotated with @Transactional(propagation = Propagation.NOT_SUPPORTED), forcing it to execute outside any transaction.

This sequence lacks an atomic context: if the mock-apply creation fails after the job posting is saved, the system is left in an inconsistent state with the posting persisted but no associated mock application.

Enclose the orchestration in @Transactional and ensure the downstream service methods respect the transaction (or remove Propagation.NOT_SUPPORTED if the mock-apply step should participate in the caller's transaction).

🤖 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
`@src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingExtensionIngestService.java`
around lines 20 - 40, The ingest orchestration in
JobPostingExtensionIngestService.ingest currently performs two writes without a
shared transaction boundary, so make the whole flow transactional by adding a
transaction to the orchestrator and ensuring the downstream calls participate in
it. Review JobPostingIngestService.ingestAndCreate and
MockApplyService.createMockApplyFromJobPosting so they don’t opt out of the
caller’s transaction; in particular, remove the NOT_SUPPORTED behavior if
mock-apply creation should be atomic with the job posting save.

@whc9999 whc9999 merged commit 154ada5 into main Jun 25, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feat New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant