Salta ai contenuti

@guestcraft/core

Questi contenuti non sono ancora disponibili nella tua lingua.

GuestCraft’s domain model, use cases and ports in pure TypeScript: no database, network, filesystem or system clock (ADR 0002). Each context has an explicit subpath; there is no root export.

Import Contents
@guestcraft/core/shared Result/errors, injected clocks/randomness, IDs, exact money/decimals, Temporal stays, country/language codes and shared text validation
@guestcraft/core/audit Audit entries and transaction-bound audit port
@guestcraft/core/events Domain event contracts and transaction-bound event port
@guestcraft/core/tenancy Workspace scopes, permission catalog, roles and team management
@guestcraft/core/properties Property creation, configuration and scoped reads
@guestcraft/core/reservations Inventory, guests, stays, rates, quotes, policies, prepayments and front desk
@guestcraft/core/folios Append-only ledger, split folios with payers, routes and transfers, extras, manual payments/refunds, settlement and TaxCalculator port
@guestcraft/core/blocks OOO/OOS unit blocks, inventory adjustments and maintenance tickets
@guestcraft/core/channex Connections, booking projection/import, guarded ARI publication and Messages behind ports
@guestcraft/core/channex/testing The in-memory Messages repository, held to PostgreSQL’s contract by packages/db; tests only
@guestcraft/core/integrations Workspace API keys, organization tokens and client sessions narrowed to their creator’s (or minter’s) live access and limited to their scope (ClientSessionScope), first-party guest sessions (guestSessions, the GuestSessionIssuer contract) (ADR 0047), the grants members give OAuth applications on the consent page, within what they hold (OAuth applications), webhook endpoints, thin events and delivery with retries and automatic disabling (ADR 0040)
@guestcraft/core/night-audits Business dates, the night-audit checklist, its financial plan and room-charge reconciliation (ADR 0043)
@guestcraft/core/reports Read-only property performance, pickup, cash/folio revenue and cancellation trends with historical coverage; workspace and organization consolidation; the organization’s stored exchange rates
@guestcraft/core/countries Dated country-rule contracts and pure calculations; workflow consumption planned

Time, randomness and identifiers are injected. Expected failures return Result; bugs throw InvariantError (ADR 0008). Money uses currency-aware minor units and exact BigInt arithmetic. Decimal input is bounded to 128 UTF-16 code units and 64 fractional digits before parsing; exchange rates additionally allow at most 20 significant digits. Stay dates use Temporal.PlainDate (ADR 0007).

Shared text(value, { max, multiline }) rejects C0/C1 controls, lone surrogates, bidi embedding/override/isolate and deprecated U+206A–U+206F controls, plus U+200B/U+2060/U+FEFF/U+061C. Joiners (ZWNJ/ZWJ), direction marks, soft hyphens and emoji tags remain valid text. Multiline notes, descriptions and cancellation text permit LF, CRLF and tabs. Single-line fields also refuse U+2028/U+2029. humanName applies NFC and trimming before validating the stored UTF-16 length on accepted writes. Existing guest references are checked for existence without revalidating stored contact fields. Ordering uses code units, independent of the host locale.

Reservation reads use read-only repeatable snapshots. Inventory checks, assignment, lifecycle and optimistic guest/reservation edits follow ADR 0024. The front desk, Planning and guest workflows consume those operations through the public API. API 3.0.0 requires an owning property when creating a standalone guest. Edits keep the existing owner, and new OTA guests inherit the booking property. Legacy unowned guests are not backfilled automatically. Versioned duplicate dismissal, manual merge, consent history and owning-property reassignment follow ADR 0045. Merge and reassignment require unrestricted property scope; consent histories never combine.

Rates and quotes share effective nightly prices and restrictions; quoteRates requires a positive stay length (invalid internal calls throw InvariantError). See rates.

Policies freeze sold conditions and deposit amounts. Room policy decisions use Money, Temporal.PlainDate and Temporal.Instant in the domain; database and HTTP adapters retain the existing decimal/date/instant JSON representation. Ledger reconciliation compares decision values independently of JSON member order. A frozen prepaymentAmount is authoritative even after nights change. For legacy snapshots without it, readers calculate the obligation from the stored penalty and nights. A null prepaymentDueAt is recovered from the snapshot’s deadline, arrival time and zone. Only a due-at-booking rule falls back to acceptance or reservation creation. See policies and ADR 0032.

