PostgreSQL example
PostgreSQL 테이블 설계 예시
uuid 기본키, timestamptz, jsonb, 부분 인덱스, 외래키를 포함한 PostgreSQL 테이블 설계 예시입니다.
상황
PostgreSQL 테이블 설계 예시
SaaS 프로젝트에서 계정, 워크스페이스, 멤버십, 감사 로그를 PostgreSQL 기준으로 설계하는 예시입니다.
핵심 타입
uuid, timestamptz, jsonb
중요 관계
accounts 1:N workspaces
주의점
소프트 삭제와 부분 인덱스
요구사항
요구사항
- 한 계정은 여러 워크스페이스를 가질 수 있습니다.
- 사용자는 워크스페이스마다 다른 역할을 가질 수 있습니다.
- 감사 로그는 구조화되지 않은 메타데이터를 함께 저장해야 합니다.
테이블 설계
테이블 설계
accounts고객 조직- id uuid PK
- name text
- plan text
- created_at timestamptz
users사용자- id uuid PK
- email citext UNIQUE
- display_name text
- created_at timestamptz
workspaces작업 공간- id uuid PK
- account_id uuid FK
- name text
- deleted_at timestamptz
workspace_members워크스페이스 멤버- workspace_id uuid PK/FK
- user_id uuid PK/FK
- role text
- added_at timestamptz
audit_events감사 이벤트- id uuid PK
- workspace_id uuid FK
- actor_user_id uuid FK
- event_type text
- metadata jsonb
관계
관계
accounts 1:N workspacesusers N:M workspaces through workspace_membersworkspaces 1:N audit_eventsusers 1:N audit_events
설계 포인트
설계 포인트
이메일에는 citext 또는 lower 인덱스를 사용합니다
PostgreSQL에서 이메일 대소문자 중복을 막으려면 citext 확장이나 lower(email) unique index를 적용합니다.
소프트 삭제에는 부분 인덱스가 유용합니다
deleted_at이 null인 활성 워크스페이스만 이름 중복을 막으려면 WHERE deleted_at IS NULL 조건의 부분 인덱스를 둘 수 있습니다.
jsonb는 보조 정보에만 사용합니다
감사 로그 metadata처럼 이벤트마다 속성이 달라지는 데이터에는 jsonb가 좋지만, 자주 조인하거나 필터링하는 핵심 값은 컬럼으로 분리합니다.
구현 전 체크
구현 전 체크
- uuid 생성은 gen_random_uuid() 기본값을 사용합니다.
- created_at, updated_at은 timestamptz로 저장합니다.
- workspace_members는 복합 PK로 중복 멤버십을 막습니다.
SQL 예시
CREATE TABLE workspace_members (
workspace_id uuid REFERENCES workspaces(id),
user_id uuid REFERENCES users(id),
role text NOT NULL CHECK (role IN ('owner', 'editor', 'viewer')),
added_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (workspace_id, user_id)
);
다른 ERD 예시
다른 ERD 예시
예시를 그대로 따라 그리거나, 가입 전 데모 캔버스에서 테이블과 관계를 먼저 만져볼 수 있습니다.