$ man tshabbic.projects.seniord
SENIORD(8)Senior Design @ Stevens Institute of TechnologySENIORD(8)
Name

seniord -- senior design

Description

Ever year, Stevens CS hosts Senior Design -- a 2-semester-long software development journey that involves forming a team of up to six people and finding a sponsor whose project each team either feels passionate about, or confident in their ability to implement.

In my case, after forming a team of six (including myself), we found a sponsor who was requesting a Senior Design team capable of resolving rank synchronization issues between their community's Discord server and their Minecraft server. For example, say a user on their Discord server gets promoted from a Member to a Moderator, or some other important figure -- after a staff member updates their rank, they would also need to launch their Minecraft client, login to the server, recall the promotee's in-game name (which may involve having switching back to Discord to retrieve it, as in-game names and discord usernames often do not match), and bestow upon them an equivalent rank.

Our sponsors' request was rather simple: design a plugin for their Minecraft server that reduces the inconvenience of ensuring a user's Discord roles match with their in-game roles.

As such, and per the schedule our Senior Design Professor provided us, we spent the first half of the course planning and architecting our designs to fulfill such a request, performing tasks such as validating and gathering insight on the problems users faced, conducting risk assessment and management, (re)learning the basics of the Agile methods we were already using, etc. We eventually decided that the simplest and most effective way to resolve the issue our target demographic / audience was facing was a Discord bot where staff could simply issue commands (see Usage below) to synchronize ranks between a member's Discord and Minecraft account, using Discord as the source of truth. The bot itself would be embedded in a Minecraft plugin, so no need for any cloud service or dedicated process to unnecessarily use resources when the server itself is down, not to mention the additional socket programming it would take!

Once the design was finalized in the first semester, we began our implementation shortly after in the second semester, which more or less went smoothly as we collaborated on our Java codebase, figuring out how to configure and use Gradle, etc. Almost too good to be true right? Well... one day while we were testing our plugin, we realized the testing server / Docker environment that they setup for us had crashed. Shortly after realizing this, our sponsor mentioned that the production servers were also down, and nobody at the organization knew why.
It was at this moment our sponsor reached out to me individually and asked if I'd like ssh(1) access to poke around and see if I could troubleshoot the issue, to which I gladly said yes, confident in my abilities thanks to some of the graduate courses I'd taken (namely Advanced Programming in the Unix Environment). With newfound root access and all, I effectively became the system administrator overnight!

Upon gaining access to the system, I attempted to look for our test server on the remote host, and I did eventually find it, but everything seemed normal until I tried manually running our server to see what the issue was, where it was revealed that it was failing to start due to ENOSPC, or "No space left on device". After seeing this, I executed a combination of du(1) and df(1) to identify the file systems and directories taking up the most storage (although I did consider the possibility that all the inodes in the file system had been exhausted, which would also raise ENOSPC, but was unlikely to be the case). I then discovered there were dozens of 300GB+ backup files hidden away in a directory belonging to our sponsor's production server! After immediately discussing this with our sponsor and agreeing on which backups to keep, I removed the unnecessary backups, and boom! Our test server worked again!

Unfortunately however, our sponsor's production server would still not boot, this time with a different error:

java.lang.Exception: Failed to load configuration file: spigot.yml
[...]
Caused by: org.bukkit.configuration.InvalidConfigurationException: while scanning a simple key
in 'reader', line 149, column 5:
se
^

Once again using my knowledge obtained from the aforementioned course, I immediately decided to run ls -l in the directory containing the production server's spigot.yml file (i.e., the server's configuration file), and noticed that the file was exactly 4096 bytes in size -- interesting. It just so happens that write(2) can only atomically write up to as many bytes as the block size on the file system where the file in question resides, which in this case, was indeed 4096. Just to confirm, I checked the contents of the file, and it was indeed abruptly cutoff. After comparing to an online, known-good version of the file, I concluded that, at the systems level, the first call to write(2) succeeded, and the second call failed due to ENOSPC as another large backup likely consumed the remaining disk space in between the server functioning as normal and the moment the config (and some other important files not mentioned) was written to.

It sure was a good thing I asked our sponsor for which backups to keep earlier, because thankfully this was easily fixed by replacing the affected files with their non-truncated counterparts, and just like that the production server worked without issue again!


A little later, our senior design sponsor once again reached out to me specifically to help set up another testing environment, but this time for an entirely separate Senior Design team that they were sponsoring. This was simple enough, I just copied our own testing environment and changed the Docker container's UUID and we were good to go. Only one slight issue, the other Senior design team needed remote access via ssh(1) to test their own project, and our sponsor would rather have not granted them root access. As such, I created a new, unprivileged user, adding them to a dedicated group, and used chown(1) and chmod(1) to allow their group access to their testing server, but not our own testing server, nor our sponsor's production server; which also involved adding a special sudo rules via sudo visudo (modifying /etc/sudoers.d/<group name>) such that they could start, stop, and retrieve the logs generated by their testing server running inside a Docker container -- a dangerous task that was carried out with great care, as otherwise it could potentially allow for local privilege escalation.

All of these additional responsibilities were tasks, the likes of which I (and everyone else on my team) had absolutely no responsibility for, or expectation of performing; and yet, I took them on anyway, because I knew I could, that I could finally lend the expertise I had worked so hard for over nearly four years of grueling studies to obtain to benefit someone in the so-called "real world" for the first time.

Usage

Note that to perform these commands, at least one of the Discord roles of the executing user must be explicitly whitelisted to do so in the plugin's configuration file.

/exec [command ...]


Attempts to run the given command on the server as if it were the server itself!

/ranksync <discord_user> <ingame_name> [verbose]


Attempt to synchronize a user's discord role with their in-game Minecraft role.
If the optional parameter 'verbose' is 'true', the command will also output a mapping of which Discord roles correspond to the rank(s) the target was given, for debugging purposes.

History

This Senior Design project was carried out from Fall 2025 to Spring 2026 @ Stevens Institute of Technology, and was presented in front of hundreds of people at the Stevens Innovation Expo on Friday, May 8th, 2026 by all members of the team.

Notice

Source code and demonstrations are not available here, as I do not have rightful ownership of the code and have not acquired written permission to use or display it.

If and when permission is acquired, it will be present similar to other entries.