02Architecture, Schema Translation & Security Mapping

I turned the mandate into a blueprint my team could build against.

Translating legacy SQL to Snowflake and designing robust automated verification systems — because I wasn't going to find out about a broken join from a controller three weeks after go-live.

Legacy → cloud-native

Translating Legacy Schemas to Cloud-Native Models

I didn't let the team just port the schema over. I made three explicit calls about how the data would actually move, and held the line on each of them through the build.

Bulk history load

I had every wave do a full historical load into Snowflake first, validated before anyone flipped on the incremental feed.

Incremental / CDC dual-run

I ran both platforms in parallel and reconciled daily, so I could prove the target was current before anyone depended on it.

Code conversion

I sized T-SQL-to-Snowflake-Scripting conversion as its own workstream — I knew going in it would be the bulk of the engineering effort.

The architecture, end to end

Before anyone wrote a mapping row, this is the picture I put in front of Steering and Data Engineering both — one diagram, so nobody was building against a different mental model of how data actually moved.

Artifact · System architectureinfographic · legacy → cloud
LEGACY SQL Server EDW ~1,200 objects MIGRATION PIPELINE Bulk history load Incremental / CDC dual-run Code conversion — T-SQL → Scripting ✓ RECONCILIATION GATE SNOWFLAKE CLOUD RAW Landed, unmodified STAGING Transformed, reconciled MARTS Domain-modeled, report-ready BI & REPORTING Tableau · Power BI 250 rationalized reports SECURITY & GOVERNANCE RBAC + Masking Column-level, PII fields

The schema translation, field by field

This is the one document where I forced the legacy schema, the new schema, and the actual business meaning to agree in a single row. Every cell closed a question I didn't want reopened during UAT.

Why this artifact

Without a mapping row that names the transformation and the owner, ambiguity doesn't disappear — it just gets resolved by whoever writes the SQL, quietly, weeks later. This is the single place engineers and the business had to agree before code got written.

Artifact · Field mappingexcerpt · Sales/Revenue domain
Source (SQL Server)Type · grainTransformationTarget (Snowflake)ValidationOwner
FactOpportunity.CloseAmt MONEY · per opp / snapshot MONEY→NUMBER(19,4); FX to USD on close date; null rejected, not defaulted FACT_OPPORTUNITY.CLOSE_AMOUNT_USD Sum + row-count reconcile; FK to DIM_ACCOUNT resolves Sales Finance SME
FactOpportunity.CloseDate DATETIME · per opp DATETIME→TIMESTAMP_NTZ; timezone normalized FACT_OPPORTUNITY.CLOSE_DATE Min/max date parity per period Sales Finance SME
DimAccount.AcctId IDENTITY · per account IDENTITY→sequence; surrogate key re-seeded & remapped DIM_ACCOUNT.ACCOUNT_KEY Distinct-count parity; no orphan facts Data Governance

I also built an interactive deep-dive on this mapping — where each cell explains what it carries and what I owned as TPM: open the mapping deep-dive →

Re-mapping security, not just schema

Schema translation wasn't just data types. I owned re-mapping the access model too: legacy AD-group table permissions became Snowflake role-based access control, with column-level masking policies I required on every PII field — SSN, email, phone — for anyone outside Finance and Compliance.

Deciding what to rebuild, migrate, or kill

Artifact · Dispositionper report
ReportConsumersMy callWhy
Revenue by SegmentSales Finance, ExecRebuildHigh-value; worth re-modeling for Snowflake performance
Pipeline SnapshotSales OpsMigrateRe-point to new source; logic unchanged
Legacy Quota v3 (copy)— none in 12 moRetireDuplicate of active report; no recent access

The risks I tracked from day one

Why this artifact

Risks I don't write down are risks I only remember after they've become issues. A live register with a named owner per line is what turns "we should probably watch that" into someone actually watching it.

Artifact · Risk registerlive · I reviewed it weekly
#RiskSeverityHow I mitigated itOwner
R1Source data-quality gaps surface during loadHighI had discovery profile the data and agree cleansing rules before build startedData Eng
R2Financial metric fails reconciliation post-loadHighI set zero-tolerance sum parity and required grain stated on both sides of every mapping rowMe / SME
R3T-SQL code conversion underestimatedMediumI sized conversion as its own workstream and evaluated an accelerator toolData Eng
R4SME availability during design & UATMediumI named owners per domain in the RACI and booked their time in advanceMe
R6Dual-run sync drift between platformsLowDaily reconciliation during dual-run with drift alertsData Eng

Setting the bar before anyone wrote a join

How We Proved the Numbers Matched

I decided early that "migrated" wasn't a status I'd accept — only "reconciled" was. And because Snowflake accepts but doesn't enforce PK/FK constraints, I knew integrity checks had to move out of the schema and into the test suite, not stay assumed.

Why this artifact

Snowflake won't tell you your keys are broken — it just lets you build on top of a bad join. Writing the tolerance down before build started meant I couldn't quietly loosen the bar later to hit a date.

Artifact · Reconciliation suiteper object, per wave
TestWhat it provesTolerance I set
Row-count parityNo rows dropped or duplicated in transit0
Sum / metric parityFinancial totals match — revenue to the penny0 on financials
Checksum / hashRow-level values identical, not just aggregates0
Referential integrityNo orphan facts — the check Snowflake won't run itself0 orphans
Report parityOld dashboard vs. new, same inputs, same outputvisual sign-off

Scar tissue

What I actually decided here

What I Actually Decided Here

Decision: Once I realized Snowflake doesn't enforce runtime PK/FK constraints, I halted the sprint coding that was already underway to build PK/FK verification directly into the automated test suite instead of trusting the schema.

Friction: The architects balked — two weeks of added design overhead when we were already behind on the build calendar wasn't an easy sell.

Outcome: It caught what the schema never would have — and it kept silent duplicate records out of the financial reports during execution, which is exactly where they would have surfaced first.