Spensara Spensara Knowledge Base & Documentation Repository

Repository Docs & Knowledge Base

Consolidated Spensara documentation repository (722 Markdown & architecture documents in ../repository)
Built Word Documents (.docx): Spensara Overview (.docx) Capability Assessment (.docx) Brink POS Ingestion Analysis (.docx) The Borg Ingestion Architecture (.docx)

Branches (328)

Branch-specific documentation across extract-raw-xml, feature-fleet-import, kds_cdc_improvments, life-cycle, and tenat-admin.
branches/life-cycle/research/temp/brink-pos-integration-research.md 15,467 bytes · Updated Oct 23, 2026 10:44 AM EDT
Raw File

Brink POS PoC integration note

Goal

Define the minimum viable approach for a Brink POS API pull PoC that:

  • pulls Brink SOAP data for one tenant-location
  • stores raw responses safely
  • lands a small source-shaped Brink staging subset
  • fills the first useful curated tables
  • keeps enough metadata for debugging and reruns

This document is intentionally PoC-oriented. It is not the final production design.

PoC decisions

  • Use Brink as a read-only API pull source.
  • Start with these Brink calls only:
  • Sales2.GetOrders
  • Kitchen.GetOrderBumpTimes
  • Kitchen.GetOrderItemBumpTimes
  • Settings2.GetLastModifiedTime
  • selected settings lookups for items, modifier groups, destinations, taxes, tenders, employees, and kitchen queues
  • Store raw SOAP responses in S3.
  • Reuse existing kdsaidb metadata for the PoC:
  • TenantWarehouseMapping
  • IngestionBatch
  • IngestionCheckpoint
  • Do not require new control-plane metadata tables for the PoC.
  • Use structured logs for per-call detail instead of a dedicated pull-attempt table.

Brink constraints

  • Brink is SOAP over HTTPS with WSDLs.
  • Auth is header-based: AccessToken, LocationToken.
  • TLS 1.2 or 1.3 is required.
  • ResultCode = 0 means success.
  • GetOrders is heavy and Brink recommends conservative polling.
  • Brink mixes business date, UTC timestamps, and location-local DateTimeOffset watermarks.
  • Try generated SOAP clients first for Sales2, Settings2, and Kitchen.
  • If generated code is awkward, switch quickly to a thin hand-written SOAP client for the small PoC call set.
  • Keep all Brink transport details behind one adapter boundary.

PoC staging scope

The Brink PoC staging scope is limited to what can support the current curated contracts in backend/Kds.Ai.Warehouse/Models/Curated/CuratedCanonicalModels.cs.

Important simplification rule for the PoC:

  • keep staging source-shaped, but keep it simple
  • Sales2.GetOrders does not need to be fully exploded into many staging tables on day one
  • prefer one primary order-centered staging landing plus only the child tables that clearly help staging -> curated transformations, replay, or debugging
  • move canonical reshaping and business semantics into curated

In scope staging tables

  • staging.brink_orders
  • optional normalized child tables from Sales2.GetOrders when they materially simplify curated publication:
  • staging.brink_order_entries
  • staging.brink_order_entry_modifiers
  • staging.brink_order_taxes
  • staging.brink_order_entry_taxes
  • staging.brink_order_payments
  • staging.brink_order_payment_details
  • staging.brink_items
  • staging.brink_modifier_groups
  • staging.brink_modifier_group_items
  • staging.brink_destinations
  • staging.brink_tables
  • staging.brink_kitchen_queues
  • staging.brink_taxes
  • staging.brink_tenders
  • staging.brink_employees
  • staging.brink_order_bump_times
  • staging.brink_order_item_bump_times

Optional PoC support tables

  • staging.brink_current_business_dates
  • staging.brink_api_call_log
  • staging.brink_raw_payload_manifest

For the PoC, these optional tables can be skipped if the same information is available through IngestionBatch, IngestionCheckpoint, structured logs, and S3 raw object paths.

Out of scope for the PoC

  • full settings sync
  • labor sync
  • future-date orders and deposit flows
  • inventory
  • loyalty
  • hourly sales
  • production-grade replay/backfill control plane

