Skip to content

The product catalog

What the Systems, Attributes, Categories, and Factors screens manage — and why NanaSelect owns this model instead of borrowing Drupal's.

What it is

The catalog is NanaSelect's own structured model of the NanaWall product line:

  • Systems — the products themselves (NW Aluminum 640, SL45, …), each carrying its attribute values and its links back to nanawall.com (PDP path, imagery).
  • Attributes — the dimensions systems differ on (operation type, thermal performance, sightlines, …). These are the rows of the public comparison view.
  • Categories — admin-only grouping that orders attributes into legible sections; categories never surface to buyers directly.
  • Factors — the questions of the guided flow. Each factor asks about one buyer-relevant criterion and maps onto the attributes that answer it.

Systems × attributes say what each product is; factors turn those same dimensions into decisions a novice can make one at a time.

Why it exists

nanawall.com (Drupal) already has product pages — but its model is built for presentation, not selection. Recommending a system requires knowing, structurally, which attributes matter, how systems compare on them, and which question teaches each trade-off. That selection-oriented shape doesn't exist in Drupal and would be painful to retrofit there.

So NanaSelect owns a clean catalog tuned for selection, and stays connected rather than forked: the Drupal sync pulls product data in on demand, and deep links carry buyers back out to nanawall.com's PDPs and configurator. This is the "standalone, but connected" principle — see why it works.

How controlled vocabularies are identified

Two of the catalog's structures are controlled vocabularies — closed sets an operator curates, that other data points at: an enum attribute's allowed values, and the global cost-tier ladder.

Both originally keyed on their label. That is the natural first design and it has one severe consequence: the name is the identity, so renaming a value in use would orphan every stored payload and every reference pointing at it. The catalog's answer was to forbid the rename — an in-use value was locked, and fixing a typo meant a migration.

That is reversed. Each row now carries an opaque surrogate id, minted once at creation and never recomputed, and everything that refers to a value refers to that id. label became display-only, so renaming is a single-column update that breaks nothing. Alongside sits an alias table holding every name a value has ever worn — which is what makes a rename durable rather than merely safe: a stored payload, an older reference, or a Drupal sync still carrying the old spelling all resolve to the same row. A rename is one UPDATE; a re-sync afterwards recognises its own value instead of re-creating it.

Removal is still guarded, and always will be. Indirection makes renaming safe because the row survives; a delete takes the row — and the identity every reference points at — away with it. That is a referential problem, not a naming one.

The two vocabularies are asymmetric, deliberately. The enum catalog was fully contracted: its label column is gone and the id is the primary key. The tier ladder keeps tier as its key, frozen — written once at creation, never rewritten, with label carrying display. It behaves as a surrogate that happens to have originated as a label, which delivers the same guarantee; four consumers (stored tier payloads, tier rule thresholds, the systems tier facet, and the right-sizing ordinals) still speak that string, so dropping it would be a second high-risk engine migration bought for spelling alone. The asymmetry is recorded in schema.ts on both tables, and a contract check in npm run check enforces the invariant that actually matters on both: no code may construct an identity from a label.

In the admin

ScreenHow-to
SystemsManaging systems
Attributes · CategoriesManaging attributes
FactorsManaging factors

Learn more