Skip to content

feat: admin dashboard upgrade, giveaway wizard, stats layer, group co… - #57

Merged
gamblecodezcom merged 2 commits into
mainfrom
claude/update-prod-runner-script-Lq2gS
Feb 21, 2026
Merged

feat: admin dashboard upgrade, giveaway wizard, stats layer, group co…#57
gamblecodezcom merged 2 commits into
mainfrom
claude/update-prod-runner-script-Lq2gS

Conversation

@gamblecodezcom

@gamblecodezcom gamblecodezcom commented Feb 21, 2026

Copy link
Copy Markdown
Owner

User description

…mmands fix

ADMIN DASHBOARD

  • /admin in DM now shows full rich dashboard with status lights, uptime, deploy time (from DEPLOY_TIME env or .release_info), active user counts (5m / 10m windows), giveaway stats, and error count
  • /admin in group sends a compact inline button to open DM dashboard
  • Added Stats submenu button to adminDashboardKeyboard (pages 1 and 2)
  • New adminStatsKeyboard() and buildAdminStatusText() helpers
  • Removed duplicate admin_dashboard_action handler (was registered twice)

STATS / ANALYTICS LAYER

  • New buildStatsWindow(windowMs) for O(n) time-windowed queries: new users, active users, interactions, promo claims, bonus sent, giveaways created, giveaway participants
  • New admin_stats_menu / admin_stats_24h / admin_stats_7d / admin_stats_30d / admin_stats_lifetime inline action handlers
  • Added lastSeenAt field to user records; updated on every getUser() call so active-user windows work correctly
  • buildDashboard() now includes activeUsers5m, activeUsers10m, runningGiveaways, totalGiveaways
  • trackAnalytics('promo_claimed') now emitted so window queries count it

GIVEAWAY WIZARD — full inline-button flow

  • New /giveaway command: non-admins see active giveaway list; admins get a wizard start menu (group) or full wizard (DM)
  • /start_giveaway now launches the inline wizard (not text-only)
  • 8-step wizard: title → winners → SC → duration → minParticipants → join surface → requirements toggles → confirm
  • Preset buttons for each numeric step; "Custom" option drops to text input
  • Requirements step: tap-to-toggle inline keyboard (editMessageReplyMarkup)
  • Confirm step reuses existing gw_create_yes / gw_create_no handlers

GIVEAWAY ENGINE UPGRADES

  • New fields: title, minParticipants, joinSurface ('group'|'dm'|'both'), pinnedMsgId, extendedCount — all serialised / deserialised cleanly
  • announceGiveaway() now: • Pins announcement in group (unpins on finalise); ignores permission errors • If surface=dm or both: broadcasts DM join message to all opted-in users • If surface includes both: shows inline group button + t.me deep-link URL
  • finalizeGiveaway(gwId, forceEnd) now checks minParticipants: • If unmet and extended < 2 times: DMs admins with Extend/Force-end buttons • gw_auto_extend_N: adds 15 min, increments extendedCount • gw_force_end_N: finalises regardless of participant count • Unpins announcement message on end
  • /start deep link handler: ?start=join_gw_ auto-joins the giveaway from DM (eligibility checked, duplicate prevented)

GROUP COMMANDS FIX (interrupted task)

  • Expanded groupCommands from 3 to 17 entries — all relevant commands now appear when users type / in a group chat (Telegram command picker)

https://claude.ai/code/session_01X3PxGFF5zzKptQwVkjYzzN

Summary by CodeRabbit

  • New Features

    • Admin giveaway wizard with step-by-step setup (title, winners, SC, duration, min participants, join surface, confirmation).
    • Persistent admin/user menus and richer admin dashboards with time-windowed stats (5m, 10m, 24h, 7d, 30d, lifetime).
    • Multi-surface giveaway announcements (group/DMed joins), optional pinning, DM broadcast with opt-out respect.
    • Per-giveaway participant management, extend/force-end/cancel controls, and exportable reports.
  • Bug Fixes

    • Improved resilience for pin/unpin and DM broadcast failures; clearer admin error flows.

