skip to content
naft.pink
2024 — 2025archived

Art Gallery

Client work: a gallery and auction site on React and Django REST Framework. I owned the auctions system end to end, made the call to build on rspack, and shipped without a credit. Ran from 2024 until it was replaced in 2025.

  • Owned the auctions system outright — frontend and backend, end to end.
  • Made the call to build on rspack/rsbuild instead of webpack, while that was still a new and slightly risky choice.
  • CMS capabilities so the site could be reconfigured without a redeploy, since it was going to outlive my involvement.
  • Phone and email verification, custom templates rather than the framework defaults.
  • Heavy render-path optimisation — memoisation, stable callbacks, keeping re-renders off the hot lists.
  • Subcontracted, but working at the same level as the contractor and known to the client directly.

outcome — Shipped and stayed live for the client through 2025, then replaced by a newer site — a normal end for contract work that had already done its job.

  • React
  • RSPack
  • DjangoRestFramework

This one was a job, not a project. I came in as a subcontractor on a gallery and auction site and had enough latitude that in practice I was operating at the same level as the contractor — talking to the client directly rather than through a layer, and making stack decisions rather than receiving them.

My name isn't in the footer. That's normal for the arrangement and I knew the deal going in, but it's the reason a chunk of my actual track record isn't findable by looking me up.

the auctions system#

The piece I owned outright, frontend and backend. Auctions are a deceptively nasty thing to build: the data is live, the stakes are money, and every interesting bug is a race. Two people bid the same amount at the same instant. Someone's connection drops between the bid and the confirmation. A lot closes while a bid is in flight.

Owning both halves was the thing that made it tractable. When the same person writes the endpoint and the component consuming it, the contract between them can be exactly as strict as the problem needs, and there's no negotiation about whose side handles the edge case.

the rspack call#

I pushed for rspack and rsbuild over webpack, and it was a real call rather than a preference — rspack was new, the ecosystem was thin, and webpack was the answer nobody gets blamed for.

I'd already used it on a class project the year before, where being wrong would have cost nothing — which is exactly why I was willing to argue for it somewhere it mattered.

The reasoning was that webpack API compatibility made the downside cheap: if it went badly, most of the config would port back. Small recoverable downside against build times that would keep the iteration loop alive as the asset count grew. It's the decision I'd point at if someone asked whether I chase new tools — I do, but only where being wrong is survivable.

making it fast, and keeping it fast#

An image-heavy site with live auction state is mostly a render-path problem. A lot of the work was unglamorous profiling: memoising the expensive derivations, stabilising callbacks so list rows stopped re-rendering on every tick of auction state, and keeping the components that update frequently away from the ones that are expensive to draw.

None of that shows up in a screenshot. It's the difference between a listing page that scrolls and one that stutters every time a bid lands.

building for the handover#

The other thing I'd defend: CMS capabilities, so as much as possible could be reconfigured without a redeploy. Not because it was clever, but because the site was designed to outlive my involvement, and anything that needed a deploy was going to need me.

The verification flows fall under the same heading — phone and email, with templates written by hand instead of the framework defaults. Entirely edge cases: codes expire, people mistype, people request a new one four times in ten seconds, people change their number halfway through. Invisible when it works, and the whole experience when it doesn't.

That's the difference between writing code for a project and writing it for a client. The second one has to keep working after you leave.

how it ended#

Replaced with a new site sometime around 2025. Normal end for contract work — it did its job for the stretch it was up, and I'd already handed it off.

The same arrangement produced one more job after this one — a booking site for a dog grooming business — which ended a good deal less normally.

all projects