Phantom — Platform Features & UX Review (July 2026)
A deep code analysis of the entire platform (Laravel dashboard + Node bot, ~50 bot modules, ~90 dashboard pages) with concrete, code-grounded recommendations for what to add, improve, and expand. Every "missing" claim below was verified against the actual code, with file references.
Executive summary
Phantom is unusually strong in security (Wick-tier: anti-raid, anti-nuke, firewall, honeypot, phantom-network threat sharing), tickets (transcripts, canned responses, ratings — Ticket Tool-tier), moderation (cases + a full appeals system), and it has several genuinely uncommon modules (reviews, partnerships, interactive panels, custom bots, auto-assist RAG AI). The dashboard already has best-in-class bones: searchable Discord-populated channel/role pickers, live embed previews, placeholder pickers, team-role permission delegation, and an onboarding tour.
The biggest opportunities, in order of impact:
- Streamer alerts are global-only — one channel, one message, one ping role shared by all 25 streamers per platform. Per-streamer overrides is the single highest-value upgrade and directly matches what Streamcord/Pingcord users expect.
- 28 of the 33 documented outbound webhook events never fire. The whole webhook infrastructure (signing, retries, dashboard UI, docs) exists, but the bot never emits. Finishing this turns a dead feature into a real developer platform.
- Economy has no shop, no bank, no activities — the module header itself says "future shop purchases."
- Levelling lacks image rank cards and role/channel XP multipliers — table stakes vs MEE6/Arcane, and the canvas infra already exists in
welcome/image.js. - Dashboard has no settings change-history and no config export/import — the biggest day-to-day admin pain for team-run and multi-server owners.
1. Streamer alerts — the headline upgrade
Current state (verified)
- Platforms: Twitch (EventSub push + Helix polling backstop), YouTube (page scrape + Atom feed), Kick (public API), TikTok (multi-fallback scrape). Uploads/VODs announced for all four via a 5-min video sweep.
- Config is stored per platform as a JSON blob on
guild_settings(twitch_config, etc.). Per guild per platform: onechannel_id, oneping_role_id, up to 5live_role_ids, onemessagetemplate (500 chars), one keyword/game filter set, and a list of up to 25 streamers. - Per-streamer, the only stored data is: username/handle, display name, and an optional linked Discord member (used for the live role). Nothing else. (
bot/src/streamer-alerts/registry.js:76-140) - The embed is fully hardcoded in
bot/src/streamer-alerts/announce.js:94-108— fixed per-platform color, fixed layout, fixed fields. Themessagetemplate only prepends text above it. - Stream-end handling: edits the announcement to a fixed grey "ended" card. No delete option, no VOD link, no duration/peak stats.
1a. Per-streamer overrides (the core ask)
Add an optional overrides object to each entry in streamers[]/creators[], falling back to the platform-level config when unset:
{
"username": "shroud",
"display_name": "Shroud",
"discord_user_id": "…",
"overrides": {
"channel_id": "…", // per-streamer announcement channel
"message": "…", // per-streamer go-live message
"ping_role_id": "…", // per-streamer ping role
"live_role_ids": ["…"], // per-streamer live role(s)
"filters": { … }, // per-streamer title/category filters
"enabled": true, // pause one streamer without removing them
"embed": { … } // see 1b
}
}Implementation notes:
registry.jscurrently builds onesliceper (guild, platform) applied to every streamer. Change the slice builders to resolvestreamer.overrides ?? platformDefaultsper entry — the poller and announce paths already operate per-streamer state row, so the change is contained to slice resolution + controller validation.- Dashboard: each row in the "Tracked streamers" list gets an expandable "Customise" section (channel picker, message textarea with placeholder picker, role pickers) that shows "Using server default" until overridden. The existing
channel-picker/role-picker/placeholder-pickerBlade components drop straight in. - Keep controllers'
normalize()clamping caps per override (reuse existing limits).
1b. Custom embed builder for alerts
The repo already has a full Embed Builder (EmbedBuilderController, live Discord-styled preview at resources/views/dashboard/embed-builder/_edit_preview.blade.php) — it just isn't wired to streamer alerts. Let admins either:
- pick a saved embed template per platform (and per streamer via overrides), with alert placeholders resolved at send time; or
- use a scoped inline builder: color, title, description, show/hide viewer count & category fields, image vs thumbnail, author icon (streamer avatar — already cached in
discord_avatar_urlbut never used in embeds), footer.
Also add an optional "Watch now" link button (message components) — cheap and looks premium.
1c. Preview / test send
There is currently no way to see an announcement without a real go-live (verified: no test route or UI in any of the four views). Add:
- a live preview pane (same pattern as the embed builder preview) rendering the message + embed with sample data; and
- a "Send test alert" button that posts a real test announcement to the configured channel with fake stream data. One route + a
buildLivePayload()call with a synthetic stream object.
1d. Richer placeholders & docs
- Current:
{streamer} {title} {game} {url}(Twitch/Kick),{creator} {title} {url} {type}(YT/TikTok).{creator}and{type}work but are undocumented in the UI. - Add:
{viewers},{platform},{member}(mention of the linked Discord member),{timestamp},{profile_image}(for embed use), and unify{streamer}/{creator}as aliases everywhere. - Surface all of them in the existing placeholder-picker component instead of the static hint text.
1e. Stream-end & lifecycle options
- Per platform (and per-streamer override): on stream end → edit to ended card (current), delete announcement, or leave as-is.
- Enrich the ended card: stream duration, peak/average viewers (the poller already sees viewer counts every sweep — track max in the state row), and a VOD link when the video sweep finds one.
- Customisable ended message template (currently a fixed grey card).
- Optional per-streamer re-announce cooldown (suppress rapid offline/online flaps beyond the existing debounce).
1f. Distribution & platform expansion
- Crosspost/publish automatically when the alert channel is an Announcement channel (one API call, big multiplier for community servers).
- Optional auto-thread per stream ("discuss the stream here").
- Kick webhooks:
kick.js:11-13already notes Kick's officiallivestream.statuswebhook as a future option — implement it to cut the 45s poll latency. - New platforms, in rough order of demand/effort: Trovo, Rumble, Facebook Gaming.
- Unify the four dashboard pages (Twitch/YouTube/Kick/TikTok) into one "Streamer Alerts" surface with per-platform tabs — a streamer active on two platforms is currently configured twice with duplicated UI.
1g. Caps as premium levers
25 streamers/platform and 5 live roles are low vs competitor premium tiers (50–100+). Keep 25 for Pro base, sell higher caps in a future tier (see §6).
2. New notification platforms (beyond streamers)
Verified: the only external-content alert system is streamer-alerts. Twitter/X, Reddit, Instagram, RSS etc. appear only as decorative profile links in PublicLinkSanitiser — there is no poller for any of them.
Recommended additions, ordered by effort-to-value:
- RSS/Atom feeds — easiest (the YouTube watcher already parses Atom). Generic "post new feed items to a channel" with template + filters. Unlocks blogs, patch notes, subreddits-via-RSS, itch/Steam news.
- Reddit — new posts in a subreddit (public JSON API), with flair/keyword filters. Huge for gaming communities.
- Bluesky — public firehose/API, trivially pollable, growing creator base.
- Twitter/X — high demand but API pricing is hostile; consider only if a paid API budget exists (or accept RSS-bridge fragility).
All of these slot into the existing streamer-alerts architecture (registry → poller sweep → announce with template), so the marginal cost per platform is low.
3. Finish the half-built features (quick wins, verified in code)
| Item | Where | State |
|---|---|---|
| Outbound webhook events | config/api.php defines 33 event types; WebhookEvents::emit() called in only 3 PHP places | 28/33 events never fire. The bot (where joins, tickets, level-ups, giveaways, automod, starboard, modmail happen) emits zero. Recommended: bot-side emission via the existing Postgres NOTIFY pattern → PHP WebhookDispatcher, which already has signing, retries, auto-disable, and dashboard UI. |
| Giveaway invite-bonus entries | bot/src/giveaways/requirements.js computeBonus case 'invites' | Empty branch with a comment saying it awaits an invite tracker — but bot/src/invites/ exists. Wire it up. |
Giveaway verified_email requirement | requirements.js:56 | Always passes (` |
| First-message-per-user lookup | commands/handlers/info.js:218 | Replies "coming soon." |
| Catalog stub audit | commands/handlers/index.js:45 | Generic stubHandler replies "hasn't landed yet" for any catalog command without a handler — audit catalog keys vs HANDLERS map to find live shells. |
| API write scopes without routes | config/api.php vs routes/api.php | Scopes exist for cases.update, tickets.message/close, giveaways.end/reroll, levelling.adjust but no routes — add the endpoints or trim the scope catalog. |
4. Bot feature expansions (verified absent)
Economy (biggest module gap)
- Shop + items + inventory — flagged as "future" in
economy/engine.jsitself. Sellable role rewards, custom items, item-use hooks. - Bank / deposit / withdraw / interest — single wallet only today; a vault is prerequisite to…
- Activities: work / crime / rob / fish / beg with cooldowns and per-role payouts (the per-role earn pattern already exists in
resolveEarn). Today, free servers have zero economy games because all gambling is in the premium casino. - Level-up currency rewards — trivia already bridges XP↔currency; level-ups only grant roles.
Levelling
- Image rank cards —
/level rankis an embed with an ASCII bar; the canvas infra fromwelcome/image.jsis right there. Ship customisable rank cards (background, accent color) matching the welcome-card presets. - Per-role / per-channel XP multipliers (boost roles, boosted channels) — single global
xp_multipliertoday. - Seasons / leaderboard resets / prestige — no scheduled resets exist.
- Voice-only leaderboard — voice XP is tracked but has no dedicated leaderboard or multipliers.
Community & engagement
- Birthday module — personal birthdays are already stored via
/p me birthday-set, but nothing consumes them. Add birthday announcements channel, birthday role for the day, and templated message. Very high demand, low effort given data exists. - Autoresponder (keyword → response, no prefix) — custom commands are prefix-only; there is no "reply when a message contains X." Core Carl-bot/Dyno feature.
- Welcome DM —
welcome/sender.jsonly posts to channels; add an optional private greeting with its own template. - Multiple starboards — single
channel_idtoday; support per-emoji boards with distinct thresholds. - Slash-registered custom commands — register user-defined commands as guild slash commands instead of prefix-only.
- Suggestion discussion threads — auto-open a thread per suggestion.
- Server events / RSVP — extend scheduled-messages + reminder-scheduler into announced events with signups and reminder DMs; integrate Discord native Scheduled Events.
- Temporary self-roles — wire
temp-rolesdurations into reaction-role panels (e.g. self-assign event role that expires). - Counting extras — milestones, per-user counting leaderboard, high-score.
- AI automod tier — automod is fully deterministic today; an optional AI toxicity classifier is a natural premium add (AI plumbing already exists via auto-assist/trivia).
5. Dashboard & UX improvements (verified)
- Settings change-history + rollback.
GuildAuditEntryonly records bot actions; settings controllers (Welcome, Logging, XP, Economy, Automod…) write no audit entries. Add "who changed what, when" per module with diff view and one-click revert — the single best feature for team-run servers, and it pairs with the existing team-permissions system. - Config export / import / clone-from-server. Guild settings page offers only destructive Reset/Wipe. Add JSON export of module configs and "copy settings from another server I manage." (Server Templates cover structure, not module config.)
- Unify the save model. ~10 pages autosave, ~49 use explicit Save buttons, and there is no shared unsaved-changes guard — a big form can be lost by navigating away. Standardise on debounced autosave (the
window.Phantom.makeDebouncedSavehelper exists) or add a shared dirty-guard. - Global settings search / command palette. Sidebar search only filters nav labels; with ~90 pages, add Ctrl+K search over module names and individual settings ("log channel for bans" → jumps to the field).
- True welcome-card preview. The dashboard emulates the canvas card in CSS (noted in-code as approximate). Add a server-rendered PNG preview endpoint using the bot's actual
image.jsrenderer so glow/font/layout tuning is WYSIWYG. - Finish the shared-JS migration.
dashboard-helpers.jsdocuments that toast/fetch/save logic is duplicated across 15+ blades with divergent error handling;guild-settings.blade.phpstill hand-rolls its own fetch. Completing the migration unifies UX and shrinks the 58k-line blade footprint. - Theme option. The dashboard is hard-dark only (no light theme, no
prefers-color-schemehandling) — worth at least a contrast/light option for accessibility. - Finer-grained delegation (later). Team permissions are per-module view/edit; per-category scoping (e.g. "manage tickets only in the support category") is a plausible enterprise feature.
6. Integrations, API & monetization
- Wire bot-side webhook emission first (§3) — everything else (Zapier/Make connector, "server events API" marketing) depends on events actually firing.
- Zapier / Make connector — near-free once events fire; strong enterprise upsell.
- Email digests / weekly server reports —
config/mail.phpexists but mail is unwired (MAIL_MAILER=log); the Analytics service already computes growth/retention/insights. A weekly owner digest is a classic premium hook. - Premium tier ladder. Today there is a single boolean Pro gate (
premium_until) over ~8 features. Given the depth of free modules, there is headroom for Basic/Pro/Enterprise tiers differentiated by caps (streamers per platform, live roles, custom commands, panels, webhook endpoints, API rate limits) rather than by locking whole modules — caps monetize power users without gutting the free experience. Streamer-alert per-streamer overrides, custom alert embeds, AI automod, and email digests are all natural higher-tier features.
7. Suggested priority order
| # | Item | Impact | Effort |
|---|---|---|---|
| 1 | Per-streamer overrides (channel/message/ping/roles/filters/enable) | Very high | Medium |
| 2 | Alert preview + test-send button | High | Low |
| 3 | Custom alert embeds (wire existing embed builder) + Watch button | High | Medium |
| 4 | Wire the 28 dead webhook events bot-side | High | Medium |
| 5 | Giveaway invite-bonus wiring + verified_email fix | Medium | Low |
| 6 | Birthday module (data already exists) | High | Low-Med |
| 7 | Image rank cards + XP role/channel multipliers | High | Medium |
| 8 | Economy shop/bank/activities | Very high | High |
| 9 | Settings change-history + config export/import | High | Medium |
| 10 | Autoresponder + welcome DM | Medium | Low-Med |
| 11 | RSS + Reddit alert platforms | Medium | Medium |
| 12 | Stream-end options (delete/custom card, duration, peak viewers, VOD link) | Medium | Low-Med |
| 13 | Unified streamer-alerts dashboard page + crosspost + auto-threads | Medium | Medium |
| 14 | Save-model unification + global settings search | Medium | Medium |
| 15 | Events/RSVP module, multi-starboard, slash custom commands, seasons | Medium | High |
Key files referenced throughout: bot/src/streamer-alerts/{registry,poller,announce}.js, app/Http/Controllers/{Twitch,YouTube,Kick,TikTok}Controller.php, config/api.php, app/Services/Webhooks/WebhookDispatcher.php, bot/src/economy/engine.js, bot/src/levelling/, bot/src/welcome/image.js, bot/src/giveaways/requirements.js, config/premium.php, config/team-permissions.php, resources/js/dashboard-helpers.js.
