diff --git a/!install!!/fix_tjj.py b/!install!!/fix_tjj.py
deleted file mode 100644
index fcdcae5..0000000
--- a/!install!!/fix_tjj.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env python3
-import subprocess, os
-
-BASE = '/home/tomsjavajive.com/public_html'
-
-# ── Fix 1: Remove wholesale and careers from footer ──────────
-print("[1] Fixing footer...")
-f = BASE + '/includes/footer.php'
-with open(f) as fh:
- c = fh.read()
-
-before = len(c)
-c = c.replace('
Wholesale\n', '')
-c = c.replace(' Careers\n', '')
-# Also try without leading spaces
-c = c.replace('Wholesale\n', '')
-c = c.replace('Careers\n', '')
-
-with open(f, 'w') as fh:
- fh.write(c)
-removed = before - len(c)
-print(f" Footer: removed {removed} chars (wholesale + careers)")
-
-# ── Fix 2: Check account pages for errors ───────────────────
-print("\n[2] Checking account pages...")
-for page in ['rewards', 'wishlist', 'reviews']:
- path = f'{BASE}/account/{page}.php'
- r = subprocess.run(
- ['/usr/local/lsws/lsphp85/bin/php', '-d', 'display_errors=1',
- '-d', 'error_reporting=32767', path],
- capture_output=True, text=True
- )
- output = r.stdout + r.stderr
- errors = [l for l in output.split('\n')
- if any(x in l for x in ['Fatal','Error','Undefined','undefined','Call to'])]
- if errors:
- print(f" {page}.php ERRORS:")
- for e in errors[:3]:
- print(f" {e[:120]}")
- else:
- # Check if page has actual HTML content
- has_html = '<' in r.stdout and len(r.stdout) > 100
- print(f" {page}.php: {'OK - has content' if has_html else 'WARNING - minimal output'}")
-
-# ── Fix 3: Check admin customers Modal ──────────────────────
-print("\n[3] Checking admin customers...")
-f2 = BASE + '/admin/customers.php'
-with open(f2) as fh:
- c2 = fh.read()
-
-print(f" Modal.open present: {'Modal.open' in c2}")
-print(f" openCustomerModal present: {'openCustomerModal' in c2}")
-print(f" admin.js exists: {os.path.exists(BASE+'/admin/assets/admin.js')}")
-
-# Check if admin.js has Modal object
-if os.path.exists(BASE+'/admin/assets/admin.js'):
- with open(BASE+'/admin/assets/admin.js') as fh:
- js = fh.read()
- print(f" Modal object in admin.js: {'Modal' in js}")
- print(f" admin.js size: {len(js)} chars")
-else:
- print(" admin.js MISSING - this is why customer modal doesn't work!")
- # Create a basic Modal object
- modal_js = """
-// Modal helper
-const Modal = {
- open: function(id) {
- const el = document.getElementById(id);
- if (el) { el.style.display = 'flex'; el.classList.add('active'); }
- },
- close: function(id) {
- const el = document.getElementById(id);
- if (el) { el.style.display = 'none'; el.classList.remove('active'); }
- }
-};
-document.addEventListener('keydown', function(e) {
- if (e.key === 'Escape') {
- document.querySelectorAll('.modal-overlay.active').forEach(m => {
- m.style.display = 'none'; m.classList.remove('active');
- });
- }
-});
-document.addEventListener('click', function(e) {
- if (e.target.classList.contains('modal-overlay')) {
- e.target.style.display = 'none'; e.target.classList.remove('active');
- }
-});
-"""
- os.makedirs(BASE+'/admin/assets', exist_ok=True)
- with open(BASE+'/admin/assets/admin.js', 'w') as fh:
- fh.write(modal_js)
- print(" Created admin.js with Modal object")
-
-# ── Fix 4: Check account page includes ─────────────────────
-print("\n[4] Checking account page structure...")
-for page in ['rewards', 'wishlist', 'reviews']:
- path = f'{BASE}/account/{page}.php'
- with open(path) as fh:
- content = fh.read()
- has_auth = 'CustomerAuth::require' in content
- has_header = "require_once" in content and 'header' in content
- has_footer = 'footer' in content
- print(f" {page}.php: auth={has_auth}, header={has_header}, footer={has_footer}, size={len(content)}")
-
-print("\nDone!")
diff --git a/!install!!/migration_v2.sql b/!install!!/migration_v2.sql
deleted file mode 100644
index b4cbb58..0000000
--- a/!install!!/migration_v2.sql
+++ /dev/null
@@ -1,37 +0,0 @@
--- 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`;
diff --git a/!install!!/migration_v3.sql b/!install!!/migration_v3.sql
deleted file mode 100644
index 8b55223..0000000
--- a/!install!!/migration_v3.sql
+++ /dev/null
@@ -1,96 +0,0 @@
--- 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;
-
diff --git a/!install!!/schema.sql b/!install!!/schema.sql
deleted file mode 100644
index 131425f..0000000
--- a/!install!!/schema.sql
+++ /dev/null
@@ -1,402 +0,0 @@
--- 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;
diff --git a/.htaccess b/.htaccess
index 745dda8..df1797e 100644
--- a/.htaccess
+++ b/.htaccess
@@ -8,9 +8,10 @@ RewriteEngine On
# includes/*.php, and .git/ were all still reachable live despite the
# RedirectMatch rules further down) — only mod_rewrite matching on REQUEST_URI
# is confirmed to actually work here. This must come before other rewrites.
-RewriteCond %{REQUEST_URI} ^/(\.git|config/|includes/.*\.php|install/|db/)
+RewriteCond %{REQUEST_URI} ^/(\.git|config/|includes/.*\.php|install/|!install!!/|db/)
RewriteRule .* - [F,L]
-RewriteCond %{REQUEST_URI} \.sql$
+RewriteCond %{REQUEST_URI} \.sql$ [OR]
+RewriteCond %{REQUEST_URI} \.py$
RewriteRule .* - [F,L]
# Force HTTPS (uncomment in production)
diff --git a/config/config.php b/config/config.php
index d79e975..932a7ce 100644
--- a/config/config.php
+++ b/config/config.php
@@ -1,66 +1,2 @@