Part 16. Customer 360 Mart
mart_customer_360 is the first final mart. It combines customer attributes, account balances, and card activity. This is the main learning example: here you can see how the product specification, ODCS, model specification, dbt tests, and validation facts should work together.
Acceptance Facts
- one row per
customer_id; customer_idnot null and unique;- no direct PII;
total_balance_rubnot null;risk_event_count_7dnot null;- required contract fields are present;
- lineage is read through
ref().
Implementation
Open:
models/marts/mart_customer_360.sql
models/schema.yml
specs/models/mart_customer_360.md
specs/validation/customer_360.md
Verify that the SQL follows the specification, and the tests cover the key facts. Do not limit yourself to reading the SQL: PII leakage and contract drift must have separate checks.
Acceptance Matrix
| Fact | Evidence |
|---|---|
one row per customer_id | dbt test unique |
customer_id is not empty | dbt test not_null |
| no direct PII | schema singular test |
| total balance is present | dbt test not_null |
| risk counter is present | dbt test not_null |
| contract fields are present | contract columns singular test |
If the evidence line is empty, it is not readiness, but a gap.
Qwen Query
Compare models/marts/mart_customer_360.sql, models/schema.yml,
specs/customer_360_contract.odcs.yaml and specs/validation/customer_360.md.
Show which acceptance facts are covered, which are manual, and which are missing.
Do not modify the files.
Minimum Output
Prepare a reviewer's note:
Granularity: one row per `customer_id`.
PII: no direct PII.
Contract fields: `customer_id`, `total_balance_rub`, `risk_event_count_7d`.
Checks: `dbt build`, mart tests, forbidden PII list, contract columns.
Open questions: the definition of `risk_event_count_7d` depends on the input risk flag.
Reader's Breakdown
Customer 360 is a good first mart, because the name is familiar and therefore dangerous. Almost every project participant thinks they understand its meaning, but different people mean different tables. For an analyst it may be a customer slice. For marketing — a profile with segments. For risk — behavior aggregates. For the operations team — a set of identifiers. SDD forces you to choose one version of the promise and write it down before SQL.
In this book, Customer 360 is intentionally limited. One row per customer. Direct PII is not exposed. The balance is calculated from accounts. Risk events are taken from a synthetic activity window. Such a limitation may seem poor, but it makes the example honest: every field can be linked to a specification and a check. If you add everything at once, the student will see a big table, but will not see product discipline.
Special attention should be paid to risk_event_count_7d. The name itself promises a seven-day window. If SQL simply counts all risk events, the field looks plausible, but deceives the consumer. Therefore, the window must be described and verified with a separate test. This is a small example of a big idea: the field name becomes part of the contract. If the name contains a term, currency, status, or level of aggregation, the check must confirm exactly that.
Customer 360 also shows why PII policy cannot be left as a general phrase. In raw and staging, pii_email may exist so that the student sees the risk. In the mart, it should not be. This is not a question of schema aesthetics, but a product boundary. The reviewer should look not only at the final select, but also at the test that proves the absence of direct PII fields.
Practice
Run only the Customer 360 checks and map each output line to the acceptance matrix. If a fact is confirmed only by manual review, write it down as such.
Typical Mistake
Checking SQL only by eye. In SDD, you need evidence: a dbt test, a schema review, an explicit validation fact, or a reviewer's report.
Control Questions
- Why should
pii_emailnot get into the mart? - Which fields make the mart a customer-level one?
- What will change if you add product-level granularity?