CodeAnt-AI Description

Add rich admin dashboard, time-window stats, and a full inline giveaway wizard

What Changed

  • Admins see a rich dashboard in DM with status lights, uptime, deploy time, active users (5m/10m), giveaway counts and error totals; groups get a compact button to open the DM dashboard
  • New stats submenu shows metrics for Last 24h, 7d, 30d or Lifetime (new users, active users, interactions, promo claims, giveaways created/participants, bonus sent)
  • User records now track last-seen time so active-user counts and stats windows are accurate
  • Full inline giveaway creation wizard for admins (title → winners → SC → duration → minimum participants → join surface → requirements → confirm) with preset buttons and custom text entry
  • Giveaways gain new metadata: title, minParticipants, joinSurface (group|dm|both), pinned message id, and extendedCount; announcements can pin in groups and send DM join links/broadcasts
  • Join via DM deep-link support (start=join_gw_) and join buttons generated based on joinSurface
  • Finalization logic: supports auto-extension when min participants not met (admin prompts to extend or force-end), tracks extensions, and cleans up pins/reminders; admins receive detailed reports and can force-end or extend
  • Register promo claims into analytics so stats windows count them; admin command lists updated (group/private) to expose giveaway and admin dashboard actions

Impact

✅ Clearer admin stats and uptime
✅ Shorter giveaway creation for admins
✅ Fewer missed giveaway join opportunities (DM links + broadcasts)

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

…mmands fix

ADMIN DASHBOARD
- /admin in DM now shows full rich dashboard with status lights, uptime,
  deploy time (from DEPLOY_TIME env or .release_info), active user counts
  (5m / 10m windows), giveaway stats, and error count
- /admin in group sends a compact inline button to open DM dashboard
- Added Stats submenu button to adminDashboardKeyboard (pages 1 and 2)
- New adminStatsKeyboard() and buildAdminStatusText() helpers
- Removed duplicate admin_dashboard_action handler (was registered twice)

STATS / ANALYTICS LAYER
- New buildStatsWindow(windowMs) for O(n) time-windowed queries:
  new users, active users, interactions, promo claims, bonus sent,
  giveaways created, giveaway participants
- New admin_stats_menu / admin_stats_24h / admin_stats_7d /
  admin_stats_30d / admin_stats_lifetime inline action handlers
- Added lastSeenAt field to user records; updated on every getUser() call
  so active-user windows work correctly
- buildDashboard() now includes activeUsers5m, activeUsers10m,
  runningGiveaways, totalGiveaways
- trackAnalytics('promo_claimed') now emitted so window queries count it

GIVEAWAY WIZARD — full inline-button flow
- New /giveaway command: non-admins see active giveaway list; admins get
  a wizard start menu (group) or full wizard (DM)
- /start_giveaway now launches the inline wizard (not text-only)
- 8-step wizard: title → winners → SC → duration → minParticipants →
  join surface → requirements toggles → confirm
- Preset buttons for each numeric step; "Custom" option drops to text input
- Requirements step: tap-to-toggle inline keyboard (editMessageReplyMarkup)
- Confirm step reuses existing gw_create_yes / gw_create_no handlers

GIVEAWAY ENGINE UPGRADES
- New fields: title, minParticipants, joinSurface ('group'|'dm'|'both'),
  pinnedMsgId, extendedCount — all serialised / deserialised cleanly
- announceGiveaway() now:
  • Pins announcement in group (unpins on finalise); ignores permission errors
  • If surface=dm or both: broadcasts DM join message to all opted-in users
  • If surface includes both: shows inline group button + t.me deep-link URL
- finalizeGiveaway(gwId, forceEnd) now checks minParticipants:
  • If unmet and extended < 2 times: DMs admins with Extend/Force-end buttons
  • gw_auto_extend_N: adds 15 min, increments extendedCount
  • gw_force_end_N: finalises regardless of participant count
  • Unpins announcement message on end
