Skip to Content
Data LayerSearch & Explore

Search & Explore

Once records are in, the ExploreBlock ships a complete browse surface: per-tenant Orama index, faceted sidebar, search bar, sort, pagination — driven by the DataSchema annotations.

Two surfaces, one engine

SurfaceFileUsed for
/[tenantDomain]/exploresrc/app/(frontend)/[tenantDomain]/explore/page.tsxFull-screen dashboard, sidebar + cards + map
ExploreSectionBlocksrc/domains/cms/components/blocks/explore-section-block.tsxPage-builder section, contained cards listing
ExploreBlocksrc/domains/cms/components/blocks/explore-block/index.tsxShared component used by both

Both consume the same per-tenant Orama index. The full-screen dashboard is auto-mounted; the section block can be added to any page via the page builder or shipmore page build.

Variants

ExploreBlock is a multi-purpose atom that renders the same data in structurally different ways. The variant decides the renderer tree and the chrome (facets, search, sort, pagination):

type ExploreVariant = 'grid' | 'table' | 'gallery' | 'feed' | 'comparison' | 'map' | 'minimal'
VariantRendererFacetsSearchSortPagination
gridGridRenderersidebaryesyesfooter
tableTableRenderertopbaryesnofooter
feedFeedRenderertopbarnoyesinfinite
mapMapRenderersheetyesnonone
minimalMinimalRenderernonenononone

Pick the variant that matches the project shape: directories → grid, data platforms → table, signal sites → feed, geographic data → map, embedded teasers → minimal.

Variant is structural renderer dispatch, not class-utility variance. Use Tailwind/shadcn for visual polish inside a renderer; use the variant lookup map for swapping the whole tree.

Detail pages

Every record has a public detail page at /[tenantDomain]/explore/[slug]. The current first-pass template handles every archetype by reading the schema:

  1. Heroimage or logo field
  2. Title + subtitle + verified + rating — header
  3. Categoriescategory-roled values
  4. Descriptionsummary + long-form text fields
  5. Facts tablefactPrimary, factSecondary, plus unrouted facetable numerics
  6. Map embed — only if location field exists
  7. Sidebar — facetable numerics (“at a glance”)
  8. JSON-LD — auto-emitted per record

Same template, different content per archetype.

Orama specifics

  • In-memory — the index lives in the Node process as a module-level singleton. Cold start rebuilds from records.
  • Per-tenant — one index per tenant; never cross-contaminated.
  • Synchronous — Orama v3+ calls are sync; plays well with React Server Components.
  • Edge-incompatible — never set runtime = 'edge' on Present routes; the singleton needs Node module state.
  • What’s indexed — only fields with searchable: true (full-text) or facetable: true (filter/aggregate). cardVisibility: 'detail-only' does not affect indexing.

For very high tenant × listing counts, swap to Orama Cloud (or the parked Typesense / Meilisearch adapter) by replacing src/domains/present/orama/. The component contract stays the same.

Tuning the index

After changing searchable, facetable, or field types in the DataSchema, run:

shipmore schema apply --tenant <domain> --fields-file shipmore import --tenant <domain> --reindex # rebuild without re-importing rows

(Or restart the Node process; cold start rebuilds the index from records.)

SEO

  • Sitemap entries auto-generated for every published record at /[tenantDomain]/explore/[slug].
  • JSON-LD per record on the detail page (driven by the role taxonomy — title, image, rating, factPrimary, etc.).
  • next-sitemap config at next-sitemap.config.cjs includes per-tenant sitemaps.
  • Pagefind is wired for the docs site; for tenant content, Orama is the search.

See Features → Content for the broader page builder context.