Files
2nd/10_Wiki/Topics/Architecture/Alliance_(동맹).md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

190 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: wiki-2026-0508-alliance-동맹
title: Alliance (동맹)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Guild, Clan, Faction, 동맹]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [game-design, social-systems, mmo, architecture]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: Game backend (Colyseus, Nakama, custom)
---
# Alliance (동맹)
## 매 한 줄
> **"매 player-formed group — shared goals, shared resources, shared identity"**. 매 MMO/SLG 의 retention 핵심 system. 매 EverQuest guild (1999) → World of Warcraft guild (2004) → Lords Mobile/Rise of Kingdoms 동맹 (2017+). 매 2026 modern SLG (4X/RTS hybrid) 의 core loop driver — solo player retention < 7 days, alliance member retention > 90 days 의 typical metric.
## 매 핵심
### 매 구조
- **Membership tier**: Leader / Officers (R4/R5) / Members / Recruits.
- **State**: roster, treasury, buff inventory, war declarations, territory.
- **Permissions**: hierarchical RBAC — invite/kick/promote/demote/disband.
- **Lifecycle**: create → recruit → grow → war → decline → disband.
### 매 server-authoritative invariants
- 매 single alliance per player 의 enforcement (atomic).
- Member cap (typical 50100) — atomic check-and-insert.
- Treasury balance — race-free debit/credit (transactional).
- War state machine — pending/active/peace transitions.
### 매 응용
1. **SLG 4X game** (Lords Mobile pattern) — alliance buffs, rallies, KvK.
2. **MMO guild** (WoW pattern) — guild bank, calendar, perk levels.
3. **Mobile RPG clan** (Clash of Clans pattern) — clan wars, donations.
4. **Social fitness app** (Strava clubs) — challenges, leaderboards.
## 💻 패턴
### Schema (Postgres)
```sql
CREATE TABLE alliances (
id BIGSERIAL PRIMARY KEY,
tag VARCHAR(5) UNIQUE NOT NULL,
name VARCHAR(40) NOT NULL,
leader_id BIGINT NOT NULL REFERENCES players(id),
member_cap SMALLINT NOT NULL DEFAULT 50,
treasury_gold BIGINT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE alliance_members (
player_id BIGINT PRIMARY KEY REFERENCES players(id),
alliance_id BIGINT NOT NULL REFERENCES alliances(id) ON DELETE CASCADE,
rank SMALLINT NOT NULL, -- 1=member..5=leader
joined_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX ON alliance_members (alliance_id);
```
### Atomic join (server)
```typescript
async function joinAlliance(playerId: bigint, allianceId: bigint) {
return await db.tx(async (t) => {
// 1. Player must not be in any alliance
const existing = await t.oneOrNone(
"SELECT 1 FROM alliance_members WHERE player_id=$1 FOR UPDATE", [playerId]);
if (existing) throw new Error("ALREADY_IN_ALLIANCE");
// 2. Member cap check (lock alliance row)
const a = await t.one(
"SELECT member_cap, (SELECT COUNT(*) FROM alliance_members WHERE alliance_id=$1)::int AS n " +
"FROM alliances WHERE id=$1 FOR UPDATE", [allianceId]);
if (a.n >= a.member_cap) throw new Error("ALLIANCE_FULL");
await t.none(
"INSERT INTO alliance_members(player_id, alliance_id, rank) VALUES($1,$2,1)",
[playerId, allianceId]);
});
}
```
### Permission check
```typescript
const PERMS = {
invite: 2, // R2+
kick: 3, // R3+
promote:4, // R4+
disband:5, // leader only
} as const;
function can(memberRank: number, action: keyof typeof PERMS): boolean {
return memberRank >= PERMS[action];
}
```
### Alliance chat (Redis pub/sub)
```typescript
// Publish
await redis.publish(`alliance:${allianceId}:chat`,
JSON.stringify({ from: playerId, msg, ts: Date.now() }));
// Subscribe (per connected client)
const sub = redis.duplicate();
await sub.subscribe(`alliance:${allianceId}:chat`, (raw) => {
ws.send(raw);
});
```
### War declaration state machine
```typescript
type WarState = "PEACE" | "PENDING" | "ACTIVE" | "COOLDOWN";
const transitions: Record<WarState, WarState[]> = {
PEACE: ["PENDING"],
PENDING: ["ACTIVE", "PEACE"],
ACTIVE: ["COOLDOWN"],
COOLDOWN: ["PEACE"],
};
function transition(from: WarState, to: WarState) {
if (!transitions[from].includes(to))
throw new Error(`INVALID_TRANSITION ${from}->${to}`);
}
```
### Treasury (idempotent donation)
```typescript
async function donate(playerId: bigint, amt: bigint, idemKey: string) {
await db.tx(async (t) => {
const dup = await t.oneOrNone(
"SELECT 1 FROM idempotency WHERE key=$1", [idemKey]);
if (dup) return;
await t.none("INSERT INTO idempotency(key) VALUES($1)", [idemKey]);
await t.none("UPDATE players SET gold = gold - $2 WHERE id=$1 AND gold >= $2", [playerId, amt]);
await t.none("UPDATE alliances SET treasury_gold = treasury_gold + $2 WHERE id=$1", [allianceId, amt]);
});
}
```
### Member roster cache invalidation
```typescript
async function onMembershipChange(allianceId: bigint) {
await redis.del(`alliance:${allianceId}:roster`);
await redis.publish(`alliance:${allianceId}:events`, JSON.stringify({type:"ROSTER_CHANGED"}));
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Casual mobile, < 30 members | Single-shard SQL, simple roster |
| MMO, 100+ members, real-time chat | Sharded SQL + Redis pub/sub |
| Cross-server alliance war (KvK) | Event-sourced log + global service |
| Persistent territory control | Server-authoritative grid + alliance ownership |
**기본값**: 매 Postgres alliance/member tables + Redis pub/sub for chat/presence + idempotent treasury operations.
## 🔗 Graph
- 변형: [[Guild]] · [[Clan]] · [[Faction]]
- Adjacent: [[Leaderboard]]
## 🤖 LLM 활용
**언제**: 매 long-session retention 의 game (MMO, SLG, persistent world), 매 social cooperation 의 core mechanic.
**언제 X**: 매 short-session arcade, 매 strict-PvP only without cooperation, 매 < 1k DAU 의 single-player feel.
## ❌ 안티패턴
- **Client-authoritative membership**: 매 cheat 의 trivial (forge join). 매 server-authoritative 만.
- **No member cap**: 매 mega-alliance dominance — 매 game balance 의 destruction.
- **Synchronous broadcast**: 매 large alliance (500+) 의 chat fan-out blocks. 매 async pub/sub 의 사용.
- **Disband without grace period**: 매 leader 의 grief vector. 매 24h cooldown.
## 🧪 검증 / 중복
- Verified (Lords Mobile design, EVE Online corporation system, WoW guild system, Clash of Clans clan system).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content (game alliance system architecture) |