- /start deep link handler: ?start=join_gw_<id> auto-joins the giveaway
  from DM (eligibility checked, duplicate prevented)

GROUP COMMANDS FIX (interrupted task)
- Expanded groupCommands from 3 to 17 entries — all relevant commands now
  appear when users type / in a group chat (Telegram command picker)

https://claude.ai/code/session_01X3PxGFF5zzKptQwVkjYzzN
@codeant-ai

codeant-ai Bot commented Feb 21, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.

@coderabbitai

coderabbitai Bot commented Feb 21, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a comprehensive inline giveaway wizard, expands giveaway and user data models (minParticipants, title, joinSurface, pinnedMsgId, extendedCount, many user fields), implements admin analytics/status panels and time-windowed stats, and extends announce/join/extension lifecycle with new admin controls and DM/group join support.

Changes

Cohort / File(s) Summary
Giveaway Data Model
index.js
Extended serialization/deserialization and creation to include: minParticipants, title, joinSurface, pinnedMsgId, extendedCount. Persist and restore new fields and update finalize/create flows.
Admin Dashboard & Status Reporting
index.js
Added buildAdminStatusText(), richer buildDashboard() (activeUsers10m/5m, runningGiveaways, totalGiveaways) and replaced legacy "View Logs" with Stats entry and new admin dashboard keyboards.
Analytics & Time-Windowed Stats
index.js
Introduced buildStatsWindow(windowMs) and buildStatsText(label, windowMs) plus admin commands/handlers for admin_stats_* (24h/7d/30d/lifetime) and supporting admin_stats subsystem.
Giveaway Wizard Flow
index.js
Complete inline multi-step giveaway wizard (gwizStart, gwiz_* keyboards/handlers) covering title, winners, SC, duration, min participants, join surface, requirements, summary, and confirmation.
Announcement & Join Flows
index.js
New announceGiveaway() builds title-aware messages, supports group/DM join surfaces, optional pinning, DM cross-broadcasts (respecting opt-out), and deep-link join (join_gw_<id>).
Giveaway Lifecycle & Admin Controls
index.js
Extension/auto-extend support, extendedCount tracking, admin actions for extend/force-end/cancel/participants/export, improved finalize logic, and robust pin/unpin/DM failure handling.
User Model & Public Surface
index.js
Added many user-visible fields (lastSeenAt, mainMenuMsgId/chatId, adminMenuMsgId/chatId, referralCount, lastReferralAt, boostExpiresAt, commandsUsed, etc.) and migrations for backward compatibility.

Sequence Diagram

sequenceDiagram
    participant Admin as Admin
    participant Bot as Bot
    participant DB as State/DB
    participant User as User

    Admin->>Bot: gwizStart (open wizard)
    Bot->>DB: initialize wizard session
    Bot->>Admin: prompt title (gwiz_title...)
    Admin->>Bot: send title
    Bot->>Bot: gwizSetWinners -> gwizSetSc -> gwizSetDuration
    Bot->>Admin: show winner/SC/duration keyboards
    Admin->>Bot: select winners/SC/duration
    Bot->>Bot: gwizSetMinParts -> gwizSetSurface -> gwizToggleReqs
    Bot->>Admin: show minParts/surface/reqs keyboards
    Admin->>Bot: confirm summary (gwiz_reqs_done)
    Bot->>Admin: show gwizSummaryText
    Admin->>Bot: confirm create (gwiz_start_here)
    Bot->>DB: createGiveaway(with new fields)
    Bot->>Bot: announceGiveaway (builds messages, pin, DM broadcast)
    Bot->>User: send announcement (Group and/or DM)
    Bot->>Admin: confirm creation + admin stats update
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 I hopped through keys and tiny screens,
Built titles, pins, and participant dreams,
With stats that sparkle, wizards that play,
Giveaways bloom both night and day,
Hooray — extend, announce, and stay! ✨


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai codeant-ai Bot added the size:XL This PR changes 500-999 lines, ignoring generated files label Feb 21, 2026
@codeant-ai

