lumnik. / scenarios All scenarios · Français

40,000 items browsed page by page in the PWA

Goal Browse a whole catalogue in the PWA without ever loading more than 50 rows at a time.

Two CSV exports, two entities, two linked views, one app. The hub serves the catalogue in pages of 50.

manifests/10-products.yaml
apiVersion: connectors.lumnik.io/v1kind: Connectormetadata:  name: pwa-pagination-products  connector_type: csv-file  scopes: [pwa-pagination]spec:  transport:    kind: local    path: /tmp/lumnik-scenario/pwa_pagination/m_product.csv  parser:    has_header: true  after_process: none  mapping:    dataset:      - require-headers:          columns: [m_product_id, m_product_category_id, name, description, isactive]    cell:      - parse-number: { column: m_product_id, integer: true }      - parse-number: { column: m_product_category_id, integer: true }      - clean:          columns: [name, description]          strip: true          remove-control-chars: true          normalize-unicode: NFC      - strip-invisible: { columns: [name] }      - replace-smart-quotes: { columns: [description] }
manifests/15-product-categories.yaml
apiVersion: connectors.lumnik.io/v1kind: Connectormetadata:  name: pwa-pagination-product-categories  connector_type: csv-file  scopes: [pwa-pagination]spec:  transport:    kind: local    path: /tmp/lumnik-scenario/pwa_pagination/m_product_category.csv  parser:    has_header: true  after_process: none  mapping:    dataset:      - require-headers:          columns: [m_product_category_id, name, description, isactive]    cell:      - parse-number: { column: m_product_category_id, integer: true }      - clean:          columns: [name, description]          strip: true          remove-control-chars: true          normalize-unicode: NFC      - strip-invisible: { columns: [name] }      - replace-smart-quotes: { columns: [name, description] }      - decode-html-entities: { columns: [name, description] }
manifests/20-product.yaml
kind: Entityname: PwaPaginationProductlabel: Article du cataloguedescription: "Articles du catalogue, enrichis avec leur catégorie. Une ligne représente un article."match: [product_id]scopes: [pwa-pagination]columns:  product_id:    label: "Identifiant de l'article"  category_id:    label: "Identifiant de la catégorie"  category_name:    label: "Catégorie"  reference:    label: "Référence"  description:    label: "Description"  active:    label: "Actif"sources:  - table: t_pwa_pagination_products    map:      m_product_id: product_id      m_product_category_id: category_id      name: reference      description: description      isactive: activejoins:  - table: t_pwa_pagination_product_categories    from: category_id    to: m_product_category_id    map:      name: category_name
manifests/25-category.yaml
kind: Entityname: PwaPaginationCategorylabel: Catégorie d'articlesdescription: "Catégories utilisées pour classer les articles du catalogue. Une ligne représente une catégorie."match: [category_id]scopes: [pwa-pagination]columns:  category_id:    label: "Identifiant de la catégorie"  name:    label: "Catégorie"  description:    label: "Description"  active:    label: "Active"sources:  - table: t_pwa_pagination_product_categories    map:      m_product_category_id: category_id      name: name      description: description      isactive: active
manifests/30-products-view.yaml
apiVersion: apps.lumnik.io/v1kind: Viewmetadata:  name: pwa-pagination-productsspec:  scope: pwa-pagination  table: connector.v_pwapaginationproduct  title: Catalogue des articles  columns: [product_id, reference, description, category_name, active]  links:    - column: category_name      targetView: pwa-pagination-categories      filters:        name: "{category_name}"
manifests/35-categories-view.yaml
apiVersion: apps.lumnik.io/v1kind: Viewmetadata:  name: pwa-pagination-categoriesspec:  scope: pwa-pagination  table: connector.v_pwapaginationcategory  title: Catégories  columns: [name, description, active]  links:    - column: name      targetView: pwa-pagination-products      filters:        category_name: "{name}"
manifests/40-pwa-pagination-app.yaml
apiVersion: apps.lumnik.io/v1kind: Appmetadata:  name: pwa-paginationspec:  title: Catalogue  scope: pwa-pagination  icon: generic  theme:    accentColor: "#8b7ff0"    backgroundColor: "#14121f"  tabs: [fiches]  default: false
Rows per page
50
Products browsed, each once
40233

evidence: replay.log · transform v1

Limits

  • Opaque cursor; no direct jump to page n.
  • Synthetic data.
  • The data and the PWA are French: the screenshots show the app as a French user sees it.

Catalogue · records

40,000 items on a phone.

Page by page.

Neither loading everything nor losing a row.

Synthetic catalogue

The problem

Loading everything freezes the screen.

  • 40,000 rows do not fit on a phone.
  • Naive paging skips or repeats rows.
  • Categories sit in another file.

Nothing is changed

Two CSV exports, as they are.

  • Two entities, two views.
  • An app reduced to records.
  • No application to build.

What had to be written

tabs: [fiches]

An app reduced to records.

A 150-line scenario of declarations.

What the user sees

Pages of 50.

  • A table on a computer.
  • Cards on a phone.
  • A category can be clicked.

Screenshots of 21 October 2026, values checked at the replay of 3 November.

The proof

The whole catalogue, no duplicate.

  • Two distinct pages of 50 rows.
  • A cursor walks all 40,233 items.
  • Replay of 3 November 2026.

The limit

No direct jump to page n.

  • The cursor is opaque.
  • You move one page at a time.
  • Synthetic data.

Try it

The scenario replays end to end.

CSV, entities, views, app: every step is published with its output.

This scenario runs on lumnik Open, free and open source.

Try lumnik Open →