Feature 10: Guilds & Social
Overview
Guilds (persistent groups up to 200 members with ranks, bank, leveling, and buffs), friends list, party formation for group content, and timed raid lobbies. Chat is handled externally via Discord — this feature covers the in-game social structures only.
Dependencies
- Feature 02 (Character Creation)
- Feature 09 (Economy) — guild bank, gold costs
Technical Tasks
1. Database Migrations
- Create migration
0009_create_social.sql:guilds: id, name (unique), tag (unique, 2-4 chars), leader_id, level, xp, bank_gold, active_buff, buff_expires, max_members, discord_invite_url, created_atguild_members: guild_id, character_id (PK), rank (leader/officer/member/recruit), joined_at- Index: guild_members(character_id)
friends: character_id, friend_id (PK), status (pending/accepted), created_atparties: id, leader_id, type (duo/standard/raid), max_size, status (forming/ready/in_run/completed), quest_id, scheduled_at, created_atparty_members: party_id, character_id (PK), role (tank/healer/dps/support), ready (bool)
2. Guild Logic (crates/game)
- Create
src/guilds.rs:GUILD_CREATION_COST: u64 = 10_000(gold)guild_max_members(guild_level: u16) -> u16: starts at 50, increases with levelguild_xp_for_level(level: u16) -> u64: XP required for next guild levelguild_buff_options() -> Vec<GuildBuff>:- +10% XP for 24 hours
- +10% gold for 24 hours
- -10% crafting time for 24 hours
- Only one buff active at a time
guild_buff_cost(buff: &GuildBuff) -> u64: gold cost from guild bank
3. Guild Queries (crates/db)
- Create
src/queries/guilds.rs:create_guild(pool, name, tag, leader_id) -> Guildfind_guild_by_id(pool, id) -> Option<Guild>find_guild_by_name(pool, name) -> Option<Guild>find_guild_members(pool, guild_id) -> Vec<GuildMember>find_character_guild(pool, character_id) -> Option<(Guild, GuildMember)>add_member(pool, guild_id, character_id, rank)remove_member(pool, guild_id, character_id)update_member_rank(pool, guild_id, character_id, new_rank)update_guild_settings(pool, guild_id, discord_url?)activate_guild_buff(pool, guild_id, buff, expires_at, cost)add_guild_xp(pool, guild_id, xp)
4. Party Queries (crates/db)
- Create
src/queries/parties.rs:create_party(pool, leader_id, type, quest_id?, scheduled_at?) -> Partyfind_party_by_id(pool, id) -> Option<Party>find_character_party(pool, character_id) -> Option<Party>add_party_member(pool, party_id, character_id, role)remove_party_member(pool, party_id, character_id)set_member_ready(pool, party_id, character_id, ready)check_all_ready(pool, party_id) -> boolupdate_party_status(pool, party_id, status)
5. Guild Routes (crates/api)
- Create
src/routes/guilds.rs:POST /api/guilds:- Body:
{ character_id, name, tag } - Validate: name/tag unique, character not in guild, has 10K gold
- Deduct gold, create guild, add creator as leader
- Body:
GET /api/guilds/:id:- Public info: name, tag, level, member count, leader name
GET /api/guilds/:id/members:- Member list with names, ranks, last active
POST /api/guilds/:id/join:- Body:
{ character_id } - Add as recruit (open join — no invite required for now)
- Validate: not already in a guild, guild not full
- Body:
POST /api/guilds/:id/leave:- Remove from guild. Leader cannot leave (must transfer leadership first)
POST /api/guilds/:id/invite:- Body:
{ character_name }— officer+ only
- Body:
PUT /api/guilds/:id/settings:- Body:
{ discord_invite_url? }— leader/officer only
- Body:
POST /api/guilds/:id/promote:- Body:
{ character_id, new_rank }— leader only
- Body:
POST /api/guilds/:id/kick:- Body:
{ character_id }— officer+ only, cannot kick higher rank
- Body:
POST /api/guilds/:id/buff:- Body:
{ buff_id }— officer+ only, deducts from guild bank
- Body:
POST /api/guilds/:id/bank/deposit:- Body:
{ character_id, amount }— deposit gold to guild bank
- Body:
POST /api/guilds/:id/transfer-leadership:- Body:
{ new_leader_id }— leader only
- Body:
6. Friends Routes (crates/api)
- Create
src/routes/social.rs:GET /api/characters/:id/friends:- Return friends list with status (pending/accepted), names, levels
POST /api/friends/add:- Body:
{ character_id, friend_name } - Create pending friend request
- Body:
POST /api/friends/accept/:friend_character_id:- Accept pending request (creates reciprocal entry)
DELETE /api/friends/:friend_character_id:- Remove friend (both directions)
7. Party Routes (crates/api)
- Create
src/routes/parties.rs:POST /api/parties:- Body:
{ leader_id, type, quest_id?, scheduled_at? } - Create party, add leader
- Body:
GET /api/parties/:id:- Party info: members, roles, ready status, quest, schedule
POST /api/parties/:id/join:- Body:
{ character_id, role } - Validate: party not full, correct type limits (duo=2, standard=4, raid=8)
- Body:
POST /api/parties/:id/leave:- Remove from party. If leader leaves, disband.
POST /api/parties/:id/ready:- Body:
{ character_id }— toggle ready status
- Body:
POST /api/parties/:id/start:- Leader only, all members must be ready
- Start group run (uses Feature 07 run system with party_id)
8. Client — Guild & Social UI
- Create
routes/(game)/guild/+page.svelte:- Guild overview: name, tag, level, XP bar, member count
- Member list: name, rank, last active, promote/kick actions
- Guild bank: current gold, deposit button
- Active buff display with “Activate Buff” selector
- Discord link button
- Settings (for officers+): Discord URL
- Create
routes/(game)/social/+page.svelte:- Friends tab: friends list, add friend input, pending requests
- Parties tab: current party, create party, join party
- Create party lobby view for group content coordination
Tests
Unit Tests
guild_max_members: 50 at level 1, scales correctlyguild_buff_cost: returns correct costs per buff type- Guild rank hierarchy: leader > officer > member > recruit
Integration Tests
POST /api/guildscreates guild, deducts 10K goldPOST /api/guildsrejects when already in a guildPOST /api/guildsrejects duplicate name/tagPOST /api/guilds/:id/joinadds as recruitPOST /api/guilds/:id/joinrejects when guild fullPOST /api/guilds/:id/leaveremoves memberPOST /api/guilds/:id/leaveby leader → 409POST /api/guilds/:id/promotechanges rankPOST /api/guilds/:id/kickremoves member (officer+)POST /api/guilds/:id/kickrejects kicking higher rankPOST /api/guilds/:id/buffactivates buff, deducts from bankPOST /api/guilds/:id/buffrejects when buff already activePOST /api/guilds/:id/bank/depositadds gold to guild bankPOST /api/guilds/:id/transfer-leadershipchanges leaderPOST /api/friends/addcreates pending requestPOST /api/friends/acceptcreates mutual friendshipDELETE /api/friends/:idremoves both directionsPOST /api/partiescreates party with leaderPOST /api/parties/:id/joinadds member up to maxPOST /api/parties/:id/startstarts group run when all readyPOST /api/parties/:id/startrejects when not all ready