Folios support frozen room charges, extras, manual payments/refunds, net/full ledger views and non-fiscal statements. A reservation’s folios (up to ten, each with a payer, optional room and routes) share one ledger; transfer pairs move charges and payments between them and net to zero. The last active room settles the reservation and a room with its own folio settles that folio; credit must be returned and debt requires settlement or an audited folios.approve_open_balance approval. Caller posting keys cannot use system prefixes or contain :line:; replay follows exact movement relationships. Taxes require a module on the TaxCalculator port; fiscal documents remain planned. See folios.

Online payments are implemented in payments, through each workspace’s own Stripe account: payment links copied or shown as a QR code, saved cards that confirm card guarantees, damage-deposit holds, provider refunds and disputes. Only the provider’s signed events and reads settle them, and a provider object changes money only through the identifier GuestCraft recorded when it created or claimed it. An OTA booking’s card is moved to Stripe through Channex’s Stripe Tokenization App and charged off-session, a virtual card only within its dates, currency and balance. Cash settlements apply the country pack’s cash rounding. See payments and ADR 0054.

Channex projection returns Result. Cosmetic contact defects never quarantine inventory facts: the adapter canonicalizes OTA languages using i18n, retaining raw values in the encrypted archive; core drops any remaining invalid optional contacts, uppercases countries and maps UK to GB. Guest names, OTA channel names and reservation references replace dangerous characters with spaces, collapse whitespace and normalize to NFC. Joiners and emoji spellings are preserved. Oversized optional values are dropped; oversized names use OTA, without slicing graphemes. Inventory/money defects still quarantine with specific reasons. Per-revision parse failures with trustworthy identity, property and timestamp metadata receive invalid_revision receipts only when their property is linked, room-mapped and not unlinked, in either account mode. Entries without that envelope remain upstream and mark import health failed while later entries continue. Legacy archive retries canonicalize the raw language again. Mapping and durable intake are described in ADR 0028.

Connection account modes, scope guards and property recovery cursors are described under Shared accounts in ADRs 0028/0034. Shared is the default; only an audited edit with channex.manage_account_mode enables exclusive booking consumption. Confirmed property linking, mapped-only activation and audited reversible unlink are specified in ADR 0028. Pending cleanup remains fenced and visible in health. Webhook registration requires an active room mapping. A retired upstream target stays fenced after the local property links elsewhere; unlink restarts recovery for remaining properties. New unknown-room-type quarantines are acknowledged after archive and retried once per connection version when room mapping is available. Pre-upgrade quarantines require manual retry. Replay failures are isolated per receipt, with a bounded backoff for transient ones; only the replayed receipt becomes stale when Channex holds a newer revision. Reconnect requires the new key’s own property list to contain every linked property and every pending webhook removal; a key change leaves pending removals to be confirmed only by a listed webhook.

Channex Messages uses the property-scoped messages.read, messages.send and messages.configure grants (the workspace inbox spans the member’s properties). messages.ts holds the operator use cases: their authorization, the inbox, replies and templates, guarded request decisions, retention, guest-content erasure and server-resolved composer variables. message-lifecycle.ts holds the activation’s lifecycle: consented activation on a linked, room-mapped property in named phases (recover what an earlier request left, ensure a confirmed installation, commit the activation, compensate an owned attempt), the operator’s stop and the decision about an unconfirmed installation. message-sync.ts holds the drain: the outbox first (only the remote send is guarded, so an accepted reply is never sent again), then each property’s ingest from the property-filtered live feed, failing closed on any foreign item. It isolates only failures of Channex or the database; a bug is recorded and thrown to the job runner, even when recording it fails (ADR 0008). message-admission.ts holds the admission of every Channex Messages request (a committed check of the activation’s binding: local property, upstream property, generation) and the one stop path of unlink, deactivation and a 403: commit stopping (stopLocally, the same for every reason), uninstall GuestCraft’s own installation, settle an unfinished activation’s install attempt, remove its webhook, commit stopped. A stop returns retryable503while durable request decisions remain in flight; their unknown outcomes are reconciled with bounded reads and an operator retries the stop. It does not wait for admitted thread reads and sends, because Channex refuses those once the installation is gone; it also waits while an install attempt is not settled, and an installation is adopted or removed only when Channex’s answer or an operator confirmed it as GuestCraft’s. Every stored result is checked again under the row lock unlink takes; work of a retired upstream property is read-only history. See ADR 0044.

