This comprehensive study plan is meticulously crafted to empower aspiring and current data professionals with the essential and advanced knowledge required to excel as a Database Schema Designer. A thoughtfully designed database schema is the fundamental blueprint for any robust application, ensuring data integrity, optimal performance, maintainability, and scalability. This plan will systematically guide you through the core principles of data modeling, SQL mastery, database design best practices, and a critical understanding of various database technologies, both relational and NoSQL.
This plan is ideally suited for:
As part of the "Database Schema Designer" workflow, this deliverable represents Step 2: gemini → generate_code. In this crucial phase, we translate the conceptual and logical database design into a detailed, production-ready physical schema using Data Definition Language (DDL).
Our goal is to provide a robust, scalable, and maintainable database structure that meets the identified requirements for a typical online bookstore application. This output includes the SQL DDL for creating tables, defining relationships, setting constraints, and optimizing for performance.
This document provides the detailed database schema for an "Online Bookstore" application. The design focuses on clarity, data integrity, and performance, supporting core functionalities such as user management, book cataloging, order processing, and customer reviews.
The schema is designed with the following key principles in mind:
The database schema models the following core entities and their relationships:
Here's a high-level overview of the tables and their primary columns:
users: user_id (PK), username, email, password_hash, first_name, last_name, user_type, created_at, updated_at.authors: author_id (PK), first_name, last_name, biography, created_at, updated_at.books: book_id (PK), isbn, title, author_id (FK), description, price, publication_date, publisher, stock_quantity, image_url, created_at, updated_at.categories: category_id (PK), name, description, created_at, updated_at.book_categories: book_id (FK, PK), category_id (FK, PK).orders: order_id (PK), user_id (FK), order_date, total_amount, status, shipping_address, billing_address, created_at, updated_at.order_items: order_item_id (PK), order_id (FK), book_id (FK), quantity, price_at_purchase, created_at, updated_at.reviews: review_id (PK), book_id (FK), user_id (FK), rating, comment, review_date, created_at, updated_at.The following SQL DDL is designed for PostgreSQL, a robust and widely-used relational database system. It includes CREATE TABLE statements, primary and foreign key constraints, unique constraints, check constraints, and indexes.
-- SQL DDL for Online Bookstore Database Schema (PostgreSQL)
--
-- This script creates all necessary tables, defines primary and foreign keys,
-- unique constraints, check constraints, and indexes for optimal performance
-- and data integrity.
-- Set a specific schema if desired, otherwise tables will be created in 'public'
-- CREATE SCHEMA IF NOT EXISTS bookstore;
-- SET search_path TO bookstore, public;
-- -----------------------------------------------------------------------------
-- Table: users
-- Description: Stores information about users (customers, administrators).
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS users (
user_id BIGSERIAL PRIMARY KEY, -- Unique identifier for the user
username VARCHAR(50) UNIQUE NOT NULL, -- Unique username for login
email VARCHAR(100) UNIQUE NOT NULL, -- Unique email address
password_hash VARCHAR(255) NOT NULL, -- Hashed password for security
first_name VARCHAR(50), -- User's first name
last_name VARCHAR(50), -- User's last name
user_type VARCHAR(20) DEFAULT 'customer' NOT NULL, -- e.g., 'customer', 'admin'
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Record creation timestamp
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -- Last update timestamp
);
-- Index for faster lookups by email and user_type
CREATE INDEX IF NOT EXISTS idx_users_email ON users (email);
CREATE INDEX IF NOT EXISTS idx_users_user_type ON users (user_type);
-- -----------------------------------------------------------------------------
-- Table: authors
-- Description: Stores information about book authors.
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS authors (
author_id BIGSERIAL PRIMARY KEY, -- Unique identifier for the author
first_name VARCHAR(100) NOT NULL, -- Author's first name
last_name VARCHAR(100) NOT NULL, -- Author's last name
biography TEXT, -- Short biography of the author
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Record creation timestamp
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Last update timestamp
CONSTRAINT uq_author_name UNIQUE (first_name, last_name) -- Ensure unique author names
);
-- Index for faster lookups by author name
CREATE INDEX IF NOT EXISTS idx_authors_last_name ON authors (last_name);
CREATE INDEX IF NOT EXISTS idx_authors_first_name ON authors (first_name);
-- -----------------------------------------------------------------------------
-- Table: books
-- Description: Stores details about books available in the bookstore.
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS books (
book_id BIGSERIAL PRIMARY KEY, -- Unique identifier for the book
isbn VARCHAR(13) UNIQUE NOT NULL, -- International Standard Book Number (e.g., ISBN-13)
title VARCHAR(255) NOT NULL, -- Title of the book
author_id BIGINT NOT NULL, -- Foreign key to authors table
description TEXT, -- Detailed description of the book
price NUMERIC(10, 2) NOT NULL, -- Price of the book (e.g., 999.99)
publication_date DATE, -- Date the book was published
publisher VARCHAR(100), -- Publisher of the book
stock_quantity INTEGER DEFAULT 0 NOT NULL, -- Current stock level
image_url VARCHAR(255), -- URL to the book's cover image
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Record creation timestamp
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Last update timestamp
CONSTRAINT fk_author_id FOREIGN KEY (author_id) REFERENCES authors(author_id) ON DELETE RESTRICT,
CONSTRAINT chk_book_price CHECK (price >= 0), -- Price cannot be negative
CONSTRAINT chk_stock_quantity CHECK (stock_quantity >= 0) -- Stock cannot be negative
);
-- Indexes for efficient searching and joining
CREATE INDEX IF NOT EXISTS idx_books_isbn ON books (isbn);
CREATE INDEX IF NOT EXISTS idx_books_title ON books (title);
CREATE INDEX IF NOT EXISTS idx_books_author_id ON books (author_id);
CREATE INDEX IF NOT EXISTS idx_books_price ON books (price);
CREATE INDEX IF NOT EXISTS idx_books_publication_date ON books (publication_date);
-- -----------------------------------------------------------------------------
-- Table: categories
-- Description: Stores different categories or genres for books.
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS categories (
category_id BIGSERIAL PRIMARY KEY, -- Unique identifier for the category
name VARCHAR(100) UNIQUE NOT NULL, -- Name of the category (e.g., 'Fiction', 'Science')
description TEXT, -- Description of the category
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Record creation timestamp
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -- Last update timestamp
);
-- Index for faster lookups by category name
CREATE INDEX IF NOT EXISTS idx_categories_name ON categories (name);
-- -----------------------------------------------------------------------------
-- Table: book_categories
-- Description: Junction table for many-to-many relationship between books and categories.
-- A book can belong to multiple categories, and a category can have multiple books.
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS book_categories (
book_id BIGINT NOT NULL, -- Foreign key to books table
category_id BIGINT NOT NULL, -- Foreign key to categories table
PRIMARY KEY (book_id, category_id), -- Composite primary key
CONSTRAINT fk_book_categories_book FOREIGN KEY (book_id) REFERENCES books(book_id) ON DELETE CASCADE,
CONSTRAINT fk_book_categories_category FOREIGN KEY (category_id) REFERENCES categories(category_id) ON DELETE CASCADE
);
-- Indexes for efficient joining and lookup
CREATE INDEX IF NOT EXISTS idx_book_categories_book_id ON book_categories (book_id);
CREATE INDEX IF NOT EXISTS idx_book_categories_category_id ON book_categories (category_id);
-- -----------------------------------------------------------------------------
-- Table: orders
-- Description: Stores customer order information.
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS orders (
order_id BIGSERIAL PRIMARY KEY, -- Unique identifier for the order
user_id BIGINT NOT NULL, -- Foreign key to users table (customer who placed the order)
order_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Date and time the order was placed
total_amount NUMERIC(10, 2) NOT NULL, -- Total amount of the order
status VARCHAR(50) DEFAULT 'pending' NOT NULL, -- e.g., 'pending', 'processing', 'shipped', 'delivered', 'cancelled'
shipping_address TEXT NOT NULL, -- Shipping address for the order
billing_address TEXT, -- Billing address (can be same as shipping)
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Record creation timestamp
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Last update timestamp
CONSTRAINT fk_order_user FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE RESTRICT,
CONSTRAINT chk_order_total_amount CHECK (total_amount >= 0),
CONSTRAINT chk_order_status CHECK (status IN ('pending', 'processing', 'shipped', 'delivered', 'cancelled'))
);
-- Indexes for efficient order tracking and user history
CREATE INDEX IF NOT EXISTS idx_orders_user_id ON orders (user_id);
CREATE INDEX IF NOT EXISTS idx_orders_order_date ON orders (order_date DESC);
CREATE INDEX IF NOT EXISTS idx_orders_status ON orders (status);
-- -----------------------------------------------------------------------------
-- Table: order_items
-- Description: Stores individual items within an order.
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS order_items (
order_item_id BIGSERIAL PRIMARY KEY, -- Unique identifier for the order item
order_id BIGINT NOT NULL, -- Foreign key to orders table
book_id BIGINT NOT NULL, -- Foreign key to books table
quantity INTEGER NOT NULL, -- Quantity of the book ordered
price_at_purchase NUMERIC(10, 2) NOT NULL, -- Price of the book at the time of purchase
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Record creation timestamp
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Last update timestamp
CONSTRAINT fk_order_item_order FOREIGN KEY (order_id) REFERENCES orders(order_id) ON DELETE CASCADE,
CONSTRAINT fk_order_item_book FOREIGN KEY (book_id) REFERENCES books(book_id) ON DELETE RESTRICT,
CONSTRAINT chk_order_item_quantity CHECK (quantity > 0), -- Quantity must be positive
CONSTRAINT chk_order_item_price CHECK (price_at_purchase >= 0) -- Price cannot be negative
);
-- Composite index for efficient lookups of items within an order and for specific books in orders
CREATE UNIQUE INDEX IF NOT EXISTS uq_order_item_book ON order_items (order_id, book_id);
CREATE INDEX IF NOT EXISTS idx_order_items_order_id ON order_items (order_id);
CREATE INDEX IF NOT EXISTS idx_order_items_book_id ON order_items (book_id);
-- -----------------------------------------------------------------------------
-- Table: reviews
-- Description: Stores user reviews and ratings for books.
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS reviews (
review_id BIGSERIAL PRIMARY KEY, -- Unique identifier for the review
book_id BIGINT NOT NULL, -- Foreign key to books table
user_id BIGINT NOT NULL, -- Foreign key to users table (
Workflow Step 3 of 3: review_and_document
Date: October 26, 2023
Project: E-commerce Platform Database
Prepared For: [Customer Name/Team]
This document presents the detailed database schema for the E-commerce Platform, a critical component designed to support robust and scalable online retail operations. The schema has been meticulously designed to ensure data integrity, optimal performance, and flexibility for future growth. It encompasses core entities such as Users, Products, Orders, Carts, and Reviews, establishing clear relationships and adhering to industry best practices.
This deliverable provides a comprehensive overview, detailed table specifications, design rationale, SQL DDL scripts, and actionable recommendations for implementation.
The proposed schema is built around a relational model, optimized for transactional consistency and efficient data retrieval. It aims to capture all essential information required for a modern e-commerce application.
The primary purpose of this database schema is to:
The core entities identified and modeled in this schema include:
The schema establishes clear relationships between entities:
User can place multiple Orders and add multiple Products to their Cart.Product can belong to one or more Categories.Order consists of multiple OrderItems, each linking to a specific Product.Cart consists of multiple CartItems, each linking to a specific Product.User can write multiple Reviews for different Products.Product can receive multiple Reviews from different Users.This section provides a granular breakdown of each table, including its purpose, columns, data types, constraints, and relationships.
(Note: The following is an example schema for an e-commerce platform. Actual schema will vary based on specific requirements gathered.)
Users| Column Name | Data Type | Constraints | Description |
| :------------ | :---------------- | :-------------------------------------------- | :------------------------------------------------ |
| user_id | UUID / BIGINT | PRIMARY KEY, NOT NULL, UNIQUE | Unique identifier for each user. |
| username | VARCHAR(50) | NOT NULL, UNIQUE | User's chosen username for login. |
| email | VARCHAR(100) | NOT NULL, UNIQUE | User's email address, used for communication. |
| password_hash | VARCHAR(255) | NOT NULL | Hashed password for security. |
| first_name | VARCHAR(50) | NULLABLE | User's first name. |
| last_name | VARCHAR(50) | NULLABLE | User's last name. |
| address | TEXT | NULLABLE | User's primary shipping/billing address. |
| phone_number| VARCHAR(20) | NULLABLE | User's contact phone number. |
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Timestamp of user registration. |
| updated_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Last update timestamp for user profile. |
| is_admin | BOOLEAN | NOT NULL, DEFAULT FALSE | Flag to indicate if the user has admin privileges.|
Users (1) -- (M*) Orders (via user_id)
Users (1) -- (M*) Reviews (via user_id)
Users (1) -- (1*) Carts (via user_id)
idx_users_username, idx_users_email (for fast lookups)Categories| Column Name | Data Type | Constraints | Description |
| :-------------- | :---------------- | :-------------------------------------------- | :------------------------------------------------ |
| category_id | UUID / INT | PRIMARY KEY, NOT NULL, UNIQUE | Unique identifier for each category. |
| name | VARCHAR(100) | NOT NULL, UNIQUE | Name of the category (e.g., "Electronics"). |
| description | TEXT | NULLABLE | Detailed description of the category. |
| parent_id | UUID / INT | NULLABLE, FOREIGN KEY references category_id | Self-referencing FK for hierarchical categories. |
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Timestamp of category creation. |
| updated_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Last update timestamp for category. |
Categories (1) -- (M*) Products (via category_id in Products table, if a product can only have one category)
Categories (1) -- (M*) Categories (self-referencing parent_id for subcategories)
idx_categories_nameProducts| Column Name | Data Type | Constraints | Description |
| :-------------- | :---------------- | :-------------------------------------------- | :------------------------------------------------ |
| product_id | UUID / BIGINT | PRIMARY KEY, NOT NULL, UNIQUE | Unique identifier for each product. |
| name | VARCHAR(255) | NOT NULL | Name of the product. |
| description | TEXT | NULLABLE | Detailed product description. |
| price | DECIMAL(10, 2) | NOT NULL, CHECK (price >= 0) | Current selling price of the product. |
| stock_quantity| INT | NOT NULL, DEFAULT 0, CHECK (stock_quantity >= 0) | Current available stock quantity. |
| category_id | UUID / INT | NOT NULL, FOREIGN KEY references Categories | Category the product belongs to. |
| image_url | VARCHAR(255) | NULLABLE | URL to the product's main image. |
| sku | VARCHAR(50) | NOT NULL, UNIQUE | Stock Keeping Unit, unique product code. |
| weight_g | DECIMAL(10, 2) | NULLABLE, CHECK (weight_g >= 0) | Product weight in grams. |
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Timestamp of product creation. |
| updated_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Last update timestamp for product details. |
Products (M*) -- (1) Categories (via category_id)
Products (1) -- (M*) OrderItems (via product_id)
Products (1) -- (M*) CartItems (via product_id)
Products (1) -- (M*) Reviews (via product_id)
idx_products_name, idx_products_category_id, idx_products_skuOrders| Column Name | Data Type | Constraints | Description |
| :-------------- | :---------------- | :-------------------------------------------- | :------------------------------------------------ |
| order_id | UUID / BIGINT | PRIMARY KEY, NOT NULL, UNIQUE | Unique identifier for each order. |
| user_id | UUID / BIGINT | NOT NULL, FOREIGN KEY references Users | Foreign key linking to the user who placed the order. |
| order_date | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Date and time the order was placed. |
| total_amount | DECIMAL(10, 2) | NOT NULL, CHECK (total_amount >= 0) | Total monetary value of the order. |
| status | VARCHAR(50) | NOT NULL, DEFAULT 'Pending' | Current status of the order (e.g., Pending, Processing, Shipped, Delivered, Cancelled). |
| shipping_address| TEXT | NOT NULL | Shipping address for the order. |
| payment_method| VARCHAR(50) | NULLABLE | Method used for payment (e.g., Credit Card, PayPal). |
| payment_status| VARCHAR(50) | NOT NULL, DEFAULT 'Pending' | Status of the payment (e.g., Pending, Paid, Failed, Refunded). |
| updated_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Last update timestamp for order status. |
Orders (M*) -- (1) Users (via user_id)
Orders (1) -- (M*) OrderItems (via order_id)
idx_orders_user_id, idx_orders_order_date, idx_orders_statusOrderItemsOrders to Products, capturing the specific state of a product at the time of order.| Column Name | Data Type | Constraints | Description |
| :-------------- | :---------------- | :-------------------------------------------- | :------------------------------------------------ |
| order_item_id | UUID / BIGINT | PRIMARY KEY, NOT NULL, UNIQUE | Unique identifier for each order item. |
| order_id | UUID / BIGINT | NOT NULL, FOREIGN KEY references Orders | Foreign key linking to the parent order. |
| product_id | UUID / BIGINT | NOT NULL, FOREIGN KEY references Products | Foreign key linking to the product purchased. |
| quantity | INT | NOT NULL, CHECK (quantity > 0) | Quantity of the product ordered. |
| price_at_purchase| DECIMAL(10, 2) | NOT NULL, CHECK (price_at_purchase >= 0) | Price of the product at the time of purchase (important for historical accuracy). |
OrderItems (M*) -- (1) Orders (via order_id)
OrderItems (M*) -- (1) Products (via product_id)
idx_orderitems_order_id, idx_orderitems_product_id(order_id, product_id) to ensure a product appears only once per order item.Carts| Column Name | Data Type | Constraints | Description |
| :------------ | :---------------- | :-------------------------------------------- | :------------------------------------------------ |
| cart_id
\n