# Hotel Page-Type → Schema-Type Map

The G1 (설계) deliverable: every page template gets an assigned schema `@type` and a
required-property list *before* anyone authors entries. Locking this map first is what
prevents the most expensive error — authoring hundreds of entries against the wrong type.

This is the reusable, hotel-domain map. The worked example is JHR (Josun Hotels &
Resorts, `josunhotel.com`) — a multi-brand, multi-language, multi-property group — but
the mapping applies to any lodging-group site (it replaces the earlier client-specific
draft). Adapt the brand/property layer to the client; the page-type → type rules are stable.

## Site shape this map assumes

```
대표 허브 (group)        →  Organization + WebSite        (one canonical node set, @id-anchored)
브랜드 허브 (brand)       →  Brand / Organization + Hotel families
개별 호텔 (property)      →  Hotel / LodgingBusiness / Resort
  ├─ 객실 (rooms)        →  HotelRoom / Suite (nested or itemList)
  ├─ 다이닝 (dining)     →  Restaurant / BarOrPub
  ├─ 시설·웨딩·연회       →  LocalBusiness / MeetingRoom (nested)
  ├─ 프로모션 (offers)    →  Offer / AggregateOffer
  └─ FAQ / 안내          →  FAQPage
```

Each rendered URL also multiplies by **language × device** (ko/en/ja/zh × PC/MOBILE),
which is why the entry count reaches the thousands. The schema `@type` does **not**
change across language/device — only the localized string values do. (Use that fact:
NAP, geo, and `@id` must stay identical across the language variants of one property;
Layer 4 will catch it when they drift.)

## The map

| Page template (Korean / English) | Primary `@type` | Required (P0) | Add these (recommended) |
|---|---|---|---|
| 대표 홈 / group home | `WebSite` (+ `Organization`) | name, url / name, url | publisher, potentialAction(SearchAction), inLanguage / logo, sameAs |
| 브랜드 허브 / brand hub | `Organization` (+ `Brand`) | name, url | logo, sameAs, brand |
| 호텔 메인 / property home | `Hotel` (or `LodgingBusiness`, `Resort`) | name, address | telephone, image, priceRange, geo, url, starRating, aggregateRating |
| 객실 목록·상세 / rooms | `Hotel` w/ `containsPlace`→`HotelRoom`/`Suite`, or `ItemList` | name, address (host) | image, occupancy, bed, amenityFeature |
| 다이닝 / restaurant | `Restaurant` (or `BarOrPub`) | name, address | servesCuisine, priceRange, telephone, menu, openingHoursSpecification, acceptsReservations |
| 부대시설·웨딩·연회 / facilities | `LocalBusiness` w/ `MeetingRoom` nested | name, address | telephone, openingHoursSpecification, image, url |
| 프로모션·패키지 / offers | `Offer` (or `AggregateOffer`) | price, priceCurrency / lowPrice, priceCurrency | availability, url, validFrom, priceValidUntil |
| 멤버십 / membership | `MemberProgram` | name | hasTiers, hostingOrganization, url |
| 위치·오시는 길 / location | `Hotel` w/ `geo`→`GeoCoordinates` | name, address | geo (lat/long), hasMap |
| FAQ / 자주 묻는 질문 | `FAQPage` → `Question`/`Answer` | mainEntity / name, acceptedAnswer / text | — |
| 공지·매거진·기사 / article | `Article` / `NewsArticle` / `BlogPosting` | headline | author, datePublished, image, dateModified, publisher |
| 모든 하위 페이지 / breadcrumbs | `BreadcrumbList` → `ListItem` | itemListElement / position | item, name |

## Conventions that keep Layer 4 green

- **Anchor shared nodes by `@id`.** Define `Organization` and `WebSite` once
  (`https://…/#organization`, `https://…/#website`) and reference them everywhere with
  `{"@id": "…"}`. Avoids `DANGLING_ID` (define before you reference) and `DUPLICATE_ID`
  (don't redefine with different content).
- **One canonical NAP per property.** The same `telephone` and `streetAddress` must
  appear in every language/device variant of a property, or `NAP_*_MISMATCH` (P0) fires.
- **Distinct descriptions.** A reused boilerplate description across ≥3 pages →
  `DUPLICATE_DESCRIPTION` (P1). Write per-page copy.
- **geo as `{latitude, longitude}`** in decimal degrees; Korea is lat ≈ 33–39, lon ≈
  124–132. Transposing them trips `GEO_SWAPPED`.
- **No placeholders.** `예시 / 수정필요 / 임시 / lorem / {{…}}` anywhere → `PLACEHOLDER_TEXT`
  (P0). The gate exists precisely to stop these from reaching the client.

## Using the map in the lifecycle

- **G1 설계:** fill this table for the client's actual templates; that *is* the schema
  spec. DoD: every template has a type + required list.
- **G2 개발:** authors produce entries against it; `--strict` run; zero P0 to advance.
- **G3+:** the map is the reference reviewers and the validator agree on.
