offdataai
Retail & E-commerce · data model template

Retail POS data model

Normalized (3NF) OLTP model of a retail point-of-sale system modeled on NCR / Square / Oracle Xstore structures. Store, register, cashier, product, inventory, transaction, tender, return, and loyalty tables are each normalized with surrogate and natural keys and connected by child-to-parent foreign keys. Customer and cashier PII and card suffixes are classified and masked.

Operational store-level point-of-sale data: the store fleet, registers, and cashiers, a product master with per-store inventory, sales transactions and their line items, the tenders that settle them, returns and return lines against prior sales, and the loyalty customers and accounts that earn points. It is a normalized (3NF) relational model that mirrors the source system, suited to operational databases and to landing source data faithfully.

3NFRetail & E-commercePCI-DSSGDPR
12
tables
106
columns
19
relationships
8
PII columns

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

Subject areas

store_opsmerchandisecustomerssalesreturns

Design decisions

  • Transaction header / line / tender split

    A POS basket is one header with many scanned lines settled by one or more tenders; modeling them as three tables matches the receipt structure and lets a sale be paid by split tender.

  • Returns reference the original sale

    Return transactions and return lines softly reference the original sales transaction and line so refunds can be validated against the purchase and shrink/disposition tracked.

  • Card data minimization for PCI-DSS

    Tenders store only a masked card_last4 and auth code, never the full PAN, keeping the POS store database out of PCI cardholder-data scope.

  • Normalized (3NF) for store-level OLTP

    POS is high-volume write OLTP at each lane requiring referential integrity and minimal anomalies; a normalized relational model on Postgres is preferred over a sales star schema, which is built downstream.

Tables in the Retail POS 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.

Tables (12)

store

Grain: one row per retail store / location

Store master.

ColumnTypeKeys
store_keybigintPK
store_numbervarcharBK
store_namevarchar
store_formatvarchar
address_linevarchar
cityvarchar
regionvarchar
countryvarchar
timezonevarchar
is_activeboolean

register

Grain: one row per POS register / lane in a store

ColumnTypeKeys
register_keybigintPK
store_keybigint
register_numbervarcharBK
device_serialvarchar
register_typevarchar
is_activeboolean

cashier

Grain: one row per cashier / store associate

ColumnTypeKeys
cashier_keybigintPK
store_keybigint
employee_idvarcharBK
full_namevarcharPII
emailvarcharPII
rolevarchar
hire_datedate
is_activeboolean

product

Grain: one row per product / item master

ColumnTypeKeys
product_keybigintPK
skuvarcharBK
upcvarchar
product_namevarchar
departmentvarchar
categoryvarchar
retail_pricedecimal
tax_categoryvarchar
is_weighedboolean
is_activeboolean

inventory

Grain: one row per product per store on-hand position

ColumnTypeKeys
inventory_keybigintPK
store_keybigint
product_keybigint
quantity_on_handdecimal
reorder_pointdecimal
safety_stockdecimal
last_counted_attimestamp

customer

Grain: one row per identified retail customer

ColumnTypeKeys
customer_keybigintPK
customer_numbervarcharBK
first_namevarcharPII
last_namevarcharPII
emailvarcharPII
phonevarcharPII
postal_codevarcharPII
marketing_opt_inboolean

loyalty_account

Grain: one row per loyalty membership for a customer

ColumnTypeKeys
loyalty_account_keybigintPK
customer_keybigint
loyalty_numbervarcharBK
tiervarchar
points_balanceinteger
lifetime_pointsinteger
enrolled_datedate
loyalty_statusvarchar

sales_transaction

Grain: one row per POS sales transaction (basket)

Basket header.

ColumnTypeKeys
sales_transaction_keybigintPK
store_keybigint
register_keybigint
cashier_keybigint
customer_keybigint
transaction_numbervarcharBK
business_datedate
transacted_attimestamp
transaction_typevarchar
subtotal_amountdecimal
discount_amountdecimal
tax_amountdecimal
total_amountdecimal
item_countinteger

transaction_line

Grain: one row per line item on a sales transaction

ColumnTypeKeys
transaction_line_keybigintPK
sales_transaction_keybigint
product_keybigint
line_numberinteger
quantitydecimal
unit_pricedecimal
line_discountdecimal
extended_amountdecimal
tax_codevarchar

tender

Grain: one row per tender / payment settling a transaction

ColumnTypeKeys
tender_keybigintPK
sales_transaction_keybigint
tender_typevarchar
amountdecimal
change_givendecimal
card_last4varcharPII
auth_codevarchar
tender_statusvarchar

return_transaction

Grain: one row per return against a prior sale

ColumnTypeKeys
return_transaction_keybigintPK
store_keybigint
register_keybigint
cashier_keybigint
original_transaction_keybigint
return_numbervarcharBK
returned_attimestamp
return_reasonvarchar
refund_amountdecimal
refund_methodvarchar

return_line

Grain: one row per line item on a return

ColumnTypeKeys
return_line_keybigintPK
return_transaction_keybigint
product_keybigint
original_line_keybigint
quantitydecimal
unit_pricedecimal
refund_amountdecimal
dispositionvarchar

Relationships

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

  • register.store_key → store (many-to-one)
  • cashier.store_key → store (many-to-one)
  • inventory.store_key → store (many-to-one)
  • inventory.product_key → product (many-to-one)
  • loyalty_account.customer_key → customer (many-to-one)
  • sales_transaction.store_key → store (many-to-one)
  • sales_transaction.register_key → register (many-to-one)
  • sales_transaction.cashier_key → cashier (many-to-one)
  • sales_transaction.customer_key → customer (many-to-one)
  • transaction_line.sales_transaction_key → sales_transaction (many-to-one)
  • transaction_line.product_key → product (many-to-one)
  • tender.sales_transaction_key → sales_transaction (many-to-one)
  • return_transaction.store_key → store (many-to-one)
  • return_transaction.register_key → register (many-to-one)
  • return_transaction.cashier_key → cashier (many-to-one)
  • return_transaction.original_transaction_key → sales_transaction (many-to-one)
  • return_line.return_transaction_key → return_transaction (many-to-one)
  • return_line.product_key → product (many-to-one)
  • return_line.original_line_key → transaction_line (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