Appendix B: Database Entity Relationship Diagram

Version: 4.0.0 Last Updated: February 25, 2026 Database: PostgreSQL 16 Total Tables: 51+


B.1 Overview

Note (v5.0.0): The POS Platform uses Row-Level Security (RLS) with tenant_id columns, NOT Schema-Per-Tenant. See Chapter 07 for current database strategy and Chapter 05 Module 5 for tenant management. The ERD diagrams below should be interpreted with this context – all tenant-scoped tables include a tenant_id UUID NOT NULL column with RLS policies enforcing isolation.

Zone fields removed (BRD v19): Zone tracking has been removed as of BRD v19. Any zone-related fields shown in the diagrams below are no longer part of the current schema. See Chapter 05 Decision #107.

Additional tables not shown: tax_jurisdictions, tax_rates, rfid_tag_templates, rfid_tag_mappings, session_operators, register_ip_changes. See Chapter 05 and Chapter 09 for complete table definitions.

This appendix contains the complete Entity Relationship Diagram (ERD) for the POS Platform database. The schema is organized by domain with Row-Level Security (RLS) tenant isolation.


B.2 Schema Organization

pos_platform (database)
    |
    +-- shared (schema)
    |       Contains: tenants, modules, system settings
    |
    +-- tenant_nexus (schema per tenant)
    |       Contains: All tenant-specific tables
    |
    +-- tenant_retailco (schema per tenant)
            Contains: All tenant-specific tables

B.3 Complete Entity Relationship Diagram

╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
║                                    POS PLATFORM - COMPLETE ENTITY RELATIONSHIP DIAGRAM                             ║
║                                                  51 Tables | 14 Domains                                            ║
╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║                                                                                                                     ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                         DOMAIN 1: MULTI-TENANCY (shared schema)                             ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐                                       ║  ║
║  ║    │        tenants           │           │    tenant_modules        │                                       ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤                                       ║  ║
║  ║    │ PK id UUID               │───────────│ PK id UUID               │                                       ║  ║
║  ║    │    name VARCHAR(100)     │     1:N   │ FK tenant_id UUID        │──┐                                    ║  ║
║  ║    │    subdomain VARCHAR(50) │           │    module_code VARCHAR   │  │                                    ║  ║
║  ║    │    status ENUM           │           │    enabled BOOLEAN       │  │     ┌──────────────────────────┐  ║  ║
║  ║    │    plan ENUM             │           │    config JSONB          │  │     │    system_settings       │  ║  ║
║  ║    │    schema_name VARCHAR   │           │    activated_at TIMESTP  │  │     ├──────────────────────────┤  ║  ║
║  ║    │    settings JSONB        │           └──────────────────────────┘  ├────►│ PK id UUID               │  ║  ║
║  ║    │    created_at TIMESTAMP  │                                         │     │ FK tenant_id UUID        │  ║  ║
║  ║    │    updated_at TIMESTAMP  │                                         │     │    key VARCHAR(100)      │  ║  ║
║  ║    └──────────────────────────┘                                         │     │    value JSONB           │  ║  ║
║  ║                                                                          │     │    updated_at TIMESTAMP  │  ║  ║
║  ║                                                                          │     └──────────────────────────┘  ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                           │                                                        ║
║                                                           │ tenant_id (implicit via schema)                        ║
║                                                           ▼                                                        ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                     DOMAIN 2: LOCATIONS & REGISTERS                                          ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │       locations          │           │       registers          │       │    operating_hours       │   ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    │ PK id UUID               │──────────►│ PK id UUID               │       │ PK id UUID               │   ║  ║
║  ║    │    code VARCHAR(10)      │    1:N    │ FK location_id UUID      │       │ FK location_id UUID      │◄──┤   ║  ║
║  ║    │    name VARCHAR(100)     │           │    name VARCHAR(50)      │       │    day_of_week INT       │   ║  ║
║  ║    │    type ENUM             │           │    status ENUM           │       │    open_time TIME        │   ║  ║
║  ║    │    status ENUM           │           │    terminal_id VARCHAR   │       │    close_time TIME       │   ║  ║
║  ║    │    address_line1 VARCHAR │           │    last_active TIMESTAMP │       │    is_closed BOOLEAN     │   ║  ║
║  ║    │    address_line2 VARCHAR │           │    config JSONB          │       └──────────────────────────┘   ║  ║
║  ║    │    city VARCHAR(100)     │           └──────────────────────────┘                                       ║  ║
║  ║    │    state VARCHAR(50)     │                                                                              ║  ║
║  ║    │    zip VARCHAR(20)       │                                                                              ║  ║
║  ║    │    country VARCHAR(2)    │                                                                              ║  ║
║  ║    │    phone VARCHAR(20)     │                                                                              ║  ║
║  ║    │    timezone VARCHAR(50)  │                                                                              ║  ║
║  ║    │    shopify_location_id   │                                                                              ║  ║
║  ║    │    settings JSONB        │                                                                              ║  ║
║  ║    │    created_at TIMESTAMP  │                                                                              ║  ║
║  ║    └──────────────────────────┘                                                                              ║  ║
║  ║              │                                                                                                ║  ║
║  ╚══════════════╪═══════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                 │                                                                                                   ║
║                 │ location_id                                                                                       ║
║                 ▼                                                                                                   ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                        DOMAIN 3: USERS & EMPLOYEES                                           ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │         users            │           │    user_permissions      │       │      user_sessions       │   ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    │ PK id UUID               │──────────►│ PK id UUID               │       │ PK id UUID               │   ║  ║
║  ║    │    email VARCHAR(255)    │    1:N    │ FK user_id UUID          │       │ FK user_id UUID          │◄──┤   ║  ║
║  ║    │    password_hash VARCHAR │           │    permission VARCHAR    │       │    token_hash VARCHAR    │   ║  ║
║  ║    │    first_name VARCHAR    │           │    granted_by UUID       │       │    device_info JSONB     │   ║  ║
║  ║    │    last_name VARCHAR     │           │    granted_at TIMESTAMP  │       │    ip_address INET       │   ║  ║
║  ║    │    role ENUM             │           └──────────────────────────┘       │    expires_at TIMESTAMP  │   ║  ║
║  ║    │    pin_hash VARCHAR      │                                              │    created_at TIMESTAMP  │   ║  ║
║  ║    │ FK home_location_id UUID │◄─────────────────────────────────────────────└──────────────────────────┘   ║  ║
║  ║    │    status ENUM           │                                                                              ║  ║
║  ║    │    last_login TIMESTAMP  │           ┌──────────────────────────┐                                       ║  ║
║  ║    │    created_at TIMESTAMP  │           │    time_clock_entries    │                                       ║  ║
║  ║    └──────────────────────────┘           ├──────────────────────────┤                                       ║  ║
║  ║              │                            │ PK id UUID               │                                       ║  ║
║  ║              │                            │ FK user_id UUID          │◄──────────────────────────────────────┤   ║  ║
║  ║              │                            │ FK location_id UUID      │                                       ║  ║
║  ║              │                            │    clock_in TIMESTAMP    │                                       ║  ║
║  ║              │                            │    clock_out TIMESTAMP   │                                       ║  ║
║  ║              │                            │    break_minutes INT     │                                       ║  ║
║  ║              │                            │    status ENUM           │                                       ║  ║
║  ║              │                            │    notes TEXT            │                                       ║  ║
║  ║              │                            └──────────────────────────┘                                       ║  ║
║  ╚══════════════╪═══════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                 │                                                                                                   ║
║                 │ user_id                                                                                           ║
║                 ▼                                                                                                   ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                        DOMAIN 4: PRODUCTS & CATALOG                                          ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │      categories          │           │       products           │       │    product_variants      │   ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    │ PK id UUID               │◄──────────│ PK id UUID               │──────►│ PK id UUID               │   ║  ║
║  ║    │ FK parent_id UUID (self) │     N:1   │    sku VARCHAR(50)       │  1:N  │ FK product_id UUID       │   ║  ║
║  ║    │    name VARCHAR(100)     │           │    name VARCHAR(255)     │       │    sku VARCHAR(50)       │   ║  ║
║  ║    │    slug VARCHAR(100)     │           │    description TEXT      │       │    barcode VARCHAR(50)   │   ║  ║
║  ║    │    sort_order INT        │           │ FK category_id UUID      │       │    options JSONB         │   ║  ║
║  ║    │    is_active BOOLEAN     │           │ FK vendor_id UUID        │       │    price DECIMAL(10,2)   │   ║  ║
║  ║    └──────────────────────────┘           │    base_price DECIMAL    │       │    compare_price DECIMAL │   ║  ║
║  ║                                           │    cost DECIMAL(10,2)    │       │    cost DECIMAL(10,2)    │   ║  ║
║  ║    ┌──────────────────────────┐           │    tax_class VARCHAR     │       │    weight DECIMAL        │   ║  ║
║  ║    │        vendors           │           │    status ENUM           │       │    is_active BOOLEAN     │   ║  ║
║  ║    ├──────────────────────────┤           │    shopify_product_id    │       │    shopify_variant_id    │   ║  ║
║  ║    │ PK id UUID               │◄──────────│    created_at TIMESTAMP  │       │    created_at TIMESTAMP  │   ║  ║
║  ║    │    name VARCHAR(100)     │     N:1   └──────────────────────────┘       └──────────────────────────┘   ║  ║
║  ║    │    code VARCHAR(20)      │                       │                                  │                   ║  ║
║  ║    │    contact_name VARCHAR  │                       │                                  │                   ║  ║
║  ║    │    email VARCHAR(255)    │                       │                                  │                   ║  ║
║  ║    │    phone VARCHAR(20)     │                       ▼                                  ▼                   ║  ║
║  ║    │    address JSONB         │           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │    payment_terms VARCHAR │           │    product_images        │       │    variant_prices        │   ║  ║
║  ║    │    is_active BOOLEAN     │           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    └──────────────────────────┘           │ PK id UUID               │       │ PK id UUID               │   ║  ║
║  ║                                           │ FK product_id UUID       │       │ FK variant_id UUID       │   ║  ║
║  ║                                           │    url VARCHAR(500)      │       │ FK price_list_id UUID    │   ║  ║
║  ║                                           │    alt_text VARCHAR      │       │    price DECIMAL(10,2)   │   ║  ║
║  ║                                           │    position INT          │       │    effective_from DATE   │   ║  ║
║  ║                                           └──────────────────────────┘       │    effective_to DATE     │   ║  ║
║  ║                                                                              └──────────────────────────┘   ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                           │                                                        ║
║                                                           │ variant_id                                             ║
║                                                           ▼                                                        ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                            DOMAIN 5: INVENTORY                                                ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │    inventory_levels      │           │  inventory_transactions  │       │  inventory_reservations  │   ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    │ PK id UUID               │           │ PK id UUID               │       │ PK id UUID               │   ║  ║
║  ║    │ FK variant_id UUID       │◄──────────│ FK variant_id UUID       │       │ FK variant_id UUID       │◄──┤   ║  ║
║  ║    │ FK location_id UUID      │     1:N   │ FK location_id UUID      │       │ FK location_id UUID      │   ║  ║
║  ║    │    on_hand INT           │           │    transaction_type ENUM │       │ FK order_id UUID         │   ║  ║
║  ║    │    available INT         │           │    quantity INT          │       │    quantity INT          │   ║  ║
║  ║    │    reserved INT          │           │    previous_qty INT      │       │    expires_at TIMESTAMP  │   ║  ║
║  ║    │    reorder_point INT     │           │    new_qty INT           │       │    status ENUM           │   ║  ║
║  ║    │    reorder_qty INT       │           │    reference_type VARCHAR│       │    created_at TIMESTAMP  │   ║  ║
║  ║    │    bin_location VARCHAR  │           │    reference_id UUID     │       └──────────────────────────┘   ║  ║
║  ║    │    updated_at TIMESTAMP  │           │    cost DECIMAL(10,2)    │                                       ║  ║
║  ║    │ UK (variant_id, loc_id)  │           │    notes TEXT            │                                       ║  ║
║  ║    └──────────────────────────┘           │ FK created_by UUID       │                                       ║  ║
║  ║              │                            │    created_at TIMESTAMP  │                                       ║  ║
║  ║              │                            └──────────────────────────┘                                       ║  ║
║  ║              │                                                                                                ║  ║
║  ║              │           ┌──────────────────────────┐       ┌──────────────────────────┐                     ║  ║
║  ║              │           │   inventory_transfers    │       │   transfer_line_items    │                     ║  ║
║  ║              │           ├──────────────────────────┤       ├──────────────────────────┤                     ║  ║
║  ║              │           │ PK id UUID               │──────►│ PK id UUID               │                     ║  ║
║  ║              │           │ FK from_location_id UUID │  1:N  │ FK transfer_id UUID      │                     ║  ║
║  ║              │           │ FK to_location_id UUID   │       │ FK variant_id UUID       │                     ║  ║
║  ║              └──────────►│    status ENUM           │       │    qty_requested INT     │                     ║  ║
║  ║                          │    priority ENUM         │       │    qty_shipped INT       │                     ║  ║
║  ║                          │    tracking_number VARCH │       │    qty_received INT      │                     ║  ║
║  ║                          │    carrier VARCHAR       │       │    qty_damaged INT       │                     ║  ║
║  ║                          │ FK requested_by UUID     │       └──────────────────────────┘                     ║  ║
║  ║                          │ FK shipped_by UUID       │                                                        ║  ║
║  ║                          │ FK received_by UUID      │                                                        ║  ║
║  ║                          │    shipped_at TIMESTAMP  │                                                        ║  ║
║  ║                          │    received_at TIMESTAMP │                                                        ║  ║
║  ║                          │    created_at TIMESTAMP  │                                                        ║  ║
║  ║                          └──────────────────────────┘                                                        ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                           │                                                        ║
║                                                           │ variant_id, location_id                                ║
║                                                           ▼                                                        ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                         DOMAIN 6: ORDERS & SALES                                             ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │         orders           │           │      order_line_items    │       │     order_discounts      │   ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    │ PK id UUID               │──────────►│ PK id UUID               │       │ PK id UUID               │   ║  ║
║  ║    │    order_number VARCHAR  │     1:N   │ FK order_id UUID         │       │ FK order_id UUID         │◄──┤   ║  ║
║  ║    │    receipt_number VARCHAR│           │ FK variant_id UUID       │       │ FK line_item_id UUID     │   ║  ║
║  ║    │ FK location_id UUID      │           │    sku VARCHAR           │       │    discount_type ENUM    │   ║  ║
║  ║    │ FK register_id UUID      │           │    name VARCHAR          │       │    discount_value DECIMAL│   ║  ║
║  ║    │ FK customer_id UUID      │           │    quantity INT          │       │    discount_amount DECIM │   ║  ║
║  ║    │ FK created_by UUID       │           │    unit_price DECIMAL    │       │    code VARCHAR          │   ║  ║
║  ║    │    status ENUM           │           │    discount_amount DECIM │       │    reason VARCHAR        │   ║  ║
║  ║    │    subtotal DECIMAL      │           │    tax_amount DECIMAL    │       └──────────────────────────┘   ║  ║
║  ║    │    discount_total DECIM  │           │    line_total DECIMAL    │                                       ║  ║
║  ║    │    tax_total DECIMAL     │           │    cost DECIMAL          │                                       ║  ║
║  ║    │    total DECIMAL(10,2)   │           │    fulfillment_status EN │                                       ║  ║
║  ║    │    channel ENUM          │           └──────────────────────────┘                                       ║  ║
║  ║    │    source VARCHAR        │                       │                                                      ║  ║
║  ║    │    notes TEXT            │                       │                                                      ║  ║
║  ║    │    metadata JSONB        │                       │                                                      ║  ║
║  ║    │    voided_at TIMESTAMP   │                       │                                                      ║  ║
║  ║    │ FK voided_by UUID        │                       ▼                                                      ║  ║
║  ║    │    void_reason VARCHAR   │           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │    created_at TIMESTAMP  │           │        returns           │       │    return_line_items     │   ║  ║
║  ║    │    completed_at TIMESTP  │           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    └──────────────────────────┘           │ PK id UUID               │──────►│ PK id UUID               │   ║  ║
║  ║              │                            │    return_number VARCHAR │  1:N  │ FK return_id UUID        │   ║  ║
║  ║              │                            │ FK original_order_id UUID│       │ FK original_line_id UUID │   ║  ║
║  ║              │                            │ FK location_id UUID      │       │ FK variant_id UUID       │   ║  ║
║  ║              │                            │ FK customer_id UUID      │       │    quantity INT          │   ║  ║
║  ║              │                            │ FK processed_by UUID     │       │    refund_amount DECIMAL │   ║  ║
║  ║              │                            │    status ENUM           │       │    reason ENUM           │   ║  ║
║  ║              │                            │    refund_total DECIMAL  │       │    condition ENUM        │   ║  ║
║  ║              │                            │    refund_method ENUM    │       │    restocked BOOLEAN     │   ║  ║
║  ║              │                            │    created_at TIMESTAMP  │       └──────────────────────────┘   ║  ║
║  ║              │                            └──────────────────────────┘                                       ║  ║
║  ╚══════════════╪═══════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                 │                                                                                                   ║
║                 │ order_id                                                                                          ║
║                 ▼                                                                                                   ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                            DOMAIN 7: PAYMENTS                                                 ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │        payments          │           │   payment_refunds        │       │    payment_batches       │   ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    │ PK id UUID               │──────────►│ PK id UUID               │       │ PK id UUID               │   ║  ║
║  ║    │ FK order_id UUID         │     1:N   │ FK payment_id UUID       │◄──────│ FK location_id UUID      │   ║  ║
║  ║    │    payment_method ENUM   │           │ FK return_id UUID        │  N:1  │    batch_date DATE       │   ║  ║
║  ║    │    amount DECIMAL(10,2)  │           │    amount DECIMAL        │       │    status ENUM           │   ║  ║
║  ║    │    status ENUM           │           │    status ENUM           │       │    total_amount DECIMAL  │   ║  ║
║  ║    │    authorization_code    │           │    gateway_refund_id     │       │    transaction_count INT │   ║  ║
║  ║    │    gateway_transaction_id│           │    created_at TIMESTAMP  │       │    settled_at TIMESTAMP  │   ║  ║
║  ║    │    card_brand VARCHAR    │           └──────────────────────────┘       │    created_at TIMESTAMP  │   ║  ║
║  ║    │    card_last_four VARCHAR│                                              └──────────────────────────┘   ║  ║
║  ║    │    entry_method ENUM     │                                                          │                   ║  ║
║  ║    │    terminal_id VARCHAR   │                                                          │                   ║  ║
║  ║    │ FK batch_id UUID         │◄─────────────────────────────────────────────────────────┘                   ║  ║
║  ║    │    tip_amount DECIMAL    │                                                                              ║  ║
║  ║    │    metadata JSONB        │                                                                              ║  ║
║  ║    │    created_at TIMESTAMP  │                                                                              ║  ║
║  ║    └──────────────────────────┘                                                                              ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                                                                                     ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                       DOMAIN 8: CUSTOMERS & LOYALTY                                          ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │       customers          │           │   loyalty_transactions   │       │    customer_tags         │   ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    │ PK id UUID               │──────────►│ PK id UUID               │       │ PK id UUID               │   ║  ║
║  ║    │    customer_number VARCH │     1:N   │ FK customer_id UUID      │       │ FK customer_id UUID      │◄──┤   ║  ║
║  ║    │    first_name VARCHAR    │           │ FK order_id UUID         │       │ FK tag_id UUID           │   ║  ║
║  ║    │    last_name VARCHAR     │           │    transaction_type ENUM │       │    applied_at TIMESTAMP  │   ║  ║
║  ║    │    email VARCHAR(255)    │           │    points INT            │       │    expires_at TIMESTAMP  │   ║  ║
║  ║    │    phone VARCHAR(20)     │           │    balance_after INT     │       │    applied_by UUID       │   ║  ║
║  ║    │    address JSONB         │           │    description VARCHAR   │       └──────────────────────────┘   ║  ║
║  ║    │    loyalty_tier ENUM     │           │    created_at TIMESTAMP  │                                       ║  ║
║  ║    │    loyalty_points INT    │           └──────────────────────────┘       ┌──────────────────────────┐   ║  ║
║  ║    │    lifetime_spend DECIM  │                                              │          tags            │   ║  ║
║  ║    │    total_orders INT      │                                              ├──────────────────────────┤   ║  ║
║  ║    │    marketing_opt_in BOOL │                                              │ PK id UUID               │   ║  ║
║  ║    │    sms_opt_in BOOLEAN    │           ┌──────────────────────────┐       │    name VARCHAR(50)      │   ║  ║
║  ║    │    tax_exempt BOOLEAN    │           │    customer_notes        │       │    category VARCHAR      │   ║  ║
║  ║    │    notes TEXT            │           ├──────────────────────────┤       │    color VARCHAR(7)      │   ║  ║
║  ║    │    metadata JSONB        │           │ PK id UUID               │       │    is_auto BOOLEAN       │   ║  ║
║  ║    │    created_at TIMESTAMP  │──────────►│ FK customer_id UUID      │       └──────────────────────────┘   ║  ║
║  ║    │    updated_at TIMESTAMP  │     1:N   │ FK created_by UUID       │                                       ║  ║
║  ║    └──────────────────────────┘           │    note TEXT             │                                       ║  ║
║  ║                                           │    created_at TIMESTAMP  │                                       ║  ║
║  ║                                           └──────────────────────────┘                                       ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                                                                                     ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                           DOMAIN 9: GIFT CARDS                                                ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐                                       ║  ║
║  ║    │       gift_cards         │           │  gift_card_transactions  │                                       ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤                                       ║  ║
║  ║    │ PK id UUID               │──────────►│ PK id UUID               │                                       ║  ║
║  ║    │    card_number VARCHAR   │     1:N   │ FK gift_card_id UUID     │                                       ║  ║
║  ║    │    card_number_hash VARCH│           │ FK order_id UUID         │                                       ║  ║
║  ║    │    initial_balance DECIM │           │    transaction_type ENUM │                                       ║  ║
║  ║    │    current_balance DECIM │           │    amount DECIMAL        │                                       ║  ║
║  ║    │    status ENUM           │           │    balance_after DECIMAL │                                       ║  ║
║  ║    │    type ENUM             │           │    reference VARCHAR     │                                       ║  ║
║  ║    │    purchased_at TIMESTAMP│           │    created_at TIMESTAMP  │                                       ║  ║
║  ║    │ FK purchased_by UUID     │           └──────────────────────────┘                                       ║  ║
║  ║    │ FK purchase_order_id UUID│                                                                              ║  ║
║  ║    │    recipient_email VARCH │                                                                              ║  ║
║  ║    │    recipient_name VARCHAR│                                                                              ║  ║
║  ║    │    message TEXT          │                                                                              ║  ║
║  ║    │    expires_at TIMESTAMP  │                                                                              ║  ║
║  ║    │    created_at TIMESTAMP  │                                                                              ║  ║
║  ║    └──────────────────────────┘                                                                              ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                                                                                     ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                       DOMAIN 10: CASH MANAGEMENT                                              ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │         shifts           │           │     cash_movements       │       │     cash_counts          │   ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    │ PK id UUID               │──────────►│ PK id UUID               │       │ PK id UUID               │   ║  ║
║  ║    │ FK register_id UUID      │     1:N   │ FK shift_id UUID         │       │ FK shift_id UUID         │◄──┤   ║  ║
║  ║    │ FK opened_by UUID        │           │    movement_type ENUM    │       │    count_type ENUM       │   ║  ║
║  ║    │ FK closed_by UUID        │           │    amount DECIMAL        │       │    expected DECIMAL      │   ║  ║
║  ║    │    status ENUM           │           │ FK performed_by UUID     │       │    actual DECIMAL        │   ║  ║
║  ║    │    opening_float DECIMAL │           │ FK witnessed_by UUID     │       │    variance DECIMAL      │   ║  ║
║  ║    │    expected_cash DECIMAL │           │    reason VARCHAR        │       │    breakdown JSONB       │   ║  ║
║  ║    │    actual_cash DECIMAL   │           │    reference_number VARC │       │ FK counted_by UUID       │   ║  ║
║  ║    │    variance DECIMAL      │           │    notes TEXT            │       │    counted_at TIMESTAMP  │   ║  ║
║  ║    │    opened_at TIMESTAMP   │           │    created_at TIMESTAMP  │       │    notes TEXT            │   ║  ║
║  ║    │    closed_at TIMESTAMP   │           └──────────────────────────┘       └──────────────────────────┘   ║  ║
║  ║    │    notes TEXT            │                                                                              ║  ║
║  ║    └──────────────────────────┘                                                                              ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                                                                                     ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                           DOMAIN 11: RFID                                                     ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │       rfid_tags          │           │   rfid_scan_sessions     │       │      rfid_scans          │   ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    │ PK id UUID               │           │ PK id UUID               │──────►│ PK id UUID               │   ║  ║
║  ║    │    epc VARCHAR(64)       │           │ FK location_id UUID      │  1:N  │ FK session_id UUID       │   ║  ║
║  ║    │ FK variant_id UUID       │           │    zone_id VARCHAR       │       │ FK tag_id UUID           │   ║  ║
║  ║    │    serial_number BIGINT  │           │    session_type ENUM     │       │    epc VARCHAR(64)       │   ║  ║
║  ║    │    status ENUM           │           │ FK started_by UUID       │       │    rssi INT              │   ║  ║
║  ║    │ FK current_location UUID │           │ FK completed_by UUID     │       │    antenna_id INT        │   ║  ║
║  ║    │ FK printed_at_location   │           │    status ENUM           │       │    read_count INT        │   ║  ║
║  ║    │    printed_at TIMESTAMP  │           │    started_at TIMESTAMP  │       │    first_seen TIMESTAMP  │   ║  ║
║  ║    │ FK printed_by UUID       │           │    completed_at TIMESTAMP│       │    last_seen TIMESTAMP   │   ║  ║
║  ║    │    last_seen_at TIMESTP  │           │    summary JSONB         │       └──────────────────────────┘   ║  ║
║  ║    │    created_at TIMESTAMP  │           └──────────────────────────┘                                       ║  ║
║  ║    │ UK epc                   │                                                                              ║  ║
║  ║    └──────────────────────────┘                                                                              ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                                                                                     ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                         DOMAIN 12: EVENTS & SYNC                                              ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐       ┌──────────────────────────┐   ║  ║
║  ║    │      domain_events       │           │      sync_queue          │       │    conflict_resolutions  │   ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤       ├──────────────────────────┤   ║  ║
║  ║    │ PK id UUID               │           │ PK id UUID               │       │ PK id UUID               │   ║  ║
║  ║    │    event_type VARCHAR    │           │    device_id VARCHAR     │       │    conflict_type VARCHAR │   ║  ║
║  ║    │    aggregate_type VARCHAR│           │    direction ENUM        │       │    entity_type VARCHAR   │   ║  ║
║  ║    │    aggregate_id UUID     │           │    event_type VARCHAR    │       │    entity_id UUID        │   ║  ║
║  ║    │    payload JSONB         │           │    payload JSONB         │       │    server_value JSONB    │   ║  ║
║  ║    │    correlation_id UUID   │           │    local_sequence INT    │       │    local_value JSONB     │   ║  ║
║  ║    │    causation_id UUID     │           │    status ENUM           │       │    resolved_value JSONB  │   ║  ║
║  ║    │    version INT           │           │    attempts INT          │       │    resolution_method EN  │   ║  ║
║  ║    │    created_at TIMESTAMP  │           │    last_attempt TIMESTP  │       │ FK resolved_by UUID      │   ║  ║
║  ║    │ IX (aggregate_type, id)  │           │    error_message TEXT    │       │    resolved_at TIMESTAMP │   ║  ║
║  ║    │ IX (created_at)          │           │    created_at TIMESTAMP  │       │    notes TEXT            │   ║  ║
║  ║    └──────────────────────────┘           └──────────────────────────┘       └──────────────────────────┘   ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                                                                                     ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║                                         DOMAIN 13: AUDIT & LOGS                                               ║  ║
║  ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣  ║
║  ║                                                                                                              ║  ║
║  ║    ┌──────────────────────────┐           ┌──────────────────────────┐                                       ║  ║
║  ║    │       audit_logs         │           │     api_request_logs     │                                       ║  ║
║  ║    ├──────────────────────────┤           ├──────────────────────────┤                                       ║  ║
║  ║    │ PK id UUID               │           │ PK id UUID               │                                       ║  ║
║  ║    │    action VARCHAR(50)    │           │    method VARCHAR(10)    │                                       ║  ║
║  ║    │    entity_type VARCHAR   │           │    path VARCHAR(500)     │                                       ║  ║
║  ║    │    entity_id UUID        │           │    status_code INT       │                                       ║  ║
║  ║    │    old_values JSONB      │           │    duration_ms INT       │                                       ║  ║
║  ║    │    new_values JSONB      │           │ FK user_id UUID          │                                       ║  ║
║  ║    │ FK performed_by UUID     │           │    ip_address INET       │                                       ║  ║
║  ║    │    ip_address INET       │           │    user_agent VARCHAR    │                                       ║  ║
║  ║    │    user_agent VARCHAR    │           │    request_body JSONB    │                                       ║  ║
║  ║    │    created_at TIMESTAMP  │           │    created_at TIMESTAMP  │                                       ║  ║
║  ║    │ IX (entity_type, id)     │           │ IX (created_at)          │                                       ║  ║
║  ║    │ IX (performed_by)        │           │ IX (user_id)             │                                       ║  ║
║  ║    │ IX (created_at)          │           └──────────────────────────┘                                       ║  ║
║  ║    └──────────────────────────┘                                                                              ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                                                                                     ║
╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝

B.4 Table Summary by Domain

DomainTablesPrimary Tables
1. Multi-Tenancy3tenants, tenant_modules, system_settings
2. Locations3locations, registers, operating_hours
3. Users4users, user_permissions, user_sessions, time_clock_entries
4. Products5categories, vendors, products, product_variants, product_images, variant_prices
5. Inventory5inventory_levels, inventory_transactions, inventory_reservations, inventory_transfers, transfer_line_items
6. Orders6orders, order_line_items, order_discounts, returns, return_line_items
7. Payments3payments, payment_refunds, payment_batches
8. Customers5customers, loyalty_transactions, customer_tags, tags, customer_notes
9. Gift Cards2gift_cards, gift_card_transactions
10. Cash3shifts, cash_movements, cash_counts
11. RFID3rfid_tags, rfid_scan_sessions, rfid_scans
12. Events3domain_events, sync_queue, conflict_resolutions
13. Audit2audit_logs, api_request_logs
TOTAL51

B.5 Key Relationships

One-to-Many (1:N)

ParentChildForeign Key
tenantstenant_modulestenant_id
locationsregisterslocation_id
locationsoperating_hourslocation_id
usersuser_permissionsuser_id
usersuser_sessionsuser_id
userstime_clock_entriesuser_id
categoriescategories (self)parent_id
categoriesproductscategory_id
vendorsproductsvendor_id
productsproduct_variantsproduct_id
productsproduct_imagesproduct_id
product_variantsinventory_levelsvariant_id
product_variantsinventory_transactionsvariant_id
product_variantsorder_line_itemsvariant_id
ordersorder_line_itemsorder_id
ordersorder_discountsorder_id
orderspaymentsorder_id
ordersreturnsoriginal_order_id
returnsreturn_line_itemsreturn_id
paymentspayment_refundspayment_id
payment_batchespaymentsbatch_id
customersorderscustomer_id
customersloyalty_transactionscustomer_id
customerscustomer_tagscustomer_id
customerscustomer_notescustomer_id
gift_cardsgift_card_transactionsgift_card_id
shiftscash_movementsshift_id
shiftscash_countsshift_id
inventory_transferstransfer_line_itemstransfer_id
rfid_scan_sessionsrfid_scanssession_id

