# Database Schema ## Overview The database uses PostgreSQL with SQLAlchemy ORM. All tables are auto-created from models. ## Tables ### users User accounts and profile information. | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | id | INTEGER | PRIMARY KEY | User identifier | | email | VARCHAR | UNIQUE, INDEXED | User email | | username | VARCHAR | UNIQUE, INDEXED | Username (optional, for login) | | hashed_password | VARCHAR | NOT NULL | Bcrypt hashed password | | full_name | VARCHAR | NOT NULL | User's full name | | phone | VARCHAR | UNIQUE, INDEXED | Phone number (optional, for login) | | address | VARCHAR | NULLABLE | Street address | | city | VARCHAR | NULLABLE | City | | postal_code | VARCHAR | NULLABLE | Postal/ZIP code | | country | VARCHAR | NULLABLE | Country | | is_active | BOOLEAN | DEFAULT TRUE | Account status | | is_admin | BOOLEAN | DEFAULT FALSE | Admin privileges | | must_change_password | BOOLEAN | DEFAULT FALSE | Force password change | | password_reset_pin | VARCHAR | NULLABLE | Password reset PIN | | pin_expires_at | DATETIME | NULLABLE | PIN expiration time | | created_at | DATETIME | DEFAULT NOW() | Account creation date | **Login Options:** Users can login with email, username, or phone number ### categories Product categories. | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | id | INTEGER | PRIMARY KEY | Category identifier | | name | VARCHAR | UNIQUE, INDEXED | Category name | | slug | VARCHAR | UNIQUE, INDEXED | URL-friendly slug | | description | VARCHAR | NULLABLE | Category description | **Predefined Categories:** - Shoes - Shirts - Pants - Hats - Accessories ### products Product inventory and details. | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | id | INTEGER | PRIMARY KEY | Product identifier | | name | VARCHAR | INDEXED | Product name | | description | TEXT | NOT NULL | Product description | | price | FLOAT | NOT NULL | Regular price | | discount_price | FLOAT | NULLABLE | Sale price if on sale | | category_id | INTEGER | FOREIGN KEY | Reference to category | | gender | VARCHAR | NOT NULL | men/women | | brand | VARCHAR | NOT NULL | Product brand | | sizes | JSON | NOT NULL | Array of available sizes | | colors | JSON | NOT NULL | Array of available colors | | stock | INTEGER | DEFAULT 0 | Quantity available | | images | JSON | NOT NULL | Array of image URLs | | is_featured | BOOLEAN | DEFAULT FALSE | Featured product flag | | is_on_sale | BOOLEAN | DEFAULT FALSE | Sale flag | | created_at | DATETIME | DEFAULT NOW() | Product added date | **indexes:** - category_id (FOREIGN KEY) ### cart User shopping carts. | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | id | INTEGER | PRIMARY KEY | Cart identifier | | user_id | INTEGER | FOREIGN KEY UNIQUE | Reference to user | | created_at | DATETIME | DEFAULT NOW() | Cart creation date | **Relationships:** - One cart per user - Can contain multiple cart_items ### cart_items Items in shopping carts. | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | id | INTEGER | PRIMARY KEY | Cart item identifier | | cart_id | INTEGER | FOREIGN KEY | Reference to cart | | product_id | INTEGER | FOREIGN KEY | Reference to product | | quantity | INTEGER | DEFAULT 1 | Item quantity | | size | VARCHAR | NULLABLE | Selected size | | color | VARCHAR | NULLABLE | Selected color | **Relationships:** - Belongs to cart - References product ### orders Customer orders. | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | id | INTEGER | PRIMARY KEY | Order identifier | | user_id | INTEGER | FOREIGN KEY | Reference to user | | order_number | VARCHAR | UNIQUE, INDEXED | Human-readable order # | | status | VARCHAR | DEFAULT 'pending' | pending/paid/shipped/delivered | | total_amount | FLOAT | NOT NULL | Order total | | shipping_address | VARCHAR | NOT NULL | Shipping street | | shipping_city | VARCHAR | NOT NULL | Shipping city | | shipping_postal_code | VARCHAR | NOT NULL | Shipping postal code | | shipping_country | VARCHAR | NOT NULL | Shipping country | | created_at | DATETIME | DEFAULT NOW() | Order creation date | | updated_at | DATETIME | DEFAULT NOW() | Last update date | **Relationships:** - Belongs to user - Can contain multiple order_items ### order_items Items in orders. | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | id | INTEGER | PRIMARY KEY | Order item identifier | | order_id | INTEGER | FOREIGN KEY | Reference to order | | product_id | INTEGER | FOREIGN KEY | Reference to product | | quantity | INTEGER | NOT NULL | Item quantity | | price | FLOAT | NOT NULL | Price at purchase time | | size | VARCHAR | NULLABLE | Selected size | | color | VARCHAR | NULLABLE | Selected color | **Note:** Price is stored to preserve historical data ### wishlist User wishlists. | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | id | INTEGER | PRIMARY KEY | Wishlist item identifier | | user_id | INTEGER | FOREIGN KEY | Reference to user | | product_id | INTEGER | FOREIGN KEY | Reference to product | | created_at | DATETIME | DEFAULT NOW() | Added to wishlist date | **Constraint:** UNIQUE(user_id, product_id) - one entry per user-product pair ### contact_messages Contact form submissions. | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | id | INTEGER | PRIMARY KEY | Message identifier | | full_name | VARCHAR | NOT NULL | Sender full name | | email | VARCHAR | NOT NULL | Sender email | | phone | VARCHAR | NULLABLE | Sender phone (optional) | | subject | VARCHAR | NOT NULL | Message subject | | message | TEXT | NOT NULL | Message content | | created_at | DATETIME | DEFAULT NOW() | Submission date | | is_read | BOOLEAN | DEFAULT FALSE | Admin read status | | status | VARCHAR | DEFAULT 'new' | Status: new/read/replied | | admin_notes | TEXT | NULLABLE | Internal admin notes | **Constraints:** CHECK (status IN ('new', 'read', 'replied')) **Indexes:** status, is_read, created_at ## Relationships Diagram ``` users ├─ 1:1 ─→ cart │ ├─ 1:many ─→ cart_items │ └─ many:1 ─→ products ├─ 1:many ─→ orders │ ├─ 1:many ─→ order_items │ └─ many:1 ─→ products └─ many:many ─→ products (via wishlist) categories └─ 1:many ─→ products contact_messages (standalone) ``` ## Sample Data The seed script includes: **Categories:** 5 - Shoes, Shirts, Pants, Hats, Accessories **Products:** 15+ - emphasis on shoes (Nike, Adidas, Cole Haan, Salomon, etc.) - Mix of men's and women's items - Various price points ($19.99 - $189.99) - Sale and featured items **Users:** 2 - user@example.com (password: password123) - jane@example.com (password: password123) ## Indexing Strategy Indexed columns for performance: - users.email (UNIQUE) - users.username (UNIQUE, partial index on non-null) - users.phone (UNIQUE, partial index on non-null) - categories.name (UNIQUE) - categories.slug (UNIQUE) - products.name - products.category_id - orders.order_number (UNIQUE) - orders.user_id - contact_messages.status - contact_messages.is_read - contact_messages.created_at ## Backup and Restore ### Backup Database ```bash pg_dump -U postgres ecommerce_db > backup.sql ``` ### Restore Database ```bash psql -U postgres ecommerce_db < backup.sql ``` ## Connection Pooling In production, consider using a connection pool. SQLAlchemy is configured in `database.py`. ## Migration Notes If modifying models: 1. Update the model in `app/models/` 2. Tables auto-create via `Base.metadata.create_all()` 3. For existing databases, manually ALTER TABLE ## Performance Optimization - Indexes on frequently queried columns - JSON columns for flexible attributes - Pagination implemented in list queries - EAGER loading relationships where needed ## Data Validation - Pydantic schemas validate all input - Email validation via EmailStr - Price and quantity constraints - Product stock management ## Time Zone All timestamps are stored in UTC (datetime.utcnow())