Skip to content

Add Promo Manager, Content Drops, admin UI updates and runtime improvements - #88

Merged
gamblecodezcom merged 2 commits into
mainfrom
codex/add-new-admin-promo-manager
Feb 26, 2026
Merged

Add Promo Manager, Content Drops, admin UI updates and runtime improvements#88
gamblecodezcom merged 2 commits into
mainfrom
codex/add-new-admin-promo-manager

Conversation

@gamblecodezcom

@gamblecodezcom gamblecodezcom commented Feb 26, 2026

Copy link
Copy Markdown
Owner

User description

Motivation

  • Replace legacy single-code promo handling with a DB-backed Promo Manager to support multiple promos, claims, cooldowns and admin approval workflows.
  • Improve admin UX and safety for broadcasts, SSHV console, tips/content drops, health checks and menus for clearer operational control.
  • Make runtime persistence and scheduler behavior more robust and add discovery/registration for broadcast targets.
  • Add documentation and an authoritative functionality map for AI/code audits and contributor guidance.

Description

  • Introduced a Promo Manager: added promoManagerStore persistence, promo normalization, eligibility evaluation, claim records, CLI admin commands (/pmapprove, /pmdeny) and full create/edit/pause/delete/preview flows reachable from a new Promo Manager admin UI; promo DB saved to data/promo-manager-db.json and loaded/saved via loadPromoManagerDb()/savePromoManagerDb() in index.js.
  • Replaced legacy single promo UI with promo manager-backed user flows: /promo and claim flow now show DB-backed promos and enforce new rules (new-user vs existing, wager requirements, cooldowns, claim limit, auto-approve vs admin review).
  • Content Drops (formerly Tips) enhancements: renamed UX copy to "Content Drops", added robust target resolution and posting via postTipToConfiguredTarget, auto-register forwarded chats, /register_chat command, improved scheduler, and admin test/send controls.
  • Admin & UX improvements: reorganized admin persistent menus (Promo Manager, Broadcasts & Drops, Tests & Bugs), added announcement builder (toggle DM/channel/group, parse mode) and sendAnnouncementTargets helper, added verify_bot_setup and register_chat commands, and many callback handlers / aliases for compatibility.
  • SSHV and health improvements: sandbox-restriction hinting for failing commands, safer editor save with error handling and logging, added TLS-aware health checks, GC timers unref'd, and extra admin logs for sshv actions.
  • Runtime and config tweaks: .env.example clarified WEBAPP_HMAC_KEY and placeholders, .gitignore adjusted to keep .env.example and added data/*.json/backups patterns, added broadcastConfigStore, PROMO_STATUS/PROMO_REQUIREMENT enums and numerous migration/shimming changes to keep backward compatibility for older persisted state.
  • Docs and governance: added RUNEWAGER_FUNCTIONALITY_MAP.md (comprehensive functionality map) and updated CLAUDE.md with AI agent contract requirements.
  • Tests and smoke-checks: tightened smoke tests in test/smoke.test.js to verify that literal callback_ids and bot.action handlers are covered (scans project JS files, validates literal and regex handlers).

Testing

  • Ran a syntax check via node --check index.js as part of the smoke test and it passed.
  • Ran the project's automated test suite (smoke/unit tests) including the updated test/smoke.test.js which validates callback/button handler coverage; the test run completed and tests passed.
  • Manual startup checks exercised the tips scheduler and bot health endpoint (TLS-aware path) during development and no automated failures were observed.

Codex Task

Summary by CodeRabbit

Release Notes

  • Documentation

    • Added comprehensive functionality documentation outlining bot architecture, user flows, and command mappings.
    • Added AI coder contract requirements to ensure consistent development practices.
  • Chores

    • Updated environment configuration documentation with improved setup guidance.
    • Enhanced build configuration to properly manage data files and backups.
    • Added automated verification tests for system consistency.

CodeAnt-AI Description

Add static smoke test for callback/action coverage, expand functionality map, and clarify WEBAPP_HMAC_KEY in env example

What Changed

  • New smoke test scans JavaScript files to ensure inline-menu callback IDs have corresponding action handlers (literal or regex), failing the test if any callback buttons are uncovered.
  • Added a comprehensive RUNEWAGER_FUNCTIONALITY_MAP.md that documents user flows, admin menus, button-to-action mappings, state machines, and expected behaviors as the authoritative audit.
  • .env.example now explains how to generate and use a 32-byte WEBAPP_HMAC_KEY so operators know how to securely configure webapp payload/CSRF signing.
  • CLAUDE.md appended mandatory AI coder contract guidance referencing the functionality map to improve developer audits and consistency.

Impact

✅ Fewer missing callback handler regressions reaching runtime
✅ Clearer setup instructions for webapp HMAC configuration
✅ Faster developer onboarding and audits with a single source-of-truth

💡 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.

@codeant-ai

codeant-ai Bot commented Feb 26, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai

coderabbitai Bot commented Feb 26, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Configuration and documentation updates for the Runewager bot. Enhanced .env.example with HMAC key guidance, refined .gitignore rules for environment templates and runtime data, added comprehensive functionality documentation map, updated developer contract requirements in CLAUDE.md, and introduced smoke tests validating callback handler coverage.

Changes

Cohort / File(s) Summary
Configuration
.env.example, .gitignore
Added inline documentation for WEBAPP_HMAC_KEY generation; refined ignore rules to preserve env template files and exclude runtime JSON data and backups directories.
Documentation
CLAUDE.md, RUNEWAGER_FUNCTIONALITY_MAP.md
Added AI coder contract requirements mandating review and updates to functionality map; created comprehensive bot documentation covering architecture, flows, commands, state management, permissions, and safety controls.
Testing
test/smoke.test.js
Introduced smoke tests with utility functions to verify all callback button IDs have corresponding literal handlers or dynamic action patterns, preventing orphaned callbacks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

size:XL

Poem

🐰 A map unfolds, so clear and bright,
Callbacks checked—each one in sight,
Environment whispers secrets true,
Data tucked away from view,
Contracts signed, the path is set,
The finest bot we've built just yet!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title claims to add 'Promo Manager, Content Drops, admin UI updates and runtime improvements', but the actual file changes show only documentation and config updates: .env.example comments, .gitignore rules, CLAUDE.md policy text, RUNEWAGER_FUNCTIONALITY_MAP.md documentation, and smoke test utilities. No implementation of the claimed features is present in the changeset. Either update the PR title to reflect the actual changes (e.g., 'Add Runewager functionality documentation and smoke test validation') or include the actual feature implementation files in this PR.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/add-new-admin-promo-manager

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Feb 26, 2026
@codeant-ai

codeant-ai Bot commented Feb 26, 2026

Copy link
Copy Markdown

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Pattern Matching
    The regex used to extract action regex patterns may mis-handle regex literals that contain escaped slashes or more complex patterns and may produce false negatives/positives. The current approach is brittle for any bot.action(/.../) handlers that include escaped characters or flags ordering differences.

  • File Traversal
    The new recursive file collector walks the repository and will include the test file itself and other non-source folders unless explicitly excluded. It also does not guard against symbolic links which may cause loops or unexpected files to be scanned. This can produce false positives or heavy I/O on large repos.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (4)
.gitignore (1)

32-41: Redundant entries: data/*.json already covers the individual JSON files.

Lines 32–37 list specific JSON files, but line 40 adds data/*.json which already matches all of them. Consider removing the redundant individual entries for cleaner maintainability.

Proposed consolidation
 # Runtime state files
-data/analytics.json
-data/dashboard.json
-data/helpful_messages.json
-data/promo-history.json
-data/runtime-state.json
-data/sshv-sessions.json
-
-# Runtime generated data + backups
+# Runtime generated data (JSON state + backups)
 data/*.json
 data/backups/**
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.gitignore around lines 32 - 41, Remove the redundant explicit JSON file
entries (data/analytics.json, data/dashboard.json, data/helpful_messages.json,
data/promo-history.json, data/runtime-state.json, data/sshv-sessions.json) and
rely on the existing glob entry data/*.json to cover them; keep the
data/backups/** entry for backups. Update the .gitignore by deleting the
individual data/*.json lines while ensuring data/*.json and data/backups/**
remain to preserve the intended ignores.
test/smoke.test.js (1)

58-72: Consider using __dirname for consistent path resolution.

The test uses '.' as the root directory, which depends on the current working directory at execution time. For robustness across different test runners and execution contexts, consider deriving the root from __dirname (as done in test/runtime.test.js).

Proposed fix
+const rootDir = path.resolve(__dirname, '..');
+
 test('menu callback buttons map to handlers (literal or dynamic patterns)', () => {
-  const jsFiles = collectJsFiles('.');
+  const jsFiles = collectJsFiles(rootDir);
   const combinedSource = jsFiles
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/smoke.test.js` around lines 58 - 72, The test currently calls
collectJsFiles('.') which relies on the process CWD; change it to derive the
root from __dirname (e.g., pass __dirname or a path.resolve/ path.join based on
__dirname) so collectJsFiles and subsequent fs.readFileSync calls use a stable
test directory; update the test invocation where collectJsFiles('.') is used
(and import/require path if needed) so combinedSource is built from files under
__dirname instead of '.'.
.env.example (1)

17-17: Document valid LOG_LEVEL values.

As per coding guidelines, the LOG_LEVEL environment variable should document its valid values.

Proposed fix
-LOG_LEVEL=info
+LOG_LEVEL=info  # Valid values: debug, info, warn, error
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env.example at line 17, Update the .env.example entry for LOG_LEVEL to
document the valid log levels and the default; specifically, replace or augment
"LOG_LEVEL=info" with a comment or inline note listing accepted values (e.g.,
TRACE, DEBUG, INFO, WARN, ERROR, FATAL or similar lowercase variants like trace,
debug, info, warn, error, fatal) and indicate the default ("info") and expected
format so that consumers know allowable values for LOG_LEVEL.
RUNEWAGER_FUNCTIONALITY_MAP.md (1)

266-306: Add language specifier to fenced code blocks.

The flowchart blocks at lines 266, 279, 289, and 298 lack language specifiers, which triggers markdownlint warnings (MD040). Use text or plaintext for pseudo-code/flowcharts.

Example fix for one block
-```
+```text
 /promo or menu_claim_bonus
    -> load active promos
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@RUNEWAGER_FUNCTIONALITY_MAP.md` around lines 266 - 306, Add a language
specifier (e.g., text or plaintext) to each fenced code block used for
flowcharts so markdownlint MD040 is resolved: update the blocks that start with
"/promo or menu_claim_bonus", "admin_cmd_announce_start or /announce", "Admin
forwards message from channel/group", and "Admin starts wizard (gwiz)" to use
```text (or ```plaintext) instead of bare ``` so the pseudo-code/flow diagrams
are explicitly marked as plain text.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.env.example:
- Line 6: The .env entry for WEBAPP_HMAC_KEY has a space before the inline
comment and an unquoted empty value which can break dotenv parsers; update the
block referencing WEBAPP_HMAC_KEY by either moving the explanatory comment to
its own preceding line and setting WEBAPP_HMAC_KEY="" (quoted empty string) or
by quoting the value and removing the stray space so it reads with an explicit
empty quoted value and the comment on a separate line; ensure the symbol
WEBAPP_HMAC_KEY is left blank but quoted and that comments are not inline after
the =.

---

Nitpick comments:
In @.env.example:
- Line 17: Update the .env.example entry for LOG_LEVEL to document the valid log
levels and the default; specifically, replace or augment "LOG_LEVEL=info" with a
comment or inline note listing accepted values (e.g., TRACE, DEBUG, INFO, WARN,
ERROR, FATAL or similar lowercase variants like trace, debug, info, warn, error,
fatal) and indicate the default ("info") and expected format so that consumers
know allowable values for LOG_LEVEL.

In @.gitignore:
- Around line 32-41: Remove the redundant explicit JSON file entries
(data/analytics.json, data/dashboard.json, data/helpful_messages.json,
data/promo-history.json, data/runtime-state.json, data/sshv-sessions.json) and
rely on the existing glob entry data/*.json to cover them; keep the
data/backups/** entry for backups. Update the .gitignore by deleting the
individual data/*.json lines while ensuring data/*.json and data/backups/**
remain to preserve the intended ignores.

In `@RUNEWAGER_FUNCTIONALITY_MAP.md`:
- Around line 266-306: Add a language specifier (e.g., text or plaintext) to
each fenced code block used for flowcharts so markdownlint MD040 is resolved:
update the blocks that start with "/promo or menu_claim_bonus",
"admin_cmd_announce_start or /announce", "Admin forwards message from
channel/group", and "Admin starts wizard (gwiz)" to use ```text (or
```plaintext) instead of bare ``` so the pseudo-code/flow diagrams are
explicitly marked as plain text.

In `@test/smoke.test.js`:
- Around line 58-72: The test currently calls collectJsFiles('.') which relies
on the process CWD; change it to derive the root from __dirname (e.g., pass
__dirname or a path.resolve/ path.join based on __dirname) so collectJsFiles and
subsequent fs.readFileSync calls use a stable test directory; update the test
invocation where collectJsFiles('.') is used (and import/require path if needed)
so combinedSource is built from files under __dirname instead of '.'.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dca4f5c and a474ddc.

📒 Files selected for processing (6)
  • .env.example
  • .gitignore
  • CLAUDE.md
  • RUNEWAGER_FUNCTIONALITY_MAP.md
  • index.js
  • test/smoke.test.js

Comment thread .env.example
ADMIN_IDS=YOUR_TELEGRAM_USER_ID
BOT_TOKEN=
WEBAPP_HMAC_KEY=
WEBAPP_HMAC_KEY= # 32-byte secret for HMAC-signing webapp payloads/CSRF tokens; generate with: openssl rand -hex 32 (or openssl rand -base64 32); keep secret and never commit real values

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix .env format: remove space before comment and quote the empty value.

The static analysis correctly flags that spaces around = and unquoted values can cause parsing issues with some dotenv implementations. The comment is helpful but should be on a separate line or the value should be properly formatted.

Proposed fix
-WEBAPP_HMAC_KEY=  # 32-byte secret for HMAC-signing webapp payloads/CSRF tokens; generate with: openssl rand -hex 32 (or openssl rand -base64 32); keep secret and never commit real values
+# 32-byte secret for HMAC-signing webapp payloads/CSRF tokens
+# Generate with: openssl rand -hex 32 (or openssl rand -base64 32)
+# Keep secret and never commit real values
+WEBAPP_HMAC_KEY=""
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
WEBAPP_HMAC_KEY= # 32-byte secret for HMAC-signing webapp payloads/CSRF tokens; generate with: openssl rand -hex 32 (or openssl rand -base64 32); keep secret and never commit real values
# 32-byte secret for HMAC-signing webapp payloads/CSRF tokens
# Generate with: openssl rand -hex 32 (or openssl rand -base64 32)
# Keep secret and never commit real values
WEBAPP_HMAC_KEY=""
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 6-6: [SpaceCharacter] The line has spaces around equal sign

(SpaceCharacter)


[warning] 6-6: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env.example at line 6, The .env entry for WEBAPP_HMAC_KEY has a space
before the inline comment and an unquoted empty value which can break dotenv
parsers; update the block referencing WEBAPP_HMAC_KEY by either moving the
explanatory comment to its own preceding line and setting WEBAPP_HMAC_KEY=""
(quoted empty string) or by quoting the value and removing the stray space so it
reads with an explicit empty quoted value and the comment on a separate line;
ensure the symbol WEBAPP_HMAC_KEY is left blank but quoted and that comments are
not inline after the =.

Comment thread test/smoke.test.js
const patterns = [];
const matches = source.matchAll(/bot\.action\(\s*\/(.+?)\/([dgimsuvy]*)/g);
for (const m of matches) {
try {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The smoke test that verifies every menu callback button has a corresponding handler becomes ineffective because extractActionRegexPatterns includes the generic bot.action(/.*/, ...) catch‑all pattern, so every callback ID will match at least one dynamic regex and uncovered will always be empty; to make the test meaningful, the catch‑all pattern (and other similarly generic patterns) should be excluded from dynamicActionPatterns. [logic error]