Many-to-Many (M:N)

Table AJunctionTable B
customerscustomer_tagstags
product_variantsvariant_pricesprice_lists

B.6 Indexes

Critical Performance Indexes

-- Orders lookup
CREATE INDEX idx_orders_location_date ON orders(location_id, created_at DESC);
CREATE INDEX idx_orders_customer ON orders(customer_id);
CREATE INDEX idx_orders_receipt ON orders(receipt_number);

-- Inventory queries
CREATE INDEX idx_inventory_levels_variant_location
    ON inventory_levels(variant_id, location_id);
CREATE INDEX idx_inventory_levels_location_reorder
    ON inventory_levels(location_id) WHERE on_hand <= reorder_point;

-- Product search
CREATE INDEX idx_products_sku ON products(sku);
CREATE INDEX idx_product_variants_barcode ON product_variants(barcode);
CREATE INDEX idx_products_search ON products USING gin(to_tsvector('english', name));

-- Customer lookup
CREATE INDEX idx_customers_email ON customers(lower(email));
CREATE INDEX idx_customers_phone ON customers(phone);
CREATE INDEX idx_customers_search ON customers
    USING gin(to_tsvector('english', first_name || ' ' || last_name));

-- Event sourcing
CREATE INDEX idx_domain_events_aggregate ON domain_events(aggregate_type, aggregate_id);
CREATE INDEX idx_domain_events_created ON domain_events(created_at);

