fix(admin,application,identity): 데이터 소유권을 소유 시스템으로 되돌리고 끊긴 경로 연결 - #145
Conversation
전형 결과는 admin 이 산출하지만 수험생에게 보이는 합격 여부의 소유자는 application 이다. 그런데 application_db.pass_results 를 쓰는 코드가 없어 gRPC 가 내보내는 pass_status 는 항상 NOT_ANNOUNCED 였다. - application.proto 에 AnnouncePassResults RPC 추가. admin 이 산출 결과를 위임할 통로가 생겼다. PENDING 은 발표가 아니므로 거부한다. - 발표는 한 번에 전부 반영하거나 전부 거부한다. 일부만 반영되면 누가 발표되었는지 admin 과 application 의 판단이 갈린다. - identity 는 하드코딩한 NOT_ANNOUNCED 대신 원본 값을 돌려준다. identity 의 프로젝션은 create/cancel 시점에만 갱신되어, application 에서 원서를 제출하면 낡은 DRAFT 에 머물렀다. 그 상태로 취소하면 로컬 가드가 APPLICATION_CANCEL_NOT_ALLOWED 로 막았다. - 조회할 때마다 원본을 다시 읽어 프로젝션을 맞춘다. 원본이 응답하지 않을 때만 마지막으로 본 값을 돌려준다. - 취소 가능 여부는 원본을 가진 application 이 판단한다. 아웃박스와 이벤트 소비자는 구동부가 없어 그대로 두고, 브로커가 들어올 때 연결할 지점을 주석으로 남겼다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
admin_db.applicant 는 application_db.applicants 를 열세 컬럼 복제한 사본이었다. 게다가 이 테이블에 행을 넣는 코드가 플랫폼 어디에도 없어, 지원자 조회·통계·전형· 수험번호 발급·문서 발급이 모두 빈 테이블 위에서 돌고 있었다. ApplicantJpaEntity 주석이 예고한 대로 gRPC 조회로 대체한다. - application.proto 에 ListApplicants 추가. 제출된 원서 전체를 넘긴다. 제출 시점에 채워지지 않을 수 있는 값(생년월일·지역·전형·학력)은 optional 로 두어 admin 이 "미기재"와 "값 없음"을 구분할 수 있게 했다. - admin_db 는 applicant_screening 으로 바꾼다. 접수 번호·수험 번호·원서 도착 여부· 전형 상태·성적만 남기고 식별자는 application 의 지원자 식별자를 그대로 쓴다. - 접수 번호는 처음 본 원서에 한 번만 부여해 저장한다. 조회 결과로 다시 계산하면 원서가 취소될 때 번호가 밀려 이미 발급한 수험표·파일 이름과 어긋난다. - 필터와 페이지는 메모리에서 처리한다. 두 저장소에 걸친 조건이라 한쪽 쿼리로 내릴 수 없고, 기존 코드도 이미 회차 전체를 읽는 것을 전제로 한다. 성적도 두 시스템이 따로 계산하고 있었다. admin 의 성적 정책은 항목별 원점수를 필요로 하는데 그 출처가 없어 한 번도 동작한 적이 없다. - ScoreCalculator 가 총점과 함께 항목별 원점수를 내고, admin 은 이 값을 받아 쓴다. 계산의 소유자를 application 하나로 둔다. - 전형 산출 결과는 AnnouncePassResults 로 application 에 반영한다. 반영이 실패하면 admin 쪽 저장도 함께 되돌아간다. 지역이나 전형이 비어 있는 원서는 어느 정원으로 셀지 정할 수 없어 전형 산출과 지역·전형 분포 집계에서 제외한다. API 변경: 지원자 응답의 region·admissionType·graduationStatus·birthDate 가 null 일 수 있고, applicantId 는 항상 채워진다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
configuration 은 `dsm_Entry/Backend/application/application_<접수코드>.pdf` 로 원서
원본을 올리는데, admin 은 자기 버킷의 `application/application_<접수번호>.pdf` 를
찾고 있었다. 키 루트도 버킷도 달라 `GET /applicants/{id}/application-document` 가
파일이 실제로 있어도 항상 APPLICATION_DOCUMENT_NOT_FOUND 였다.
- admin 의 객체 키에 configuration 과 같은 루트를 붙인다.
- admin 의 버킷을 configuration 과 같은 AWS_S3_BUCKET 으로 맞춘다.
- 두 시스템이 서로를 의존하지 않아 컴파일러가 어긋남을 못 잡으므로,
configuration 이 쓰는 키를 값으로 적어 둔 테스트로 못 박는다.
배포 시 admin 의 STORAGE_BUCKET 을 configuration 과 같은 AWS_S3_BUCKET 으로
바꿔야 한다. admin 이 이미 올려 둔 수험표는 새 키로 다시 생성된다(요청 시점에
새로 만들어 올리는 구조라 이관이 필요 없다).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 비어 있는 값이 섞인 집합 비교를 명시적인 헬퍼로 바꿔 의도를 드러낸다. - save 가 saveAll 을 자기호출하면 프록시를 지나지 않아 트랜잭션이 걸리지 않는다. 두 진입점에 각각 경계를 두고 실제 저장은 private 으로 내린다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are limited based on label configuration. 🏷️ Required labels (at least one) (1)
🚫 Excluded labels (none allowed) (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
|
남긴 항목을 이슈로 끊었습니다.
문의(QnA) 건은 #144 에 이미 있어 새로 만들지 않았습니다. #149 는 이 PR 에서 방어적으로 처리한 부분(지역이 비어 있는 원서를 전형 산출에서 제외)의 근본 원인입니다. |
|
대신 고쳐주셔서 감사합니다 |
이 PR 에 CI 가 붙지 않는 이유리뷰하실 때 "체크가 왜 CodeRabbit 하나뿐이지?" 로 헷갈리실 수 있어 남깁니다. 조건이 두 겹입니다. 1. 빌드/테스트 워크플로가 develop 에 없습니다
2. 트리거가 base 와 맞지 않습니다 on:
pull_request:
branches: [main, develop]이 PR 은 #143 위에 스택되어 따라서 #95 가 머지되고 이 PR 의 base 가 develop 으로 바뀐 뒤에야 CI 가 돕니다. 두 조건이 모두 필요합니다. 기준선: 지금 develop 계열에서 이미 깨져 있는 테스트#95 의 마지막 실행(run 34419489779) 결과입니다.
이 PR 의 변경과 무관한 선행 실패입니다. 다만 이 PR 이 이 PR 의 검증 상태작업 환경에 Bazel 이 없어(
머지 전에 반드시 한 번 돌려 주세요. |
배경
데이터 소유권 검증에서 확인된 결함을 우선순위대로 고칩니다. 세 가지 모두 "소유자가 아닌 시스템이 데이터를 들고 있거나, 소유자에게 가는 경로가 아예 없는" 같은 뿌리입니다.
Important
#143 위에 스택된 PR입니다. base 가
bug/139-notice-not-visible이라 #143 이 먼저 머지되어야 합니다. 마이그레이션 번호(V002→V003)와admin-adapter-out/deps.bzl이 #143 과 겹쳐서 develop 기준으로는 충돌합니다.무엇을 고쳤나
1. 합격 발표 경로가 끊겨 있었다 (
9aaa392)application_db.pass_results를 쓰는 코드가 프로덕션에 하나도 없어서, gRPC 가 내보내는pass_status는 항상NOT_ANNOUNCED였습니다. identity 의 합격 조회는 아예 값을 하드코딩하고 있었습니다.application.proto에AnnouncePassResults추가 — admin 이 산출 결과를 위임하는 통로getApplicationResult()의 하드코딩 제거2. identity 프로젝션이 낡은 상태에 머물렀다 (
9aaa392)프로젝션이
create/cancel때만 갱신되어, application 에서 원서를 제출하면 identity 는 계속DRAFT로 보고 있었습니다. 그 상태로 취소하면 로컬 가드가APPLICATION_CANCEL_NOT_ALLOWED로 막았습니다.3. admin 이 지원자 원본을 복제하고 있었다 (
fb1bebd)admin_db.applicant는application_db.applicants를 열세 컬럼 복제한 사본이었고, 이 테이블에 행을 넣는 코드가 플랫폼 어디에도 없었습니다. 지원자 조회·통계·전형·수험번호 발급·문서 발급이 전부 빈 테이블 위에서 돌고 있었습니다.ApplicantJpaEntity주석이 예고한 대로 gRPC 조회로 대체합니다.application.proto에ListApplicants추가admin_db는applicant_screening으로 축소 — 접수 번호·수험 번호·원서 도착 여부·전형 상태·성적만. 식별자는 application 의 지원자 식별자를 그대로 씁니다.ScoreCalculator하나로 둡니다. admin 의 성적 정책은 항목별 원점수를 필요로 하는데 출처가 없어 한 번도 동작한 적이 없었습니다.AnnouncePassResults로 반영합니다. 실패하면 admin 쪽 저장도 함께 되돌아갑니다.4. admin 이 없는 위치에서 원서 원본을 찾고 있었다 (
53c237c)configuration 은
dsm_Entry/Backend/application/application_<접수코드>.pdf로 올리는데 admin 은 자기 버킷의application/application_<접수번호>.pdf를 찾았습니다. 키 루트도 버킷도 달라GET /applicants/{id}/application-document가 파일이 실제로 있어도 항상 404 였습니다.배포 시 필요한 조치
STORAGE_BUCKET→AWS_S3_BUCKET(configuration 과 같은 값)APPLICATION_GRPC_HOST/APPLICATION_GRPC_PORT추가V003__replace_applicant_with_screening.sql적용 (applicant테이블 DROP)기존
applicant행은 application 시스템이 없던 시절의 데이터라 실제 원서와 식별자를 맞출 방법이 없어 이관하지 않습니다. #139 의notice와 같은 판단입니다.API 변경
지원자 응답의
region·admissionType·graduationStatus·birthDate가 null 일 수 있습니다. application 의 제출 검증이 이 값들을 요구하지 않기 때문이고, 값이 비어 있는 원서는 전형 산출과 지역·전형 분포 집계에서 제외합니다.applicantId는 반대로 항상 채워집니다.검증
Warning
로컬에서 빌드·테스트를 돌리지 못했습니다. 이 환경에 Bazel 이 설치되어 있지 않습니다(
bazel: command not found). 아래 테스트는 작성만 했고 실행 결과를 확인하지 못했으니, CI 나 로컬에서 반드시 한 번 돌려 주세요.추가한 테스트:
PassResultCommandServiceTest— 발표 저장, 없는 지원자 거부, 단계 중복 거부, PENDING 거부ApplicationGrpcServiceTest— 발표 RPC 매핑, 미발표 상태 거부, 목록의 선택 항목 유무GrpcApplicantDataAdapterTest— 원서 매핑, 미기재 항목 보존, 1차/최종 단계 구분, PENDING 미전송DocumentNamingTest— configuration 이 쓰는 객체 키와 일치남긴 것
검증에서 4~5번으로 분류한 항목은 제품 결정이 섞여 있어 이슈로 남깁니다.
question_answer가 고아 레코드가 되는 문제faqs/recruitment_guidelines에 쓰기 경로가 없는 문제🤖 Generated with Claude Code