field-applicability.js

Overview

services/api/src/modules/match/field-applicability.js defines the backend applicability rules for Match. It is a minimal, read-only port of the canonical frontend table, limited to the 11 fields that Match compares in this phase. The source explicitly says Match never imports apps/backoffice-web code, so this file exists as a deliberate duplication with manual synchronization.

The module serves one narrow purpose: decide whether a given Match field makes sense for a propertyType. It does not inspect field values, and it does not infer not_applicable from missing data. The source treats null or absence as a separate concern from structural applicability.

[!IMPORTANT] This file is a deliberate backend copy of the frontend applicability table. If the frontend table changes, this file must be updated manually.

How it works

The module keeps two frozen lookup tables and one exported function. The exported function chooses a table for the given propertyType, falls back to a permissive default, and returns false only when the field is explicitly marked false. The comparison layer uses this check before physical and infrastructure comparisons. fileciteturn0file6turn0file3

flowchart TD
    A[isMatchFieldApplicableToPropertyType] --> B[Select propertyType table]
    B --> C{propertyType known}
    C -->|yes| D[MATCH_APPLICABILITY_BY_PROPERTY_TYPE]
    C -->|no| E[PERMISSIVE_MATCH_APPLICABILITY]
    D --> F[Check field entry]
    E --> F
    F --> G[Return true unless explicit false]

The runtime flow is intentionally small. A caller passes a field name and an optional propertyType. The module resolves a table, checks the field, and returns a boolean. Tests confirm that unknown propertyType values use the permissive default. fileciteturn0file8turn0file9

Key components

{
    "title": "isMatchFieldApplicableToPropertyType",
    "content": "Public function that decides whether a Match field applies to a given propertyType. It returns a boolean and treats any value other than explicit false as applicable.",
    "type": "function",
    "filePath": "services/api/src/modules/match/field-applicability.js",
    "badges": [
        "public"
    ]
}

The module is centered on read-only lookup data. All tables are wrapped with Object.freeze, which makes the applicability definitions immutable at runtime.

Data & fields

The file exports one field list and one function. It also defines two internal frozen maps that control the applicability decision. The source describes this as the backend mirror of the frontend table, limited to Match’s current comparison scope. fileciteturn0file0turn0file6

[
    {
        "name": "MATCH_APPLICABILITY_FIELDS",
        "type": "string[]",
        "required": true,
        "description": "Ordered list of the 11 fields that Match checks for structural applicability."
    },
    {
        "name": "PERMISSIVE_MATCH_APPLICABILITY",
        "type": "Record<string, boolean>",
        "required": true,
        "description": "Internal fallback table where every supported field resolves to true."
    },
    {
        "name": "MATCH_APPLICABILITY_BY_PROPERTY_TYPE",
        "type": "Record<string, Record<string, boolean>>",
        "required": true,
        "description": "Internal propertyType matrix used to resolve field applicability."
    },
    {
        "name": "field",
        "type": "string",
        "required": true,
        "description": "One of MATCH_APPLICABILITY_FIELDS."
    },
    {
        "name": "propertyType",
        "type": "string",
        "description": "meta.propertyType for the Offer or Requirement already resolved by the pair gate."
    }
]

MATCH_APPLICABILITY_FIELDS

This exported array contains exactly 11 fields. The file states that they are the 8 physical fields plus the 3 infrastructure declarations used by Match today.

  • bedrooms
  • bathrooms
  • halfBathrooms
  • parkingSpots
  • constructionArea
  • landArea
  • frontage
  • depth
  • waterDeclaration
  • electricityDeclaration
  • drainageDeclaration

PERMISSIVE_MATCH_APPLICABILITY

This internal table marks all 11 fields as applicable. The module uses it as the fallback for other and any unknown propertyType. The tests confirm that unknown types keep the permissive behavior. fileciteturn0file6turn0file8

MATCH_APPLICABILITY_BY_PROPERTY_TYPE

This internal matrix defines the structural applicability per propertyType. Its entries are the source of truth for the file’s boolean result. The function does not derive applicability from values; it only reads this map.

  • house

    • true: bedrooms, bathrooms, halfBathrooms, parkingSpots, constructionArea, landArea
    • false: frontage, depth, waterDeclaration, electricityDeclaration, drainageDeclaration
  • apartment

    • true: bedrooms, bathrooms, halfBathrooms, parkingSpots, constructionArea
    • false: landArea, frontage, depth, waterDeclaration, electricityDeclaration, drainageDeclaration
  • land

    • true: landArea, frontage, depth, waterDeclaration, electricityDeclaration, drainageDeclaration
    • false: bedrooms, bathrooms, halfBathrooms, parkingSpots, constructionArea
  • office

    • true: bathrooms, parkingSpots, constructionArea
    • false: bedrooms, halfBathrooms, landArea, frontage, depth, waterDeclaration, electricityDeclaration, drainageDeclaration
  • commercial

    • true: bathrooms, halfBathrooms, parkingSpots, constructionArea, landArea, frontage, depth, waterDeclaration, electricityDeclaration, drainageDeclaration
    • false: bedrooms
  • warehouse

    • true: parkingSpots, constructionArea, landArea, frontage, depth, waterDeclaration, electricityDeclaration, drainageDeclaration
    • false: bedrooms, bathrooms, halfBathrooms
  • industrial

    • true: parkingSpots, constructionArea, landArea, frontage, depth, waterDeclaration, electricityDeclaration, drainageDeclaration
    • false: bedrooms, bathrooms, halfBathrooms
  • other

    • Uses PERMISSIVE_MATCH_APPLICABILITY
    • All 11 fields resolve to true

Behaviors

  • isMatchFieldApplicableToPropertyType [badge:public] — Resolves a boolean applicability result for one field and one propertyType.
  • return table[field] !== false — Treats only explicit false as non-applicable.
  • Object.freeze(...) — Keeps the exported and internal tables read-only.
  • Default fallback to PERMISSIVE_MATCH_APPLICABILITY — Preserves permissive behavior for other and unknown propertyType values.

[!NOTE] The function does not validate the field name itself. It only checks the selected table entry and returns true unless the entry is exactly false.

Gotchas & edge cases

[!WARNING] null or missing values do not mean not_applicable here. This file answers only the structural question: whether a field belongs to a propertyType. The source says evidence absence and structural non-applicability are different states.

[!IMPORTANT] The backend copy must stay aligned with the frontend copy. The source explicitly references apps/backoffice-web/src/features/publish-wizard/lib/fieldApplicability.js as the canonical origin for this duplication.

[!CAUTION] other and unknown propertyType values do not fail closed. They use the permissive table, which marks all 11 fields as applicable. The tests confirm that behavior. fileciteturn0file8turn0file9

This module sits inside the Match comparison path. The source ties it to services/api/src/modules/match/comparison-contract.js, where applicability is resolved before physical and infrastructure comparisons. It also records the frontend mirror in apps/backoffice-web/src/features/publish-wizard/lib/fieldApplicability.js, and mentions docs/03-architecture/data-models.md as the place where the intentional duplication is documented. fileciteturn0file1turn0file4

  • services/api/src/modules/match/comparison-contract.js — consumes this applicability result before Match compares physical and infrastructure fields.
  • apps/backoffice-web/src/features/publish-wizard/lib/fieldApplicability.js — canonical frontend source mirrored here.
  • docs/03-architecture/data-models.md — referenced by the source as the duplication record.