offdataai
Retail & E-commerce · data model template

Retail Loyalty Program & Rewards Analytics data model

Kimball warehouse for retail loyalty: a transaction-grain points earn/burn fact, a periodic member-period snapshot for balances and liability, a redemption-event fact for reward economics, and a tier-change-event fact with role-played previous/new tier dimensions. Conformed dimensions cover member (SCD2 with PII), tier, store, offer, reward catalog, transaction type, product category, redemption channel, and change reason, with date and period for daily and periodic grains.

Retail loyalty program & rewards analytics for an omnichannel retailer: points earned on purchases and burned on catalog rewards, tiers (silver / gold / platinum / diamond) with points and spend thresholds, and a member lifecycle of new → active → at-risk → lapsed. The mart supports active-member counts, points liability, redemption rate, tier mix, attach rate, breakage percent, and cohort retention across in-store, web, app, and partner channels. It is a Kimball dimensional model: fact tables at a declared grain surrounded by conformed dimensions, ready for BI tools and a semantic layer.

KimballRetail & E-commerceGDPRCCPAPCI-DSS
15
tables
141
columns
19
relationships
2
PII columns

Opening the template creates a project with the ERD, platform-native DDL, a dbt project and documentation already generated (recommended platform: Snowflake). Edit it in plain English or on the canvas, then ship it to any supported warehouse.

Subject areas

points_transactionsmember_stateredemptionstier_changesconformed_dimensions

Design decisions

  • Transaction-grain points fact for earn-and-burn

    Loyalty programs are intrinsically event-driven: every earn, redeem, adjust, and expire moves the points balance. Modelling the fact at one row per points event preserves the full event stream needed for points-flow, breakage, and channel attribution.

  • Periodic member snapshot for balance and liability

    Active-member counts, points liability, and tier mix are best answered from a periodic snapshot at the member-by-period grain rather than re-aggregating the event stream, and the snapshot also carries lifecycle segment and tenure for retention cohorts.

  • Dedicated redemption fact for reward economics

    Reward redemption has its own grain (one row per burn event) and its own measures — points used, face value, cost-to-serve, partner fulfilment — that don't belong inside a general points-transaction fact; separating the redemption fact keeps measures clean and reward-catalog drill-down crisp.

  • Tier-change fact with role-played previous and new tier

    Tier movement is the primary engagement signal in a loyalty program. Capturing each transition as its own fact with two role-playing FKs into dim_tier (previous_tier_key and new_tier_key) makes upgrade / downgrade and anniversary-reset analysis a straightforward dimensional query.

  • SCD2 on dim_member to preserve as-was tier and segment

    Tier and lifecycle segment change over time as members earn, lapse, and recover; type-2 history on dim_member preserves the as-was tier and segment so cohort retention, attach rate, and win-back attribution remain comparable across periods.

Tables in the Retail Loyalty Program & Rewards Analytics model

Every table with its grain, columns, types and keys. PK marks a primary key, BK a business key and PII a column classified as personal data, which gets a masking strategy by default.

Fact tables (4)

fct_points_transaction

Grain: one row per points earn / burn / adjust / expire event (transaction grain)

Transaction-grain earn-and-burn fact powering points-flow and breakage analysis.

ColumnTypeKeys
points_transaction_keybigintPK
transaction_date_keybigint
member_keybigint
store_keybigint
transaction_type_keybigint
offer_keybigint
product_category_keybigint
transaction_idvarchar
sales_receipt_idvarchar
points_earnedbigint
points_redeemedbigint
points_adjustedbigint
points_expiredbigint
transaction_amountdecimal
points_valuedecimal
currencyvarchar
channelvarchar
is_bonusboolean

fct_member_period_snapshot

Grain: one row per member per reporting period (periodic snapshot of program state)

Periodic-snapshot fact for points liability, tier mix, and lifecycle reporting.

ColumnTypeKeys
member_period_snapshot_keybigintPK
period_keybigint
member_keybigint
current_tier_keybigint
points_balancebigint
points_earned_periodbigint
points_redeemed_periodbigint
points_expired_periodbigint
lifetime_points_earnedbigint
spend_amount_perioddecimal
lifetime_spenddecimal
order_count_periodinteger
tenure_monthsinteger
days_since_last_activityinteger
currencyvarchar
membership_statusvarchar
is_paying_tierboolean

fct_reward_redemption

Grain: one row per reward redemption (burn event grain)

Burn-event fact for redemption rate, reward economics, and partner attribution.

ColumnTypeKeys
reward_redemption_keybigintPK
redemption_date_keybigint
member_keybigint
reward_catalog_keybigint
store_keybigint
redemption_channel_keybigint
redemption_idvarchar
points_usedbigint
reward_face_valuedecimal
redemption_costdecimal
discount_applieddecimal
currencyvarchar
redemption_outcomevarchar
is_partner_rewardboolean

fct_tier_change_event

Grain: one row per member tier transition (upgrade / downgrade / anniversary reset)

Tier-transition fact with role-played previous/new tier for movement analysis.