Staging source matrix

Staging tableBrink sourceAPI/service callBrink contract referenceEndpoint and docs reference
staging.brink_ordersorder headersSales2.GetOrdersOrderEndpoint: https://{{server}}.brinkpos.net/Sales2.svc; docs: https://brinkapiportal.parpos.com/sales2#GetOrders
staging.brink_order_entriesorder linesSales2.GetOrdersOrderEntry, OrderItem, OrderGiftCardEndpoint: https://{{server}}.brinkpos.net/Sales2.svc; docs: https://brinkapiportal.parpos.com/sales2#GetOrders
staging.brink_order_entry_modifiersentry modifiersSales2.GetOrdersOrderItemModifierEndpoint: https://{{server}}.brinkpos.net/Sales2.svc; docs: https://brinkapiportal.parpos.com/sales2#GetOrders
staging.brink_order_taxesorder-level taxesSales2.GetOrdersOrderTaxEndpoint: https://{{server}}.brinkpos.net/Sales2.svc; docs: https://brinkapiportal.parpos.com/sales2#GetOrders
staging.brink_order_entry_taxesentry-level taxesSales2.GetOrdersOrderEntryTaxEndpoint: https://{{server}}.brinkpos.net/Sales2.svc; docs: https://brinkapiportal.parpos.com/sales2#GetOrders
staging.brink_order_paymentspayment headersSales2.GetOrdersOrderPaymentEndpoint: https://{{server}}.brinkpos.net/Sales2.svc; docs: https://brinkapiportal.parpos.com/sales2#GetOrders
staging.brink_order_payment_detailspayment detail eventsSales2.GetOrdersOrderPaymentDetailEndpoint: https://{{server}}.brinkpos.net/Sales2.svc; docs: https://brinkapiportal.parpos.com/sales2#GetOrders
staging.brink_itemsitem masterSettings2.GetSettings or Settings.GetItemsMenuItem or ItemEndpoints: https://{{server}}.brinkpos.net/Settings2.svc, https://{{server}}.brinkpos.net/Settings.svc; docs: https://brinkapiportal.parpos.com/settings2#GetSettings, https://brinkapiportal.parpos.com/settings#GetItems
staging.brink_modifier_groupsmodifier group headersSettings2.GetModifierGroups or Settings.GetModifierGroupsModifierGroupEndpoints: https://{{server}}.brinkpos.net/Settings2.svc, https://{{server}}.brinkpos.net/Settings.svc; docs: https://brinkapiportal.parpos.com/settings2#GetModifierGroups, https://brinkapiportal.parpos.com/settings#GetModifierGroups
staging.brink_modifier_group_itemsmodifier group membershipSettings2.GetModifierGroups or Settings.GetModifierGroupsModifierGroup child membershipEndpoints: https://{{server}}.brinkpos.net/Settings2.svc, https://{{server}}.brinkpos.net/Settings.svc; docs: https://brinkapiportal.parpos.com/settings2#GetModifierGroups, https://brinkapiportal.parpos.com/settings#GetModifierGroups
staging.brink_destinationsdestination lookupSettings2.GetDestinations or Settings.GetDestinationsDestinationEndpoints: https://{{server}}.brinkpos.net/Settings2.svc, https://{{server}}.brinkpos.net/Settings.svc; docs: https://brinkapiportal.parpos.com/settings2#GetDestinations, https://brinkapiportal.parpos.com/settings#GetDestinations
staging.brink_tablestable lookupSettings2.GetTablesTableEndpoint: https://{{server}}.brinkpos.net/Settings2.svc; docs: https://brinkapiportal.parpos.com/settings2#GetTables
staging.brink_kitchen_queueskitchen queue lookupSettings2.GetKitchenQueuesKitchenQueueEndpoint: https://{{server}}.brinkpos.net/Settings2.svc; docs: https://brinkapiportal.parpos.com/settings2#GetKitchenQueues
staging.brink_taxestax lookupSettings2.GetTaxes or Settings.GetTaxesTaxEndpoints: https://{{server}}.brinkpos.net/Settings2.svc, https://{{server}}.brinkpos.net/Settings.svc; docs: https://brinkapiportal.parpos.com/settings2#GetTaxes, https://brinkapiportal.parpos.com/settings#GetTaxes
staging.brink_tenderstender lookupSettings.GetTendersTenderEndpoint: https://{{server}}.brinkpos.net/Settings.svc; docs: https://brinkapiportal.parpos.com/settings#GetTenders
staging.brink_employeesemployee lookupSettings2.GetEmployees or Settings2.GetSettings(Employee)EmployeeEndpoint: https://{{server}}.brinkpos.net/Settings2.svc; docs: https://brinkapiportal.parpos.com/settings2#GetEmployees, https://brinkapiportal.parpos.com/settings2#GetSettings
staging.brink_order_bump_timeskitchen order bump eventsKitchen.GetOrderBumpTimesOrderBumpTimeEndpoint: https://{{server}}.brinkpos.net/Kitchen.svc; docs: https://brinkapiportal.parpos.com/kitchen#GetOrderBumpTimes
staging.brink_order_item_bump_timeskitchen item bump eventsKitchen.GetOrderItemBumpTimesOrderItemBumpTimeEndpoint: https://{{server}}.brinkpos.net/Kitchen.svc; docs: https://brinkapiportal.parpos.com/kitchen#GetOrderItemBumpTimes

