Skip to content
Rupak Dey

Navigate

Work

News

Links

Theme

Projects

Engineering

Aggie Find-It: Campus Lost and Found

Role
The requirements documentation, and the front end views and routing
Period
Sep 2024 – Dec 2024
Stack
  • Java
  • JavaFX
  • FXML
  • MongoDB

Context#

Students report a lost item; building administrators log what turns up and search it by name, description, building and category. Four of us built it over ten weeks in the autumn of 2024, ending at 2,235 hand-written lines across 30 files. Five started: the fifth wrote the problem statement and the value proposition, then took their name off the team page on the day the first code commit landed.

I wrote most of the requirements documentation, including twenty user stories with effort estimates and acceptance tests, and built the front end: the page-routing shell and nine of the eleven FXML views. A teammate wrote the MongoDB data access layer and most of the admin dashboard.

What we built#

A JavaFX desktop client connecting straight to MongoDB Atlas. There is no server tier, no API and no service layer.

Two-tier architecture: a JavaFX desktop client, holding eleven views and a single static data-access class, connects straight over the MongoDB driver to an Atlas database of four unlinked collections. No server tier exists between them.JavaFX desktop clientshell, 11 FXML views,11 controllersstatic calls,String results, no modelssql_link14 static methodsships with thedatabase credentialMongoDB driver over TLSnew connection per queryno backend tierMongoDB Atlasdatabase CS371, no indexesItemsno matchingRequestAdminUserStudentUser

That shape has one direct consequence: every installed copy of the application carries the database credential, because there is nothing else to hold it.

Eleven FXML views sit over eleven controllers, with one class, sql_link, holding all fourteen data-access methods. Four collections get created implicitly on first write, with no indexes and no schema validation. Search is a case-insensitive regex over name and description, with exact matching on building and category, and every read is one query fired by a user action: there is no change stream, listener or polling, so two clients never see each other's writes until somebody clicks Reload.

The cost of passing rows as text#

sql_link returns query results as comma-joined strings, and the controllers split them apart again. No domain object exists anywhere in the codebase.

That looks like a shortcut inside a data-access method. Its consequences are all somewhere else.

Because rows arrive as text, an item's database ID never reaches the interface. So when an administrator selects a row and clicks Delete, the controller cannot delete by ID. It re-queries using the four values visible in the table and removes the first match:

String item = sql_link.itemSearch(currentRowSelected.get(0), currentRowSelected.get(1),
                                  currentRowSelected.get(2), currentRowSelected.get(3));
sql_link.removeItem(item.strip().split(", ")[0].strip());

Two items sharing a name, description, building and category is ordinary in a lost and found. The wrong one gets deleted, and nothing reports a problem.

The same decision surfaces twice more. Two methods emit two different text formats, parsed two different ways in the same controller, so a change to either silently breaks a caller. And any description containing a comma followed by a space corrupts the row it belongs to.

What we specified, and what we shipped#

The team kept a project wiki. Its nonfunctional requirements page, dated 2 October 2024, asks for hashing and salting for password storage, role-based access control, input validation against injection, and smooth performance beyond a hundred concurrent users.

What shipped was a single unsalted round of SHA-256, with each user's role encoded by prefixing that hash with a digit. There is no session object and no authorization check past the login screen, so the admin dashboard is protected by not being linked to, and anyone can register as an administrator by ticking a checkbox on the sign-up form. Search interpolates user input into an unanchored regular expression against an unindexed collection, on the interface thread. Every query opens its own database connection.

Two of the user stories carry acceptance tests the code fails outright. The wiki's index also links a page called "Verification and Validation: how we tested and verified the software" that nobody ever wrote, alongside tests that nobody ever wrote either. JUnit is declared in the build file and src/test/ is empty.

What this shows#

Writing the security requirements down did not produce them, because nothing in the process ever checked. The requirements page and the code sit in version control six weeks apart, and the page that was meant to document verification is one of three the team never got to.

The narrower lesson is about the text-passing decision. It was made inside one method and caused a correctness bug in a different layer, one that no amount of care in the controller could have prevented. Returning typed objects carrying an ID would have made the delete bug impossible to write.

Two things here I would still defend. The building lookup handles scroll-wheel zoom with sensible bounds, and the request form's twelve-hour clock conversion gets both the noon and midnight cases right before handing off a date.