CHAPELLIA
Rotate to unlock
SHOP NOW
CONTACT US
POPULAR SEARCHES
FEATURED
Strata Series
5 characters · Limited drop
ON SALE
Verify a Piece
Check authenticity
Hall of Fame
Top collectors
CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS
CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS CHAPELLIA FREE SHIPPING ON ALL ORDERS
FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS
FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS FREE SHIPPING ON ALL ORDERS
Behind The Build
Entry #001

Building the Archive Nobody Asked For

The record was supposed to be a page. It became the part of the project that every other part now depends on, and that was not a plan.

The Challenge

The original brief was a single page listing what had been made, in order.

That lasted about a month. A list can hold what exists; it cannot hold why a thing exists, what it replaced, or what was rejected on the way. Those turned out to be the questions people actually asked, and none of them fit in a column.

The harder constraint was that the categories were not knowable in advance. There would be notes, letters, stories, journals — and then a dozen more nobody had thought of yet. Whatever was built had to survive being wrong about its own shape.

Exploration

The first approach was a table per category. It is the obvious approach and it works well for two categories.

At four it was already clear where it ended: every new category meant a migration, a model, a route, a view, and a set of near-identical bugs to find again. The cost of adding a category was rising rather than falling, which is the wrong direction for something expected to hold dozens.

The second approach was one pair of generic tables — categories and entries — with the parts that genuinely differ per category held in a JSON column. The parts that do not differ are columns like anything else.

The Build

Two tables, two models, one list view, one detail layout. Adding a category became a single row.

The detail layout was written with every block optional. A category that has no recipient does not render a recipient; a category with no signature loses the block entirely rather than falling back to a default. That rule was not in the first version and every category added since has needed it.

The URL for a category is derived, not stored — section plus slug, computed in one method that is also read in reverse when a request comes in. Because both directions read the same map, they cannot drift apart.

Unexpected Problems

The first surprise was a bulleted list rendering as indented paragraphs. The framework's CSS reset removes list markers, and no content in the first two categories had contained a list, so the bug shipped invisibly and waited.

The second was worse. Two systems ended up sharing one URL prefix — a legacy table and the new categories — and the route had to check the legacy table first to keep existing pages alive. That is correct and it means a category can be shadowed by a legacy row with the same slug, silently, with the page still returning a perfectly healthy 200.

The third was self-inflicted: an indented conditional in a template printed its own indentation into the output of six pages that had not changed. The fix was to put the directive at column zero and write down why, because it looks like an error and will be tidied by someone otherwise.

The Final Decision

Everything stayed generic. No category has been given its own table, model, or layout, and the count is now past twenty.

The shadowing problem was answered in two parts rather than one: the slug that was most likely to collide was renamed out of the way, and a guard was added to the regression sweep so any future collision fails loudly. Renaming alone would have fixed the instance; the guard fixes the class.

The system has been wrong about its own shape three times and survived each one, which is the only property that was actually being designed for. What it has not yet been tested by is a category that genuinely does not fit — and there are a dozen of those waiting.
Behind The Build Notes
The per-category prototype is kept in the archive even though it was never deployed. It is the clearest available argument for the generic approach, and the argument stops being obvious about a year after the decision.
Related Entries
Entry #002
The Feature We Removed Twice
Back to Behind The Build

Pilih Lokasi