Curated fill matrix

Curated tableInput staging tablesBrink contract referenceEndpoint and docs referencePoC fill strategy
curated.kitchen_item_status_eventsstaging.brink_order_item_bump_times, staging.brink_kitchen_queues, staging.brink_orders, staging.brink_order_entriesOrderItemBumpTime, Order, OrderEntry, KitchenQueueKitchen.GetOrderItemBumpTimes: https://brinkapiportal.parpos.com/kitchen#GetOrderItemBumpTimes; Sales2.GetOrders: https://brinkapiportal.parpos.com/sales2#GetOrdersSupported. Derive one row per item bump using synthetic status semantics where needed.
curated.kitchen_order_itemsstaging.brink_order_entries, staging.brink_order_item_bump_times, staging.brink_orders, staging.brink_itemsOrderEntry, OrderItemBumpTime, Order, MenuItem or ItemSales2.GetOrders, Kitchen.GetOrderItemBumpTimes, item docsSupported. Map food/item lines into the current kitchen item contract.
curated.kitchen_ordersstaging.brink_orders, staging.brink_order_bump_times, staging.brink_destinations, staging.brink_kitchen_queuesOrder, OrderBumpTime, Destination, KitchenQueueSales2.GetOrders, Kitchen.GetOrderBumpTimes, destination docsSupported. Map Brink orders into current kitchen order rows with canonical defaults where needed.
curated.pos_transaction_itemsstaging.brink_order_entries, staging.brink_order_entry_modifiers, staging.brink_order_entry_taxes, staging.brink_orders, staging.brink_itemsOrderEntry, OrderItemModifier, OrderEntryTax, OrderSales2.GetOrders, item docsSupported. Use canonical projection into the current Aloha-shaped contract.
curated.pos_transactionsstaging.brink_orders, staging.brink_destinations, staging.brink_employeesOrder, Destination, EmployeeSales2.GetOrders, destination docs, employee docsSupported. Use order header data as the source of the transaction row.
curated.pos_transaction_tendersstaging.brink_order_payments, staging.brink_order_payment_details, staging.brink_tenders, staging.brink_orders, staging.brink_employeesOrderPayment, OrderPaymentDetail, TenderSales2.GetOrders, Settings.GetTendersSupported. Transform Brink payments into the current tender-style transaction contract.
curated.pos_tablesstaging.brink_tablesTableSettings2.GetTables: https://brinkapiportal.parpos.com/settings2#GetTablesSupported as a direct lookup mapping.
curated.pos_tendersstaging.brink_tendersTenderSettings.GetTenders: https://brinkapiportal.parpos.com/settings#GetTendersSupported as a direct lookup mapping with many nullable fields.
curated.pos_catalog_itemsstaging.brink_items, staging.brink_taxesMenuItem or Item, Taxitem docs, tax docsSupported. Map only fields with safe Brink equivalents.
curated.pos_modifiersstaging.brink_modifier_groups, staging.brink_modifier_group_items, staging.brink_itemsModifierGroup, child membershipmodifier docs, item docsSupported. Canonical projection only, not one-to-one parity.
curated.pos_ordersstaging.brink_orders, staging.brink_order_payments, staging.brink_destinationsOrder, OrderPayment, DestinationSales2.GetOrders, destination docsOptional in the PoC. Add only if we agree on a simple canonical mapping.
curated.pos_order_itemsstaging.brink_order_entries, staging.brink_orders, staging.brink_items, staging.brink_order_entry_modifiersOrderEntry, Order, ItemSales2.GetOrders, item docsOptional in the PoC. Add only if we agree on a simple canonical mapping.
curated.pos_menu_itemsstaging.brink_items, staging.brink_destinations, staging.brink_kitchen_queuesMenuItem or Item, Destination, KitchenQueueitem docs, destination docs, queue docsOptional in the PoC. Only if the current contract can be filled without excessive source-specific hacks.
curated.customersstaging.brink_orderscustomer-related fields on OrderSales2.GetOrders: https://brinkapiportal.parpos.com/sales2#GetOrdersOut of scope unless Brink order payloads give stable customer data for the current contract.
curated.pos_table_definitionsnonenonenoneOut of scope for the PoC.
curated.loyalty_customersnonenonenoneOut of scope for the PoC.
curated.pos_hourly_salesnonenonenoneOut of scope for the PoC.
curated.inventory_itemsnonenonenoneOut of scope for the PoC.

