A comprehensive Discord bot built with Discord.js v14 for managing the Project NexTech community server. This bot handles member verification, volunteer hours tracking, event management, calendar synchronization, and various administrative tasks.
- Features
- Commands
- Setup
- Configuration
- Google Sheets Integration
- Automated Features
- Project Structure
- Member Verification System - Automated onboarding with verification forms and admin approval
- Google Sheets Integration - Real-time sync with membership data, hours tracking, events, and contacts
- Calendar Synchronization - Automatic Discord event creation from iCal feeds
- Volunteer Hours Tracking - Track and display volunteer hours with leaderboards
- Event Management - View and filter upcoming events by department
- Contact Directory - Quick access to leadership contact information
- Role Management - Automated role assignment based on membership status
- Region & Country Roles - Create and manage geographic roles with proper formatting
- Member Cache System - Persistent caching for improved performance
- DM Forwarding - Forward direct messages to verification team
- Broadcast System - Send announcements to all members via DM
- Role-based access control for sensitive commands
- Cooldown system to prevent command spam
- Permission checks for administrative functions
- Ephemeral responses for privacy-sensitive information
Send a direct message to filtered groups of members.
Permissions: NT Executive Committee or Verification Team
Cooldown: 5 minutes
Options:
message(required) - The message to broadcastrecipients(required) - Choose who receives the message:- All NT Members - Everyone with NT Member role
- Enrolled - Members with NT Enrolled role
- Unenrolled - Members with NT Unenrolled role
- Unverified - Members with unverified roles
- Paused - Members marked as Paused/Not a Member in Membership Status sheet
- Custom CSV - Members from a CSV file (see generate-broadcast-list.js)
csv_url(optional) - URL or file path to CSV when using Custom CSV optionconfirm(required) - Must be set toTrueto confirm sending
Features:
- Sends embeds with sender information
- Tracks success/failure counts
- Reports delivery statistics
- Rate-limited to 250 messages per minute with automatic retry
- Supports filtering by role or Google Sheets data
- CSV support with automatic parsing (skips first 6 rows, reads column B)
- Handles HTTP/HTTPS URL downloads and local file paths
Create a new region role with proper formatting, ordering, and optional member assignment.
Permissions: NT Executive Committee only
Cooldown: None
Options:
region_name(required) - Name of the region (e.g., "Ontario")country_code(required) - Two-letter country code (e.g., "CA")country_name(required) - Full country name (e.g., "Canada")members(optional) - Comma-separated member IDs to add to roles
Features:
- Automatic Role Naming: Creates roles in the format:
- Region:
RegionName (CC #)(e.g., "Ontario (CA 1)") - Country:
CountryName (CC)(e.g., "Canada (CA)")
- Region:
- Auto-Numbering: Automatically assigns the next sequential number for regions within the same country
- Smart Country Role Handling:
- Checks if country role already exists
- Creates new country role if needed
- Uses existing country role if available
- Automatic Role Positioning: Places roles in the correct hierarchy:
- Country roles above region roles
- Maintains consistent ordering
- Places above base roles, below administrative roles
- Batch Member Assignment: Optionally adds multiple members to both country and region roles
- Validation: Checks for existing roles and validates member IDs before creation
- Interactive Confirmation: Shows preview with confirmation buttons before creating roles
- Error Handling: Reports which members were successfully added and which failed
Example Usage:
/createregion region_name:Ontario country_code:CA country_name:Canada
/createregion region_name:Texas country_code:US country_name:United States members:123456789,987654321
Synchronize NT Enrolled/Unenrolled roles based on membership status from Google Sheets.
Permissions: NT Executive Committee or Administrator
Cooldown: 60 seconds
Functionality:
- Fetches membership status from Google Sheets
- Assigns "NT Enrolled" role to active members (Member, New Member, Paused)
- Assigns "NT Unenrolled" role to inactive members (Not a Member)
- Skips users with "NT Board Member" role
- Provides detailed statistics of role changes
Manually verify a new member and assign appropriate roles.
Permissions: Verification Team, EC, Leadership, or Administrator
Cooldown: 10 seconds
Options:
user(required) - The user to verifyname(required) - Full name of the userirl_connection(required) - Whether they have IRL connection to existing membergrade(optional) - Grade level (7th-12th, college years)school(optional) - School nameregion(optional) - Region with autocompleterobotics_team(optional) - Robotics team number or nameinvite_source(optional) - How they found Project NexTech
Features:
- Automatic Nickname Conflict Detection & Resolution:
- Detects members with the same first name
- Auto-resolves when last initials are different (adds last initial to both users)
- Triggers manual modal when last initials match (requires custom nicknames)
- Only verifies users with unverified roles to prevent accidental re-verification
- Autocomplete for region selection
- Logs verification to Google Sheets
- Removes unverified roles (NT Unverified/Combined Unverified)
- Assigns NT Member role
- Assigns Server Member/Online Member roles based on IRL connection
- Assigns NT Unenrolled role by default
- Assigns region and country roles automatically
- Updates nickname to
[ɴᴛ] FirstNameor[ɴᴛ] FirstName L.format - Sends verification details to staff chat channel
- Posts welcome message in NT chat channel
- Warns about missing optional fields
Nickname Conflict Resolution:
- No Conflict: Sets nickname to
[ɴᴛ] FirstName - Different Last Initials: Auto-resolves by setting both users to
[ɴᴛ] FirstName L. - Same Last Initials: Opens interactive modal for manual nickname entry for both users
Self-verification form for new members to gain access to the server.
Permissions: NT Unverified or Combined Unverified role required
Cooldown: 10 seconds
Features:
- Opens a modal with verification form
- Collects: full name, grade, school, region, robotics team, referral source
- Submits to verification channel for admin review
- Pings Verification Team role
- Sends confirmation to user
Get the link to the Project NexTech Google Calendar.
Cooldown: 3 seconds
Features:
- Displays calendar URL in embedded format
- Quick access to all events and meetings
View contact information for department leadership.
Cooldown: 5 seconds
Options:
department(required) - Choose from:- Engineering
- Mentoring
- Programming
- Physics/Math
- Natural Sciences
- Marketing
- Logistics
- Policy/Intl
- EC (not sure?)
Features:
- Fetches contacts from Google Sheets
- Displays name, role, Discord mention, email
- Formatted in clean embeds
Get contact information for leadership of an upcoming event.
Cooldown: 5 seconds
Features:
- Shows dropdown of upcoming events
- Select an event to view department contacts
- Displays event details and department leadership info
- Interactive select menu with 60-second timeout
View upcoming events filtered by department.
Cooldown: 1 second
Options:
department(required) - Choose from:- Engineering
- Mentoring
- Programming
- Physics/Math
- Natural Sciences
- All
Features:
- Fetches events from Google Sheets
- Displays comprehensive event information:
- Date and day of week
- Status (with "NO SIGNUPS" warnings)
- Course selection
- Region
- Time
- Hours (credit)
- Location
- Notes
- Highlights undecided events with
⚠️ - Department-based filtering
- Pagination for large event lists (13 events per page)
- Interactive navigation buttons
Display all upcoming Project NexTech Info Session events from Discord.
Cooldown: 5 seconds
Features:
- Fetches Discord scheduled events
- Filters for "Project NexTech Info Session" events only
- Shows only future events (ignores past sessions)
- Displays for each session:
- Full date and time (Discord timestamp)
- Relative time until start (e.g., "in 2 days")
- Direct link to Discord event
- Presentation slides link
- Sessions sorted chronologically (earliest first)
- Visual separators between multiple sessions
- Shows total count in footer
- Encourages members to mark "Interested" on events
View volunteer hours for yourself or another member.
Cooldown: 5 seconds
Options:
user(optional) - User to check hours for (defaults to yourself)requests(optional) - Number of recent requests to display (1-10)
Features:
Default Behavior (no requests parameter):
- Displays total volunteer hours summary
- Shows user's profile picture
- Fetches data from "Member Hours Tracker" sheet
- Formatted with timestamps
With requests parameter:
- Displays recent hour verification requests
- Shows the most recent N requests (sorted by submission order)
- Fetches data from "Hour Verification" sheet
- For each request, displays:
- Request number (row in sheet)
- Hours requested
- Approval status (✅ Approved, ⏳ Pending, ❓ Other)
- Department
- Date
- Type of task
- Description of task
- Special handling:
- Denied requests: Shows status but hides hours details
- Missing requests: Shows placeholder for positions without data
- Shows total count if more requests exist than displayed
- Data pulled from Google Sheets columns:
- Column A: Name (for matching)
- Column B: Hours
- Column C: Verdict (Approved/Denied/Pending)
- Column D: Department
- Column E: Date
- Column H: Type of task
- Column I: Description
Examples:
/hours → Shows your total hours
/hours user:@John → Shows John's total hours
/hours requests:5 → Shows your last 5 verification requests
/hours user:@John requests:3 → Shows John's last 3 requests
View the volunteer hours leaderboard.
Cooldown: 10 seconds
Options:
limit(optional) - Number of top volunteers (5-25, default: 10)
Features:
- Shows top volunteers by total hours
- Medal emojis for top 3 (🥇 🥈 🥉)
- Sorted by hours descending
- Only includes members with hours > 0
Get the link to the volunteer hours request form.
Cooldown: 10 seconds
Features:
- Displays Google Form link as button
- Shows what information to include
- Formatted embed with instructions
- Node.js 16.9.0 or higher
- npm or yarn
- Discord Bot Token
- Google Cloud Service Account with Sheets API access
- Google Sheets for data storage
- Clone the repository:
git clone https://github.com/Project-NexTech/Project-NexTech-discord-bot.git
cd Project-NexTech-discord-bot- Install dependencies:
npm install- Set up environment variables:
Create a
.envfile in the root directory:
# Discord Configuration
DISCORD_TOKEN=your_discord_bot_token
CLIENT_ID=your_client_id
GUILD_ID=your_guild_id
# Role IDs
NT_MEMBER_ROLE_ID=role_id
NT_UNVERIFIED_ROLE_ID=role_id
COMBINED_UNVERIFIED_ROLE_ID=role_id
EC_ROLE_ID=role_id
VERIFICATION_TEAM_ROLE_ID=role_id
# Channel IDs
INFO_SESSION_VOICE_CHANNEL_ID=channel_id
NT_CHAT_CHANNEL_ID=channel_id
STAFF_CHAT_CHANNEL_ID=channel_id
# Google Sheets IDs
VOLUNTEERS_SHEET_ID=sheet_id
EVENTS_SHEET_ID=sheet_id
LEADERSHIP_SHEET_ID=sheet_id
VERIFICATION_SHEET_ID=sheet_id
# URLs
CALENDAR_URL=your_calendar_url
CALENDAR_ICAL_URL=your_ical_url
HOURS_FORM_URL=your_hours_form_url
INFO_SESSION_BANNER_URL=path_or_url_to_banner
# Feature Flags
CHECK_LEFT_USERS_ENABLED=false- Set up Google Sheets credentials:
- Create a service account in Google Cloud Console
- Enable Google Sheets API
- Download the credentials JSON file
- Rename it to
credentials.jsonand place it in the project root - Share your Google Sheets with the service account email
- Deploy commands:
# Deploy to your guild (instant)
node deploy-commands.js
# Deploy globally (takes up to 1 hour)
node deploy-commands.js --global- Start the bot:
node index.jsThe bot expects the following sheets:
- Tab:
Limited Data - Columns: Name (A), Email 1 (B), Email 2 (C), Discord User ID (E)
-
Tab:
San Diego Signups- Columns-based structure (each column = one event)
- Row 1: Date
- Row 2: Day of Week
- Row 3: Comment
- Row 4: Status
- Row 5: Course Selection
- Row 6: Region
- Row 7: Supervisor
- Row 8: Depart Time
- Row 9: Credit (hours)
- Row 10: Location
- Row 11: Note
-
Tab:
Member Hours Tracker- Column A: Name
- Column K: Total Hours
-
Tab:
Membership Status- Column A: Name (starts at row 10)
- Column B: Status (Member, New Member, Paused, Not a Member, Unknown)
- Tab:
Sheet1 - Columns: Name (A), Department (B), Email (C), Discord Username (D), Discord User ID (E), Role/Note (F)
- Tab:
#nextech-verify - Columns: Discord ID (A), Name (B), Grade (F), School (G), Region (H), Robotics Team (I), Invite Source (J)
The bot expects the following role names (case-insensitive):
NT MemberNT EnrolledNT UnenrolledNT Board MemberNT UnverifiedorNexTech UnverifiedCombined UnverifiedServer MemberOnline MemberVerification TeamNT Executive Committee
Region roles should follow the pattern: Region Name (CC #) (e.g., "San Diego (US 1)")
Country roles should follow the pattern: Country Name (CC) (e.g., "United States (US)")
The bot integrates with Google Sheets for:
- Volunteer hours - Fetches total hours and links Discord IDs to names
- Events - Retrieves upcoming events with all details
- Membership status - Syncs member enrollment status
- Contacts - Gets leadership contact information
- Leaderboard - Ranks members by volunteer hours
- User verification - Logs new member verification data
- Left users tracking - Marks users who left the server (red background)
Uses Google Service Account authentication with OAuth 2.0. The service account must have:
- Read access to all data sheets
- Write access to verification sheet
- Spreadsheets API scope:
https://www.googleapis.com/auth/spreadsheets
- Purpose: Improves performance for commands that need to check member data frequently
- Persistence: Cache saved to
data/member-cache.jsonon disk - Auto-Refresh: Updates every 15 minutes to keep data fresh
- Smart Logging: Only logs cache updates when member count changes or on initial load
- Benefits:
- Faster nickname conflict detection in
/verifyuser - Improved
/broadcastcommand performance - Reduces API calls to Discord
- Survives bot restarts (loads from disk on startup)
- Minimal console noise during periodic refreshes
- Faster nickname conflict detection in
- Data Stored: User ID, username, display name, roles, join date
- Exclusions: Bot accounts are not cached
- Frequency: Every 5 minutes
- Function: Creates Discord scheduled events from iCal feed
- Target: Info Session events only
- Features:
- Automatically creates stage channel events
- Updates existing events if times change
- Deletes Discord events removed from calendar
- Skips past events (> 1 hour ago)
- Adds custom banner image
- Persists mapping in
data/event-mapping.json
- Frequency: Every 6 hours (if enabled)
- Function: Checks verification sheet for users who left the server
- Action: Marks their row with red background color
- Configuration: Set
CHECK_LEFT_USERS_ENABLED=truein.env
- Trigger: User receives unverified role (from Discord onboarding)
- Action: Sends welcome message to verify ping channel
- Content: Instructions to run
/verifycommand - Skips: Users already verified via
/verifyuser
- Trigger: User successfully verified via
/verifyusercommand - Staff Notification: Sends detailed verification embed to staff chat channel
- Public Welcome: Posts welcome message in NT chat channel with instructions
- Content: Directs new members to announcements, role selection, and info sessions
- Detection: Automatically checks for existing members with same first name
- Auto-Resolution: When last initials differ, adds last initial to both users' nicknames
- Manual Resolution: When last initials match, prompts staff to set custom nicknames via interactive modal
- Prevention: Ensures unique, identifiable nicknames across all verified members
- Trigger: Bot receives direct message
- Action: Forwards to verification channel
- Includes: Message content, attachments, embeds, stickers
- Notifies: Pings Verification Team role
- Purpose: Allows users to contact verification team privately
- Prevents command spam
- Customizable per command
- Shows countdown timer in Discord timestamp format
- Resets after cooldown expires
Project-NexTech-discord-bot/
├── commands/
│ ├── admin/
│ │ ├── broadcast.js # Broadcast messages to filtered member groups
│ │ ├── createregion.js # Create region/country roles
│ │ ├── syncroles.js # Sync enrollment roles from Sheets
│ │ └── verifyuser.js # Manually verify new members
│ ├── events/
│ │ ├── events.js # View upcoming events
│ │ └── infosessions.js # Display upcoming info session events
│ ├── general/
│ │ ├── calendar.js # Get calendar link
│ │ ├── contact.js # View department contacts
│ │ ├── contactforevent.js # Get event contacts
│ │ └── verify.js # Self-verification form
│ └── hours/
│ ├── hours.js # View volunteer hours
│ ├── leaderboard.js # Hours leaderboard
│ └── requesthours.js # Get hours request form
├── events/
│ ├── ready.js # Bot startup and initialization
│ ├── interactionCreate.js # Handle commands, autocomplete, and buttons
│ ├── modalSubmit.js # Handle verification modal
│ ├── messageCreate.js # Forward DMs to verification
│ └── guildMemberUpdate.js # Welcome new unverified members
├── utils/
│ ├── sheets.js # Google Sheets API integration
│ ├── calendarSync.js # Calendar synchronization
│ ├── memberCache.js # Persistent member cache system
│ └── helpers.js # Utility functions and embed builders
├── data/
│ ├── member-cache.json # Cached member data (auto-generated)
│ ├── event-mapping.json # Calendar event ID mapping (auto-generated)
│ └── broadcast-list.csv # Custom broadcast recipient list (optional)
├── index.js # Main bot entry point
├── deploy-commands.js # Command deployment script
├── generate-broadcast-list.js # Generate CSV for custom broadcast (utility)
├── delete-command.js # Remove commands (utility)
├── list-all-commands.js # List deployed commands (utility)
├── get-role-ids.js # Retrieve role IDs (utility)
├── check-broadcast.js # Test broadcast functionality (utility)
├── credentials.json # Google Service Account credentials (not in repo)
├── credentials.example.json # Example credentials file
├── package.json # Node.js dependencies
├── .env # Environment variables (not in repo)
└── README.md # This file
- index.js - Initializes Discord client, loads commands and events
- deploy-commands.js - Registers slash commands with Discord API
- utils/sheets.js - Handles all Google Sheets operations
- utils/calendarSync.js - Syncs iCal events to Discord scheduled events
- utils/memberCache.js - Persistent member data caching system
- utils/helpers.js - Reusable functions and embed builders
- events/interactionCreate.js - Handles slash commands, autocomplete, and button interactions (including nickname conflict resolution)
- discord.js (^14.16.1) - Discord API wrapper
- googleapis (^144.0.0) - Google Sheets API
- node-ical (^0.22.1) - iCal parser for calendar sync
- dotenv (^16.4.5) - Environment variable management
- node-fetch (^2.7.0) - HTTP requests
- undici (^7.16.0) - HTTP/1.1 client
- eslint (^9.36.0) - Code linting
node deploy-commands.js # Guild deployment (instant)
node deploy-commands.js -g # Global deployment (1 hour)node list-all-commands.js # Show all registered commandsnode delete-command.js # Remove a specific commandnode get-role-ids.js # List all server role IDsnode check-broadcast.js # Test broadcast functionalitynode generate-broadcast-list.js input.csv # Process CSV for custom broadcastPurpose: Extracts names from column B of a CSV file (skipping first 6 rows) and saves to data/broadcast-list.csv for use with the /broadcast command's Custom CSV option.
- Check if commands are deployed:
node list-all-commands.js - Verify bot has proper permissions in Discord
- Check console for error messages
- Verify service account has access to all sheets
- Check that
credentials.jsonis in the root directory - Ensure sheet IDs in
.envare correct - Verify sheet tab names match expectations
- Verify
CALENDAR_ICAL_URLis accessible - Check that stage channel ID is correct
- Ensure bot has permission to manage events
- Review console logs for sync errors
- Check role names match expected patterns
- Verify bot role is above managed roles in hierarchy
- Check bot has "Manage Roles" permission
This bot is developed for Project NexTech's internal use. For questions or issues, contact the Project NexTech development team.
GPL-3.0 License
Project NexTech Development Team (Daniel) + Claude Sonnet 4.5 and a few other AI models
Last Updated: November 26, 2025