ColumnTypeKeys
tier_change_event_keybigintPK
change_date_keybigint
member_keybigint
previous_tier_keybigint
new_tier_keybigint
change_reason_keybigint
event_idvarchar
days_in_previous_tierinteger
points_at_changebigint
spend_at_changedecimal
currencyvarchar
is_upgradeboolean
is_downgradeboolean
is_anniversary_resetboolean

Dimension tables (11)

dim_date

Grain: one row per calendar day

ColumnTypeKeys
date_keybigintPK
full_datedateBK
day_of_monthsmallint
month_numbersmallint
month_namevarchar
quartersmallint
yearsmallint
is_weekendboolean
is_holidayboolean

dim_period

Grain: one row per reporting period (month / quarter) for periodic snapshots

ColumnTypeKeys
period_keybigintPK
period_codevarcharBK
period_typevarchar
period_start_datedate
period_end_datedate

dim_member

Grain: one row per loyalty member per SCD2 version

SCD type 2

ColumnTypeKeys
member_keybigintPK
member_idvarcharBK
member_namevarcharPII
emailvarcharPII
join_datedate
age_bandvarchar
gendervarchar
countryvarchar
regionvarchar
signup_channelvarchar
current_tier_at_loadvarchar
lifecycle_segmentvarchar
is_activeboolean

dim_tier

Grain: one row per loyalty tier (silver / gold / platinum / diamond)

ColumnTypeKeys
tier_keybigintPK
tier_idvarcharBK
tier_namevarchar
tier_levelsmallint
points_threshold_minbigint
spend_threshold_mindecimal
benefits_summaryvarchar
is_paid_tierboolean
currencyvarchar

dim_store

Grain: one row per physical or digital store

ColumnTypeKeys
store_keybigintPK
store_idvarcharBK
store_namevarchar
store_typevarchar
regionvarchar
countryvarchar
opened_datedate
is_activeboolean

dim_offer

Grain: one row per promotional offer or campaign earning rule

ColumnTypeKeys
offer_keybigintPK
offer_idvarcharBK
offer_namevarchar
offer_typevarchar
valid_fromdate
valid_todate
points_multiplierdecimal
is_targetedboolean

dim_reward_catalog

Grain: one row per redeemable reward in the catalog

ColumnTypeKeys
reward_catalog_keybigintPK
reward_idvarcharBK
reward_namevarchar
reward_categoryvarchar
points_requiredbigint
face_valuedecimal
partnervarchar
is_activeboolean

dim_transaction_type

Grain: one row per points transaction type (earn / redeem / expire / adjust / transfer)

ColumnTypeKeys
transaction_type_keybigintPK
transaction_typevarcharBK
descriptionvarchar
is_positive_balance_impactboolean

dim_product_category

Grain: one row per product category for attach-rate analysis

ColumnTypeKeys
product_category_keybigintPK
category_idvarcharBK
category_namevarchar
category_parentvarchar
attaches_loyaltyboolean
is_high_marginboolean

dim_redemption_channel

Grain: one row per channel a reward can be redeemed through

ColumnTypeKeys
redemption_channel_keybigintPK
redemption_channelvarcharBK
channel_namevarchar
is_digitalboolean

dim_change_reason

Grain: one row per tier-change reason (threshold-reached / anniversary-reset / manual-adjust / expiration)

ColumnTypeKeys
change_reason_keybigintPK
change_reasonvarcharBK
descriptionvarchar
is_automaticboolean

Relationships

Each relationship is a foreign key on the first table referencing the second.

  • fct_points_transaction.transaction_date_key → dim_date (many-to-one)
  • fct_points_transaction.member_key → dim_member (many-to-one)
  • fct_points_transaction.store_key → dim_store (many-to-one)
  • fct_points_transaction.transaction_type_key → dim_transaction_type (many-to-one)
  • fct_points_transaction.offer_key → dim_offer (many-to-one)
  • fct_points_transaction.product_category_key → dim_product_category (many-to-one)
  • fct_member_period_snapshot.period_key → dim_period (many-to-one)
  • fct_member_period_snapshot.member_key → dim_member (many-to-one)
  • fct_member_period_snapshot.current_tier_key → dim_tier (many-to-one)
  • fct_reward_redemption.redemption_date_key → dim_date (many-to-one)
  • fct_reward_redemption.member_key → dim_member (many-to-one)
  • fct_reward_redemption.reward_catalog_key → dim_reward_catalog (many-to-one)
  • fct_reward_redemption.store_key → dim_store (many-to-one)
  • fct_reward_redemption.redemption_channel_key → dim_redemption_channel (many-to-one)
  • fct_tier_change_event.change_date_key → dim_date (many-to-one)
  • fct_tier_change_event.member_key → dim_member (many-to-one)
  • fct_tier_change_event.previous_tier_key → dim_tier (many-to-one)
  • fct_tier_change_event.new_tier_key → dim_tier (many-to-one)
  • fct_tier_change_event.change_reason_key → dim_change_reason (many-to-one)

Related templates

All templates →
Start for $1

From requirements to AI-ready context, in one platform.

Describe your business in a conversation, start from a template or connect your own database. Your first model is ready in minutes.

Get startedBook a demo

Plans from $1/month · cancel any time