"RLS를 켜는 것과 Policy를 만드는 건 다르다"
3개 테이블 모두 RLS는 켜져 있었지만, 정작 조회 규칙(Policy)이 하나도 없어서 아무도 API로 데이터를 조회할 수 없는 상태였습니다. fail-closed라는 점에서는 안전했지만, 기능적으로는 아무것도 못 하는 것과 같았습니다.
"본인이 속한 회사 데이터만 보이게" 하는 규칙을 만들기 위해, 재사용 가능한 판단 함수 is_workspace_member()를 SECURITY DEFINER로 작성했습니다. RLS Policy가 다른 테이블을 직접 참조하면 무한 재귀나 성능 문제가 생길 수 있다는 PostgreSQL의 일반 원칙에 따라, 함수를 경유하는 구조로 설계했습니다.
여기서 문서에 없던 판단을 하나 추가했습니다. profiles 테이블의 조회 범위를 "본인 것"에서 "본인 것 또는 같은 회사 동료 것"까지 넓히자고 제안한 것입니다. 향후 담당자 표시 같은 기능에 필요할 것으로 예상했기 때문인데, 이건 제 판단이라 승인을 받은 뒤 진행했습니다. 이 정책이 workspace_members를 재귀적으로 참조하는 구조라, 리뷰에서 무한 재귀가 발생하지 않는지를 특히 집중해서 확인했습니다.
39개 테스트가 통과했고(1개는 실제 DB가 필요해 skip 처리), 서로 다른 회사 계정으로 교차 조회를 시도했을 때 빈 결과가 나오는 것까지 확인한 뒤 커밋했습니다. 이번 작업으로 확인한 건, RLS를 켜는 것과 실제로 쓸 수 있는 Policy를 만드는 것은 완전히 다른 작업이라는 점입니다.
RLS Policy는 SECURITY DEFINER 함수를 통해서만 다른 테이블을 참조해야 무한 재귀와 성능 문제를 피할 수 있다는 PostgreSQL RLS의 일반 원칙을 적용했습니다. profiles 조회 범위를 넓히는 결정은 문서에 명시되어 있지 않았지만, 담당자 표시 등 향후 필요할 것으로 예상해 제안했고 승인을 받은 뒤 진행했습니다. 리뷰 단계에서는 이 정책이 workspace_members 테이블을 재귀적으로 참조하는 구조라, 무한 재귀가 나지 않는지를 특히 집중적으로 검증했습니다.
관련 프로젝트
프로젝트 개요 비즈니스 프로세스 트랜스포메이션(BPR)을 지원하는 한국어 기반 웹 애플리케이션. 컨설팅 프로젝트의 AS-IS 프로세스 분석부터 TO-BE 설계, Blueprint 승인까지의 전체 워크플로우를 디지털화하는 플랫폼으로, EPIC 단위로 구조화된 백로그를 기반으로 개발 중. 역할 및 워크플로우 PM / Architect / Reviewer 역할 수행 Codex(구현 담당)에게 Task 단위 구현 프롬프트 설계 Codex 구현 결과를 git log, git grep, git status로 직접 검증 후 승인 승인 전에는 Codex가 commit하지 않는 엄격한 게이팅 프로세스 운영 한 번에 하나의 Backlog Task만 진행, Task 완료 전 다음 Task 착수 금지 기술적 의사결정 및 성과 워크스페이스/프로젝트 접근 권한을 DB 레벨(복합 FK, SECURITY DEFINER 트리거)과 애플리케이션 레벨(Server Action 권한 검증)의 이중 방어 구조로 설계 Hard Delete 미구현 원칙 하에 배열 필드 전체교체(replace)를 단일 트랜잭션 RPC로 처리하는 패턴 확립 및 재사용 AS-IS 프로세스 그래프의 순환 참조 탐지에 Tarjan SCC 알고리즘 적용, 차단 오류(Error)와 경고(Warning)를 분리한 이중 Validator 아키텍처 설계 도메인 규칙 위반을 커스텀 Postgres 에러 코드 체계(SIA0104)로 문서화하여 거버넌스 문서와 코드베이스 간 정합성 유지 AI 생성 데이터와 사람이 검증한 데이터를 구분하는 generatedbyai / verified 메타데이터 패턴을 여러 도메인 테이블에 일관되게 적용 진행 상태 ✅ EPIC-01 (인증 / 워크스페이스 / 프로젝트 접근) ✅ EPIC-02 (조직 / 산업 / 프로젝트) 🚧 EPIC-03 (AS-IS 프로세스 그래프) — 그래프 검증, Input/Output 스키마, Business Rule 스키마 구현 완료