Guild Schema¶
guildschema 는 Umbra 가 관리하는 Discord 길드 메타데이터와 길드별 설정을 저장한다.
Schema purpose¶
- PostgreSQL schema —
guild - Corresponding domain —
engine/guild/ - sqlc package —
db/queries/guild/
Guild 는 License, Subscription, Snapshot, Member 등 많은 도메인이 참조한다. 안정적 키와 slug 관리가 핵심.
Tables¶
guild.guilds¶
Discord 길드의 Umbra 내부 표현.
CREATE TABLE guild.guilds (
id UUID PRIMARY KEY,
discord_guild_id TEXT NOT NULL,
name TEXT NOT NULL,
icon_hash TEXT,
slug TEXT NOT NULL,
owner_user_id UUID REFERENCES identity.users(id),
owner_discord_id TEXT NOT NULL,
bot_installed_at TIMESTAMPTZ NOT NULL,
bot_removed_at TIMESTAMPTZ,
deleted_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT guilds_discord_guild_id_unique UNIQUE (discord_guild_id),
CONSTRAINT guilds_slug_unique UNIQUE (slug),
CONSTRAINT guilds_slug_format CHECK (slug ~ '^[a-z0-9-]{3,30}$')
);
Columns
| Column | Type | Constraints | Description |
|---|---|---|---|
id | UUID v7 | PK | Umbra 내부 Guild ID |
discord_guild_id | TEXT | UNIQUE, NOT NULL | Discord snowflake |
name | TEXT | NOT NULL | 길드 이름 (캐시) |
icon_hash | TEXT | — | Discord icon hash |
slug | TEXT | UNIQUE, NOT NULL | 웹 조인 URL 용 |
owner_user_id | UUID | FK nullable | → identity.users.id, Owner 가 Umbra 가입 안 했으면 NULL |
owner_discord_id | TEXT | NOT NULL | Discord user snowflake (항상 저장) |
bot_installed_at | TIMESTAMPTZ | NOT NULL | 최초/최근 봇 설치 시각 |
bot_removed_at | TIMESTAMPTZ | — | 봇 강퇴 시각. 재설치 시 NULL 로 복원 |
deleted_at | TIMESTAMPTZ | — | Discord 길드 자체 삭제 시 |
created_at | TIMESTAMPTZ | NOT NULL | |
updated_at | TIMESTAMPTZ | NOT NULL |
Indexes
| Index | Columns | Purpose |
|---|---|---|
guilds_pkey | (id) | PK |
guilds_discord_guild_id_unique | (discord_guild_id) | Discord ID 조회 |
guilds_slug_unique | (slug) | 웹 조인 slug 조회 |
guilds_owner_user_idx | (owner_user_id) WHERE owner_user_id IS NOT NULL | owner 의 길드 목록 |
guilds_active_idx | (id) WHERE bot_removed_at IS NULL AND deleted_at IS NULL | 활성 길드 |
Foreign keys
| Column | References | On delete |
|---|---|---|
owner_user_id | identity.users(id) | SET NULL (owner 가 탈퇴해도 Guild 유지) |
Invariants
slug형식: 소문자 영숫자 + 하이픈, 3~30자 (CHECK 제약)bot_removed_at이 NULL 이 아니면 실제 봇 부재 상태deleted_at설정 시 복구 불가능 상태
guild.guild_configs¶
길드별 Umbra 설정. Guild 와 1:1.
CREATE TABLE guild.guild_configs (
guild_id UUID PRIMARY KEY REFERENCES guild.guilds(id),
notification_channel_id TEXT,
web_join_auto_role_id TEXT,
antinuke_enabled BOOLEAN NOT NULL DEFAULT FALSE,
antinuke_auto_action BOOLEAN NOT NULL DEFAULT FALSE,
antinuke_thresholds JSONB NOT NULL DEFAULT '{}',
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Columns
| Column | Type | Constraints | Description |
|---|---|---|---|
guild_id | UUID | PK, FK | → guilds.id |
notification_channel_id | TEXT | — | Umbra 알림 채널 (Discord channel snowflake) |
web_join_auto_role_id | TEXT | — | 웹 조인 시 자동 부여 역할 |
antinuke_enabled | BOOLEAN | NOT NULL | Pro 이상에서만 true 가능 |
antinuke_auto_action | BOOLEAN | NOT NULL | Enterprise 에서만 true 가능 |
antinuke_thresholds | JSONB | NOT NULL | 커스텀 임계값 (비어있으면 기본값 사용) |
updated_at | TIMESTAMPTZ | NOT NULL |
Foreign keys
| Column | References | On delete |
|---|---|---|
guild_id | guild.guilds(id) | CASCADE |
Invariants
antinuke_auto_action = true이면antinuke_enabled = true필수 (애플리케이션 레벨)- Plan 불일치 체크 (Free 에서
antinuke_enabled = true불가) 는 Licensing 에서 강제 antinuke_thresholdsJSONB 예시:
{
"mass_role_delete": { "count": 5, "window_seconds": 300 },
"mass_channel_delete": { "count": 3, "window_seconds": 300 },
"mass_kick": { "count": 10, "window_seconds": 300 }
}
Relationships¶
erDiagram
GUILDS ||--|| GUILD_CONFIGS : has
GUILDS ||--o{ MEMBERS : contains
GUILDS ||--o{ LICENSES : licensed
GUILDS ||--o{ SNAPSHOTS : backed_up
USERS ||--o{ GUILDS : owns
Cross-schema references¶
| From | To | Semantics |
|---|---|---|
guild.guilds.owner_user_id | identity.users.id | Owner |
member.members.guild_id | guild.guilds.id | 멤버가 속한 길드 |
licensing.licenses.guild_id | guild.guilds.id | 길드 권한 |
billing.subscriptions.guild_id | guild.guilds.id | 길드 구독 |
recovery.snapshots.guild_id | guild.guilds.id | 길드 스냅샷 |
recovery.antinuke_incidents.guild_id | guild.guilds.id | AntiNuke 감지 이력 |
Query patterns¶
GetGuildByID— 내부 PK 조회GetGuildByDiscordID— Discord ID 로 조회GetGuildBySlug— 웹 조인용InsertGuildOnBotInstall— 봇 설치 시 upsertMarkBotRemoved— 강퇴 처리MarkGuildDeleted— 길드 삭제 처리UpdateOwner— owner 변경UpsertGuildConfig— 설정 저장ListActiveGuildsOfUser— 대시보드의 내 길드 목록
Data retention¶
- Guilds — 영구 보관 (감사 목적).
deleted_atsoft delete. - Guild configs — Guild CASCADE
- 봇 강퇴 후에도 60일간 License/Subscription 을 suspend 상태로 유지 → 재설치 시 복구 가능
Migration history¶
| Date | Change | Rationale |
|---|---|---|
| 2026-04-xx | 초기 스키마 | MVP |
See also¶
domain/guild.md— Guild 도메인data/schema-overview.md— 전체 스키마 관계data/licensing-schema.md— 참조하는 Licenseadr/0020-postgres-schema-per-domain.md— schema 분리