Keep the common core smaller than you think
Our common core covers source and property identity, transaction type, property category, price and currency, typed area fields, bedrooms, bathrooms, location, media, contacts, observation timestamps, and provenance. A field enters the core only when we can keep its meaning stable across supported markets.
We never collapse internal area, gross area, plot area, and gross leasable area into one number merely because each may use square metres. Unit compatibility is not semantic compatibility; comparing the wrong area types produces precise-looking but invalid price-per-area values.
Keep the original value beside every normalized one
We store the source text separately from numeric amounts, ISO currency codes, unit types, and mapped enums. Local category labels remain available even after mapping. Addresses are decomposed only into components the source actually supports; we do not invent a universal hierarchy.
Parsing is locale-aware for decimal separators, compact price notation, and measurement units. When a value cannot be parsed safely, we preserve the assertion and emit an omission or warning. A visible gap is safer than a plausible number with the wrong magnitude.
Give local facts a typed extension, not a junk drawer
Market-specific facts live in documented extension groups when they do not belong in the common core. Extensions still require stable names, types, omission behavior, and provenance. An unbounded `misc` object only moves the schema problem downstream.
We promote a field into the common contract only after its meaning proves consistent across sources and customer workflows. Popularity alone is not enough; the field needs a definition that remains true when the next market is added.
Treat meaning changes as breaking changes
A renamed field is obviously breaking. A changed enum definition, implicit unit, address assumption, or omission rule can be more dangerous because the JSON still validates while its meaning changes underneath the consumer.
We version those semantic changes, publish compatibility notes, and test real rows from each affected market. Schema acceptance therefore includes both structural validation and value-level invariants such as valid currency-unit pairs, typed area compatibility, and traceable omissions.
- Test values and meanings, not only JSON shape.
- Keep area types separate before calculating ratios.
- Review extension fields for accidental common-core promotion.
- Run real rows from every affected market through migrations.