Сохраняйте исходную область доступа кабинета
Обменяйте выданную одноразовую bootstrap capability через exchange-access и передавайте полученное продолжение кабинета через security scheme guestPortalToken. Личность, профиль, строка истории, UUID proof или grant сами по себе не разрешают нативное управление.
Оставляйте сценарий на его фактическом разрешённом origin. Проверенные hosted-домены могут обслуживать /guest, /guest/notifications и /guest/notifications/settings только в рамках текущего строгого допуска хоста и публикации. Сессия кабинета не расширяет исходную аудиторию reservation, waitlist, preorder или QR. Изолированный widget frame остаётся /widgets/:connectionId; не передавайте gpc bearer в другую вкладку или origin через URL.
Храните OTP, входные данные проверки контакта, Portal/native capabilities и ответы с данными доступа вне Redux, query cache, публичных URL, логов и аналитики. Удаляйте использованный bootstrap-фрагмент из страницы владельца; не заменяйте его continuation token. Выход отзывает сессию кабинета.
Начальный вход доступен из текущего управления своей бронью или waitlist через reservations.preparePortalEntry либо из preorder READ SESSION через public-preorders.preparePortal. Сохраните исходный idempotency key до отправки. Обе команды возвращают только приватный reentryContext hint и фиксированный срок. Запросите настоящий код через request-reentry и подтвердите его через confirm-reentry, прежде чем принять Portal continuation. Сервер выбирает существующий контакт; ID бронирования, hint, квитанция запроса и неподтверждённый контакт доступа не дают.
Для bootstrap-входа приватно сохраните исходный gpb2 token и постоянный exchangeId UUID до отправки exchange-access. При неопределённом ответе или после перезагрузки явно повторите ту же пару. Восстановление возвращает исходное continuation и срок только при актуальности исходных личности, сессии и токена; оно не ротирует и не продлевает доступ. Без exchangeId обмен остаётся одноразовым. Удаляйте ожидающие приватные данные при истечении срока, окончательном отказе, выходе и смене личности.
- Обменять начальный токен гостевого кабинета
- Получить свой гостевой профиль
- Отозвать сессию гостевого кабинета
- Подготовить восстановление контакта из своей брони или waitlist
- Подготовить восстановление контакта из своей сессии предзаказа
- Запросить целевой повторный вход в Guest Portal
- Подтвердить целевой повторный вход в Guest Portal
Первый успешный сценарий
На каждом шаге следуйте точному generated-контракту метода и сохраняйте приватный контекст восстановления в исходной аудитории.
- Через текущее нативное управление подготовьте приватный contact hint, сохраните исходный UUID запроса кода, затем явно запросите и подтвердите действительно доставленный код. Альтернатива — обмен выданного bootstrap с сохранённым exchangeId. После подтверждённого continuation прочитайте текущие профиль, лояльность и согласия.
- Прочитайте историю с ограниченной cursor-пагинацией и точные нативные детали с текущим подтверждением контакта.
- Для нативного управления завершите свежий целевой proof и явно отправьте исходную команду; проверяйте receipt отдельно от текущего nullable доступа.
- Для QR-истории покажите нативный текст согласия и явно свяжите только исходную membership, затем читайте её собственные квитанции.
- Изменяйте доступные profile/marketing поля с их expectedRevision, при необходимости используйте отдельные privacy requests и отзывайте Portal session при выходе.
Читайте ограниченную историю без получения управления
history возвращает сводки RESERVATION, WAITLIST, PREORDER, QR_VISIT, VISIT и ORDER. Продолжайте только с возвращённым cursor и неизменной областью гостя и заведения; останавливайтесь в конце. История, нативные детали и квитанции требуют текущего серверного подтверждения контакта. Наличие профиля или старое время проверки не заменяют свежее подтверждение.
reservation-details, waitlist-details и preorder-details возвращают только точную read-проекцию владельца. hasVerifiedSource не выдаёт bearer. Нативная проекция preorder может быть null; originalGuarantee и currentGuarantee бронирования — отдельные исходные и текущие факты. Обычное истечение управления не стирает допустимую историю, но история никогда не продлевает grant.
payment-receipts возвращает не более 25 допустимых исходных квитанций использованного согласия на страницу. Непрозрачный PAYMENT_RECEIPTS cursor принадлежит правилам этой истории и не взаимозаменяем с общим history cursor. Сохраняйте исходную квитанцию отдельно от текущих средств и применения. Чтение не списывает оплату и не выдаёт управление, payment access или доступ ко всему счёту сессии.
Завершите свежую серверную проверку нативного входа
Выберите один точный targetKind RESERVATION, WAITLIST или PREORDER и его targetId. Нативный владелец проверяет сохранённый источник и фактический browser Origin до подготовки proof. Явные contactType, contact и displayName должны соответствовать источнику; ни клиент, ни строка истории не выбирают verification reference.
prepare-native-entry-proof возвращает выбранный сервером proofId и исходное подтверждение PREPARED. Передайте настоящий доставленный шестизначный код в verify-native-entry-proof. Неверный код расходует канонический бюджет попыток до ответа HTTP 400. Неопределённый ответ повторяйте с теми же ключом и кодом; другой введённый код — новая явная попытка проверки с новым ключом. Не отправляйте фиктивный OTP ради чтения статуса.
native-entry-proof-from-reentry принимает настоящий использованный reentryChallengeId для точной текущей сессии кабинета и версии контакта. Этот UUID не является bearer и не выводится из недавнего времени входа. Сервер связывает его с proof этой цели.
После перезагрузки или потерянного подтверждения один раз явно прочитайте native-entry-proof с сохранёнными target и proofId. PREPARED, VERIFIED и CONSUMED описывают только сохранённый жизненный цикл proof. Чтение не отправляет OTP, не продлевает срок и не выдаёт capability управления; не опрашивайте его циклически и не подменяйте проверку.
- До отправки сохраните точную цель, ключ подготовки и входные данные в существующем приватном контексте восстановления владельца.
- Явно подготовьте проверку контакта либо свяжите настоящий использованный reentry challenge текущей сессии.
- Для PREPARED запросите у гостя доставленный код и отправьте одну явную команду проверки.
- При неопределённости сохраните исходные ключ и входные данные и восстановите тот же proof; не готовьте замену.
- После настоящей проверки явно запросите нативный вход с точным proofId и отдельным сохранённым ключом команды.
Отделяйте исходную квитанцию выдачи от текущего доступа
issue-native-entry атомарно использует целевой proof через нативного владельца. Ответ разделяет receipt — неизменное исходное подтверждение без секретов — и current — независимо оценённое текущее продолжение. proofId/grantId и issuedAt/expiresAt квитанции сохраняются исходными при повторе.
current.state принимает AVAILABLE, SUPERSEDED, EXPIRED, REPROOF_REQUIRED или UNAVAILABLE. current.manageToken и effectiveExpiresAt могут быть null. Показывайте исходное подтверждение и при недоступном текущем входе; не считайте квитанцию bearer и не выдавайте новый grant ради восстановления потерянного ответа.
До отправки сохраните исходные issue key, target и proofId. После потерянного ответа или перезагрузки явно повторите тот же ключ и входные данные в исходной разрешённой аудитории. Другие данные с тем же ключом отклоняются; повтор не продлевает срок и не возрождает отозванные права. Возвращённую текущую нативную capability используйте только внутри её reservation/waitlist/preorder-сценария.
import { createGuestClient } from '@hallify/sdk/browser';
const guest = createGuestClient();
// Save this nonsecret command in the owning private recovery journal before send.
export function retainNativeEntryCommand({ targetKind, targetId, proofId, key }) {
const args = Object.freeze({
targetKind,
targetId,
'idempotency-key': key,
issueGuestPortalNativeEntryDto: Object.freeze({ proofId }),
});
return Object.freeze({
args,
send: (guestPortalToken) =>
guest['guest-portal'].issueNativeEntry(args, {
auth: { guestPortalToken },
}),
});
}
// On an uncertain response, explicitly call the saved command again.
// Inspect data.receipt independently from data.current and its nullable manageToken.Связывайте исходную QR membership с явным согласием на историю
Прочитайте portal-association-statement с исходными живыми sessionId, tableGuestToken и фактическим Origin. Покажите точные возвращённые locale, termsVersion и termsDigest. Подготовка фиксирует membership/session/seat, личность, commandId, expectedRevision и текст согласия; первая association использует expectedRevision 0.
prepare-portal-booking-proof и associate-portal-history допускают либо один tableGuestToken, либо tableGuestToken вместе с guestPortalToken. Проверка BOOKING с одним table token резервирует точную будущую Portal session и использует выбранный сервером изолированный настоящий OTP challenge. При принятии гость явно передаёт доставленный код; неверные попытки расходуют бюджет. Возвращённые verificationId/proofId выбирает сервер; это ссылки, а не capabilities. Для reentry verificationId равен null.
prepare-portal-reentry-proof требует ОБА tableGuestToken И guestPortalToken, а также настоящий использованный PORTAL_REENTRY challenge этой текущей Portal session и версии контакта. Один Portal token, один table token или недавнее время входа не удовлетворяют этому отдельному reentry-методу.
associate-portal-history атомарно использует точный подготовленный proof и первый ACCEPT. Храните outcome, associationId и исходный decision отдельно от nullable continuation. Первая проверенная association с одним table token может вернуть зарезервированное Portal continuation; вызов существующей сессии возвращает null. Потерянный ответ восстанавливайте теми же исходными ключом и телом, QR capability и Origin, без повторной подготовки или выбора другого места.
import { createGuestClient } from '@hallify/sdk/browser';
const guest = createGuestClient();
// originalBody contains the server statement and a real consumed reentry challenge.
export function retainQrReentryPreparation({ sessionId, originalKey, originalBody }) {
const args = structuredClone({
sessionId,
'idempotency-key': originalKey,
prepareGuestPortalQrReentryProofDto: originalBody,
});
return ({ tableGuestToken, guestPortalToken }) =>
guest['table-access'].preparePortalReentryProof(args, {
auth: { tableGuestToken, guestPortalToken },
});
}Сохраняйте QR-квитанции за исходной membership
QR_VISIT использует associationId как ID истории. qr-visit, qr-own-order-requests и qr-own-order-request читают только неизменные исходные membership, session и seat. Перенос заказа, объединение столов или новая посадка не передают владение квитанциями другому гостю и не раскрывают SESSION_BILL. Отсутствующие или повреждённые frozen witnesses дают недоступную проекцию вместо реконструкции из текущих CRM или Orders.
Текущий владелец кабинета может читать qr-consent и отзывать согласие без нового OTP или живой membership. WITHDRAW добавляется при expectedRevision; повтор возвращает именно то исходное решение даже после последующего reconsent. Он не стирает другую неизменную квитанцию и не создаёт table authority.
Для reconsent получите текущие серверные statement/revision, подготовьте свежий целевой BOOKING proof или proof использованного reentry и явно вызовите accept-qr-history-consent. Reconsent остаётся связан с исходной association и не требует живой table membership. Он не преодолевает hardRevoked и не восстанавливает native table/payment grant. Приватная история дополнительно требует текущего подтверждения контакта, читаемого proof и последнего ACCEPT.
- Прочитать собственный исходный QR-визит
- Прочитать текущие согласие на QR-историю и текст согласия
- Получить собственные исходные квитанции QR-заказов
- Прочитать одну собственную зафиксированную квитанцию QR-заказа
- Подготовить свежее подтверждение контакта для повторного QR-согласия
- Подготовить повторное QR-согласие из настоящего текущего reentry
- Добавить свежее подтверждённое согласие на QR-историю
- Отозвать согласие на собственную QR-историю
Используйте generated browser methods и приватную команду восстановления
Browser SDK группирует Portal methods в guest['guest-portal'], а начальную native QR association — в guest['table-access']. Передавайте capabilities в per-call auth по guestPortalToken/tableGuestToken, точно как объявляет операция. Generated args намеренно не содержат дубликаты auth или Origin headers; фактический Origin задаёт браузер. Node partner client и серверные ключи — отдельная поверхность, а не гостевые capabilities кабинета.
reentry-context — PRIVATE COMMAND (POST), а не кэшируемые метаданные профиля. Он возвращает nullable приватные reentryContext hint/expiry для канонического восстановления контакта, которому ещё может требоваться настоящая свежая OTP-проверка. Это не проверенный контакт и не Portal/native bearer. Не помещайте ответ в RTK query, Redux, URL или межвкладочную передачу credentials. Продолжайте через существующий канонический сценарий восстановления контакта.
import { createGuestClient } from '@hallify/sdk/browser';
const guest = createGuestClient();
export async function requestPrivateRecoveryTarget(guestPortalToken) {
const { data } = await guest['guest-portal'].reentryContext(undefined, {
auth: { guestPortalToken },
});
// Keep this nullable private target in the owning recovery flow only.
// It is neither verified contact nor a Portal/native bearer.
return data.reentryContext;
}Восстанавливайте явные исходные команды без polling
До идемпотентной native-entry или QR-команды сохраняйте исходные operation, source audience, target, command/proof IDs, idempotency key и точные входные данные в существующем приватном контексте восстановления владельца. Сохраняйте приватность OTP и токенов; SDK не предоставляет хранилище capabilities. При UNKNOWN, потерянном ответе или перезагрузке явное восстановление использует исходную identity. Чтение или более новый профиль не доказывают результат неопределённой команды.
SdkError.apiCode раскрывает стабильный API code; SdkError.outcome описывает исход запроса, включая неопределённость после отправленной мутации. SDK не повторяет запрос и не создаёт ключ автоматически. Изменение OTP — новая явная попытка проверки, а не точный повтор старой команды; она расходует оставшийся канонический бюджет. Соблюдайте expiry, отзыв source, текущее подтверждение контакта и нативный отказ без обхода.
Профиль, лояльность, marketing/consent decisions и privacy requests сохраняют отдельные существующие контракты. Примеры определяют функции с переданным синтетическим контекстом и не отправляют команды при загрузке страницы. Они не доказывают browser, database, HTTP или provider qualification.