ARI publication uses explicit mapping/takeover, absolute values, generation-bound claims, task repair, booking holds and automatic catch-up through injected ports (ADR 0034). Reports use frozen nights; metric definitions are in ADR 0031. Tenancy enforces the last-administrator rule and a catalog of explicit stable capabilities, each declaring whether it acts on one property or on the workspace. can combines an effective grant with the workspace and concrete property, fail-closed for members limited to selected properties; canAcrossProperties authorizes the few reads that span every property the caller may reach. Built-in compatibility is pinned to the pre-catalog matrices, and identity persistence stays behind db/auth. See roles and property access.

Country packs validate dated cash-rounding and consumer-price rules at startup. Cash rounding is consumed by cash settlements; consumer prices are planned: not yet consumed by price workflows. Pure calculation tests and successful conformance checks do not implement that operator workflow (ADR 0015).

Run pnpm --filter @guestcraft/core test for unit/property rules. Property tests use 1,000 cases by default; FC_RUNS and FC_SEED change the budget/replay seed. Run pnpm quality for all gates including real PostgreSQL integration and coverage.

The reservation, rate, folio and booking-import orchestration has fast use-case tests using @guestcraft/testing/memory. A shared contract in the database integration suite checks property gates, uniqueness, rollback, reload, inventory and versions against PostgreSQL. The memory fake has no room-block or ARI ports and throws for the booking-import feed projections; use the database integration suite for those paths.

Property business dates, automatic and manual night audits are described in the workflow contract and ADR 0043. The night audit keeps the existing check-in charge timing; local-time scheduling, configured automatic no-shows and fee-free expired options share the same durable day-close path.

Guest duplicate review uses stored normalized email and phone equality keys; folded names only explain a pair already supported by a strong contact match. More than five visible live profiles sharing a key appear once as a shared-contact group, with paged members. Dismissals are filtered before pagination; dismissal and undo are audited only when state changes. Guest lists exclude absorbed identities unless includeMerged is requested. Every write on an absorbed identity fails with guest.absorbed and the final visible survivor id. Profile reads compress that pointer; a hidden chain fails closed.

Consent history is newest first, ordered by its recorded guest version before time and id. guestConsentCurrent reads each purpose’s latest decision independently of history pages; GUEST_CONSENT_PURPOSES defines the country-neutral catalog. Actor names are read projections. guestMerges exposes visible absorbed names and merge times, without former contact snapshots. Guest read projections include owning-property names and visible reservation counts.

Merged survivors are operator editable. Later OTA revisions retain their chosen identity and persist newer incoming contacts on the reservation as otaContact; profile notices contain only fields that differ, arrived after that field’s last review, and have never been dismissed for that guest/field. Snapshots are newest first. Keeping a current field is a version-checked, audited dismissal that remembers every dismissed exact value, including null, across future revisions and reservations. Ordinary updateGuest edits review only fields whose contact value actually changes, using injected time; notes, consents and unrelated version bumps do not suppress notices. Applying a notice overlays its partial contact on the current profile and preserves operator notes. These reviews stay with their original identity on merge. Merge bumps moved reservation versions and records each ordinary update event and audit entry in the merge transaction.

Counterparties are an organization directory reached from the organization’s active workspaces; open items, their append-only entries (debits, allocations, write-offs, releases, cancellations) and receipts belong to one workspace. Closing a folio linked to a counterparty books one receivable_transfer movement and opens its item; reopening reverses it exactly. OTA-collected bookings open expected payouts from the revision’s facts. See the receivables guide and ADR 0051.

Night audit settings, configured no-shows and expired tentative options share the durable property-date audit workflow. Cash drawer shifts provide currency-aware opening float, server-linked cash activity and versioned counted closure. See the night audit contract and cash shift contract for public operations, permissions, recovery, persistence and the Vercel daily-trigger cadence limit.

The tenancy contracts include browser organization/workspace administration and organization Activity. workspaces.configure is an unrestricted workspace permission, granted to the built-in administrator and delegable only within the existing live ceiling. Organization owner/admin authority is required for workspace creation and archival; instance administration is a separate persisted identity capability.