-- Audit trail
CREATE INDEX idx_audit_logs_entity ON audit_logs(entity_type, entity_id);
CREATE INDEX idx_audit_logs_user ON audit_logs(performed_by);
CREATE INDEX idx_audit_logs_time ON audit_logs(created_at DESC);

-- RFID
CREATE UNIQUE INDEX idx_rfid_tags_epc ON rfid_tags(epc);
CREATE INDEX idx_rfid_tags_variant ON rfid_tags(variant_id);

B.7 Partitioning Strategy

Time-Based Partitioning

-- Orders partitioned by month
CREATE TABLE orders (
    id UUID,
    created_at TIMESTAMP,
    -- other columns
) PARTITION BY RANGE (created_at);

CREATE TABLE orders_2025_01 PARTITION OF orders
    FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
CREATE TABLE orders_2025_02 PARTITION OF orders
    FOR VALUES FROM ('2025-02-01') TO ('2025-03-01');
-- etc.

-- Domain events partitioned by month
CREATE TABLE domain_events (
    id UUID,
    created_at TIMESTAMP,
    -- other columns
) PARTITION BY RANGE (created_at);

-- Audit logs partitioned by month
CREATE TABLE audit_logs (
    id UUID,
    created_at TIMESTAMP,
    -- other columns
) PARTITION BY RANGE (created_at);

