Skip to content

chore: Worker Link tenant 무결성과 PostgreSQL RLS 보강 - #90

Merged
krestar merged 9 commits into
mainfrom
feat/34-worker-link-rls
Aug 6, 2026
Merged

chore: Worker Link tenant 무결성과 PostgreSQL RLS 보강#90
krestar merged 9 commits into
mainfrom
feat/34-worker-link-rls

Conversation

@krestar

@krestar krestar commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

왜 필요한가요?

Worker Link 관련 자식 테이블은 기존 단일 FK만으로 응답·파일·멱등성 기록이 서로 다른 사업장에 연결되는 것을 DB에서 완전히 차단하지 못했습니다.

PR #87에서 추가된 worker_document.task_id 또한 (task_id, company_id) FK만으로는 같은 사업장에 속한 다른 근로자의 Task를 WorkerDocument에 연결할 수 있었습니다.

또한 Worker Link RLS 정책과 token bootstrap을 실제 Worker Link 스키마에 맞게 완성하고, 제한 runtime role에서 tenant 격리가 유지되는지 PostgreSQL로 검증할 필요가 있습니다.

#34의 실제 runtime/migration role 구성, 최소 GRANT, Secret 주입, RLS 활성화 및 staging smoke는 #9와 연계된 후속 작업으로 남습니다. 따라서 이 PR은 #34를 자동으로 닫지 않습니다.

무엇이 바뀌나요?

  • API·도메인·DB 변경:

    • V16 공통 migration에서 worker_response_uploadworker_document_upload_idempotencycompany_id를 추가합니다.
    • 기존 데이터를 신뢰 가능한 부모 관계에서 backfill한 뒤 NOT NULL로 전환합니다.
    • Worker Link, Worker Response, StoredFile 및 자식 테이블에 tenant-aware 복합 UNIQUE·FK를 적용합니다.
    • worker_link.replaces_link_id를 동일 사업장 복합 FK와 ON DELETE RESTRICT로 전환합니다.
    • 동일 StoredFile이 여러 Worker Response에 연결되지 않도록 복합 UNIQUE를 추가합니다.
    • worker_document(task_id, worker_id, company_id) 복합 FK로 같은 사업장의 다른 근로자 Task 연결을 차단합니다.
    • 문서 등록 시 Task 존재 여부와 Task–Worker 일치 여부를 Application Service에서도 검증합니다.
    • Worker Response 업로드와 문서 업로드 멱등성 저장·조회 경로에 company_id를 전달합니다.
  • 권한·Workflow 변경:

    • Worker Link 발급 transaction에서 ActorContext.companyId를 PostgreSQL tenant context에 바인딩합니다.
    • V17 PostgreSQL migration에서 Worker Response Upload 정책을 직접 company_id 비교 방식으로 전환합니다.
    • Worker Document Upload Idempotency 테이블에 tenant RLS 정책을 추가합니다.
    • Worker Link bootstrap은 token hash가 일치하면서 ACTIVE이고 DB 시각 기준 미만료인 링크만 company_id를 반환합니다.
    • V17에서는 ENABLE ROW LEVEL SECURITY를 실행하지 않습니다.
  • AI·외부 연동 변경:

    • 변경 없음
  • 문서·배포 변경:

    • PostgreSQL RLS rollout 문서에 V16 최초 배포 전제와 V17 적용 범위를 기록합니다.
    • V16은 pre-V16 애플리케이션과 동시에 같은 DB에 쓰는 상황에 backward-compatible하지 않습니다.
    • 현재는 운영 DB·운영 트래픽·구버전 Pod가 없는 최초 배포 전이므로 해당 전제를 충족합니다.
    • 실제 role·GRANT·Secret·RLS 활성화와 staging smoke는 #9와 연계합니다.
    • RLS 활성화는 조건 충족 후 별도의 forward-only Flyway migration으로 수행하며 버전 번호를 현재 예약하지 않습니다.

어떻게 검증했나요?

  • .\gradlew.bat clean test
  • .\gradlew.bat build
  • /health와 Swagger UI 확인
  • 정상 요청
  • 잘못된 입력
  • 권한 부족
  • 다른 사업장 접근 차단
  • 필요한 상태 전이·Idempotency

