Back to selected work

Independent product

Source Compare

Source Compare is a collaborative image-versioning tool I built to give visual work a clear history: alternatives, votes, and the approved result in one shared record.

An asset branches into alternatives, a preferred direction emerges, and the approved image becomes the next point in the record.

The problem

The file rarely carried the whole decision.

Saving another image was easy. Preserving what that image represented was harder.

On a solo project, filenames and folders hold the process together for a while, as long as the discipline holds. As revisions accumulate, names begin carrying more and more hidden meaning: which version came first, which one is current, which alternatives belong together, and whether “final” actually means final.

Once several people are involved, that context fragments further. The files live in cloud storage, feedback arrives through chat or email, and approval happens in a meeting or another design tool. Each system keeps one piece of the work. None of them keeps the relationship between the alternatives and the direction the team picked.

A naming convention can distinguish files. It cannot preserve their relationships, the feedback around them, or the decision that moved the work forward.
Filenames carried accidental meaning
Names such as final, final-v2, and final-approved made files distinct, but required everyone to interpret the same informal convention correctly.
Storage preserved files, not relationships
Folders and version history kept older assets without showing which images were alternatives in the same round, or how one round led to the next.
Feedback drifted away from the asset
Comments in chat, email, and meetings named an exact image at the time, then drifted loose from the version they described.
Approval hid the path
The finished image survived. The rejected alternatives, the team's preferences, and the order of the decisions that produced it did not.

Source Compare focused on that missing structure: keeping visual alternatives, rounds of work, team votes, and the approved result connected in one navigable record.

The product model

A hierarchy for both the asset and its decisions.

Source Compare organizes work as a small, explicit hierarchy. Each level answers a different question, from the broad body of work down to one uploaded image.

  1. ProjectThe shared body of work and its collaborators.
  2. ItemOne asset that needs to move toward approval.
  3. VersionA round of edits in the item’s history.
  4. Iteration / commitOne concrete image alternative inside that round.

In the data model, a commit stores both its version and iteration number. Source Compare treats that commit as the particular image being reviewed.

The project view

Approved work stays distinct from work in progress.

A project opens to its approved items: assets that have reached a final decision. A second view holds the items still gathering versions and votes. That separation keeps the current deliverables visible without erasing the work that produced them.

ApprovedDecision recorded; latest accepted asset available.
In progressVersions remain open for alternatives and votes.
Source Compare project view showing three approved item cards with thumbnail previews of their latest versions
The item overview uses each asset’s latest-version thumbnails to make a project scannable without flattening its history.

The working view

The history and the current choice share one screen.

The item-detail view pairs a version tree with the selected image. Alternatives from the current version sit beside it, while upload, download, voting, navigation, and approval remain available in context.

Source Compare item detail for a cacti image, with a branching version tree, selected asset, alternative thumbnails, vote markers, and approval control
A complete item-detail view: version tree at left; current asset, alternatives, voting state, navigation, and approval at right.

Voting through versions

The votes draw a path through the tree.

Each collaborator can vote for one iteration within a version. Source Compare finds the most-voted alternative in each round and connects those choices into a path through the version tree.

v1 · iteration 1v2 · iteration 2v3 · iteration 1

Ties appear as yellow dotted branches. When a vote changes, the path redraws to reflect the new preference. Approval records the chosen endpoint and moves the item into the project’s approved view.

Implementation

A full-stack system for relational state and image storage.

I built it with a Next.js and React interface, an Apollo GraphQL API, a Prisma data layer backed by PostgreSQL, and S3-presigned image uploads. GraphQL Shield rules checked authentication and project membership around reads, uploads, voting, and mutations.

Collaboration uses two related scopes. A friendship establishes a reusable relationship between people, while follower records grant access one project at a time. Accepting a friend request confirms any pending project invitation from that person; it does not expose every project either person owns.

  • Next.js + React
  • Apollo GraphQL
  • Prisma + PostgreSQL
  • Amazon S3 uploads
  • GraphQL Shield permissions

Looking back

Complex frontend work is mostly state with consequences.

Source Compare made that lesson concrete. A vote changed the preferred path; an approval changed how an item appeared at the project level; a permission decision affected which transitions a person could make at all.

The lesson was to model those transitions explicitly and enforce them below the interface layer. The page could walk someone through a complicated workflow, but the data and authorization rules still had to make contradictory states hard to create.