B.8 Constraints Summary

Unique Constraints

TableColumnsPurpose
tenantssubdomainUnique tenant subdomain
locationscodeUnique location code per tenant
usersemailUnique user email per tenant
productsskuUnique SKU per tenant
product_variantsskuUnique variant SKU per tenant
product_variantsbarcodeUnique barcode per tenant
ordersorder_numberUnique order number per tenant
ordersreceipt_numberUnique receipt per tenant
customerscustomer_numberUnique customer ID per tenant
gift_cardscard_numberUnique card number per tenant
rfid_tagsepcGlobally unique EPC
inventory_levelsvariant_id, location_idOne record per variant-location

Check Constraints

-- Positive quantities
ALTER TABLE inventory_levels ADD CONSTRAINT chk_on_hand_positive
    CHECK (on_hand >= 0);
ALTER TABLE order_line_items ADD CONSTRAINT chk_quantity_positive
    CHECK (quantity > 0);

-- Valid percentages
ALTER TABLE order_discounts ADD CONSTRAINT chk_discount_valid
    CHECK (discount_value >= 0 AND discount_value <= 100);

-- Valid statuses
ALTER TABLE orders ADD CONSTRAINT chk_order_status
    CHECK (status IN ('pending', 'completed', 'voided', 'refunded'));

