RFC one-pager, NX-674

Amenities Single Source of Truth

The catalog owns what the amenity is. Property, building, category, and unit layers own what is true locally.

Super simple summary Stop copying names like WiFi everywhere. Store WiFi once in a catalog, then link every local item to it with catalogId.
Status
Draft RFC
Author
Vikrant
Core table
Catalog
UI entry
Unit page

What changes?

Identity vs local data
πŸ“š

1. Catalog

One row per canonical amenity, equipment, or appliance. It has kind, name, and provider mappings.

πŸ“

2. Layer items

Existing JSONB arrays stay. Items keep local fields like location, brand, notes, status, and instructions.

πŸ”—

3. Link by ID

Layer items store catalogId. They no longer store name or kind.

🧩

4. Inherit safely

Child layers override only filled fields. They can also suppress an inherited item locally.

From flat tags to rich amenity objects

Today, amenities are often stored like thin tags or true/false fields. Sometimes extra text exists, but identity and local details are mixed together, so it is hard to trust, edit, or map consistently.

The point

Today: β€œhas WiFi: yes”

Useful for checklists, but not enough for operations, guest instructions, provider mapping, or unit-specific overrides.

{
  "wifi": true
}

Future: WiFi with real context

The catalog says this is WiFi. The property or unit stores the useful local facts around that same canonical item.

{
  "catalogId": 42,
  "location": "living room",
  "brand": "TP-Link",
  "instructions": ["Password is on the fridge"],
  "status": "operational",
  "notes": "Router restarts nightly"
}
Clean framing: this turns amenities from flat yes/no tags into canonical, provider-mapped items that can carry rich property and unit-specific information.
Catalog entry
WiFi, amenity, Hostaway ID 42
↓
Property item
catalogId 42, router location, password note
↓
Unit override
catalogId 42, special instructions for this unit
Problem todayNames and kinds are duplicated across sources. Same amenity can be spelled or classified differently.
Provider ruleNever pull from providers into PMS truth. Use mappings so Arbio can push outward later.
Nexus UXUsers can add, edit parent, create local override, suppress locally, or create a new catalog entry inline.
API ruleUse dedicated per-item CRUD, not generic full unit array replacement.

Migration in plain English

Hostaway first
1
Create tableAdd equipment_amenity_catalog.
2
Seed HostawayOne catalog row per Hostaway amenity.
3
Relink old itemsReplace old {kind,name} with catalogId.
4
Merge duplicatesKeep the richest item, report conflicts.
5
Cut overUse the new editor API and Nexus flow.

Success means the team agrees on

  • βœ“Catalog is the source of truth for kind, name, and provider mappings.
  • βœ“Layer items stay in JSONB and point to catalog rows with catalogId.
  • βœ“Inheritance uses sparse overrides and local suppression.
  • βœ“Nexus edits one item at a time through layer-targeted APIs.

Open decisions

  • !Should catalog name uniqueness be case-insensitive?
  • !Should APIs expose public catalogResourceId or numeric catalogId?
  • !Should resolved items sort alphabetically or preserve insertion order?