Demo Seed 활성/비활성(clean Docker psql DB 환경) run 정상 작동도 확인하였습니다.

실행한 주요 PostgreSQL 테스트:

.\gradlew.bat test `
  --tests "com.fowoco.server.PostgreSqlMigrationTests" `
  --tests "com.fowoco.server.common.security.PostgreSqlRlsIsolationTest"

검증 결과:

  • V16 기존 데이터 backfill과 NOT NULL 전환
  • NULL·orphan·교차 tenant 관계가 있는 migration 실패
  • 같은 사업장 다른 근로자의 Task 연결 차단
  • StoredFile의 다중 Worker Response 연결 차단
  • 제한 runtime role에서 tenant context 누락 시 fail-closed
  • company A context에서 company B 행 조회·생성 차단
  • Worker Response Upload와 업로드 멱등성 테이블 RLS 차단
  • transaction 종료 후 tenant context 비누수
  • ACTIVE·미만료 Worker Link만 bootstrap 성공
  • REVOKED·실제 만료·미등록 token hash bootstrap 차단
  • migration 적용 후에도 RLS가 비활성 상태임을 확인

보안·개인정보

  • DTO·로그·AI 입력에 불필요한 개인정보가 없습니다.
  • JWT, Worker Link 원본 토큰, API Key, 비밀번호가 없습니다.
  • 모든 사업장 데이터 접근에 company_id 범위를 검사합니다.
  • AI 결과가 자동 승인·발송되지 않습니다.
  • 기존 Worker Link 중요 변경은 AuditLog와 request_id로 추적됩니다.
  • ADR-0004의 단계적 RLS 도입 계약을 유지합니다.
  • Server에 Prompt Builder·Provider SDK·모델 routing을 추가하지 않았습니다.

API·DB·운영 영향

  • 외부 API 계약 변경이 없어 Swagger/OpenAPI·Notion 갱신이 필요하지 않습니다.
  • V16의 배포 호환성 전제를 본문과 rollout 문서에 명시했습니다.
  • DB 변경에 Flyway V16·V17 migration이 있습니다.
  • migration 번호와 소유 Issue를 확인했고 다른 기능의 테이블을 미리 만들지 않았습니다.
  • 새로운 credential이나 Secret을 저장소에 추가하지 않았습니다.
  • 배포 후 Smoke Test와 forward-only 복구 절차를 rollout 문서에 기록했습니다.

배포 주의사항

  • V16과 대응 애플리케이션 코드는 같은 릴리스로 배포해야 합니다.
  • pre-V16 애플리케이션과 V16 스키마의 동시 쓰기는 지원하지 않습니다.
  • V17은 정책과 bootstrap만 준비하며 RLS를 활성화하지 않습니다.
  • 실제 RLS 활성화는 #9의 runtime role·최소 GRANT·Secret·staging 검증이 끝난 뒤 별도 migration으로 진행합니다.

화면 또는 응답 예시

외부 API 응답 형식 변경은 없습니다.