-- Balance constraints
ALTER TABLE gift_cards ADD CONSTRAINT chk_balance_not_negative
    CHECK (current_balance >= 0);

B.9 Data Types Reference

Custom ENUM Types

-- Tenant status
CREATE TYPE tenant_status AS ENUM ('active', 'suspended', 'trial', 'cancelled');

-- Location type
CREATE TYPE location_type AS ENUM ('store', 'warehouse', 'popup', 'mobile');

-- User role
CREATE TYPE user_role AS ENUM ('super_admin', 'admin', 'manager', 'cashier', 'viewer');

-- Order status
CREATE TYPE order_status AS ENUM ('pending', 'completed', 'voided', 'refunded');

-- Payment method
CREATE TYPE payment_method AS ENUM ('cash', 'card', 'gift_card', 'loyalty', 'other');

-- Payment status
CREATE TYPE payment_status AS ENUM ('pending', 'approved', 'declined', 'refunded');

-- Inventory transaction type
CREATE TYPE inv_transaction_type AS ENUM (
    'sale', 'return', 'adjustment', 'transfer_out', 'transfer_in', 'receipt', 'shrinkage'
);

-- Cash movement type
CREATE TYPE cash_movement_type AS ENUM (
    'till_drop', 'pickup', 'paid_in', 'paid_out', 'float_adjust'
);

-- RFID tag status
CREATE TYPE rfid_status AS ENUM ('active', 'sold', 'returned', 'void', 'lost');

-- Sync direction
CREATE TYPE sync_direction AS ENUM ('push', 'pull');

This ERD represents the complete database schema for the POS Platform with 51 tables across 13 domains.


Document Information

AttributeValue
Version5.0.0
Created2025-12-29
Updated2026-02-25
AuthorClaude Code
StatusActive
SectionAppendix B

This appendix is part of the POS Blueprint Book. All content is self-contained.