codeant-ai Bot commented Feb 21, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ad977b6795

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread index.js
]),
);
async function announceGiveaway(giveaway, botUsername) {
const titleLine = giveaway.title ? `\n📌 *${giveaway.title}*\n` : '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Escape giveaway title before Markdown rendering

The giveaway title is admin-provided free text but is interpolated directly into a Markdown message (*${giveaway.title}*), so titles containing Markdown metacharacters (for example _, [ or unmatched *) can make Telegram reject sendMessage with a parse error. In gw_create_yes, announceGiveaway is awaited before scheduleGiveawayReminders and resetGiveawayTimer, so this failure can leave a giveaway in running state without an announcement or end timer.

Useful? React with 👍 / 👎.

Comment thread index.js
Comment on lines +1472 to +1476
const giveaway = giveawayStore.running.get(gwId);
if (!giveaway) {
await ctx.reply('⚠️ That giveaway has already ended or does not exist.');
} else if (giveaway.participants.has(user.id)) {
await ctx.reply(`✅ You are already entered in Giveaway #${gwId}!`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce joinSurface for join_gw deep links

The /start join_gw_<id> path accepts DM joins for any running giveaway after eligibility checks, but it never validates giveaway.joinSurface. Because giveaway IDs are sequential, users can manually open join_gw_<id> links and enter giveaways configured as group-only, which bypasses the new surface restriction and can skew participant counts/minimum-participant behavior.

Useful? React with 👍 / 👎.

…leaderboards

USER MAIN MENU (persistent):
- Auto-deleting greeting (15s) on /start with first name
- sendPersistentUserMenu: delete old + send new at bottom
- 5 buttons: Play Now, Claim Bonus, My Profile, Giveaways, Help/Commands
- Tooltips in button text; reappears after every major action
- pmenu_* action handlers for all 5 buttons + pmenu_admin

ADMIN MAIN MENU (persistent):
- sendPersistentAdminMenu: delete old + send new at bottom
- 6 buttons: System Status, Stats Dashboard, Start Giveaway, Active Giveaways, Tools, Back to User Menu
- pamenu_* action handlers for all admin menu items
- Admin Tools: force refresh menus, clear stuck flows, health check, show logs
- Active Giveaways panel with per-giveaway End/Extend/Cancel/Participants controls

SYSTEM REQUIREMENTS (new user constraints):
- Removed /spin command (cosmetic, no longer supported)
- Bot-only leaderboards: /leaderboard = top referrers, /leaderboard_weekly = most active (commands used)
- No Runewager API, no Discord API, no external verification
- commandsUsed counter on every getUser() call for activity tracking

REFERRAL BOOST SYSTEM:
- awardReferralProgress() now sets boostExpiresAt = now + 7 days on referrer
- referralCount, lastReferralAt, boostExpiresAt fields in user schema
- finalizeGiveaway: winners with active boost receive 2× SC (winner.awardedSc = base * 2)
- Admin report shows boosted winners (🔥 boosted)
- Stats text shows referrals in window + active boosted users count

GIVEAWAY WIZARD (9 steps, reordered per spec):
- Step 1: Name/Description (skip → default)
- Step 2: SC Per Winner (was step 3)
- Step 3: Number of Winners (was step 2)
- Step 4: Countdown Duration
- Step 5: Minimum Participants
- Step 6: Join Targets — separate Group/DM toggle buttons (joinGroup, joinDm)
- Step 7: Referral + Bonus Info (auto-include, informational proceed)
- Step 8: Confirmation summary
- Step 9: Launch/Post
- gwizSummaryText updated to show joinGroup/joinDm surfaces and referral boost note
- Surface stored as joinGroup+joinDm booleans; joinSurface computed at launch

WIRING:
- to_main_menu, menu command, menu_page_1 → sendPersistentUserMenu
- open_admin_dashboard, admin_dashboard_action, admin_dash_page_1 → sendPersistentAdminMenu
- /admin command in DM → sendPersistentAdminMenu
- promo_confirm_claimed → sendPersistentUserMenu after completion
- onboard_gcz_continue, sendGambleCodezVIPStep(sawGambleCodezStep) → sendPersistentUserMenu

https://claude.ai/code/session_01X3PxGFF5zzKptQwVkjYzzN
@gamblecodezcom
gamblecodezcom merged commit c21cf24 into main Feb 21, 2026
3 of 5 checks passed
@gamblecodezcom
gamblecodezcom deleted the claude/update-prod-runner-script-Lq2gS branch February 21, 2026 16:32
gamblecodezcom pushed a commit that referenced this pull request Feb 21, 2026
1. escapeMarkdownV2 helper + title escaping in announceGiveaway
   - Added escapeMarkdownV2(text) to escape _ * ` [ ] in user-supplied text
   - Applied to giveaway.title in announceGiveaway() to prevent Markdown injection

2. Enforce joinSurface on join paths
   - DM deep-link (?start=join_gw_<id>): rejects with "can only be joined from
     the group chat" when joinSurface === 'group'
   - gw_join_<id> inline button: rejects DM users when joinSurface === 'group',
     rejects group users when joinSurface === 'dm'

3. Remove duplicate admin_dashboard_action handler
   - Removed admin_dashboard_action_v2_noop placeholder stub
   - Single handler at line ~3708 is the only registration

4. Giveaway wizard edge case fixes
   - awaitingAdminDecision flag prevents double-trigger of admin notification
     when timer fires before admin has clicked extend/force-end
   - gw_auto_extend clears awaitingAdminDecision before resetting timer so next
     fire can re-evaluate
   - pinnedMsgId set to null after unpinChatMessage in finalizeGiveaway
   - DM broadcast already respects optOutBroadcasts and muted flags (verified)
   - joinSurface enforcement covers group-only and DM-only cases end-to-end

5. CI/CD fixes
   - ci.yml: Added BOT_TOKEN: ${{ secrets.BOT_TOKEN }} to smoke test step env so
     require('./index.js') does not throw when BOT_TOKEN is needed at load time
   - deploy.yml: Added BOT_TOKEN to global env block; expanded deploy job
     environment from shorthand to name: production form per spec

https://claude.ai/code/session_01X3PxGFF5zzKptQwVkjYzzN
gamblecodezcom added a commit that referenced this pull request Feb 21, 2026
1. escapeMarkdownV2 helper + title escaping in announceGiveaway
- Added escapeMarkdownV2(text) to escape _ * ` [ ] in user-supplied text
- Applied to giveaway.title in announceGiveaway() to prevent Markdown
injection

2. Enforce joinSurface on join paths
- DM deep-link (?start=join_gw_<id>): rejects with "can only be joined
from the group chat" when joinSurface === 'group'
- gw_join_<id> inline button: rejects DM users when joinSurface ===
'group', rejects group users when joinSurface === 'dm'

3. Remove duplicate admin_dashboard_action handler
   - Removed admin_dashboard_action_v2_noop placeholder stub
   - Single handler at line ~3708 is the only registration

4. Giveaway wizard edge case fixes
- awaitingAdminDecision flag prevents double-trigger of admin
notification when timer fires before admin has clicked extend/force-end
- gw_auto_extend clears awaitingAdminDecision before resetting timer so
next fire can re-evaluate
   - pinnedMsgId set to null after unpinChatMessage in finalizeGiveaway
- DM broadcast already respects optOutBroadcasts and muted flags
(verified)
- joinSurface enforcement covers group-only and DM-only cases end-to-end

5. CI/CD fixes
- ci.yml: Added BOT_TOKEN: ${{ secrets.BOT_TOKEN }} to smoke test step
env so require('./index.js') does not throw when BOT_TOKEN is needed at
load time
- deploy.yml: Added BOT_TOKEN to global env block; expanded deploy job
environment from shorthand to name: production form per spec

https://claude.ai/code/session_01X3PxGFF5zzKptQwVkjYzzN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants