Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Appendix B: Database Entity Relationship Diagram

Version: 1.0.0 Last Updated: December 29, 2025 Database: PostgreSQL 16 Total Tables: 51


Overview

This appendix contains the complete Entity Relationship Diagram (ERD) for the POS Platform database. The schema is organized by domain with a schema-per-tenant multi-tenancy model.


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

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)          │           └──────────────────────────┘                                       ║  ║
║  ║    └──────────────────────────┘                                                                              ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                                                                                     ║
╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝

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

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

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);

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);

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);

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.