# REQ-2026-04-15-reaction-roles

**From:** Chronicler #92  
**Date:** 2026-04-15  
**Priority:** HIGH — pre-launch  
**Status:** PENDING

## Summary

Add reaction role handling to Arbiter. The `#get-roles` channel has been rebuilt with bot-owned messages. Need Arbiter to handle all three reaction role sets.

## Message IDs (bot-owned, in #get-roles)

| Message ID | Purpose |
|---|---|
| `1493930565395681402` | Choose Your Path |
| `1493930595435286548` | Notification Preferences |
| `1493930614066253908` | Server Roles |

## Emoji → Role Mappings

### Message 1 — Choose Your Path
| Emoji | Role ID | Role Name |
|---|---|---|
| 🔥 | `1482490890453782612` | 🔥 Fire Path |
| ❄️ | `1482491234378448946` | ❄️ Frost Path |

### Message 2 — Notification Preferences
| Emoji | Role ID | Role Name |
|---|---|---|
| 📢 | `1491778391060381776` | Announcements |
| 🎉 | `1491778662922457199` | Events |
| 🗒️ | `1491778706312532171` | Patch Notes |

### Message 3 — Server Roles
| Emoji | Role ID | Role Name |
|---|---|---|
| 🪨 | `1491028769132253274` | Stoneblock 4 |
| 🏝️ | `1491028496284258304` | All The Mods: To the Sky |
| 🔴 | `1491029000108380170` | All The Mons |
| 🧙 | `1491029070190870548` | Mythcraft 5 |
| ⚔️ | `1491029454011629749` | Otherworld [Dungeons & Dragons] |
| 🧟 | `1491029615739801800` | DeceasedCraft |
| 🍽️ | `1493352900997415134` | Farm Crossing 6 |
| 🏡 | `1491030015746510939` | Homestead |
| 🌌 | `1491028885981102270` | Society: Sunlit Valley |
| 🌊 | `1491029215963906149` | Beyond Depth |
| ☁️ | `1491029284159094904` | Beyond Ascension |
| 🏆 | `1491029373640376330` | Wold's Vaults |
| 🤿 | `1491029708878647356` | Submerged 2 |
| 🌙 | `1491029870002569298` | Cottage Witch |
| 🌿 | `1493924685170343978` | vanilla |

## Files to Create/Modify

### 1. CREATE `src/discord/reactionRoles.js`
- Export a `REACTION_ROLE_MAP` object keyed by message ID
- Each entry maps emoji name/id → Discord role ID
- Export `handleReactionAdd(reaction, user)` and `handleReactionRemove(reaction, user)`
- Fetch partial reactions if needed (`reaction.partial`)
- Skip bot reactions
- Look up guild member and add/remove role

### 2. MODIFY `src/index.js`
- Add `GatewayIntentBits.GuildMessageReactions` to the client intents

### 3. MODIFY `src/discord/events.js`
- Import reactionRoles handlers
- Register `messageReactionAdd` and `messageReactionRemove` events on the client

## Notes
- Follow the existing pattern in events.js (clean, minimal)
- Silent-fail on missing roles/members (don't crash)
- Log adds/removes to console for debugging
- Deploy pattern: backup → clone to /tmp → copy to /opt/arbiter-3.0 → restart arbiter-3


---

## Additional Scope — Carl-bot Migration

Take over these two Carl-bot behaviors so Carl-bot can be removed.

### 4. MODIFY `src/discord/events.js`
Register `guildMemberAdd` event:
- Assign Wanderer role (`1487267974367805545`) to new member
- Send welcome DM:

```
Hey {username}! Welcome to Firefrost Gaming!
You just landed as a Wanderer — the door is open, come explore!

Quick links:
• Check out #rules first
• Say hi in #introductions
• Head to #get-roles to pick your path and grab your server channels

Questions? We're here. Welcome to the family!
```

- Silent-fail if DMs are closed

### 5. MODIFY `src/services/discordRoleSync.js` (or stripe.js)
When a subscriber reaches Awakened tier or above (i.e. after successful Stripe checkout assigns their role), send them a DM:

```
Hey {username}! You're now part of the Firefrost family! 🎉

One quick step — head to #link-your-account and use the /link command to connect your Minecraft account so we can whitelist you on our servers.

See you in-game!
```

- This should fire from the Stripe checkout flow after role assignment
- Silent-fail if DMs are closed

### Notes
- `GuildMembers` intent is already enabled — `guildMemberAdd` will work
- Check where luckpermsSync fires post-checkout — link reminder DM should fire at the same point