krestar added 7 commits August 5, 2026 12:59
- Worker Link 발급 서비스가 ActorContext를 tenant 신뢰 원본으로 사용하도록 변경
- 첫 Repository 접근 전에 transaction-local company_id 설정
- 발급 Command에서 companyId와 issuedBy 제거
- tenant context가 Repository보다 먼저 설정되는 순서 테스트 추가
- Worker Link 자식 테이블에 company_id를 backfill하고 NOT NULL로 전환
- Worker Response, 업로드 파일 및 멱등성 기록에 tenant-aware 복합 FK 적용
- Worker Link 대체 관계를 동일 사업장 복합 FK와 RESTRICT 정책으로 변경
- WorkerDocument와 Task의 근로자·사업장 복합 무결성 적용
- 문서 등록 시 Task 존재 여부와 Task–Worker 일치 검증
- Worker Link persistence 쓰기·조회 경로에 companyId 전달
- V16 migration 실패 조건과 최초 배포 비호환 전제를 문서화
- H2 기능 테스트와 PostgreSQL migration 계약 테스트 보강
- 응답 업로드 파일에 사업장 단위 복합 UNIQUE 제약 추가
- 업로드 멱등성 파일 복합 FK 조회 인덱스 추가
- 동시 연결 시 발생한 특정 UNIQUE 위반을 도메인 오류로 변환
- 다른 데이터 무결성 오류가 잘못 변환되지 않도록 제약 이름과 SQLSTATE 검증
- V16 migration 및 PostgreSQL 스키마 계약 테스트 보강
- 업로드 중복 연결 예외를 application.port에서 application.error로 이동
- Worker Response Upload 정책을 직접 company_id 비교 방식으로 전환
- Worker Document Upload 멱등성 테이블에 tenant 격리 정책 추가
- V17에서는 RLS를 활성화하지 않고 정책만 준비
- PostgreSQL migration 정책 계약 테스트 보강
- 제한 runtime role의 Worker Link tenant 격리 테스트 추가
- RLS rollout 문서에 V17 적용 범위 반영
- Worker Link bootstrap이 ACTIVE 상태의 링크만 사업장을 반환하도록 제한
- DB 현재 시각을 기준으로 만료된 링크의 tenant bootstrap 차단
- ACTIVE, REVOKED, 만료 및 미등록 token hash PostgreSQL 테스트 추가
- Worker Response Upload의 교차 tenant INSERT 차단 테스트 보강
- PostgreSQL RLS rollout 문서에 bootstrap 조건 반영
본 커밋에서 다룬 문제점은 Demo 환경 테스트 중 발견 되었습니다.
테스트의 원활함을 위해 PR과는 무관한 주제지만, fix 조치 하였습니다.

- 예약된 데모 파일의 내용이 변경되면 현재 classpath fixture로 원자적으로 교체
- 일반 파일이 아닌 storage key 경로는 덮어쓰지 않고 거부
- 동일 크기 변조 및 크기가 다른 구버전 fixture 복구 테스트 추가
- 데모 fixture 재실행 계약 문서화
@krestar krestar added area:server Spring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외 area:infra Server Dockerfile·DB 설정·CI hook·배포 가능성 영역; 통합 인프라 운영은 infra 저장소와 조율 priority:P1 핵심 작업 다음으로 처리할 중요 작업 security:privacy 개인정보·접근권한·토큰·보안 영향이 있는 작업 status:in-review 구현을 마치고 리뷰 또는 병합을 기다리는 작업 type:chore 저장소 설정·의존성·유지보수 작업 labels Aug 5, 2026
@krestar krestar changed the title feat: Worker Link tenant 무결성과 PostgreSQL RLS 보강 chore: Worker Link tenant 무결성과 PostgreSQL RLS 보강 Aug 5, 2026
@hywznn

hywznn commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

미안해요 재성님 제가 나중에 머지했어야했네요 ...

krestar and others added 2 commits August 6, 2026 09:56
- V16 공통 migration을 V20으로 변경
- V17 PostgreSQL migration을 V21로 변경
- migration 전용 테스트 이름과 직접 로딩 경로를 V20에 맞게 수정
- RLS rollout 문서와 PR 본문의 migration 번호 및 배포 전제를 갱신
- V18·V19 이후 순서로 Worker Link migration을 재배치
@krestar
krestar requested review from chaeliki and hywznn August 6, 2026 02:46
@krestar
krestar merged commit 5f71fb7 into main Aug 6, 2026
4 checks passed
@krestar
krestar deleted the feat/34-worker-link-rls branch August 6, 2026 04:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:infra Server Dockerfile·DB 설정·CI hook·배포 가능성 영역; 통합 인프라 운영은 infra 저장소와 조율 area:server Spring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외 priority:P1 핵심 작업 다음으로 처리할 중요 작업 security:privacy 개인정보·접근권한·토큰·보안 영향이 있는 작업 status:in-review 구현을 마치고 리뷰 또는 병합을 기다리는 작업 type:chore 저장소 설정·의존성·유지보수 작업

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants