Categories
Brink & Borg Architecture (2)
"The Borg": Spensara's unified ingestion tool. Architecture options and recommendation
2026-10-23 (ET). This builds on analysis.md, the Brink findings. The code facts there are based on file names and logs; see its §0.
1. Tom's leaning, as stated
The Borg gathers data from every source, then assimilates, understands, maps and plans. It normalizes everything into the curated format, and only then streams it securely into the customer's own siloed S3 bucket. Nothing uncurated reaches S3, and any source the Borg can't shape is blocked at the door. A generic, low-logic AWS process (timers plus ingestion, no transformation) then loads S3 into the curated Redshift tables on a schedule.
2. Options
- A. Edge-normalize (Tom's leaning). Curated-only in S3, and a "dumb" loader.
- B. Land raw, normalize later. This is roughly today's KDSAI design: raw goes to S3 and staging (SUPER), then normalize → curated, all in AWS.
- C. Hybrid (recommended). The Borg normalizes before the customer's bucket, and keeps a sealed, quarantined raw zone. The raw zone is write-once and time-limited, the loader never reads it, and it's used only for replay and audit.
3. Tradeoffs
| Concern | A Edge-normalize | B Raw-then-normalize | C Hybrid |
|---|---|---|---|
| Replay / reprocessing (a mapping bug, a new curated column) | Weak. The raw data is gone, so you must re-pull from the source. Brink can be re-pulled by business date, but only within its retention window. A customer's S3 data may have been overwritten. | Strong | Strong: replay from sealed raw |
| Audit / lineage ("where did this number come from?") | Only curated rows plus Borg logs | Full | Full: each curated file carries raw_object_key, contract_version, borg_version |
| Schema evolution | Clean: the contract is enforced in one place. A new field is dropped until mapped, which is safe but loses data. | Flexible but messy (drift seeps into staging) | Enforced contract, and unmapped fields are kept in raw for later backfill |
| Failure blast radius | A Borg bug corrupts curated directly, with nothing to fall back to. The loader is trivial, so its failures are small. | Bad SQL in the warehouse affects every tenant at once | A Borg bug → re-run from raw. Bad input is stopped at the gate for that source only. |
| Customer isolation | Strong: one bucket/KMS key per customer holds only curated data. That's a good story for franchise and data-ownership covenants (see the Franchise tab: brands own the data, and less raw PII leaves the store). | Weaker unless raw is also siloed | Strong if raw is also per-customer, KMS-encrypted, with a short TTL (e.g. 30–90 d), or stays on the Edge device |
| Cost | Lowest storage and the cheapest Redshift (COPY only) | More storage and more Redshift compute (transform in-warehouse) | Little extra cost: S3 IA/Glacier for raw |
| Latency | Good: one hop | Extra hop | Same as A, since raw is written in parallel |
| Ops simplicity of the AWS side | Best: Scheduler → COPY/MERGE | Complex | Same as A |
Verdict: the core of Tom's idea is right: curate at the Borg, keep AWS dumb, siloed buckets, and block what can't be shaped. Doing it without a raw copy gives up replay and lineage, and turns every Borg bug into permanent data loss. Recommendation: Option C.
One correction to "no data manipulation" in the AWS loader: it still has to do a key-based MERGE, i.e. dedupe or upsert on a natural key. Re-pulled Brink days and late voids otherwise double-count. That counts as load semantics, not transformation, and it's generic: one stored procedure parameterized by table and key.
4. Architecture (Option C)
Sources ──► BORG (container; runs in Spensara AWS per tenant, and/or on Edge 9550 for in-store sources)
1 Connect (connector per source type, creds from Secrets Manager)
2 Discover (sample + infer schema; fingerprint)
3 Map (match to a registered Mapping Contract vN → curated tables; unknown fingerprint = BLOCKED, alert, await approval)
4 Normalize (types, time zones/business date, IDs, currency; PII scrub/hash per policy)
5 Validate (contract + row rules; failing rows → quarantine)
6 Seal raw → s3://spensara-raw-{tenant}/source/date/... (Object Lock, KMS-tenant, TTL; never read by the loader)
7 Publish → s3://spensara-cur-{tenant}/{curated_table}/load_date=/batch=.parquet + _manifest.json
(manifest: batch_id, row counts, checksum, contract_version, raw keys, watermark)
AWS generic loader (no business logic):
S3 manifest event / EventBridge Scheduler (5 min) ─► Step Functions ─► Redshift Data API:
COPY → temp table → MERGE INTO curated.<table> ON <contract key> → write load_audit → ack manifest
Failure → retry 3× → SNS alert; manifest stays pending (idempotent re-run by batch_id)
Curated Redshift (per-tenant DB, as today's TenantWarehouseMapping) ─► Spensara API / analysis agents (read-only)The control plane is a small registry: Sources, Contracts (versioned), Fingerprints, Approvals, Watermarks and the batch ledger. It can reuse KDSAI's IngestionBatch, IngestionCheckpoint and KdsCdcQuarantineRecord patterns.
5. What the Borg does per source type
(a) Brink API (pull, business-date model)
- Connect: per-location Brink token + service URL (Secrets Manager); reuse
BrinkPosEndpointCatalog/BrinkPosEndpointExecutor. - Plan: every 5–15 min, re-pull the current business date for each location (
BrinkPosBusinessDateResolver/ScheduleTimeZoneResolver). Nightly, re-pull D-1/D-2. Respect rate limits, with backoff and jitter. - Map: the contracts already exist in code:
BrinkPosNormalizationCatalog+BrinkPosCuratedTargetCatalog→ curated orders, items, modifiers, payments, discounts, voids, labor and settings. The Borg is largely a re-home of the existing BrinkPos stages, moving Normalize and StagingToCurated ahead of S3 instead of inside Redshift. - Keys / dedupe: (location_id, business_date, order_id[, line_no]). Voids and refunds update the same key, and MERGE handles them.
- Drift: new or unknown Brink fields stay in the sealed raw zone, trigger an alert, and go to a contract bump plus backfill from raw. A type change on a mapped field quarantines that endpoint.
- Block at the door: an unknown endpoint or response shape gets no contract, so nothing publishes.
(b) Arbitrary customer S3 sources (push or drop; unknown shape)
- Connect: cross-account IAM role in the customer's account (ExternalId), read-only on the named prefix, with S3 event notification → Borg queue (or a poll on a schedule).
- Discover: detect the format (CSV/JSON/Parquet/XLSX), infer the schema, profile columns, and compute a fingerprint (column set + types).
- Map: an assisted mapping proposal (column → curated field, with confidence) that requires a person's approval to become Contract v1. Until then the source is blocked: raw is sealed, and nothing is published.
- Normalize: units, time zones, store/location ID crosswalk (customer store # → Spensara location), product and menu crosswalk.
- Incremental: object key + ETag ledger (exactly-once per object). For full-snapshot drops, diff against the previous snapshot by key.
- Drift: a fingerprint change stops that source only, alerts, and asks for a new contract version.
- Isolation: never co-mingle. One tenant's role can't read another tenant's prefixes, with per-tenant KMS keys.
6. Build sequence (tied to the Brink findings)
- Decide the warehouse target and the bucket layout. Redshift Serverless per-tenant DB plus
spensara-raw-{tenant}andspensara-cur-{tenant}buckets with KMS. Reconcile with Maciej's Redshift→S3/Athena PR. (1 wk, includes the review) - Generic loader first (from analysis.md B2/B5/B8: Step Functions + COPY→MERGE + manifest ledger + alarms). It works for any source once a curated Parquet file and manifest exist. (1.5 wk)
- Borg v0 = Brink. Extract the BrinkPos Extract/Normalize/Curated stages into a Borg worker container that writes sealed raw plus curated Parquet and a manifest. The 5-min intraday and nightly re-pull schedules run from EventBridge Scheduler. This delivers Tom's original ask: real-time Brink into curated. (2–2.5 wk)
- Control plane: contracts, fingerprints, approvals, quarantine and the watermark registry, plus a Bridge Admin page. (1.5 wk)
- Borg v1 = customer S3 connector, with discovery, assisted mapping and approval gating. (2–3 wk)
- Edge placement: run the same Borg container on the Intel 9550 Edge for in-store sources (KDS, printers, Aloha). It pushes curated data plus sealed raw over mTLS to the tenant buckets. (later phase)
That is about 9–11 engineer-weeks to step 5. Steps 1–3 (about 5 weeks) deliver automated Brink → curated with replay.
7. Assumptions
- Brink offers pull APIs only, with no webhook or stream, and a business-date retention window long enough for the nightly re-pull.
- Curated tables keep their current names and shapes. The Borg's output contract equals today's
curatedschema (11 tables). - Tenant = customer, as in today's
TenantWarehouseMapping. - None of the code behavior was confirmed from file contents (see analysis.md §5).