PoC metadata minimum

Use the existing control-plane metadata only:

  • TenantWarehouseMapping
  • IngestionBatch
  • IngestionCheckpoint

For the PoC, this is enough if we also do these three things:

  1. Save raw SOAP responses to S3.
  2. Record the main raw response path on the batch when practical.
  3. Emit structured logs for every Brink call.

Minimum batch usage

  • Use one IngestionBatch per Brink sync stream.
  • Recommended first stream names:
  • orders
  • order-bumps
  • item-bumps
  • settings

Minimum checkpoint usage

Use the existing IngestionCheckpoint table with these keys:

  • location:{location_key}:orders:modified-time
  • location:{location_key}:order-bumps:bump-time
  • location:{location_key}:item-bumps:bump-time
  • location:{location_key}:settings:last-modified

Rules:

  • advance checkpoints only after successful end-to-end completion of the stream
  • failed runs must not advance checkpoints
  • preserve watermark offsets exactly for Brink DateTimeOffset values

Minimum structured logging

For every Brink call, log at least:

  • tenant_id
  • batch_id
  • source_type
  • service_name
  • operation_name
  • endpoint_url
  • request_window_start
  • request_window_end
  • result_code
  • status
  • raw_response_s3_path

PoC minimum bar

The Brink PoC is good enough if:

  1. One tenant can be linked to one Brink location and endpoint stack.
  2. The adapter can pull orders, kitchen bumps, and one settings freshness check.
  3. Raw SOAP responses are saved to S3.
  4. One batch is recorded per sync stream.
  5. Checkpoints advance only after stream success.
  6. Failures do not advance checkpoints.
  7. Logs are rich enough to diagnose which Brink call failed and for what time window.
  8. The first agreed curated tables can be populated from the staging subset.

References

  • docs/ETL.md
  • docs/features/ETL/epics/06-source-adapter-brink-pos-api/
  • backend/Kds.Ai.Warehouse/Sql/Bootstrap/Tenant/Staging/
  • backend/Kds.Ai.Warehouse/Models/Curated/CuratedCanonicalModels.cs
  • https://brinkapiportal.parpos.com/
  • https://brinkapiportal.parpos.com/bestpracticeandfaqs
  • https://brinkapiportal.parpos.com/sales2
  • https://brinkapiportal.parpos.com/settings2
  • https://brinkapiportal.parpos.com/settings
  • https://brinkapiportal.parpos.com/kitchen