Skip to content

Managing Drupal data

In the admin: Drupal data — the screen this page documents (opens in the running app).

What/why: The Drupal relationship — what this screen manages and why it exists.

Purpose: see where every piece of ingested nanawall.com content came from and how fresh it is, maintain the Drupal-field → attribute and taxonomy → facet mappings, and run the populate actions that act on already-ingested data.

Since #1099 this screen no longer triggers syncs: bulk ingestion runs offline from a Drupal database dump (#1094), and the catalog refreshes by re-running ingest on a newer dump.

When to use

  • Checking what content NanaSelect holds, from which source, and how stale it is (including when the last bulk load ran and what it wrote).
  • A new attribute should start receiving a Drupal field's values (or stop).
  • Mapping ingested taxonomy terms onto attributes/factors.
  • Attaching ingested imagery to system pages, or populating system heroes from their public PDPs.

Prerequisites

The tabs

  1. Data — the content-source registry (#343) with per-source freshness (item count + age of the newest provenance stamp, unified across stores), led by the last bulk-load event: dump date, Drupal version, load time, and per-store counts. Below it, two populate actions that act on ingested data:
    • Populate entity galleries (#360) — attach each system's tagged media to its page. Preview first; apply is idempotent.
    • Populate system hero images from PDPs (#1009) — set each system's primary image from its public PDP hero, importing bytes to R2 only when genuinely absent (#384).
  2. Coverage — which systems and projects still lack imagery (#453).
  3. Mappings — the Drupal-field → attribute mapping editor (#130; the dump loader reads these on its next run) and the taxonomy → facet mapping (#344). A term maps to an attribute, a factor, or — option-granularity, #483 — a specific factor option ("Geography: Coastal"): option-level mappings let "Projects like yours" nudge up projects whose terms correspond to the buyer's concrete answers (a secondary ranking signal; the recommended/ alternative system role always dominates).

Refreshing the catalog

  1. Obtain a newer sanitized dump out of band.
  2. npm run drupal:extract -- path/to/dump.sql.gz --out extract --drupal-version <v>
  3. npm run drupal:load -- extract — writes to the local dev D1. Add --remote to write to the prod nanaselect-db instead (same command, one flag; the source and behavior are otherwise identical).

The load is idempotent (an unchanged dump converges to a no-op), stamps each row with the dump's date as provenance, and records a bulk-load event in the audit trail — which this screen's Data tab then reports. This holds for both the local and remote (--remote) targets, so a prod refresh shows up here exactly as a local one does.

Refreshing prod (--remote)

A --remote load writes to production, so it is deliberately guarded (#1336):

  • It requires a Cloudflare API token with D1 edit access (CLOUDFLARE_API_TOKEN, or CLOUDFLARE_D1_TOKEN); the database id/name come from wrangler.jsonc and the account from CLOUDFLARE_ACCOUNT_ID/--account-id.
  • Before writing it echoes the target and asks you to re-type the database name to confirm; a non-interactive run is refused unless you pass --yes.
bash
CLOUDFLARE_API_TOKEN= npm run drupal:load -- extract --remote

See the dump extraction how-to for the full local-vs-remote reference.

Behavior guarantees

  • Ingestion is one-way (Drupal → NanaSelect); nothing is ever written back.
  • Values you edited locally are held back as overrides during a load, never overwritten — and held-back items are counted, not silently skipped.
  • Every load and populate run is recorded in the audit trail.

For where each piece of product data comes from, see data provenance; for the dump pipeline's format and whitelist, see the dump extraction reference.