Postgres, PostGraphile, RLS 및 SQL
개요
이 스택의 데이터 계층 메커니즘입니다. 심층 방어(RLS를 최종 방어선으로 사용)와 하나의 합법적 데이터 경로를 구현합니다. 스택에 특화되어 있으며, PostGraphile/Postgres가 없는 프로젝트에는 적용되지 않습니다.
데이터 경로
브라우저 → 앱 서버 → PostGraphile → PostgreSQL. 정확히 하나의 합법적 경로입니다.
- 브라우저는 GraphQL/DB에 직접 접근하지 않으며, 앱은 애플리케이션 데이터를 위해 DB에 직접 쿼리하지 않습니다.
- 앱은 세션 컨텍스트를 헤더로만 전달(사용자 ID, 조직 힌트)합니다. 앱에 인가 로직이 없으며, 컨텍스트는 다운스트림에서 검증되고 신뢰되지 않습니다.
- 단일 경로 = 인증 컨텍스트, 검증, RLS를 적용할 수 있는 단일 지점입니다. 사이드 채널은 이러한 강제를 우회하는 구멍입니다.
보안 규칙
- RLS는 최종 적용 계층입니다. 앱 계층의 검사는 UX를 위한 것이며, 데이터베이스가 방어벽입니다. 상위 계층의 버그가 발생해도 다른 테넌트의 행이 유출되지 않습니다.
- 역할은 실제 세션 상태를 모델링합니다. 로그인하지 않음, 조직 없이 로그인, 조직과 함께 로그인, 연결 전용 역할, 마이그레이션 전용 역할. 역할은 의미를 가집니다.
- 권한 있는 연결 역할은 애플리케이션 쿼리를 실행하지 않습니다. 앱 쿼리는 제한되고 RLS가 적용되는 역할로 실행됩니다.
SECURITY DEFINER함수는search_path를 정의 내에 인라인으로 설정합니다. 매번, 예외 없이.- 값이 없으면
NULL이지, 빈 문자열이 아닙니다. 빈 문자열 센티넬은 금지됩니다. 값이 없으면 값을 생략하세요. - GraphQL은 DoS 공격 표면입니다. 제한하세요. 쿼리 깊이 제한과 비용/복잡성 분석을 적용하고, 예산을 초과하는 쿼리는 거부하세요. 페이지네이션 크기를 제한하세요. 앱 역할에 대해 DB **
statement_timeout**을 설정하세요. 의도적으로 필요하지 않은 한 프로덕션에서 introspection을 비활성화하세요.
SQL 스타일
- 파일당 하나의 객체 — 각 테이블, 함수, 정책, 권한 부여 집합은 자체 파일에 있습니다.
schema/object_type/name구조로 구성 — 디렉토리가 데이터베이스의 구성을 반영합니다.- 포함 순서는 의존성 순서입니다. include 매니페스트는 목차 역할을 합니다.
- 인라인으로 문서화하세요.
COMMENT ON은 객체와 같은 파일에 위치합니다. 무엇과 왜를 설명하세요. - 설명적인 별칭(테이블 이름의 단수형, 단일 문자 아님); Postgres 관용구(
current_*getter)를 따르십시오. - 타입과 사용자 대상 역할은 하드코딩된 제약 조건이 아닌 데이터입니다. — FK로 검증되고 스키마 변경 없이 확장 가능한 키/레이블/설명이 있는 조회 테이블입니다.
빠른 참조
| 규칙 | 확인 사항 |
|---|---|
새 SECURITY DEFINER 함수 | search_path가 인라인으로 설정되었습니까? |
| 테넌트 데이터가 있는 새 테이블 | RLS 정책 + 거부 테스트(graphql-contract-testing 참조)가 있습니까? |
| 값이 없음 | NULL이지 ''가 아닌가요? |
| 새로운 GraphQL 표면 | 깊이/비용 제한 및 페이지네이션 상한이 있습니까? |
| 새 객체 | 자체 파일, 의존성 순서에 따른 include, 인라인 COMMENT ON이 있습니까? |
전체 근거: engineering-constitution/references/engineering-constitution.md에 번들된 헌법 제XIII, XIV, XVIII조. 마이그레이션: zero-downtime-migrations. 계약 테스트: graphql-contract-testing.