lcatDB (Lake Champlain Anglers’ Temperature Database) was an online database and single page application (SPA) meant to provide a centralized means of recording, accessing, and analyzing vertical water temperature profiles to citizens of the Lake Champlain region. It was supported by the SUNY Plattsburgh Center for Earth & Environmental Science and the Lake Champlain Sea Grant. lcatDB was (what I consider to be) my first attempt at full stack software development. While the app never really took off and is no longer around today, I was able to demonstrate many of my strengths and learned several valuable lessons.


The UI of lcatDB very closely follows Google’s (now aged) Material Design guidelines. A hamburger menu is always available for root-level navigation and all elements are kept large, touch-friendly, and readable. Subtle iconography and color is used to draw attention to important elements and differentiate options. One element that I take pride in across most of my projects is responsive CSS, allowing for automatic adaptations to mobile, tablet, and desktop layouts.

lcatDB’s client was built using several JavaScript libraries, frameworks, and related tools, including:

  • Grunt (build system)
  • Cordova (Android/iOS builds)
  • jQuery
  • Bootstrap
  • Leaflet
  • Mustache (for page templating)

The client is structured as a SPA, and thus can run offline (albeit with some restrictions). An event queue was added to allow for offline operations to be uploaded to the server later, which was a required use-case due to poor cell service in the middle of the lake. Below is a video demo of various features and interactions!


The server is probably the least interesting to talk about, but still quite important! It’s written for Node.JS and uses a mongoDB database to store users, readings, sensor information, and various other data! It provides a REST API and, in addition to serving the static pages (the same ones available offline), it uses mustache templates to provide pages for content only accessible online. I’ll talk more about this system later and my thoughts on its use.

Passwords are stored as bcrypt hashes for essential user security. Users authenticate using client sessions which can be invalidated (logged out) server-side in case of certain user actions (eg. password resets). To ensure the accountability of data while providing basic editing features, edits to sensor information are tracked using mongoDB middleware and made visible to users. These are just some examples of security considerations made during development.

What I Would Do Differently

First of all, revisiting this codebase after working in Python 3 primarily for a few years and getting used to type annotations and IntelliSense… ouch. Very frequently I have to trace the flow of control manually with console.logs and a lot of reading. I would definitely switch to TypeScript nowadays as things would be much more navigable. However, there’s a lot of deeper issues than that. Some of these arose due to the simple passage of time: some libraries and tools get adopted and maintained, some don’t.

Firstly, lets address the use of Grunt. At the time of using it, it was relatively well-supported and I got used to it fairly quickly. The ability to mix JS scripting into your build system has a lot of benefits, though maybe a bit encouraging of hacky-ness. Nowadays, Grunt is pretty much dead. No releases in 2 years, and its mainly been surpassed by webpack. I’ve taken the hint and also begun migrating some of my older projects to webpack.

Some issues, however, arose from my own inexperience. The biggest pill to swallow from this project is: it’s time to move on from jQuery and onto a proper framework. Not to push this thing any harder than it already is, but it is infinitely less prone to breaking, with less time spent programming destructor functions and chasing bugs. jQuery’s purpose still feels mostly limited to small sites that need some dumb small feature quick and you don’t wanna deal with the poor syntax of vanilla JS, which between TS IntelliSense and GitHub Copilot isn’t really even a problem anymore.

Which leads to the root of that issue: lcatDB did not originally plan to be a SPA. That was added after many of the pages were implemented and the code was written, so the SPA capabilities were hacked on top. jQuery does not suit itself well in this use case, but at the time I couldn’t justify the time as a single developer to go back and start from scratch. And with the scale of the project growing further in a small scope-creep, the problems from jQuery scaled up as well. Despite the amount of time I spent considering my options for each choice of a library or platform, the change in scope caused a pile-up of other issues. This was the single-biggest takeaway: nail down the entire set of specifications first, then implement. Be very specific and thorough. I attempted to do this to some degree at the time, but did not yet know the right questions to ask.