Muneer Alam Work / RhinoBox

One upload. Two very different storage decisions.

RhinoBox combines a file workspace with a Go service that inspects JSON structure and recommends SQL or document storage. Its most revealing details are the boundaries between a recommendation, a database write and a downloadable archive.

RhinoBox / contribution
Designed and implemented the NoSQL storage component: deciding which data suited document storage, how to structure it and how the application should store and handle it, within a team-built hackathon project.
Timeline & status
November 2025 — public demo maintained in 2026
Team prototype
Built with
Go · PostgreSQL · MongoDB · Docker
Backend systemsBUILD NOTES / 2025–26
RhinoBox / project preview
Actual RhinoBox browser workspace with file upload and routing controls using synthetic records
RhinoBox↗
View full project screenshot ↗
Actual local application capture from the public source, with synthetic files and records.

Upload a collection of customer rows and a collection of deeply nested, inconsistent documents. Both are JSON. Treating them as the same storage problem is where the interesting part of RhinoBox begins.

Built during a hackathon at our college, the team project puts an ordinary file workspace beside a structural JSON analyzer. My responsibility was designing and implementing the NoSQL storage component: deciding what belonged there, how to structure it, where to put it and how the application should handle it. One side organizes and retrieves files. The other asks what the shape of a batch suggests about storing it in a relational or document database.

Let the data shape make a case

The Go decision engine looks at nesting, schema consistency, field variation and relationship hints. Shallow, consistent records generally favor SQL. Clearly nested or inconsistent structures lean toward NoSQL. It returns a reason, along with schema or indexing information, so the recommendation is inspectable.

This is a heuristic over structure, not a model discovering what a business means. Two datasets with similar shapes can still have different access patterns and operational needs. The explanation is a starting point for a decision.

Input shape What the analyzer can observe Why it matters
Repeated shallow rows Stable fields and types A tabular schema may fit naturally.
Deeply nested documents Hierarchy and varying fields Flattening can discard useful structure or complicate the schema.
A changed batch Different inferred shape A later upload should not quietly inherit the wrong table.

The SQL path hashes the inferred schema into a table suffix. That gives a changed structure a different destination rather than assuming a table chosen for an earlier batch is still suitable.

A recommendation is not a receipt

The storage response distinguishes the recommended backend from the backend that actually handled the write. It also separates records inserted into the database from records archived into a downloadable NDJSON file, and returns warnings.

Those fields are more important than a generic “upload successful” toast. An archive operation can fail after database rows have committed. Retrying the entire batch in response can duplicate records because the prototype does not provide idempotent ingestion. Deleting the downloaded archive is not a request to delete the database records either.

The JSON analyzer makes a structural recommendation. Database persistence and the independent NDJSON archive produce separate results, counts and warnings.
The file and the database are related outputs, not a single transaction that can be casually undone. Open the diagram ↗

That makes RhinoBox an interesting systems exercise: give the user a clear account of partial outcomes instead of hiding two operations behind one label.

The file workspace around the analyzer

Ordinary uploads have their own needs: metadata, MIME and extension classification, collections, notes, content search, deduplication and range-based streaming. The browser combines a lightweight Vite interface with Monaco for the structured-data workflow. Go handles the API, while the local Compose setup supplies PostgreSQL and MongoDB adapters.

Putting these tools together creates a place to inspect a file before deciding what to do with its contents. It does not mean every format has become a queryable database automatically.

When my brain declined the presentation

I was unwell during that hackathon. Following everything around me was harder than usual, but I kept working on my assigned storage component. At evaluation, each team member had to explain their contribution and the decisions behind it.

Then came my turn. I had implemented the NoSQL component, but at that moment I could not properly explain the difference between SQL and NoSQL.

Brilliant engineering. Questionable operating conditions.

It was funny after I recovered, rather less funny while I was standing there. The distinction between the two databases has stayed particularly memorable ever since. So has the practical lesson: taking care of myself is part of getting the project across the finish line. Implementing a feature is only half as satisfying if my brain refuses to provide technical support during the presentation.

What this version actually represents

RhinoBox is a team-built hackathon prototype that can be run locally. Authentication, tenant isolation and asynchronous ingestion are not established production features. My contribution was the NoSQL storage work; the surrounding file workspace, analyzer and integrations remain a team effort.

Its engineering story is strongest at the seams: how a structural rule becomes an explanation, how a schema change gets a distinct destination, and how the interface tells someone which part of an operation really finished.

Code & further reading

Written by Muneer Alam · Reviewed 1 November 2026