Three diagrams, one family. A1 says what the layers mean; A2 says how the compute works; B says how the product reads. All three hand off at the same node — the customer's S3 bucket — so they stitch together.
No tools here — just meaning. Layers, not steps: each is a resting shape data can sit in. Aggregation is the line between silver and gold. Replayability lives in bronze: silver is always re-derivable to a point in time from bronze.
land into bronze
what comes in, made trustworthy — without leaving the raw behind.
exactly as landed
nothing adjusted
cleaned, deduplicated, history-aware
"shining glory"
Silver can always be re-derived to any point in time by replaying bronze forward.
Fix a transform → replay history.
future: table formats + time-travel / SCD2
how we model our domain entities.
if the only way in were an API, these are what we'd have you send
transaction tables, not roll-ups
grain · cardinality · relationships
canonical-ID / stitch layer → own diagram (Emerson)
shaped to the product's query patterns — designed for experiences.
shared across customers where we can
per-customer / per-vertical variation
accrete safely · formalize at rule-of-3
same data may appear in many shapes — as long as versions land atomically
no inconsistent view, ever
reads gold
The architectural truth A1 hides: past bronze/raw, bronze-vs-silver stops mattering. It's uniformly DuckDB transforms over Parquet on S3. Ingest heterogeneity — many transports, many formats, sometimes VPNs — is quarantined to one funnel; the boundary is "getting to S3 is messy; past S3 it's just IAM + Parquet."
SFTP · customer-run scripts
scripts need updating ▸
SQL · Snowflake · APIs · S3 · SFTP
reach out & fetch
EDI · HL7v2 · FHIR · flat
full taxonomy → own diagram
Ephemeral compute · ECS / Fargate · pay-by-the-second
packed: many assets / job
fan-out · all one customer
every asset: reads Parquet from S3 → writes Parquet to S3
lingua franca of data engineering: Python + SQL
shared handoff →
not mandatory — for stateful problems
today: Glue catalog · future: dbt-authored ▸
dlt + dbt both run via Dagster plugins
the one IP-rich transform · CalcEngine
app-layer contract, not a lake asset
not called by the app in RevFind
The product reads gold two ways, both in place, both from the same bucket A2 handed off. Omni reads analytically via cross-account Athena; the RevFind API reads record-level via in-process DuckDB. Nothing writes back here.
React SPA · serves end users
tenant from claim
server-signed URL · embed data path bypasses backend
.NET minimal API · ECS · Api→Infra→Core
record-level reads of gold, per request
deliberate v1 · latency floor to evolve later
shared handoff from A2
embedded in product · cross-account, read-only
dedicated analytics account = only trust surface
+ Glue catalog
governed · MCP/agentic folds in here
analytical scans — reads the same gold/, in place