You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
User feedback indicates that advisors and farmers want to better understand the available soil management measures — what each measure entails, what it costs, which indicators it impacts, when it applies, and how it relates to other measures. Currently, the measures catalogue stores only basic fields (name, summary, description, source URL, conflicts). The NMI API provides much richer data (effect costs, applicability conditions, effect type/size, impacted indicators) that is not yet persisted or surfaced in the UI.
This issue addresses three needs:
Enrich the catalogue data pipeline — store the full measure details from the NMI API so the UI has data to show
Provide a standalone Maatregelencatalogus — a browsable, searchable overview of all available measures, accessible from the sidebar
Make measure details accessible everywhere — wherever a measure is shown or selected in the app, users can navigate to its detail page for more information
User Stories
As an advisor, I want to browse the full catalogue of available measures with search and filters so that I can learn what measures exist and find relevant ones without being in the context of a specific field.
As an advisor, I want to see the full details of any measure (description, cost indication, which indicators it impacts, applicability conditions, conflicts) so that I can make informed decisions when selecting measures for fields.
As a farmer, I want a plain-language explanation of each measure so that I understand what it means in practice without needing expert knowledge.
As an advisor, when I see a measure in the add-measure dialog or on a field's active measures list, I want to be able to open its full detail page (in a new tab) without losing my current workflow.
Acceptance Criteria
1. Enriched catalogue data (fdm-data + fdm-core)
fdm-data — API mapping
CatalogueMeasureItem type in fdm-data/src/measures/d.ts includes the full NMI API fields: effect_costs, effect_type, impacts_score, applicability, effect_size, input_modified, status, bbwp_id
getMeasuresCatalogue() maps all fields from the API response (not just name/summary/description)
hashMeasure() includes the new fields in the hash computation so changes are detected on sync
fdm-core — schema extension
measures_catalogue table gains the following columns:
m_effect_costs — numericCasted(), nullable — cost index (0–15)
m_effect_type — text(), nullable — "qual", "quant", or "classed"
m_impacts_score — text().array(), nullable — list of S_* score variables impacted
m_status — text(), nullable — measure status from API (e.g., active, deprecated)
m_bbwp_id — text(), nullable — legacy BBWP reference ID
Drizzle migration generated and applied
syncMeasuresCatalogueArray upserts the new fields
MeasureCatalogue type in fdm-core/src/measure.types.ts updated with the new fields
getMeasuresFromCatalogue returns the enriched data
New function: getMeasureFromCatalogue(fdm, m_id): Promise<MeasureCatalogue> — fetch a single catalogue entry by m_id
Design note — why individual columns, not JSONB
The deferred columns were originally postponed pending a multi-source schema design. Since BLN is the only measure source for the foreseeable future and these fields have clear types (numeric, text, array, jsonb), individual typed columns are preferred over a generic m_metadata jsonb blob. The jsonb type is used only for truly variable-structure data (m_applicability, m_effect_size, m_input_modified). If a future source (e.g., ANLb) needs different fields, nullable columns or a side table can be added then.
2. Maatregelencatalogus overview page (fdm-app)
Route
Standalone route: measures-catalogue._index.tsx at /measures-catalogue
Accessible from the farm sidebar under "Maatregelen" as a secondary link: "Alle maatregelen bekijken →"
Also accessible from the organization sidebar (if org views are present)
Page is behind PostHog feature flag "bln3"
Layout & functionality
Page title: "Maatregelencatalogus"
Search box — fuzzy search (fuzzysort) on measure name, description, summary, and BM code
All links use aria-label="Open details voor [measure name] in nieuw tabblad" for accessibility
Quick preview tooltip/popover: in the Add Measure dialog, hovering or clicking the ℹ️ button could show a compact popover with summary, cost, main impacts, and a "Meer details →" link. This is a nice-to-have enhancement on top of the full page link.
5. Indicator variable mapping utility
A shared mapping utility that resolves S_* score variable codes and B_* / A_* condition variables to human-readable Dutch labels
The m_applicability JSONB column contains an array of conditions from the NMI API. The renderer should translate each condition into human-readable format:
// Example condition from API:{variable: "B_LU_CULTCAT4",operator: "in",values: ["akkerbouw","tuinbouw"]}// Rendered as:// Gewascategorie: akkerbouw, tuinbouw
Conflict ID normalization
Conflicts from the NMI API use raw BLN IDs (e.g., "BM11"). These must be stored as FDM m_id format (e.g., "bln_BM11") for consistency with the m_id primary key. The detail page resolves conflict m_id values to names and links.
The standalone route does not require authentication/authorization beyond basic app login — the catalogue is the same for all users
This issue should be implemented after issue-bln3-1 and issue-bln3-2 so the data pipeline exists
Deprecated measures (if m_status indicates) should still have accessible detail pages for historical reference, but be visually marked and filtered out of the selection dialog by default
The variable label mapping utility is a one-time effort that benefits multiple features (measure details, indicator deep-dive, Add Measure dialog impact panel)
The quick preview popover in the Add Measure dialog is a nice-to-have; the core deliverable is the detail page + links
Background
User feedback indicates that advisors and farmers want to better understand the available soil management measures — what each measure entails, what it costs, which indicators it impacts, when it applies, and how it relates to other measures. Currently, the measures catalogue stores only basic fields (name, summary, description, source URL, conflicts). The NMI API provides much richer data (effect costs, applicability conditions, effect type/size, impacted indicators) that is not yet persisted or surfaced in the UI.
This issue addresses three needs:
User Stories
Acceptance Criteria
1. Enriched catalogue data (
fdm-data+fdm-core)fdm-data— API mappingCatalogueMeasureItemtype infdm-data/src/measures/d.tsincludes the full NMI API fields:effect_costs,effect_type,impacts_score,applicability,effect_size,input_modified,status,bbwp_idgetMeasuresCatalogue()maps all fields from the API response (not just name/summary/description)hashMeasure()includes the new fields in the hash computation so changes are detected on syncfdm-core— schema extensionmeasures_cataloguetable gains the following columns:m_effect_costs—numericCasted(), nullable — cost index (0–15)m_effect_type—text(), nullable —"qual","quant", or"classed"m_impacts_score—text().array(), nullable — list ofS_*score variables impactedm_applicability—jsonb(), nullable — applicability conditions arraym_effect_size—jsonb(), nullable — effect size definitions (for qual/classed)m_input_modified—jsonb(), nullable — input modifications (for quant)m_status—text(), nullable — measure status from API (e.g., active, deprecated)m_bbwp_id—text(), nullable — legacy BBWP reference IDsyncMeasuresCatalogueArrayupserts the new fieldsMeasureCataloguetype infdm-core/src/measure.types.tsupdated with the new fieldsgetMeasuresFromCataloguereturns the enriched datagetMeasureFromCatalogue(fdm, m_id): Promise<MeasureCatalogue>— fetch a single catalogue entry bym_idDesign note — why individual columns, not JSONB
The deferred columns were originally postponed pending a multi-source schema design. Since BLN is the only measure source for the foreseeable future and these fields have clear types (numeric, text, array, jsonb), individual typed columns are preferred over a generic
m_metadata jsonbblob. Thejsonbtype is used only for truly variable-structure data (m_applicability,m_effect_size,m_input_modified). If a future source (e.g., ANLb) needs different fields, nullable columns or a side table can be added then.2. Maatregelencatalogus overview page (
fdm-app)Route
measures-catalogue._index.tsxat/measures-catalogue"bln3"Layout & functionality
qual/quant/classed(labeled "Kwalitatief" / "Kwantitatief" / "Geclassificeerd")m_impacts_scoremapping to indicator categories (Bodem, Koolstof, Productie, Grondwater, Nutriënten, Oppervlaktewater)m_status= deprecated) shown at bottom with visual indication, or behind a "Toon inactieve maatregelen" toggle3. Measure detail page (
fdm-app)Route
measures-catalogue.$m_id.tsxat/measures-catalogue/:m_idm_idvalue (e.g.,/measures-catalogue/bln_BM7) which is URL-safem_idin the catalogue; shows 404 for unknown IDsContent sections
m_summarytext prominently displayedm_descriptiontextm_effect_costs(0–15 scale) with label (e.g., "Lage kosten", "Gemiddelde kosten", "Hoge kosten")qual→ "Kwalitatief — deze maatregel heeft een direct positief effect op de bodemkwaliteit"quant→ "Kwantitatief — deze maatregel wijzigt invoerwaarden voor de berekening"classed→ "Geclassificeerd — het effect varieert afhankelijk van perceelcondities"m_impacts_scoreS_* variables to human-readable indicator names (e.g.,S_C_N→ "Stikstofbeschikbaarheid"), with links to indicator detail pages (when available)B_LU_CULTCAT4,B_SOILTYPE_AGRare mapped to Dutch labelsm_source_urlif available, "Bron: NMI BLN3" label, last sync timestamp fromupdatedfieldm_bbwp_idshown if present, for backward traceability4. Measure links throughout the app (
fdm-app)Wherever a measure name/code appears in the app, it should be navigable to the detail page:
target="_blank"withrel="noopener noreferrer")measures.$b_id): each active measure's name is a link; an adjacent external-link icon (↗) opens in a new tabmeasures._index): measure names in the summary table link to detail pagesaria-label="Open details voor [measure name] in nieuw tabblad"for accessibility5. Indicator variable mapping utility
S_*score variable codes andB_*/A_*condition variables to human-readable Dutch labelsfdm-app/app/lib/bln3-labels.tsorfdm-data)Wireframes
Maatregelencatalogus overview
Measure detail page
Measure link in Add Measure dialog (enhanced)
Technical Notes
Route structure
These are standalone routes (not farm-scoped) because the catalogue is global. Farm-scoped pages link to them with
target="_blank"where appropriate.Loader pattern
Variable label mapping
Applicability rendering
The
m_applicabilityJSONB column contains an array of conditions from the NMI API. The renderer should translate each condition into human-readable format:Conflict ID normalization
Conflicts from the NMI API use raw BLN IDs (e.g.,
"BM11"). These must be stored as FDMm_idformat (e.g.,"bln_BM11") for consistency with them_idprimary key. The detail page resolves conflictm_idvalues to names and links.Dependencies
measures_cataloguetable must exist), issue-bln3-2 (calculator — catalogue sync viafdm-data)Notes
m_statusindicates) should still have accessible detail pages for historical reference, but be visually marked and filtered out of the selection dialog by default