djs-builder 0.6.401 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,9 +9,10 @@ Boost your Discord bot development with ease, speed, and all-in-one features.
9
9
 
10
10
  ## 📑 Table of Contents
11
11
 
12
- 1. 🎯 [Starter](#starter) – Initialize your bot with commands, events, presence, and more.
13
- 2. ⚙️ [Functions](#function) – Utilities like CreateRow, CreateBar, Wait, and GetUser.
14
- 3. ⚡ [Commands & Events](#commands--events) – Easy setup with cooldowns, permissions, logging, and anti-crash.
12
+ 1. 🎯 [Starter](#-starter) – Initialize your bot with commands, events, presence, and more.
13
+ 2. ⚙️ [Functions](#%EF%B8%8F-functions) – Utilities like CreateRow, CreateBar, Wait, and GetUser.
14
+ 3. ⚡ [Commands & Events](#-commands--events) – Easy setup with cooldowns, permissions, logging, and anti-crash.
15
+ 4. 🌐 [Dashboard](#-dashboard) – Web-based control panel for managing your bot.
15
16
 
16
17
  ---
17
18
 
@@ -69,6 +70,15 @@ const starterOptions = {
69
70
  url: "https://your.crash.webhook.url", // 🚨 Webhook for crash reports
70
71
  mention_id: "YOUR_USER_ID", // 📣 Optional: mention user on crash
71
72
  },
73
+
74
+ // 🌐 Dashboard Configuration (Full docs at the end of this page)
75
+ dashboard: {
76
+ clientID: "YOUR_DISCORD_CLIENT_ID", // 🔑 Discord Application Client ID
77
+ clientSecret: "YOUR_DISCORD_CLIENT_SECRET", // 🔐 Discord Application Client Secret
78
+ callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL
79
+ sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
80
+ port: 3000, // 🌍 Dashboard port (default: 3000)
81
+ },
72
82
  };
73
83
 
74
84
  // Start the bot
@@ -130,6 +140,14 @@ await starter(client, starterOptions);
130
140
 
131
141
  - Available via `client.files`, useful for debugging or terminal display 🛠️.
132
142
 
143
+ #### 7️⃣ Dashboard (Web Control Panel)
144
+
145
+ - Launches a **modern web-based control panel** for your bot 🌐.
146
+ - Supports Discord OAuth2 authentication 🔐.
147
+ - Manage servers, levels, giveaways, and blacklists from the browser 🎛️.
148
+
149
+ > 📖 **Full Dashboard documentation available at the end of this page** → [🌐 DASHBOARD](#-dashboard)
150
+
133
151
  ---
134
152
 
135
153
  ### 💡 Tips
@@ -552,9 +570,7 @@ module.exports = {
552
570
  The **Level System** module lets you track user experience points (XP) in **text** 💬 and **voice** 🎙️, handle **level-ups** ⬆️, and display **leaderboards** 🏅.
553
571
  Perfect for gamifying your Discord server! 🎮✨
554
572
 
555
- > **Note**: To use this module, you **MUST** have **DATABASE** conection.
556
-
557
- > **Note**: You can get all data by requiring the **Level** module.
573
+ > **Note**: To use this module, you **MUST** have **DATABASE** conection. | **Note 2**: You can get all data by requiring the **Level** module.
558
574
 
559
575
  ---
560
576
 
@@ -708,9 +724,7 @@ module.exports = {
708
724
 
709
725
  This module provides a robust and feature-rich suite of functions to effortlessly launch, monitor, manage, and conclude **Giveaways** on your Discord server. It fully supports both **Reactions** and **Buttons** for entry, featuring advanced controls like pausing, resuming, and rerolling winners. **It is highly recommended to read the Important Notes section below.** 🚨
710
726
 
711
- > **Note**: To use this module, you **MUST** have **DATABASE** conection.
712
-
713
- > **Note**: You can get all data by requiring the **giveaway** module.
727
+ > **Note**: To use this module, you **MUST** have **DATABASE** conection. | **Note 2**: You can get all data by requiring the **giveaway** module.
714
728
 
715
729
  ---
716
730
 
@@ -799,7 +813,7 @@ module.exports = {
799
813
    description: "Starts a new highly-customized giveaway.",
800
814
    run: async (client, message, args) => {
801
815
      // ⏰ Giveaway ends in 48 hours
802
-     const twoDays = 48 * 60 * 60 * 1000;
816
+ const twoDays = Date.now() + (48 * 60 * 60 * 1000);
803
817
  const channelId = 'YOUR_GIVEAWAY_CHANNEL_ID'; // 📢 Target Channel
804
818
 
805
819
      await Gstart({
@@ -811,17 +825,17 @@ module.exports = {
811
825
  // 🎨 Customization for the STARTING EMBED
812
826
        embed: {
813
827
 
814
- custom: new EmbedBuilder().setTitle("Raw Embed").toJSON(),// 💡 You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
828
+ custom: new EmbedBuilder().setTitle("Raw Embed"),// 💡 You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
815
829
              title: "🎉 **HUGE SERVER BOOST GIVEAWAY!**",
816
830
              description: "Click the button below to enter for a chance to win a free server boost!",
817
831
              color: "Blue", // Any valid Discord color
818
-             image: "https://yourimage.com/banner.png", 🖼️
832
+ image: "https://yourimage.com/banner.png", // image URL
819
833
              thumbnail: message.guild.iconURL(),
820
834
        },
821
835
 
822
836
  // 🛑 Customization for the ENDED EMBED
823
837
        endEmbed: {
824
- custom: new EmbedBuilder().setTitle("Raw Embed").toJSON(),// 💡 You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
838
+ custom: new EmbedBuilder().setTitle("Raw Embed"),// 💡 You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
825
839
              title: "🛑 Giveaway Has Concluded!",
826
840
              description: "Congratulations to the winners! Check the message below.",
827
841
              color: "Green",
@@ -834,9 +848,13 @@ module.exports = {
834
848
          emoji: "✅", // The emoji displayed on the button
835
849
          label: "Enter Giveaway!", // The text label
836
850
          style: 3, // Button style: Primary(1), Secondary(2), Success(3), Danger(4)
837
-         id: "giveaway", // Custom ID for the button
838
-
851
+         id: "djs-builder-giveaway", // Custom ID for the button
839
852
        },
853
+
854
+ // 🔒 Requirements (Optional)
855
+ requirements: {
856
+ requiredRoles: ["123456789012345678"], // 🛡️ User MUST have this role to join (Button Only)
857
+ },
840
858
      });
841
859
      message.reply("🎉 Giveaway started successfully!");
842
860
    },
@@ -867,6 +885,11 @@ This module requires specific setup steps to function correctly. Pay attention t
867
885
  - You **MUST** manually implement a listener for the **`interactionCreate`** event and use the **`GaddUser`** function to register the user entry when the button is clicked. 🖱️
868
886
  - _See the `GaddUser` section for a detailed code example._
869
887
 
888
+ - **3. Requirements (Roles):**
889
+
890
+ - The `requiredRoles` feature currently works **ONLY** with the **Button** entry method (`reaction.type: "button"`).
891
+ - When using `GaddUser`, you must pass the `guild` object as the third argument for the role check to work.
892
+
870
893
  </details>
871
894
 
872
895
  ---
@@ -1076,27 +1099,37 @@ module.exports = {
1076
1099
  run: async (interaction) => {
1077
1100
  // 1. Handle Join/Entry Button Click
1078
1101
  if (interaction.customId === "djs-builder-giveaway") {
1102
+ // ⚠️ Note: Pass 'interaction.guild' as the 3rd argument to enable Role Requirements check!
1079
1103
  const result = await GaddUser(
1080
1104
  interaction.message.id,
1081
- interaction.user.id
1105
+ interaction.user.id,
1106
+ interaction.guild
1082
1107
  );
1083
1108
 
1084
- if (result?.error === "❌ User Already Joined") {
1085
- // User already joined, offer a 'Leave' button dynamically
1086
- const row = await CreateRow([
1087
- [
1088
- {
1089
- label: "Leave Giveaway",
1090
- id: "djs-builder-giveaway-leave-" + interaction.message.id, // Dynamic ID
1091
- style: 4, // Danger Red
1092
- },
1093
- ],
1094
- ]);
1109
+ if (result?.error) {
1110
+ // Handles both "User Already Joined" and "Missing Roles" errors
1111
+ if (result.error === "❌ User Already Joined") {
1112
+ // ... (Leave button logic)
1113
+ const row = await CreateRow([
1114
+ [
1115
+ {
1116
+ label: "Leave Giveaway",
1117
+ id: "djs-builder-giveaway-leave-" + interaction.message.id, // Dynamic ID
1118
+ style: 4, // Danger Red
1119
+ },
1120
+ ],
1121
+ ]);
1122
+ return interaction.reply({
1123
+ content: "⚠️ You have **already joined** this giveaway! You can **leave** by clicking the button below.",
1124
+ components: row,
1125
+ flags: 64,
1126
+ });
1127
+ }
1128
+
1129
+ // Show error (e.g. Missing Role)
1095
1130
  return interaction.reply({
1096
- content:
1097
- "⚠️ You have **already joined** this giveaway! You can **leave** by clicking the button below.",
1098
- components: row,
1099
- flags: 64, // Ephemeral reply
1131
+ content: result.error,
1132
+ flags: 64
1100
1133
  });
1101
1134
  }
1102
1135
 
@@ -1106,6 +1139,7 @@ module.exports = {
1106
1139
  });
1107
1140
  }
1108
1141
 
1142
+
1109
1143
  // 2. Handle Leave Button Click (Dynamically Generated ID)
1110
1144
  if (
1111
1145
  interaction.customId &&
@@ -1208,8 +1242,9 @@ if (giveawayData) {
1208
1242
    "channelId": "876543210987654321", // 📢 Channel ID
1209
1243
    "messageId": "987654321098765432", // 💬 Message ID of the giveaway post
1210
1244
    "hoster": "112233445566778899", // 👤 User ID of the giveaway host
1211
-   "winwesNumber": 1, // 🔢 Number of winners set
1212
-   "winers": [], // 🏆 Array of user IDs who won (empty if not ended)
1245
+ "prize" : "code" // 🎁 prize
1246
+   "winnerCount": 1, // 🔢 Number of winners set
1247
+   "winners": [], // 🏆 Array of user IDs who won (empty if not ended)
1213
1248
    "paused": false, // ⏸️ True if the giveaway is paused
1214
1249
    "pausedTime": [], // ⏱️ Array of saved remaining times (used for resume)
1215
1250
    "endTime": "1730995200000", // 📅 Timestamp (MS) of when the giveaway should end
@@ -1223,7 +1258,7 @@ if (giveawayData) {
1223
1258
      "fields": [
1224
1259
        {
1225
1260
          "name": "🎉 Giveaway",
1226
-         "value": "- Winer(s): 1\n- Time : <t:1730995200:R>\n- Hosted By : <@112233445566778899>",
1261
+         "value": "- Winner(s): 1\n- Time : <t:1730995200:R>\n- Hosted By : <@112233445566778899>",
1227
1262
          "inline": true
1228
1263
        }
1229
1264
      ]
@@ -1499,6 +1534,7 @@ module.exports = {
1499
1534
  channelId: channel.id,
1500
1535
  winers: winnerCount,
1501
1536
  endTime: endTimeMs,
1537
+ prize : prize,
1502
1538
  embed: {
1503
1539
  title: `🎉 ${prize} Giveaway!`,
1504
1540
  image: image,
@@ -1550,7 +1586,7 @@ module.exports = {
1550
1586
  content: `${title}\n\n${listContent}`,
1551
1587
  });
1552
1588
  } else if (listContent.length <= MAX_EMBED_LENGTH) {
1553
- // Output as an Embed (Over 2000, under 4096)
1589
+ // Output as an Embed (Over 2000, under 4000)
1554
1590
  const embed = new EmbedBuilder()
1555
1591
  .setTitle(title.replace(/\*\*/g, ""))
1556
1592
  .setDescription(listContent)
@@ -1561,7 +1597,7 @@ module.exports = {
1561
1597
  embeds: [embed],
1562
1598
  });
1563
1599
  } else {
1564
- // Output as an attachment/JSON file (Over 4096 chars)
1600
+ // Output as an attachment/JSON file (Over 4000 chars)
1565
1601
  const jsonFile = new AttachmentBuilder(
1566
1602
  Buffer.from(JSON.stringify(giveaways, null, 2)),
1567
1603
  { name: `${type}_giveaways_list.json` }
@@ -1768,10 +1804,13 @@ module.exports = {
1768
1804
 
1769
1805
  </details>
1770
1806
 
1807
+ ---
1808
+
1771
1809
  </details>
1772
1810
 
1773
1811
  ---
1774
1812
 
1813
+
1775
1814
  <details>
1776
1815
  <summary>Blacklist System 🚫</summary>
1777
1816
 
@@ -1779,9 +1818,7 @@ module.exports = {
1779
1818
 
1780
1819
  The **Blacklist System** allows you to block specific **users**, **roles**, or **channels** from using your bot's commands. This is useful for moderation and preventing abuse.
1781
1820
 
1782
- > **Note**: To use this module, you **MUST** have **DATABASE** connection.
1783
-
1784
- > **Note**: You can get all data by requiring the **Blacklist** module.
1821
+ > **Note 1**: To use this module, you **MUST** have **DATABASE** connection. | **Note 2**: You can get all data by requiring the **Blacklist** module.
1785
1822
 
1786
1823
  ---
1787
1824
 
@@ -1920,7 +1957,7 @@ module.exports = {
1920
1957
  const embed = new EmbedBuilder()
1921
1958
  .setTitle("🚫 Blacklist")
1922
1959
  .setColor("Red")
1923
- .setDescription(list.map(item => `• **${item.type.toUpperCase()}**: <${item.type === 'channel' ? '#' : item.type === 'role' ? '@&' : '@'}${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4096));
1960
+ .setDescription(list.map(item => `• **${item.type.toUpperCase()}**: <${item.type === 'channel' ? '#' : item.type === 'role' ? '@&' : '@'}${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1924
1961
 
1925
1962
  return interaction.reply({ embeds: [embed], flags : 64 });
1926
1963
  } else {
@@ -1936,21 +1973,21 @@ module.exports = {
1936
1973
  const userEmbed = new EmbedBuilder()
1937
1974
  .setTitle("🚫 Blacklisted Users")
1938
1975
  .setColor("Red")
1939
- .setDescription(users.map(item => `• <@${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4096));
1976
+ .setDescription(users.map(item => `• <@${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1940
1977
  embeds.push(userEmbed);
1941
1978
  }
1942
1979
  if( roles.length) {
1943
1980
  const roleEmbed = new EmbedBuilder()
1944
1981
  .setTitle("🚫 Blacklisted Roles")
1945
1982
  .setColor("Red")
1946
- .setDescription(roles.map(item => `• <@&${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4096));
1983
+ .setDescription(roles.map(item => `• <@&${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1947
1984
  embeds.push(roleEmbed);
1948
1985
  }
1949
1986
  if( channels.length) {
1950
1987
  const channelEmbed = new EmbedBuilder()
1951
1988
  .setTitle("🚫 Blacklisted Channels")
1952
1989
  .setColor("Red")
1953
- .setDescription(channels.map(item => `• <#${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4096));
1990
+ .setDescription(channels.map(item => `• <#${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1954
1991
  embeds.push(channelEmbed);
1955
1992
  }
1956
1993
  return interaction.reply({ embeds, flags : 64 });
@@ -2111,6 +2148,218 @@ execute: Function // 🏃‍♂️ Alternative function to run the
2111
2148
 
2112
2149
  ---
2113
2150
 
2151
+ ## 🌐 DASHBOARD
2152
+
2153
+ The **Dashboard System** is a modern, lightweight web-based control panel for your Discord bot. It provides a beautiful interface to manage your bot, servers, levels, giveaways, and more! 🎛️🚀
2154
+
2155
+ **Features:**
2156
+
2157
+ - 🔐 **Discord OAuth2 Login** – Secure authentication with Discord.
2158
+ - 📊 **Bot Statistics** – View real-time bot stats (servers, users, commands, uptime).
2159
+ - 🏠 **Server Management** – Manage servers where you have admin permissions.
2160
+ - 📜 **Commands Viewer** – Browse all slash and prefix commands.
2161
+ - 🏆 **Level System Management** – View leaderboards, manage user XP and levels.
2162
+ - 🎉 **Giveaway Control** – Pause, resume, end, reroll, or delete giveaways.
2163
+ - 🚫 **Blacklist Management** – Add/remove users, roles, or channels from blacklist.
2164
+ - 🎨 **Modern UI** – Beautiful, responsive design with dark mode support.
2165
+
2166
+ > **Note**: This module requires **express**, **express-session**, **passport**, and **passport-discord** packages. | **Note 2**: You must have a **DATABASE** connection for full functionality.
2167
+
2168
+ > 💡 **Tip:** You can use Dashboard with the starter function (see [Starter](#starter)) or as a standalone function!
2169
+
2170
+ ---
2171
+
2172
+ <details>
2173
+ <summary>Dashboard with Starter ⚙️</summary>
2174
+
2175
+ When using with starter, simply add the `dashboard` option to your starter configuration:
2176
+
2177
+ ```js
2178
+ const { starter } = require("djs-builder");
2179
+ const { Client, GatewayIntentBits } = require("discord.js");
2180
+
2181
+ const client = new Client({
2182
+ intents: Object.keys(GatewayIntentBits).map((a) => GatewayIntentBits[a]),
2183
+ });
2184
+
2185
+ const starterOptions = {
2186
+ bot: {
2187
+ token: "YOUR_BOT_TOKEN",
2188
+ ownerId: "YOUR_USER_ID",
2189
+ },
2190
+ terminal: true,
2191
+
2192
+ // 🌐 Dashboard Configuration
2193
+ dashboard: {
2194
+ clientID: "YOUR_DISCORD_CLIENT_ID", // 🔑 Discord Application Client ID
2195
+ clientSecret: "YOUR_DISCORD_CLIENT_SECRET", // 🔐 Discord Application Client Secret
2196
+ callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL
2197
+ sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
2198
+ port: 3000, // 🌍 Dashboard port (default: 3000)
2199
+ },
2200
+
2201
+ // ... other options (Status, database, anticrash, etc.)
2202
+ };
2203
+
2204
+ await starter(client, starterOptions);
2205
+ ```
2206
+
2207
+ </details>
2208
+
2209
+ ---
2210
+
2211
+ <details>
2212
+ <summary>Dashboard Standalone Usage 🔧</summary>
2213
+
2214
+ You can use the Dashboard as a **standalone function** without the starter! This is useful if you already have your own bot setup or want more control.
2215
+
2216
+ ```js
2217
+ const { dashboard } = require("djs-builder");
2218
+ const { Client, GatewayIntentBits } = require("discord.js");
2219
+
2220
+ const client = new Client({
2221
+ intents: Object.keys(GatewayIntentBits).map((a) => GatewayIntentBits[a]),
2222
+ });
2223
+
2224
+ // 🔑 Login your bot first
2225
+ client.login("YOUR_BOT_TOKEN");
2226
+
2227
+ client.once("ready", () => {
2228
+ console.log(`✅ Logged in as ${client.user.tag}`);
2229
+
2230
+ // 🌐 Start the Dashboard
2231
+ dashboard(client, {
2232
+ clientID: "YOUR_DISCORD_CLIENT_ID", // 🔑 Discord Application Client ID
2233
+ clientSecret: "YOUR_DISCORD_CLIENT_SECRET", // 🔐 Discord Application Client Secret
2234
+ callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL
2235
+ sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
2236
+ port: 3000, // 🌍 Dashboard port (default: 3000)
2237
+ });
2238
+ });
2239
+ ```
2240
+
2241
+ > 💡 **Tip:** When using standalone, make sure your bot is logged in before starting the dashboard!
2242
+
2243
+ </details>
2244
+
2245
+ ---
2246
+
2247
+ <details>
2248
+ <summary>Dashboard Routes & API 📡</summary>
2249
+
2250
+ ### 📌 Dashboard Routes
2251
+
2252
+ | Route | Description |
2253
+ |-------|-------------|
2254
+ | `/` | 🏠 Homepage with bot stats |
2255
+ | `/login` | 🔐 Login page |
2256
+ | `/dashboard` | 📊 Server selection |
2257
+ | `/dashboard/:guildId` | 🏠 Server overview |
2258
+ | `/dashboard/:guildId/commands` | 📜 Commands list |
2259
+ | `/dashboard/:guildId/levels` | 🏆 Level leaderboard |
2260
+ | `/dashboard/:guildId/giveaways` | 🎉 Giveaway management |
2261
+
2262
+ ---
2263
+
2264
+ ### 📡 API Endpoints
2265
+
2266
+ The dashboard exposes several API endpoints for dynamic data:
2267
+
2268
+ ```js
2269
+ // 📊 Get bot statistics
2270
+ GET /api/stats
2271
+
2272
+ // 🏠 Get server statistics
2273
+ GET /api/:guildId/stats
2274
+
2275
+ // 👤 Get user level data
2276
+ GET /api/:guildId/user/:userId
2277
+
2278
+ // 🔍 Search members
2279
+ GET /api/:guildId/members/search?q=query
2280
+
2281
+ // 🏆 Level management
2282
+ POST /api/:guildId/level/update // Update user level
2283
+ POST /api/:guildId/level/add // Add XP to user
2284
+ POST /api/:guildId/level/reset // Reset user level
2285
+
2286
+ // 🎉 Giveaway actions
2287
+ POST /api/:guildId/giveaway/pause
2288
+ POST /api/:guildId/giveaway/resume
2289
+ POST /api/:guildId/giveaway/end
2290
+ POST /api/:guildId/giveaway/reroll
2291
+ POST /api/:guildId/giveaway/delete
2292
+
2293
+ // 🚫 Blacklist management
2294
+ POST /api/guild/:guildId/blacklist // Add to blacklist
2295
+ DELETE /api/guild/:guildId/blacklist // Remove from blacklist
2296
+ ```
2297
+
2298
+ </details>
2299
+
2300
+ ---
2301
+
2302
+ <details>
2303
+ <summary>Dashboard Options 🔧</summary>
2304
+
2305
+ ### 🔧 Configuration Options
2306
+
2307
+ | Option | Type | Required | Description |
2308
+ |--------|------|----------|-------------|
2309
+ | `clientID` | `string` | ✅ | 🔑 Your Discord Application Client ID |
2310
+ | `clientSecret` | `string` | ✅ | 🔐 Your Discord Application Client Secret |
2311
+ | `callbackURL` | `string` | ✅ | 🔗 OAuth2 redirect URL (must match Discord settings) |
2312
+ | `sessionSecret` | `string` | ✅ | 🔒 Secret key for session encryption |
2313
+ | `port` | `number` | ❌ | 🌍 Port to run the dashboard (default: 3000) |
2314
+
2315
+ ---
2316
+
2317
+ ### 📁 View Templates
2318
+
2319
+ The dashboard uses **EJS** templates located in the `views` folder:
2320
+
2321
+ | File | Description |
2322
+ |------|-------------|
2323
+ | `index.ejs` | 🏠 Homepage |
2324
+ | `login.ejs` | 🔐 Login page |
2325
+ | `dashboard.ejs` | 📊 Server selection |
2326
+ | `guild.ejs` | 🏠 Server overview |
2327
+ | `commands.ejs` | 📜 Commands list |
2328
+ | `levels.ejs` | 🏆 Level management |
2329
+ | `giveaways.ejs` | 🎉 Giveaway management |
2330
+ | `404.ejs` | ❌ Not found page |
2331
+
2332
+ </details>
2333
+
2334
+ ---
2335
+
2336
+ <details>
2337
+ <summary>Discord Developer Portal Setup 🛠️</summary>
2338
+
2339
+ ### 🛠️ How to Get Client ID & Secret
2340
+
2341
+ 1. Go to [Discord Developer Portal](https://discord.com/developers/applications) 🌐
2342
+ 2. Create a new application or select existing one 📱
2343
+ 3. Go to **OAuth2** → **General** 🔐
2344
+ 4. Copy the **Client ID** and **Client Secret** 📋
2345
+ 5. Add your **Redirect URL** (e.g., `http://localhost:3000/auth/discord/callback`) ✅
2346
+ 6. Make sure to add the URL to **Redirects** list 📝
2347
+
2348
+ ---
2349
+
2350
+ ### 💡 Tips & Notes
2351
+
2352
+ - 🔒 **Keep secrets safe** – Never expose `clientSecret` or `sessionSecret` publicly.
2353
+ - 🌐 **Production URL** – Update `callbackURL` when deploying to production.
2354
+ - 🗄️ **Database Required** – Level and Giveaway features require MongoDB connection.
2355
+ - 🎨 **Customizable** – Edit EJS templates to customize the look and feel.
2356
+ - 🔄 **Real-time Stats** – Bot statistics update automatically.
2357
+ - 🛡️ **Secure** – Only admins can manage their servers.
2358
+
2359
+ </details>
2360
+
2361
+ ---
2362
+
2114
2363
  ## 💌 Support
2115
2364
 
2116
2365
  We welcome contributions! If you have any suggestions, bug reports, or feature requests, feel free to reach out to us on Discord.