-
Notifications
You must be signed in to change notification settings - Fork 0
Feature Roadmap
A living document describing what's planned, why, and the concrete steps to ship it. Each feature also has a card on the Bot Development project board with a matching breakdown — bring those into "In Progress" when you start, and use the implementation steps below as the punch list.
- ✅ Shipped — running in production, documented, and wired into
/help - 🟡 Infrastructure ready — schema and/or
/sudo → Settingstoggle exists, but the user-facing behavior hasn't been built - 🔵 Designed — concept agreed, scope written, no infrastructure yet
- 💭 Idea — bullet on a napkin; needs more thought before estimating
The 0.7.x and 0.8.x lines covered most of the original Phase 5/6 backlog:
- ✅ Auto voice channels with persistent control panel — hubs rename in place, replacement hub spawns, attached private text channel, sticky 📋 Open Panel button, reconciler on startup
- ✅ Voice control panel buttons — Rename, Lock/Unlock, Hosts (single panel listing all members with rank emojis), Templates (Auto / Counter / Comp 5-stack / Tryhard / Chill), Claim, Delete
- ✅ Random tech default channel names —
Sloppy Ethernetstyle fallback when no rich-presence game is active - ✅
/reportflow — modal → owner DM with Approve/Reject (notify or silent) → GitHub issue - ✅
/sudo → Settingspanel — runtime config for sudo users, channels, voice cleanup delay, and the auto-thread channel list. Backed bybot_settings(key/value overrides),sudo_users(members granted sudo at runtime), andauto_thread_channels(the dynamic auto-thread list). See Slash Commands for the full sub-panel reference. - ✅ Auto Threads — channels added under
/sudo → Settings → Auto Threadsget a public thread on every non-bot message. Default thread name{author} — {first line}(100-char cap). Backed byauto_thread_channels. Requires theMessageContentprivileged intent. Shipped as a single dynamic list rather than the per-channel feature flags originally drafted (clips/food were collapsed into one panel during implementation).
Not features — operational items that unblock everything else.
- Verify
AUTO_VOICE_CATEGORY_IDandHUB_CHANNEL_IDSin.envare correct for the ITSRI guild — see issue #3 - Enable Presence Intent in Discord Developer Portal — issue #4 (resolved)
- GitHub Actions auto-deploy on push to main — done end-to-end
What it does. Once a day at a configured time, the bot reads user_profiles.birthday_month / birthday_day, finds members whose birthday is today (in their timezone, if set), and posts a celebratory message in the configured birthday channel. Birthdays are month/day only — no year stored or shown unless the user explicitly opts in to age display.
Infrastructure already in place.
-
user_profilesschema hasbirthday_monthandbirthday_dayinteger columns -
channel.birthdaysetting exists -
BIRTHDAY_CHANNEL_IDenv fallback is documented
Missing — implementation steps.
Step 1 — User-facing input UI.
- Add a birthday section to
/squishy(or a dedicated/birthdaycommand if cleaner) with a modal: month (number 1–12), day (number 1–31), optional timezone (string). Validate via Zod; reject Feb 30 etc. - Add
birthday_year_visibleboolean column touser_profiles(drizzle-kit push) for opt-in age display later. - Persist via the
userProfilesschema. Update theUser Profilesplaceholder in/sudo → Settingsto show the current count of users with birthdays set.
Step 2 — Daily scheduler.
4. New service src/services/birthdayScheduler.ts. On clientReady, schedule a setInterval-style job that fires once per minute and checks the wall-clock time against a configurable target (default 09:00 server time). Use a "last-run-date" file or DB row (bot_settings key birthday.last_run_date) to prevent double-firing on restart.
5. Query: SELECT user_id FROM user_profiles WHERE birthday_month = $1 AND birthday_day = $2 AND guild_id = $3.
6. For each match, format a message: 🎂 Happy birthday, <@${userId}>! 🎉 with random flavor lines (small array of variants).
7. Post to getSetting('channel.birthday') ?? env.BIRTHDAY_CHANNEL_ID.
Step 3 — Edge cases & opt-out.
8. Opt-out flag — add birthday_pings_enabled (default true) to user_profiles. Skip pings for users who opted out.
9. February 29 — if today is Feb 29 and the user's birthday is Feb 29, post normally; if today is Feb 28 in non-leap years and the user is Feb 29, decide whether to post early (default: yes, with a note).
10. Members who left the guild — skip; don't ping IDs that no longer resolve.
Step 4 — Docs.
11. README "Planned Features" → "Features" + add a row to the slash command table for the new birthday command.
12. Wiki Slash-Commands page + Database-Schema (birthday_pings_enabled, birthday_year_visible columns).
13. CHANGELOG.
Acceptance criteria.
- A user can set their birthday via Discord without admin help.
- On the day of their birthday, a single ping fires in the birthday channel.
- A user who opted out gets no ping even on their birthday.
- Bot restart on the day of someone's birthday doesn't double-ping (idempotency check).
What it does. A sudo-facing editor (under /sudo → Settings → User Profiles) plus a self-service flow (under /squishy) for users to manage their stored profile fields: display name, real name (sudo-only), staff category/department/tier, leadership title, birthday, opt-out toggles.
Infrastructure already in place.
-
user_profilesschema already has all the fields (real_name,display_name,birthday_*,staff_category,department,tier,leadership_title) -
/sudo → Settings → User Profilesplaceholder panel (read-only count) is wired
Missing — implementation steps.
-
Self-service
/profilecommand — modal-based editor fordisplay_nameandbirthday_*. Other fields are sudo-only. - Sudo browse UI — replace the placeholder panel with: paginated user search (by Discord display name or stored display name), pick a member → form view → editable rows (channel/role pickers where appropriate, modals for free text).
-
Auto-create profile rows on first interaction — when
/squishy,/profile, or any flow first touches a user, upsert auser_profilesrow keyed by(guild_id, user_id). -
Schema additions —
birthday_pings_enabled,birthday_year_visible(covered in birthday pings task above; do whichever ships first). -
Cross-feature usage — pre-fill
display_nameinto/staff requestmodal default, and usedisplay_namein birthday ping copy when available. -
Audit logging — every sudo edit writes to a new
audit_logstable mirroring otterbot's pattern (or reuses if it gets factored out).
Acceptance criteria.
- A user can update their own display name and birthday without sudo.
- Sudo can view + edit any field on any user, with an audit trail.
- The User Profiles count on the Settings panel reflects reality.
The largest planned feature. Three coordinated pieces: definitions, opt-in, and pings.
What it does. Members opt into game-specific Discord roles. Each game has an associated channel (or category), an optional separate "ping role" used only for LFG pings, and visibility/archive toggles. /play <game> lets opted-in members ping the ping-role for a session, with metadata like party size and time.
Infrastructure already in place.
-
gamesschema:name,role_id,channel_id,category_id,ping_role_id,is_archived,is_visible,sort_order,aliases -
user_game_prefsschema: per-user opt-in for view + ping -
/sudo → Settings → Gamesplaceholder panel (read-only count)
Missing — implementation steps.
Step 1 — Definitions (sudo-side).
- Replace the Games placeholder panel with a list view + add/edit/archive flow. Adding a game: name, optional aliases, role picker (or "create new role" button), channel picker, ping-role picker (optional, defaults to view role), category picker, sort order.
- CRUD operations + audit log entries for adds/removes/archive.
Step 2 — Member opt-in.
3. New /games command — opens a paginated select with all is_visible=true && is_archived=false games. Per-game: a row of two buttons, "View access" and "LFG pings", that toggle user_game_prefs.view_enabled and .ping_enabled. Toggling view assigns/removes the view role on Discord; toggling ping does the same for the ping role.
4. Hide archived games from the list.
Step 3 — /play LFG pings.
5. New /play <game> command with options: party_size? (int 1–32), when? (string), platform?, rank?, message? (free text 200 chars).
6. Resolve game via name or aliases (case-insensitive).
7. Post in the game's channel; ping ping_role_id. Format: ${pingRoleMention} **LFG: ${game}** — host ${authorMention}, ${partySize} needed, ${when}\n${message}.
8. Rate limiting — store last /play time per (guild_id, user_id, game_id) in a new play_pings table; reject if < 30 minutes since last. Sudo can override.
9. Anti-abuse — never @everyone or @here regardless of options. Sanitize message to strip role/user mentions outside of the host's allowed set.
Step 4 — Polish.
10. /games list shows current member count per game (pull live from the role).
11. Sort order respected in /games list.
12. Migrating archived games — keep the role but stop showing in /games.
Step 5 — Docs + project hygiene. 13. README, /help, wiki Slash-Commands + Database-Schema, CHANGELOG. 14. Move all sub-tasks above into individual project items if scope creeps; otherwise keep under one card with checkboxes.
Acceptance criteria.
- Sudo can add a new game in under a minute via
/sudo → Settings → Games. - A regular member can opt into View + Pings for two games via
/gamesand see the new roles immediately. -
/play valorant party_size:5 when:9pmpings the right role in the right channel and is rate-limited. - Archived games disappear from
/gamesbut existing role memberships are preserved.
Light sketches — bring one to "Designed" status before it goes on the project board.
-
Voice channel "party" / LFG mode — members in an auto-channel can mark themselves LFG; the channel name appends
(LFG x/y)and a button lets others join. - Auto-name cycling — if the rich-presence game changes mid-session, the auto-channel name updates to match (with rate-limit guards — Discord limits channel renames to 2/10min).
- Voice channel stats — per-channel/-hub time totals, peak concurrent counts, top creators per month. Read-only sudo dashboard.
-
OC-style stock widget for other businesses — port otterbot's
oc_stockpattern if a non-MKE business in the server wants the same kind of board. -
External webhook intake —
POST /webhook/<token>endpoint that posts to a configured channel (e.g. for GitHub Actions completion notices, Grafana alerts). Would require a small HTTP server alongside the Discord client. -
Configurable thread archive duration — extend the auto-thread feature to expose
60/1440/4320/10080minutes per channel.
- When you start working on a feature, move its project board card to In Progress.
- Add a corresponding
## [Unreleased]entry inCHANGELOG.mdwith the same name. - Treat the implementation steps above as a checklist — tick them off in commit messages or PR description.
- When the feature ships, move the card to Done, mark the row above ✅ Shipped, and prune steps from this page (keep the headline + 1-line summary so the history is readable).