lumnik. / scénarios Tous les scénarios · English

SENAITE: la boîte de Fleming qui attend sa vérification

Objectif Être prévenu quand un résultat du LIMS SENAITE dépasse sa limite, puis quand il reste sans vérification.

Un vrai SENAITE 2.6, cinq équipes de recherche, 120 boîtes de culture lues par son API JSON.

manifests/lab-docker-compose.yml
# SENAITE LIMS 2.6.0, the official image, with an empty site: the runner seeds it through its own API.name: lumnik-senaite-platesservices:  senaite:    image: senaite/senaite:v2.6.0-docker2    platform: linux/amd64                               # the only image SENAITE publishes    environment:      SITE: senaite      PASSWORD: ${SENAITE_PASSWORD:?the runner sets a throwaway admin password}    ports: ["127.0.0.1:${SENAITE_PORT:-9390}:8080"]     # this machine only
manifests/10-plates.yaml
apiVersion: connectors.lumnik.io/v1kind: Connectormetadata:  name: scenario-senaite-a  connector_type: rest-generic  scopes: [laboratory]spec:  base_url: http://host.docker.internal:9390/senaite/@@API/senaite/v1  auth:    kind: basic    username: admin    password_env: SCENARIO_SENAITE_A_PASSWORD  endpoints:    - id: analyses      path: /analysis?complete=yes                     # complete=yes: the result itself, not only the catalog's summary      method: GET      pagination:        kind: body-link        link_path: $.next                              # SENAITE writes the next page's URL, b_start=25, 50…        response_path: $.items        total_path: $.count                            # and how many analyses the list holds      target:        kind: hybrid        table: ext.scenario_senaite_a        unique_key: $.uid        promote:          - { name: sample, path: $.getRequestID, type: text }          - { name: research_group, path: $.getClientTitle, type: text }          - { name: analysis, path: $.getKeyword, type: text }          - { name: result, path: $.Result, type: decimal }          - { name: unit, path: $.getUnit, type: text }          - { name: review_state, path: $.review_state, type: text }          - { name: sampled_at, path: $.getDateSampled, type: timestamptz }
manifests/20-plate-over-limit.yaml
apiVersion: apps.lumnik.io/v1kind: Processmetadata:  name: scenario-senaite-over-limit-aspec:  scope: laboratory  on:    event: data.row.changed    table: ext.scenario_senaite_a                      # the REST connector's own table (icreated/lumnik#1816)  when:    - result>100                                       # a clean plate holds at most 100 colonies  emit:    type: decision.plate-over-limit-a    key: sample                                        # the inbox shows the sample, not the row hash (icreated/lumnik#1823)    message: "{sample} ({research_group}): {result} {unit}, a clean plate holds at most 100 — state {review_state}"
$ lm connector run scenario-senaite-c
run scheduled: fe25ee34-e7f8-4b53-9ad1-e3c04afc3d9e

$ lm run get fe25ee34-e7f8-4b53-9ad1-e3c04afc3d9e
ID        CONNECTOR           ENDPOINT  STATUS     IN   OUT  SKIPPED  DEAD-LETTERS  STARTED           ENDED             EVALUATED
fe25ee34  scenario-senaite-c  analyses  Completed  120  120  0        0             2026-11-04 23:58  2026-11-04 23:58  yes

$ lm run get fe25ee34-e7f8-4b53-9ad1-e3c04afc3d9e --wait-evaluated --timeout 2m
ID        CONNECTOR           ENDPOINT  STATUS     IN   OUT  SKIPPED  DEAD-LETTERS  STARTED           ENDED             EVALUATED
fe25ee34  scenario-senaite-c  analyses  Completed  120  120  0        0             2026-11-04 23:58  2026-11-04 23:58  yes

$ lm inbox --process scenario-senaite-over-limit-c
ID     WHEN      PROCESS                        MESSAGE                                                                                                     ENTITY_KEY
23570  just now  scenario-senaite-over-limit-c  analysisrequest-24 (Fleming group): 2400 CFU/plate, a clean plate holds at most 100 — state to_be_verified  analysisrequest-24
manifests/30-plate-review.yaml
apiVersion: apps.lumnik.io/v1kind: Workflowmetadata:  name: scenario-senaite-review-aspec:  scope: laboratory  provenance: declared  on:    table: ext.scenario_senaite_a    column: review_state                               # SENAITE's own state, as its API writes it    key: sample  dormancy:    after: 1m                                          # a lab would write 2d; shortened for the replay    message: "{doc_key} ({research_group}): {result} {unit}, {state_label} since {since}"  states:    - { code: unassigned, label: "Received, not counted", initial: true }    - { code: to_be_verified, label: "Waiting for verification" }    - { code: verified, label: "Verified", terminal: true }

Limites

  • La dormance compte depuis la première fois que lumnik voit l'état, pas depuis la date de soumission dans SENAITE.
  • Le {since} du message est une date UTC: une boîte vue à 00:09 heure de Paris le 5 novembre affiche «since 2026-11-04».
  • body-link n'envoie pas de taille: les 25 par page de SENAITE gouvernent le run. Mettre limit= dans path: pour la changer.
  • Équipes et boîtes fictives, clin d'œil à leurs homonymes; données synthétiques.

Laboratoire · microbiologie

Les résultats sont dans SENAITE.

Il faut être prévenu d'un résultat hors limite.

SENAITE 2.6, 120 boîtes de culture

Le problème

La boîte de Fleming compte 2400 colonies.

  • Une boîte propre en compte au plus 100.
  • Le résultat attend sa vérification.

Ce qui n'est pas modifié

SENAITE reste tel quel.

  • Son API JSON, telle qu'elle est.
  • Aucun module, aucun export.

Ce qu'il a fallu écrire

when: [ result>100 ]
key: sample

Un Process sur la table REST.

  • Une décision quand la boîte dépasse 100.
  • Un Workflow quand elle dort non vérifiée.

Ce qui a été corrigé

Deux trous trouvés, deux corrections.

  • Une source REST alimente un Process (#1816).
  • La décision porte le nom de l'échantillon (#1823).

Essayer

Le scénario se rejoue en local.

Chaque étape est publiée avec sa sortie.

Ce scénario tourne sur lumnik Open, gratuit et open source.

Essayer lumnik Open →