📘 Complete Project Documentation: ParadoxHeartbeat
Welcome to the ultimate documentation for project ParadoxHeartbeat. This documentation is designed to be understood by everyone – from complete beginners to experienced developers. We will explain every file, every piece of logic, and every setting.
📂 1. File Structure
Here is an overview of what you can find where:
ParadoxHeartbeat/
├── config.js # ⚙️ Main configuration (passwords, IDs, parameters)
├── index.js # 🧠 BRAIN of the whole bot and web (everything happens here)
├── support.js # 👥 List of support members (who, when, what they do)
├── tags.js # 🏷️ Saved quick responses (tags)
├── public/ # 🖼️ Files for web (images, CSS)
├── views/ # 📄 HTML templates for web (EJS)
│ ├── admin/ # Admin panel pages
│ └── transcript.ejs # Template for chat history
└── ... # Other files (package.json, README)
⚙️ 2. Configuration (config.js)
This file controls the bot's behavior. Never share it!
| Variable | Description |
|---|---|
discordToken |
"Password" for the bot. Allows it to login. |
applicationId |
Application ID (from Discord Developer Portal). |
guildId |
ID of your Discord server. |
botOwnerId |
Your ID (for commands like /forcereset). |
logChannelId |
ID of the channel where bot writes logs (deleted tickets, transcripts). |
errorChannelId |
ID of the channel for error reports (when something goes wrong). |
ultimateRoleId |
ID of "Admin" role for web panel. |
supportRoleId |
ID of "Support" role. These people see tickets. |
responseTimeoutMs |
Time (ms) after which bot stops waiting for clicks (e.g. 60000 = 1 minute). |
autoWipeClosedIntervalMs |
How often (ms) tickets from "Closed" category are wiped. |
ticketDb / panelDb |
Database credentials (MySQL). |
web.port |
Port where web panel runs (e.g. 37015). |
web.baseURL |
Public web address (for transcript links). |
openaiApiKey |
Key for ChatGPT (if AI is enabled). |
categories |
Button settings for tickets (Ark, Minecraft, Billing...). |
🚦 System Status & Error Codes
Here is an overview of states and error codes you might encounter.
System States
Green Operational Everything is working as expected. The bot is responsive, threads are managed correctly.
Orange Degraded The system is functioning, but with issues.
- Non-critical errors (e.g. Code 401, 499)
- Bot unresponsive for short periods
Red Outage / CPR Critical failure. This state triggers an automatic restart sequence.
Error Code Reference
| Code | Severity | Description |
|---|---|---|
1006 |
Critical | Connection Reset / Timeout. If persists, restart is triggered. |
401 |
Warning | Switch Panel Failed. Internal error. |
402 |
Warning | Thread Create Failed. Discord API limit or permissions. |
404 |
Warning | Roster Update Failed. Database sync issue. |
504 |
Monitor | SSH Connection Failed. The bot might be running but monitoring is down. |
🧠 3. Main Logic (index.js)
This is the most important file. It does absolutely everything. Let's break it down into parts.
A. Initialization and Helper Functions
At the beginning of the file, the bot loads libraries and prepares tools.
Function embed(title, description, color)
This function creates "cards" (embeds) for Discord.
Feature: Automatically loads the logo from icon.png and inserts it into every message.
function embed(title, description, color) {
var e = { title: title, description: description, color: color }
if (logoBuffer) { // If we have a loaded logo
e.thumbnail = { url: 'attachment://icon.png' } // Attach as thumbnail
e.footer = { text: 'Heroic Gamez', icon_url: 'attachment://icon.png' } // Also in footer
}
return e
}
Function openaiChat(messages)
Communicates with ChatGPT. Contains protection (System Instruction) that commands AI:
- Be nice and professional.
- Never offer solutions (that is human work).
- Only confirm message receipt.
B. Ticket Lifecycle
How does it work when someone clicks a button?
1. Category Selection (ticketpanel)
User types /ticketpanel and bot sends buttons (defined in config.categories).
When a user clicks a button (e.g. "Ark"):
- Bot checks if it's a specific category (Ark/Minecraft have extra version buttons).
- If not, displays a Modal (form).
2. Filling the Form (Modal)
User fills in:
- Server ID / Email
- Issue description
- (Optionally game name)
3. Channel Creation
Once the user submits the form:
- Bot creates a new channel (e.g.
ark-pepa-12345). - Sets permissions: Only user and Support role can see it.
- Saves ticket to database (
INSERT INTO tickets). - AI Welcome: Bot sends form data to ChatGPT and says: "Write a nice welcome message for this user, mention their issue, but do not solve it."
- Sends the result to the channel as an embed.
4. Closing the Ticket (/closerequest)
When finished:
- Support or user types
/closerequest. - Bot asks for a reason and sends Accept / Deny buttons.
- Upon approval:
- Ticket is marked as
closed. - Channel is moved to "Closed" category.
- Transcript (chat history) is generated and link is saved.
- User receives a DM with the link and option to rate support (1-5 stars).
- Ticket is marked as
C. The Monitoring Loop 🔄
The bot doesn't sleep; it constantly checks things in the background.
1. Auto Wipe Closed Loop
This loop runs every X minutes (based on config.autoWipeClosedIntervalMs).
- Scans all channels in database marked as "closed".
- If a channel has been closed longer than the set interval, it deletes it permanently.
- This keeps Discord clean.
2. Reminder Loop
This loop checks for inactivity in tickets.
- If support hasn't replied for more than X hours -> Reminder.
- If user hasn't replied -> Reminder.
D. The CPR Logic (Self-Healing & SSH Restart) 🚑
This is critical for stability. The bot is connected to an external monitoring system that can revive it even from clinical death.
Detecting Error 1006 (Connection Reset) This error means Discord "severed" the connection and the bot is stuck in an inconsistent state. The bot recognizes this and calls for help.
client.on('error', async function(err){
if (err.code === 1006) {
// 1. Report error to log channel (so admin knows)
await client.createMessage(chId, { embeds: [embed('System Alert', 'Connection reset (1006)...', 0xE67E22)] })
// 2. Call external "CPR" server (Remote Restart)
// This request tells the server: "I am stuck, restart my process via SSH/Docker!"
http.get('http://136.243.104.68:50030/restart', ...)
}
})
SSH Restart (How it works on the other side?) When the bot calls the URL above:
- External monitoring server receives the signal.
- Executes command (e.g. via SSH or Docker) to kill the bot process.
- Automatically starts the bot again.
- Bot wakes up clean and ready to work.
E. Web Dashboard (express)
The index.js file also runs a web server.
Admin Panel (/admin)
- Displays statistics (ticket count, support activity).
- Allows changing settings (Role IDs, Channels) without restarting the bot.
- Security: Uses
bcryptfor passwords andsessionfor login.
Transcripts (/transcripts/:id)
- Public page (no password) displaying chat history.
- Pulls data from
ticket_messagestable.
🗄️ 4. Database (MySQL)
All data is stored in these tables:
| Table | Description |
|---|---|
tickets |
Main list of tickets (ID, owner, status, channel). |
ticket_messages |
Archive of every message for transcripts. |
ticket_status |
Last time someone wrote (for coloring tickets in panel). |
ticket_details |
Details from form (Server ID, issue description). |
ticket_ratings |
Support ratings from users (stars). |
agent_activity |
Logs when support was "On Duty" or in voice channel. |
support_duty |
Current status of support (On Duty? Yes/No). |
panel_users |
Accounts for logging into admin panel. |
settings |
Dynamic bot settings (editable from web). |
tags_meta / tag_usage |
Statistics on tag usage. |
🤖 5. Bot Commands (Slash Commands)
- /ticketpanel: Creates a panel with buttons for creating tickets.
- /help: Lists commands.
- /closerequest: Requests ticket closure (with reason and delay).
- /wipeclosed: Immediately deletes all channels in "Closed" category.
- /onduty / /offduty: Toggles your status (counts towards payroll/stats).
- /agentstatus: Shows how many hours you worked this week.
- /switchpanel: Switches ticket category (e.g. from "Ark" to "Billing") and renames channel.
- /tag [name]: Sends a pre-prepared response.
- /notes: Creates a private thread in the ticket for support notes.
- /forceerror: (Test only) Simulates a bot error.
- /forcereset: (Owner only) Restarts bot via API.
🔌 API Usage & Integrations
This document details how the bot communicates with the outside world. We don't use "black-box" libraries for API calls – we manage everything ourselves using native Node.js modules (https, http) for maximum control and speed.
🧠 1. OpenAI (ChatGPT) Integration
This is the brain of the bot for text generation. We don't want the bot to sound robotic, but it also mustn't "hallucinate" technical solutions.
A. The Wrapper (openaiChat)
Instead of installing a huge openai library, we use a lightweight function that sends a clean HTTP POST request.
How it works:
- Builds JSON with model and parameters (temperature, penalty).
- Sends request to
api.openai.com. - Returns only the clean text response.
async function openaiChat(messages) {
// 1. Prepare request body
var body = JSON.stringify({
model: config.openaiModel, // e.g. "gpt-3.5-turbo"
messages: messages, // Conversation history
temperature: 0.9 // Creativity
})
// 2. Send request (Native HTTPS)
return await new Promise(function(resolve){
var req = https.request({
method: 'POST',
hostname: 'api.openai.com',
path: '/v1/chat/completions',
headers: {
'Authorization': 'Bearer ' + config.openaiApiKey
}
}, function(res){
// ... process response ...
})
req.write(body)
req.end()
})
}
B. Safety & Sanitization (sanitizeAndValidateAi)
AI likes to give advice, even when it shouldn't. We want humans to provide support. Therefore, the bot has a "censor".
Logic:
- Checks if text contains banned words (
fix,solution,try to). - If yes -> Discards it and tries again or uses fallback.
- Removes Markdown code blocks (so bot doesn't send code).
function sanitizeAndValidateAi(text) {
var lower = text.toLowerCase()
// Banned words implying technical advice
var banned = ['fix', 'resolve', 'solution', 'steps', 'guide', 'you can do']
for (var i=0; i<banned.length; i++) {
if (lower.indexOf(banned[i]) >= 0) {
console.warn('AI output violated no-solutions rule')
return null // Reject response
}
}
return text.trim()
}
C. Uniqueness Engine (getUniqueAi)
To prevent the bot from sending the same thing to everyone ("Hello, how can I help?"), we have a uniqueness system.
How it works:
- Generates a response.
- Creates a Hash (fingerprint) of it.
- Checks memory (
aiRecent) if we sent this recently. - If yes -> Discards it and tries generating another variant (up to 6 attempts).
async function getUniqueAi(type, fn){
for (var attempt=0; attempt<6; attempt++) {
var out = await fn() // Call AI
var h = hashText(out) // Create hash
if (seen(type, h)) continue // If seen, try again
remember(type, h) // Remember new phrase
return out
}
return null // Fallback
}
🚑 2. The CPR API (External Monitoring)
The bot doesn't run in a vacuum. It is connected to an external "Mothership" server (136.243.104.68) that watches over its health.
A. Error Reporting (sendErrorReport)
When an error occurs (e.g. Discord API fails), the bot "snitches" to the monitoring server.
// Sending error to external API
var req = http.request({
method: 'POST',
hostname: '136.243.104.68',
port: 50030,
path: '/api/error/' + codeVal, // E.g. /api/error/404
}, function(res){})
req.write(JSON.stringify({ message: fullMsg }))
req.end()
B. The Kill Switch (Remote Restart)
If the bot detects a critical error (Error 1006 - Connection Reset), it knows it's over. Instead of "hanging", it calls for a restart.
Why external API? Because the bot cannot restart itself (a process cannot turn itself on when it is off).
client.on('error', async function(err){
if (err.code === 1006) {
// "Hello, I'm stuck. Restart me!"
http.get('http://136.243.104.68:50030/restart', ...)
}
})
🖼️ 3. Discord API (Eris & Attachments)
Here is an example of how we work with the Discord API, specifically file uploads (Logo), which was a key requirement.
Direct File Upload
Instead of sending a URL link (which can expire or be slow), we send the image binary data directly in the request body.
// Load file into memory at start (Buffer)
var logoBuffer = fs.readFileSync(__dirname + '/public/icon.png')
// Sending message with attachment
await client.createMessage(channelId, {
embeds: [{
title: 'Hello',
// Reference attachment using internal protocol
thumbnail: { url: 'attachment://icon.png' }
}]
}, {
file: logoBuffer, // Binary data
name: 'icon.png' // Filename in attachment
})
This way, the logo loads instantly and doesn't depend on any external webserver.
Status API Reference
Base URL: http://136.243.104.68:50030/
Status Model
status: overall state (Greengreen, Orangeorange, Redred)heartbeatStatus: monitor/SSH state (Greengreen, Redred)botStatus: derived from consecutive failures (Greengreen, Orangeorange, Redred)lastCheck: ISO timestampisResetting: restart in progress flag
Endpoints
GET /api/status
Returns the current overall status and heartbeat component state.
Response example:
{
"status": "green",
"heartbeatStatus": "green",
"botStatus": "green",
"lastCheck": "2025-01-01T12:00:00.000Z",
"isResetting": false,
"consecutiveFailures": 0
}
GET /api/config
Returns UI configuration values consumed by the frontend.
Response example:
{ "iconPath": "/assets/icon.png" }
GET /api/history/:year/:month
Returns daily summary for the month (for calendar/history views).
- Params:
year(YYYY),month(MM 1–12)
Response example:
[
{ "date": "2025-12-01", "status": "green" },
{ "date": "2025-12-02", "status": "red" }
]
GET /api/day/:date
Returns all records for a specific day.
- Params:
date(YYYY-MM-DD)
Response example:
[
{ "id": 10, "type": "restart_request", "status": "red", "code": 1006, "message": "API Restart Requested", "timestamp": "2025-12-02T08:15:00Z" },
{ "id": 11, "type": "restart_complete", "status": "green", "code": null, "message": "Restart Completed Successfully", "timestamp": "2025-12-02T08:16:15Z" }
]
GET /api/incidents
Returns recent incidents (Orange orange or Red red, newest first). Use on History page.
Response example:
[
{ "id": 21, "type": "heartbeat_fail", "status": "orange", "code": 1006, "message": "Connection Failed (Attempt 10)", "timestamp": "2025-12-05T11:00:00Z" },
{ "id": 22, "type": "cpr_start", "status": "red", "code": 1006, "message": "CPR (Forced Restart) Initiated", "timestamp": "2025-12-05T11:05:00Z" }
]
GET /api/errors/:code
Returns recent incidents for a specific error code.
- Params:
code(e.g.,401,1006,499)
Response example:
[
{ "id": 31, "type": "reported_error", "status": "orange", "code": 401, "message": "Switch Panel Failed", "timestamp": "2025-12-09T09:30:00Z" }
]
POST /api/error/:code
Reports a non-restart error from external systems. Treated as Orange orange (degraded).
Body:
{ "message": "Optional detailed error description" }
POST or GET /restart
Initiates a forced restart (CPR) when the bot is unreachable (1006). Red Red status is reserved for this action.
Response example:
202 Accepted { "status": "accepted", "message": "Reset sequence initiated" }
Error Codes
1006Critical Connection Reset (critical, restart-triggering)401Warning Switch Panel Failed402Warning Thread Create Failed403Warning Voice Update Failed404Warning Roster Update Failed405Warning Interaction Failed499Warning General Error