Severity Level: Major ⚠️
- ⚠️ Catch-all bot.action(/.*/) neuters callback coverage test.
- ⚠️ Missing menu callback handlers may slip through smoke tests.
Suggested change
try {
const patternSource = m[1];
const flags = m[2];
// Ignore generic catch-all patterns like /.*/ which don't represent specific menu handlers.
if (patternSource === '.*') continue;
try {
patterns.push(new RegExp(patternSource, flags));
Steps of Reproduction ✅
1. Run the smoke tests using Node's test runner: `node --test test/smoke.test.js`; this
executes `test('menu callback buttons map to handlers (literal or dynamic patterns)',
...)` defined in `test/smoke.test.js:58-72`.

2. Inside that test (`test/smoke.test.js:64-66`), `extractActionRegexPatterns` (defined at
`test/smoke.test.js:40-50`) is called with the concatenated contents of all `.js` files,
including `index.js`.

3. In `index.js:9956` there is a generic catch‑all handler `bot.action(/.*/, async (ctx)
=> { ... });` (verified via Grep), which matches the regex
`/bot\.action\(\s*\/(.+?)\/([dgimsuvy]*)/g` used in `extractActionRegexPatterns`.

4. When `extractActionRegexPatterns` processes that line, it constructs `new RegExp('.*',
'')` and adds it to `dynamicActionPatterns`; because `/.*/.test(id)` returns `true` for
every callback ID collected from `Markup.button.callback(...)`, the filter at
`test/smoke.test.js:68-70` always finds `some(pattern => pattern.test(id))` and
`uncovered` is forced to `[]`, so the assertion at line 72 can never fail even if a menu
callback button has no specific `bot.action` handler.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** test/smoke.test.js
**Line:** 44:44
**Comment:**
	*Logic Error: The smoke test that verifies every menu callback button has a corresponding handler becomes ineffective because `extractActionRegexPatterns` includes the generic `bot.action(/.*/, ...)` catch‑all pattern, so every callback ID will match at least one dynamic regex and `uncovered` will always be empty; to make the test meaningful, the catch‑all pattern (and other similarly generic patterns) should be excluded from `dynamicActionPatterns`.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

@codeant-ai

codeant-ai Bot commented Feb 26, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

@gamblecodezcom
gamblecodezcom merged commit 5d0574a into main Feb 26, 2026
2 of 3 checks passed
@gamblecodezcom
gamblecodezcom deleted the codex/add-new-admin-promo-manager branch February 26, 2026 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant