mirror of
https://github.com/myronblair/tomsjavajive-app
synced 2026-06-30 17:50:56 -05:00
v1.0.0 - Initial backup
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* Tom's Java Jive - Generate PWA Icons
|
||||
* Creates basic SVG icons for PWA manifest
|
||||
*/
|
||||
|
||||
$sizes = [72, 96, 128, 144, 152, 192, 384, 512];
|
||||
$outputDir = __DIR__ . '/../assets/icons/';
|
||||
|
||||
if (!is_dir($outputDir)) {
|
||||
mkdir($outputDir, 0755, true);
|
||||
}
|
||||
|
||||
// Generate a simple coffee cup icon as SVG
|
||||
$svgTemplate = '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="{SIZE}" height="{SIZE}" viewBox="0 0 {SIZE} {SIZE}" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="{SIZE}" height="{SIZE}" rx="{RADIUS}" fill="#FF5E1A"/>
|
||||
<g transform="translate({OFFSET}, {OFFSET}) scale({SCALE})">
|
||||
<path fill="#FFF8F0" d="M60 20H20c-2.2 0-4 1.8-4 4v44c0 6.6 5.4 12 12 12h24c6.6 0 12-5.4 12-12V24c0-2.2-1.8-4-4-4zm-8 4v4H28v-4h24zm8 44c0 4.4-3.6 8-8 8H28c-4.4 0-8-3.6-8-8V32h40v36z"/>
|
||||
<path fill="#FFF8F0" d="M72 32h-4v8h4c2.2 0 4 1.8 4 4v8c0 2.2-1.8 4-4 4h-4v8h4c6.6 0 12-5.4 12-12v-8c0-6.6-5.4-12-12-12z"/>
|
||||
<path fill="#FFF8F0" opacity="0.6" d="M32 12c0-2.2 1.8-4 4-4s4 1.8 4 4v4h-8v-4zm12 0c0-2.2 1.8-4 4-4s4 1.8 4 4v4h-8v-4zm12 0c0-2.2 1.8-4 4-4s4 1.8 4 4v4h-8v-4z"/>
|
||||
</g>
|
||||
</svg>';
|
||||
|
||||
foreach ($sizes as $size) {
|
||||
$radius = floor($size * 0.15);
|
||||
$offset = floor($size * 0.1);
|
||||
$scale = $size / 100;
|
||||
|
||||
$svg = str_replace(
|
||||
['{SIZE}', '{RADIUS}', '{OFFSET}', '{SCALE}'],
|
||||
[$size, $radius, $offset, $scale],
|
||||
$svgTemplate
|
||||
);
|
||||
|
||||
// Save as SVG
|
||||
file_put_contents($outputDir . "icon-{$size}.svg", $svg);
|
||||
|
||||
echo "Generated icon-{$size}.svg\n";
|
||||
}
|
||||
|
||||
// Also create badge icon
|
||||
$badgeSvg = '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="36" cy="36" r="36" fill="#FF5E1A"/>
|
||||
<text x="36" y="45" font-family="Arial, sans-serif" font-size="28" font-weight="bold" fill="white" text-anchor="middle">TJ</text>
|
||||
</svg>';
|
||||
|
||||
file_put_contents($outputDir . 'badge-72.svg', $badgeSvg);
|
||||
echo "Generated badge-72.svg\n";
|
||||
|
||||
echo "\nDone! Icons generated in: $outputDir\n";
|
||||
echo "Note: For production, convert SVGs to PNGs using an image tool.\n";
|
||||
@@ -0,0 +1,435 @@
|
||||
<?php
|
||||
/**
|
||||
* Tom's Java Jive - MongoDB to MySQL Migration Script
|
||||
*
|
||||
* This script migrates data from the existing MongoDB database to MySQL.
|
||||
* Run this script once after setting up the MySQL database with schema.sql
|
||||
*
|
||||
* Usage: php migrate_from_mongodb.php [mongodb_url] [mongodb_dbname]
|
||||
*
|
||||
* Prerequisites:
|
||||
* - PHP MongoDB extension installed
|
||||
* - MySQL database created and schema.sql executed
|
||||
* - database.php configured with MySQL credentials
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
require_once __DIR__ . '/../includes/db.php';
|
||||
|
||||
// Configuration
|
||||
$mongoUrl = $argv[1] ?? getenv('MONGO_URL') ?: 'mongodb://localhost:27017';
|
||||
$mongoDbName = $argv[2] ?? getenv('MONGO_DB_NAME') ?: 'tomsjavajive';
|
||||
|
||||
echo "==============================================\n";
|
||||
echo "Tom's Java Jive - MongoDB to MySQL Migration\n";
|
||||
echo "==============================================\n\n";
|
||||
|
||||
// Check for MongoDB extension
|
||||
if (!extension_loaded('mongodb')) {
|
||||
echo "ERROR: MongoDB PHP extension is not installed.\n";
|
||||
echo "Install it with: pecl install mongodb\n";
|
||||
echo "Or: apt-get install php-mongodb\n\n";
|
||||
echo "Alternatively, export data from MongoDB using mongodump/mongoexport\n";
|
||||
echo "and import it manually.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
// Connect to MongoDB
|
||||
echo "Connecting to MongoDB at: $mongoUrl\n";
|
||||
$mongoClient = new MongoDB\Client($mongoUrl);
|
||||
$mongodb = $mongoClient->selectDatabase($mongoDbName);
|
||||
echo "Connected to MongoDB database: $mongoDbName\n\n";
|
||||
|
||||
// Test MySQL connection
|
||||
$mysql = db();
|
||||
echo "Connected to MySQL database: " . DB_NAME . "\n\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "ERROR: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to convert MongoDB document to array
|
||||
*/
|
||||
function docToArray($doc) {
|
||||
if ($doc instanceof MongoDB\Model\BSONDocument || $doc instanceof MongoDB\Model\BSONArray) {
|
||||
return json_decode(json_encode($doc), true);
|
||||
}
|
||||
return $doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to safely get nested value
|
||||
*/
|
||||
function safeGet($array, $key, $default = null) {
|
||||
return isset($array[$key]) ? $array[$key] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate Admin Users
|
||||
*/
|
||||
function migrateAdminUsers($mongodb, $mysql) {
|
||||
echo "Migrating admin users...\n";
|
||||
|
||||
$cursor = $mongodb->admin_users->find();
|
||||
$count = 0;
|
||||
|
||||
foreach ($cursor as $doc) {
|
||||
$doc = docToArray($doc);
|
||||
|
||||
try {
|
||||
$mysql->insert('admin_users', [
|
||||
'user_id' => safeGet($doc, 'user_id') ?: safeGet($doc, 'admin_id'),
|
||||
'email' => safeGet($doc, 'email'),
|
||||
'password_hash' => safeGet($doc, 'password_hash'),
|
||||
'name' => safeGet($doc, 'name'),
|
||||
'picture' => safeGet($doc, 'picture'),
|
||||
'is_admin' => 1,
|
||||
'is_master' => safeGet($doc, 'is_master') ? 1 : 0,
|
||||
'permissions' => json_encode(safeGet($doc, 'permissions', [])),
|
||||
'created_at' => safeGet($doc, 'created_at') ?: date('Y-m-d H:i:s')
|
||||
]);
|
||||
$count++;
|
||||
} catch (Exception $e) {
|
||||
echo " Warning: Could not migrate admin {$doc['email']}: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo " Migrated $count admin users\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate Customers
|
||||
*/
|
||||
function migrateCustomers($mongodb, $mysql) {
|
||||
echo "Migrating customers...\n";
|
||||
|
||||
$cursor = $mongodb->customers->find();
|
||||
$count = 0;
|
||||
|
||||
foreach ($cursor as $doc) {
|
||||
$doc = docToArray($doc);
|
||||
|
||||
try {
|
||||
$mysql->insert('customers', [
|
||||
'customer_id' => safeGet($doc, 'customer_id'),
|
||||
'email' => safeGet($doc, 'email'),
|
||||
'password_hash' => safeGet($doc, 'password_hash'),
|
||||
'name' => safeGet($doc, 'name'),
|
||||
'phone' => safeGet($doc, 'phone'),
|
||||
'shipping_address' => json_encode(safeGet($doc, 'shipping_address')),
|
||||
'billing_address' => json_encode(safeGet($doc, 'billing_address')),
|
||||
'wallet_balance' => safeGet($doc, 'account_balance', 0),
|
||||
'reward_points' => safeGet($doc, 'loyalty_points', 0),
|
||||
'is_guest' => safeGet($doc, 'is_guest') ? 1 : 0,
|
||||
'created_via' => safeGet($doc, 'created_via', 'web'),
|
||||
'created_at' => safeGet($doc, 'created_at') ?: date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
// Migrate wallet transactions
|
||||
$transactions = safeGet($doc, 'account_transactions', []);
|
||||
foreach ($transactions as $txn) {
|
||||
try {
|
||||
$mysql->insert('wallet_transactions', [
|
||||
'transaction_id' => safeGet($txn, 'transaction_id') ?: 'txn_' . bin2hex(random_bytes(6)),
|
||||
'customer_id' => $doc['customer_id'],
|
||||
'amount' => safeGet($txn, 'amount', 0),
|
||||
'balance_after' => safeGet($txn, 'balance_after', 0),
|
||||
'type' => mapTransactionType(safeGet($txn, 'type')),
|
||||
'description' => safeGet($txn, 'description'),
|
||||
'order_id' => safeGet($txn, 'order_id'),
|
||||
'created_at' => safeGet($txn, 'date') ?: date('Y-m-d H:i:s')
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
// Skip transaction errors
|
||||
}
|
||||
}
|
||||
|
||||
$count++;
|
||||
} catch (Exception $e) {
|
||||
echo " Warning: Could not migrate customer {$doc['email']}: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo " Migrated $count customers\n\n";
|
||||
}
|
||||
|
||||
function mapTransactionType($type) {
|
||||
$map = [
|
||||
'deposit' => 'deposit',
|
||||
'payment' => 'withdrawal',
|
||||
'gift_card_purchase' => 'purchase',
|
||||
'admin_deposit' => 'deposit',
|
||||
'pos_payment' => 'withdrawal',
|
||||
'refund' => 'refund'
|
||||
];
|
||||
return isset($map[$type]) ? $map[$type] : 'deposit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate Products
|
||||
*/
|
||||
function migrateProducts($mongodb, $mysql) {
|
||||
echo "Migrating products...\n";
|
||||
|
||||
$cursor = $mongodb->products->find();
|
||||
$count = 0;
|
||||
|
||||
foreach ($cursor as $doc) {
|
||||
$doc = docToArray($doc);
|
||||
|
||||
// Map blend_type to category
|
||||
$category = safeGet($doc, 'blend_type') ?: safeGet($doc, 'category') ?: 'coffee';
|
||||
|
||||
try {
|
||||
$mysql->insert('products', [
|
||||
'product_id' => safeGet($doc, 'product_id'),
|
||||
'name' => safeGet($doc, 'name'),
|
||||
'description' => safeGet($doc, 'description'),
|
||||
'price' => safeGet($doc, 'price', 0),
|
||||
'sale_price' => safeGet($doc, 'sale_price'),
|
||||
'sku' => safeGet($doc, 'sku'),
|
||||
'barcode' => safeGet($doc, 'barcode'),
|
||||
'category' => $category,
|
||||
'tags' => json_encode([safeGet($doc, 'roast_level'), safeGet($doc, 'product_type')]),
|
||||
'images' => json_encode([safeGet($doc, 'image_url')]),
|
||||
'stock' => safeGet($doc, 'stock_quantity', 100),
|
||||
'low_stock_threshold' => safeGet($doc, 'low_stock_threshold', 10),
|
||||
'weight' => safeGet($doc, 'weight'),
|
||||
'is_active' => safeGet($doc, 'in_stock', true) ? 1 : 0,
|
||||
'is_featured' => safeGet($doc, 'on_sale', false) ? 1 : 0,
|
||||
'created_at' => safeGet($doc, 'created_at') ?: date('Y-m-d H:i:s')
|
||||
]);
|
||||
$count++;
|
||||
} catch (Exception $e) {
|
||||
echo " Warning: Could not migrate product {$doc['name']}: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo " Migrated $count products\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate Orders
|
||||
*/
|
||||
function migrateOrders($mongodb, $mysql) {
|
||||
echo "Migrating orders...\n";
|
||||
|
||||
$cursor = $mongodb->orders->find();
|
||||
$count = 0;
|
||||
|
||||
foreach ($cursor as $doc) {
|
||||
$doc = docToArray($doc);
|
||||
|
||||
try {
|
||||
$mysql->insert('orders', [
|
||||
'order_id' => safeGet($doc, 'order_id'),
|
||||
'order_number' => safeGet($doc, 'order_number'),
|
||||
'customer_id' => safeGet($doc, 'customer_id'),
|
||||
'customer_email' => safeGet($doc, 'customer_email'),
|
||||
'customer_name' => safeGet($doc, 'customer_name'),
|
||||
'items' => json_encode(safeGet($doc, 'items', [])),
|
||||
'subtotal' => safeGet($doc, 'subtotal', 0),
|
||||
'shipping_cost' => safeGet($doc, 'shipping_cost', 0),
|
||||
'tax' => safeGet($doc, 'tax', 0),
|
||||
'discount' => safeGet($doc, 'discount_amount', 0),
|
||||
'total' => safeGet($doc, 'total', 0),
|
||||
'shipping_address' => json_encode(safeGet($doc, 'shipping_address')),
|
||||
'shipping_method' => safeGet($doc, 'shipping_method'),
|
||||
'payment_method' => safeGet($doc, 'payment_method'),
|
||||
'payment_status' => safeGet($doc, 'payment_status', 'pending'),
|
||||
'order_status' => safeGet($doc, 'order_status', 'pending'),
|
||||
'stripe_payment_intent' => safeGet($doc, 'checkout_session_id'),
|
||||
'tracking_number' => safeGet($doc, 'tracking_number'),
|
||||
'notes' => safeGet($doc, 'pos_notes'),
|
||||
'is_pos_order' => safeGet($doc, 'pos_order') ? 1 : 0,
|
||||
'created_at' => safeGet($doc, 'created_at') ?: date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
// Also insert into order_items for reporting
|
||||
$items = safeGet($doc, 'items', []);
|
||||
foreach ($items as $item) {
|
||||
try {
|
||||
$mysql->insert('order_items', [
|
||||
'order_id' => $doc['order_id'],
|
||||
'product_id' => safeGet($item, 'product_id'),
|
||||
'name' => safeGet($item, 'name'),
|
||||
'price' => safeGet($item, 'price', 0),
|
||||
'quantity' => safeGet($item, 'quantity', 1),
|
||||
'total' => safeGet($item, 'total', 0)
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
// Skip item errors
|
||||
}
|
||||
}
|
||||
|
||||
$count++;
|
||||
} catch (Exception $e) {
|
||||
echo " Warning: Could not migrate order {$doc['order_number']}: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo " Migrated $count orders\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate Gift Cards
|
||||
*/
|
||||
function migrateGiftCards($mongodb, $mysql) {
|
||||
echo "Migrating gift cards...\n";
|
||||
|
||||
$cursor = $mongodb->gift_cards->find();
|
||||
$count = 0;
|
||||
|
||||
foreach ($cursor as $doc) {
|
||||
$doc = docToArray($doc);
|
||||
|
||||
try {
|
||||
$mysql->insert('gift_cards', [
|
||||
'gift_card_id' => safeGet($doc, 'gift_card_id'),
|
||||
'code' => safeGet($doc, 'code'),
|
||||
'initial_balance' => safeGet($doc, 'initial_balance', 0),
|
||||
'current_balance' => safeGet($doc, 'current_balance', 0),
|
||||
'purchaser_email' => safeGet($doc, 'purchased_by_email'),
|
||||
'recipient_email' => safeGet($doc, 'recipient_email'),
|
||||
'recipient_name' => safeGet($doc, 'recipient_name'),
|
||||
'message' => safeGet($doc, 'message'),
|
||||
'is_active' => safeGet($doc, 'status') !== 'disabled' ? 1 : 0,
|
||||
'created_at' => safeGet($doc, 'created_at') ?: date('Y-m-d H:i:s')
|
||||
]);
|
||||
$count++;
|
||||
} catch (Exception $e) {
|
||||
echo " Warning: Could not migrate gift card {$doc['code']}: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo " Migrated $count gift cards\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate Reviews
|
||||
*/
|
||||
function migrateReviews($mongodb, $mysql) {
|
||||
echo "Migrating reviews...\n";
|
||||
|
||||
$cursor = $mongodb->product_reviews->find();
|
||||
$count = 0;
|
||||
|
||||
foreach ($cursor as $doc) {
|
||||
$doc = docToArray($doc);
|
||||
|
||||
try {
|
||||
$mysql->insert('reviews', [
|
||||
'review_id' => safeGet($doc, 'review_id'),
|
||||
'product_id' => safeGet($doc, 'product_id'),
|
||||
'customer_id' => safeGet($doc, 'customer_id'),
|
||||
'customer_name' => safeGet($doc, 'customer_name'),
|
||||
'customer_email' => safeGet($doc, 'customer_email'),
|
||||
'rating' => safeGet($doc, 'rating', 5),
|
||||
'title' => safeGet($doc, 'title'),
|
||||
'comment' => safeGet($doc, 'comment'),
|
||||
'is_verified_purchase' => safeGet($doc, 'verified_purchase') ? 1 : 0,
|
||||
'is_approved' => safeGet($doc, 'status') === 'approved' ? 1 : 0,
|
||||
'created_at' => safeGet($doc, 'created_at') ?: date('Y-m-d H:i:s')
|
||||
]);
|
||||
$count++;
|
||||
} catch (Exception $e) {
|
||||
echo " Warning: Could not migrate review: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo " Migrated $count reviews\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate Email Subscribers
|
||||
*/
|
||||
function migrateSubscribers($mongodb, $mysql) {
|
||||
echo "Migrating email subscribers...\n";
|
||||
|
||||
$cursor = $mongodb->email_subscribers->find();
|
||||
$count = 0;
|
||||
|
||||
foreach ($cursor as $doc) {
|
||||
$doc = docToArray($doc);
|
||||
|
||||
try {
|
||||
$mysql->insert('email_subscribers', [
|
||||
'email' => safeGet($doc, 'email'),
|
||||
'name' => safeGet($doc, 'name'),
|
||||
'is_active' => safeGet($doc, 'status') === 'active' ? 1 : 0,
|
||||
'source' => safeGet($doc, 'source', 'website'),
|
||||
'created_at' => safeGet($doc, 'subscribed_at') ?: date('Y-m-d H:i:s')
|
||||
]);
|
||||
$count++;
|
||||
} catch (Exception $e) {
|
||||
// Skip duplicate emails
|
||||
}
|
||||
}
|
||||
|
||||
echo " Migrated $count subscribers\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate Settings
|
||||
*/
|
||||
function migrateSettings($mongodb, $mysql) {
|
||||
echo "Migrating settings...\n";
|
||||
|
||||
// Shipping settings
|
||||
$shipping = $mongodb->shipping_settings->findOne(['settings_id' => 'shipping_settings']);
|
||||
if ($shipping) {
|
||||
$shipping = docToArray($shipping);
|
||||
$mysql->query(
|
||||
"UPDATE settings SET setting_value = :val WHERE setting_key = 'shipping'",
|
||||
['val' => json_encode([
|
||||
'flat_rate_enabled' => safeGet($shipping, 'flat_rate_enabled', true),
|
||||
'flat_rate_amount' => safeGet($shipping, 'flat_rate_amount', 5.99),
|
||||
'free_shipping_threshold' => safeGet($shipping, 'free_shipping_threshold', 50),
|
||||
'weight_based_enabled' => safeGet($shipping, 'weight_based_enabled', false)
|
||||
])]
|
||||
);
|
||||
echo " Migrated shipping settings\n";
|
||||
}
|
||||
|
||||
// Payment settings
|
||||
$payment = $mongodb->payment_settings->findOne(['settings_id' => 'payment_settings']);
|
||||
if ($payment) {
|
||||
$payment = docToArray($payment);
|
||||
$mysql->query(
|
||||
"UPDATE settings SET setting_value = :val WHERE setting_key = 'payment'",
|
||||
['val' => json_encode([
|
||||
'stripe_enabled' => safeGet($payment, 'stripe_enabled', true),
|
||||
'paypal_enabled' => safeGet($payment, 'paypal_enabled', false),
|
||||
'cod_enabled' => false
|
||||
])]
|
||||
);
|
||||
echo " Migrated payment settings\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
// Run migrations
|
||||
echo "Starting migration...\n\n";
|
||||
|
||||
try {
|
||||
migrateAdminUsers($mongodb, $mysql);
|
||||
migrateCustomers($mongodb, $mysql);
|
||||
migrateProducts($mongodb, $mysql);
|
||||
migrateOrders($mongodb, $mysql);
|
||||
migrateGiftCards($mongodb, $mysql);
|
||||
migrateReviews($mongodb, $mysql);
|
||||
migrateSubscribers($mongodb, $mysql);
|
||||
migrateSettings($mongodb, $mysql);
|
||||
|
||||
echo "==============================================\n";
|
||||
echo "Migration completed successfully!\n";
|
||||
echo "==============================================\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "\nMIGRATION ERROR: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
-- Migration: Add wishlist table and addresses column to customers
|
||||
-- Run this in phpMyAdmin to add the new features
|
||||
|
||||
-- Add addresses column to customers table
|
||||
ALTER TABLE `customers` ADD COLUMN `addresses` JSON DEFAULT NULL AFTER `billing_address`;
|
||||
|
||||
-- Add preferences column to customers table
|
||||
ALTER TABLE `customers` ADD COLUMN `preferences` JSON DEFAULT NULL AFTER `addresses`;
|
||||
|
||||
-- Add is_active column to customers table if not exists
|
||||
ALTER TABLE `customers` ADD COLUMN `is_active` TINYINT(1) DEFAULT 1 AFTER `preferences`;
|
||||
|
||||
-- Create wishlist table
|
||||
CREATE TABLE IF NOT EXISTS `wishlist` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`customer_id` VARCHAR(50) NOT NULL,
|
||||
`product_id` VARCHAR(50) NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY `unique_wishlist` (`customer_id`, `product_id`),
|
||||
INDEX `idx_customer` (`customer_id`),
|
||||
INDEX `idx_product` (`product_id`),
|
||||
FOREIGN KEY (`customer_id`) REFERENCES `customers`(`customer_id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY (`product_id`) REFERENCES `products`(`product_id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Add reorder_level column to products if not exists
|
||||
ALTER TABLE `products` ADD COLUMN `reorder_level` INT DEFAULT 10 AFTER `low_stock_threshold`;
|
||||
|
||||
-- Add slug column to products if not exists
|
||||
ALTER TABLE `products` ADD COLUMN `slug` VARCHAR(255) DEFAULT NULL AFTER `name`;
|
||||
ALTER TABLE `products` ADD INDEX `idx_slug` (`slug`);
|
||||
|
||||
-- Update existing products to have slugs based on name
|
||||
UPDATE `products` SET `slug` = LOWER(REPLACE(REPLACE(REPLACE(`name`, ' ', '-'), "'", ''), '"', '')) WHERE `slug` IS NULL;
|
||||
|
||||
-- Add is_pos_order to orders table
|
||||
ALTER TABLE `orders` ADD COLUMN `is_pos_order` TINYINT(1) DEFAULT 0 AFTER `notes`;
|
||||
@@ -0,0 +1,96 @@
|
||||
-- Migration: Add tables for push notifications, loyalty program, and integration settings
|
||||
-- Run this in phpMyAdmin
|
||||
|
||||
-- Push notification subscriptions
|
||||
CREATE TABLE IF NOT EXISTS `push_subscriptions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`endpoint` TEXT NOT NULL,
|
||||
`p256dh_key` VARCHAR(255) NOT NULL,
|
||||
`auth_key` VARCHAR(255) NOT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_customer` (`customer_id`),
|
||||
INDEX `idx_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Push notifications queue
|
||||
CREATE TABLE IF NOT EXISTS `push_notifications` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`notification_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`subscription_endpoint` TEXT NOT NULL,
|
||||
`payload` TEXT NOT NULL,
|
||||
`status` ENUM('pending', 'sent', 'failed') DEFAULT 'pending',
|
||||
`error_message` TEXT DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`sent_at` TIMESTAMP NULL DEFAULT NULL,
|
||||
INDEX `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Loyalty transactions history
|
||||
CREATE TABLE IF NOT EXISTS `loyalty_transactions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`transaction_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`customer_id` VARCHAR(50) NOT NULL,
|
||||
`points` INT NOT NULL,
|
||||
`type` ENUM('earn', 'redeem', 'tier_upgrade', 'birthday_bonus', 'referral_bonus', 'referral_welcome', 'adjustment', 'expiry') NOT NULL,
|
||||
`description` VARCHAR(255) DEFAULT NULL,
|
||||
`reference_amount` DECIMAL(10,2) DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_customer` (`customer_id`),
|
||||
INDEX `idx_type` (`type`),
|
||||
INDEX `idx_created` (`created_at`),
|
||||
FOREIGN KEY (`customer_id`) REFERENCES `customers`(`customer_id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Add lifetime_points and loyalty_tier to customers
|
||||
ALTER TABLE `customers`
|
||||
ADD COLUMN IF NOT EXISTS `lifetime_points` INT DEFAULT 0 AFTER `reward_points`,
|
||||
ADD COLUMN IF NOT EXISTS `loyalty_tier` ENUM('bronze', 'silver', 'gold', 'platinum') DEFAULT 'bronze' AFTER `lifetime_points`,
|
||||
ADD COLUMN IF NOT EXISTS `birthday` DATE DEFAULT NULL AFTER `loyalty_tier`,
|
||||
ADD COLUMN IF NOT EXISTS `referral_code` VARCHAR(20) DEFAULT NULL AFTER `birthday`,
|
||||
ADD COLUMN IF NOT EXISTS `referred_by` VARCHAR(50) DEFAULT NULL AFTER `referral_code`;
|
||||
|
||||
-- Add unique index on referral_code
|
||||
ALTER TABLE `customers` ADD UNIQUE INDEX IF NOT EXISTS `idx_referral_code` (`referral_code`);
|
||||
|
||||
-- Update settings table with integration keys (INSERT IGNORE to not overwrite existing)
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`, `updated_at`) VALUES
|
||||
('sendgrid_api_key', '', NOW()),
|
||||
('sendgrid_from_email', 'noreply@tomsjavajive.com', NOW()),
|
||||
('sendgrid_from_name', 'Tom''s Java Jive', NOW()),
|
||||
('twilio_account_sid', '', NOW()),
|
||||
('twilio_auth_token', '', NOW()),
|
||||
('twilio_phone_number', '', NOW()),
|
||||
('vapid_public_key', '', NOW()),
|
||||
('vapid_private_key', '', NOW()),
|
||||
('loyalty_enabled', '1', NOW()),
|
||||
('email_notifications_enabled', '1', NOW()),
|
||||
('sms_notifications_enabled', '0', NOW()),
|
||||
('push_notifications_enabled', '1', NOW());
|
||||
|
||||
-- Add Stripe checkout session column to orders
|
||||
ALTER TABLE `orders` ADD COLUMN IF NOT EXISTS `stripe_checkout_session` VARCHAR(255) DEFAULT NULL AFTER `stripe_payment_intent`;
|
||||
|
||||
-- Payment transactions table for tracking payment attempts
|
||||
CREATE TABLE IF NOT EXISTS `payment_transactions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`transaction_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`order_id` VARCHAR(50) NOT NULL,
|
||||
`customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`amount` DECIMAL(10,2) NOT NULL,
|
||||
`currency` VARCHAR(3) DEFAULT 'USD',
|
||||
`payment_method` VARCHAR(50) DEFAULT 'stripe',
|
||||
`stripe_session_id` VARCHAR(255) DEFAULT NULL,
|
||||
`stripe_payment_intent` VARCHAR(255) DEFAULT NULL,
|
||||
`status` ENUM('initiated', 'pending', 'processing', 'succeeded', 'failed', 'cancelled', 'refunded') DEFAULT 'initiated',
|
||||
`metadata` JSON DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_order` (`order_id`),
|
||||
INDEX `idx_customer` (`customer_id`),
|
||||
INDEX `idx_status` (`status`),
|
||||
INDEX `idx_stripe_session` (`stripe_session_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@@ -0,0 +1,402 @@
|
||||
-- Tom's Java Jive - MySQL Database Schema
|
||||
-- Version: 1.0
|
||||
-- Compatible with MySQL 8.0+
|
||||
|
||||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
SET AUTOCOMMIT = 0;
|
||||
START TRANSACTION;
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Database Schema for Tom's Java Jive
|
||||
-- NOTE: Database must already exist in cPanel
|
||||
-- Select your database in phpMyAdmin before importing
|
||||
-- --------------------------------------------------------
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: settings
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `settings` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`setting_key` VARCHAR(100) NOT NULL UNIQUE,
|
||||
`setting_value` JSON,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: admin_users
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `admin_users` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`user_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`email` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`password_hash` VARCHAR(255) DEFAULT NULL,
|
||||
`name` VARCHAR(255) DEFAULT NULL,
|
||||
`picture` VARCHAR(500) DEFAULT NULL,
|
||||
`is_admin` TINYINT(1) DEFAULT 1,
|
||||
`is_master` TINYINT(1) DEFAULT 0,
|
||||
`permissions` JSON DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`last_login` TIMESTAMP NULL,
|
||||
INDEX `idx_email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: customers
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `customers` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`customer_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`email` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`password_hash` VARCHAR(255) DEFAULT NULL,
|
||||
`name` VARCHAR(255) DEFAULT NULL,
|
||||
`phone` VARCHAR(50) DEFAULT NULL,
|
||||
`shipping_address` JSON DEFAULT NULL,
|
||||
`billing_address` JSON DEFAULT NULL,
|
||||
`wallet_balance` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`reward_points` INT DEFAULT 0,
|
||||
`is_guest` TINYINT(1) DEFAULT 0,
|
||||
`created_via` VARCHAR(50) DEFAULT 'web',
|
||||
`email_verified` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_email` (`email`),
|
||||
INDEX `idx_customer_id` (`customer_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: products
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `products` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`product_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`description` TEXT,
|
||||
`price` DECIMAL(10,2) NOT NULL,
|
||||
`sale_price` DECIMAL(10,2) DEFAULT NULL,
|
||||
`cost_price` DECIMAL(10,2) DEFAULT NULL,
|
||||
`sku` VARCHAR(100) DEFAULT NULL,
|
||||
`barcode` VARCHAR(100) DEFAULT NULL,
|
||||
`category` VARCHAR(100) DEFAULT NULL,
|
||||
`tags` JSON DEFAULT NULL,
|
||||
`images` JSON DEFAULT NULL,
|
||||
`stock` INT DEFAULT 0,
|
||||
`low_stock_threshold` INT DEFAULT 10,
|
||||
`weight` DECIMAL(10,2) DEFAULT NULL,
|
||||
`dimensions` JSON DEFAULT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`is_featured` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_product_id` (`product_id`),
|
||||
INDEX `idx_category` (`category`),
|
||||
INDEX `idx_is_active` (`is_active`),
|
||||
FULLTEXT INDEX `idx_search` (`name`, `description`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: orders
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `orders` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`order_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`order_number` VARCHAR(20) NOT NULL UNIQUE,
|
||||
`customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`customer_email` VARCHAR(255) NOT NULL,
|
||||
`customer_name` VARCHAR(255) DEFAULT NULL,
|
||||
`customer_phone` VARCHAR(50) DEFAULT NULL,
|
||||
`items` JSON NOT NULL,
|
||||
`subtotal` DECIMAL(10,2) NOT NULL,
|
||||
`shipping_cost` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`tax` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`discount` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`gift_card_discount` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`wallet_amount_used` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`total` DECIMAL(10,2) NOT NULL,
|
||||
`shipping_address` JSON DEFAULT NULL,
|
||||
`billing_address` JSON DEFAULT NULL,
|
||||
`shipping_method` VARCHAR(50) DEFAULT NULL,
|
||||
`payment_method` VARCHAR(50) DEFAULT NULL,
|
||||
`payment_status` ENUM('pending', 'paid', 'failed', 'refunded', 'partially_refunded') DEFAULT 'pending',
|
||||
`order_status` ENUM('pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded') DEFAULT 'pending',
|
||||
`stripe_session_id` VARCHAR(255) DEFAULT NULL,
|
||||
`stripe_payment_intent` VARCHAR(255) DEFAULT NULL,
|
||||
`tracking_number` VARCHAR(100) DEFAULT NULL,
|
||||
`tracking_url` VARCHAR(500) DEFAULT NULL,
|
||||
`notes` TEXT DEFAULT NULL,
|
||||
`is_pos_order` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_order_id` (`order_id`),
|
||||
INDEX `idx_customer_id` (`customer_id`),
|
||||
INDEX `idx_customer_email` (`customer_email`),
|
||||
INDEX `idx_order_status` (`order_status`),
|
||||
INDEX `idx_payment_status` (`payment_status`),
|
||||
INDEX `idx_created_at` (`created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: order_items (normalized for reporting)
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `order_items` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`order_id` VARCHAR(50) NOT NULL,
|
||||
`product_id` VARCHAR(50) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`price` DECIMAL(10,2) NOT NULL,
|
||||
`quantity` INT NOT NULL,
|
||||
`total` DECIMAL(10,2) NOT NULL,
|
||||
INDEX `idx_order_id` (`order_id`),
|
||||
INDEX `idx_product_id` (`product_id`),
|
||||
FOREIGN KEY (`order_id`) REFERENCES `orders`(`order_id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: gift_cards
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `gift_cards` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`gift_card_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`code` VARCHAR(20) NOT NULL UNIQUE,
|
||||
`initial_balance` DECIMAL(10,2) NOT NULL,
|
||||
`current_balance` DECIMAL(10,2) NOT NULL,
|
||||
`purchaser_email` VARCHAR(255) DEFAULT NULL,
|
||||
`recipient_email` VARCHAR(255) DEFAULT NULL,
|
||||
`recipient_name` VARCHAR(255) DEFAULT NULL,
|
||||
`message` TEXT DEFAULT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`expires_at` TIMESTAMP NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_code` (`code`),
|
||||
INDEX `idx_is_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: gift_card_transactions
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `gift_card_transactions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`gift_card_id` VARCHAR(50) NOT NULL,
|
||||
`order_id` VARCHAR(50) DEFAULT NULL,
|
||||
`amount` DECIMAL(10,2) NOT NULL,
|
||||
`balance_after` DECIMAL(10,2) NOT NULL,
|
||||
`type` ENUM('purchase', 'redemption', 'refund') NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_gift_card_id` (`gift_card_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: wallet_transactions
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `wallet_transactions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`transaction_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`customer_id` VARCHAR(50) NOT NULL,
|
||||
`amount` DECIMAL(10,2) NOT NULL,
|
||||
`balance_after` DECIMAL(10,2) NOT NULL,
|
||||
`type` ENUM('deposit', 'withdrawal', 'purchase', 'refund', 'reward') NOT NULL,
|
||||
`description` VARCHAR(255) DEFAULT NULL,
|
||||
`order_id` VARCHAR(50) DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_customer_id` (`customer_id`),
|
||||
INDEX `idx_type` (`type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: reviews
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `reviews` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`review_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`product_id` VARCHAR(50) NOT NULL,
|
||||
`customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`customer_name` VARCHAR(255) NOT NULL,
|
||||
`customer_email` VARCHAR(255) NOT NULL,
|
||||
`rating` INT NOT NULL CHECK (rating >= 1 AND rating <= 5),
|
||||
`title` VARCHAR(255) DEFAULT NULL,
|
||||
`comment` TEXT,
|
||||
`is_verified_purchase` TINYINT(1) DEFAULT 0,
|
||||
`is_approved` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_product_id` (`product_id`),
|
||||
INDEX `idx_is_approved` (`is_approved`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: email_campaigns
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `email_campaigns` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`campaign_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`subject` VARCHAR(255) NOT NULL,
|
||||
`content` TEXT NOT NULL,
|
||||
`recipient_type` ENUM('all', 'customers_only', 'subscribers_only') DEFAULT 'all',
|
||||
`status` ENUM('draft', 'scheduled', 'sent', 'cancelled') DEFAULT 'draft',
|
||||
`scheduled_at` TIMESTAMP NULL,
|
||||
`sent_at` TIMESTAMP NULL,
|
||||
`recipients_count` INT DEFAULT 0,
|
||||
`opened_count` INT DEFAULT 0,
|
||||
`clicked_count` INT DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: email_subscribers
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `email_subscribers` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`email` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`name` VARCHAR(255) DEFAULT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`source` VARCHAR(50) DEFAULT 'website',
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_is_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: abandoned_carts
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `abandoned_carts` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`cart_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`customer_email` VARCHAR(255) DEFAULT NULL,
|
||||
`items` JSON NOT NULL,
|
||||
`subtotal` DECIMAL(10,2) NOT NULL,
|
||||
`recovery_email_sent` TINYINT(1) DEFAULT 0,
|
||||
`recovered` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_customer_email` (`customer_email`),
|
||||
INDEX `idx_recovered` (`recovered`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: referrals
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `referrals` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`referral_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`referrer_customer_id` VARCHAR(50) NOT NULL,
|
||||
`referral_code` VARCHAR(20) NOT NULL UNIQUE,
|
||||
`referred_customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`referred_email` VARCHAR(255) DEFAULT NULL,
|
||||
`status` ENUM('pending', 'completed', 'expired') DEFAULT 'pending',
|
||||
`reward_amount` DECIMAL(10,2) DEFAULT 5.00,
|
||||
`reward_given` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_referral_code` (`referral_code`),
|
||||
INDEX `idx_referrer` (`referrer_customer_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: visitor_sessions
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `visitor_sessions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`session_id` VARCHAR(100) NOT NULL UNIQUE,
|
||||
`visitor_id` VARCHAR(50) NOT NULL,
|
||||
`ip_address` VARCHAR(45) DEFAULT NULL,
|
||||
`user_agent` TEXT DEFAULT NULL,
|
||||
`current_page` VARCHAR(500) DEFAULT NULL,
|
||||
`referrer` VARCHAR(500) DEFAULT NULL,
|
||||
`country` VARCHAR(100) DEFAULT NULL,
|
||||
`city` VARCHAR(100) DEFAULT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`page_views` INT DEFAULT 1,
|
||||
`started_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`last_activity` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_is_active` (`is_active`),
|
||||
INDEX `idx_last_activity` (`last_activity`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: categories
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `categories` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`category_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`slug` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`description` TEXT DEFAULT NULL,
|
||||
`image` VARCHAR(500) DEFAULT NULL,
|
||||
`parent_id` VARCHAR(50) DEFAULT NULL,
|
||||
`sort_order` INT DEFAULT 0,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_slug` (`slug`),
|
||||
INDEX `idx_is_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: coupons
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `coupons` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`coupon_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`code` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`discount_type` ENUM('percentage', 'fixed') NOT NULL DEFAULT 'percentage',
|
||||
`discount_value` DECIMAL(10,2) NOT NULL,
|
||||
`min_order_amount` DECIMAL(10,2) DEFAULT NULL,
|
||||
`max_uses` INT DEFAULT NULL,
|
||||
`times_used` INT DEFAULT 0,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`starts_at` TIMESTAMP NULL,
|
||||
`expires_at` TIMESTAMP NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_code` (`code`),
|
||||
INDEX `idx_is_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: password_reset_tokens
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `password_reset_tokens` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`email` VARCHAR(255) NOT NULL,
|
||||
`token` VARCHAR(255) NOT NULL,
|
||||
`user_type` ENUM('admin', 'customer') NOT NULL,
|
||||
`expires_at` TIMESTAMP NOT NULL,
|
||||
`used` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_token` (`token`),
|
||||
INDEX `idx_email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: sessions
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `sessions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`session_id` VARCHAR(128) NOT NULL UNIQUE,
|
||||
`user_id` VARCHAR(50) DEFAULT NULL,
|
||||
`user_type` ENUM('admin', 'customer') DEFAULT NULL,
|
||||
`data` TEXT,
|
||||
`ip_address` VARCHAR(45) DEFAULT NULL,
|
||||
`user_agent` VARCHAR(255) DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`expires_at` TIMESTAMP NOT NULL,
|
||||
INDEX `idx_session_id` (`session_id`),
|
||||
INDEX `idx_expires_at` (`expires_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Insert default settings
|
||||
-- --------------------------------------------------------
|
||||
INSERT INTO `settings` (`setting_key`, `setting_value`) VALUES
|
||||
('store_name', '"Tom\'s Java Jive"'),
|
||||
('store_email', '"support@tomsjavajive.com"'),
|
||||
('store_phone', '""'),
|
||||
('store_address', '""'),
|
||||
('currency', '"USD"'),
|
||||
('currency_symbol', '"$"'),
|
||||
('tax_rate', '0'),
|
||||
('shipping', '{"flat_rate_enabled": true, "flat_rate_amount": 5.99, "free_shipping_threshold": 50, "weight_based_enabled": false}'),
|
||||
('payment', '{"stripe_enabled": true, "paypal_enabled": false, "cod_enabled": false}'),
|
||||
('email', '{"sendgrid_api_key": "", "sender_email": "noreply@tomsjavajive.com", "sender_name": "Tom\'s Java Jive"}');
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user