Database-migration-scripts-for-deployment-fixes

This commit is contained in:
SysAdmin 2025-09-29 17:30:34 +01:00
parent 51cc0463de
commit 8fc58bb918
3 changed files with 843 additions and 0 deletions

View File

@ -0,0 +1,520 @@
CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
"MigrationId" TEXT NOT NULL CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY,
"ProductVersion" TEXT NOT NULL
);
BEGIN TRANSACTION;
CREATE TABLE "Bots" (
"Id" TEXT NOT NULL CONSTRAINT "PK_Bots" PRIMARY KEY,
"BotKey" TEXT NOT NULL,
"Name" TEXT NOT NULL,
"Description" TEXT NOT NULL,
"Type" INTEGER NOT NULL,
"Status" INTEGER NOT NULL,
"Settings" TEXT NOT NULL,
"CreatedAt" TEXT NOT NULL,
"LastSeenAt" TEXT NULL,
"LastConfigSyncAt" TEXT NULL,
"IsActive" INTEGER NOT NULL,
"Version" TEXT NOT NULL,
"IpAddress" TEXT NOT NULL,
"PlatformUsername" TEXT NOT NULL,
"PlatformDisplayName" TEXT NOT NULL,
"PlatformId" TEXT NOT NULL,
"PersonalityName" TEXT NOT NULL
);
CREATE TABLE "Categories" (
"Id" TEXT NOT NULL CONSTRAINT "PK_Categories" PRIMARY KEY,
"Name" TEXT NOT NULL,
"Description" TEXT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
"IsActive" INTEGER NOT NULL
);
CREATE TABLE "Customers" (
"Id" TEXT NOT NULL CONSTRAINT "PK_Customers" PRIMARY KEY,
"TelegramUserId" INTEGER NOT NULL,
"TelegramUsername" TEXT NOT NULL,
"TelegramDisplayName" TEXT NOT NULL,
"TelegramFirstName" TEXT NOT NULL,
"TelegramLastName" TEXT NOT NULL,
"Email" TEXT NULL,
"PhoneNumber" TEXT NULL,
"AllowMarketing" INTEGER NOT NULL,
"AllowOrderUpdates" INTEGER NOT NULL,
"Language" TEXT NOT NULL,
"Timezone" TEXT NOT NULL,
"TotalOrders" INTEGER NOT NULL,
"TotalSpent" decimal(18,2) NOT NULL,
"AverageOrderValue" decimal(18,2) NOT NULL,
"FirstOrderDate" TEXT NOT NULL,
"LastOrderDate" TEXT NOT NULL,
"CustomerNotes" TEXT NULL,
"IsBlocked" INTEGER NOT NULL,
"BlockReason" TEXT NULL,
"RiskScore" INTEGER NOT NULL,
"SuccessfulOrders" INTEGER NOT NULL,
"CancelledOrders" INTEGER NOT NULL,
"DisputedOrders" INTEGER NOT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
"LastActiveAt" TEXT NOT NULL,
"DataRetentionDate" TEXT NULL,
"IsActive" INTEGER NOT NULL
);
CREATE TABLE "ShippingRates" (
"Id" TEXT NOT NULL CONSTRAINT "PK_ShippingRates" PRIMARY KEY,
"Name" TEXT NOT NULL,
"Description" TEXT NULL,
"Country" TEXT NOT NULL,
"MinWeight" decimal(18,2) NOT NULL,
"MaxWeight" decimal(18,2) NOT NULL,
"Price" decimal(18,2) NOT NULL,
"MinDeliveryDays" INTEGER NOT NULL,
"MaxDeliveryDays" INTEGER NOT NULL,
"IsActive" INTEGER NOT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL
);
CREATE TABLE "Users" (
"Id" TEXT NOT NULL CONSTRAINT "PK_Users" PRIMARY KEY,
"Username" TEXT NOT NULL,
"PasswordHash" TEXT NOT NULL,
"Email" TEXT NULL,
"Role" TEXT NOT NULL,
"CreatedAt" TEXT NOT NULL,
"IsActive" INTEGER NOT NULL
);
CREATE TABLE "BotMetrics" (
"Id" TEXT NOT NULL CONSTRAINT "PK_BotMetrics" PRIMARY KEY,
"BotId" TEXT NOT NULL,
"MetricType" INTEGER NOT NULL,
"Value" TEXT NOT NULL,
"Metadata" TEXT NOT NULL,
"RecordedAt" TEXT NOT NULL,
"Category" TEXT NOT NULL,
"Description" TEXT NOT NULL,
CONSTRAINT "FK_BotMetrics_Bots_BotId" FOREIGN KEY ("BotId") REFERENCES "Bots" ("Id") ON DELETE CASCADE
);
CREATE TABLE "BotSessions" (
"Id" TEXT NOT NULL CONSTRAINT "PK_BotSessions" PRIMARY KEY,
"BotId" TEXT NOT NULL,
"SessionIdentifier" TEXT NOT NULL,
"Platform" TEXT NOT NULL,
"StartedAt" TEXT NOT NULL,
"LastActivityAt" TEXT NOT NULL,
"EndedAt" TEXT NULL,
"OrderCount" INTEGER NOT NULL,
"MessageCount" INTEGER NOT NULL,
"TotalSpent" TEXT NOT NULL,
"Language" TEXT NOT NULL,
"Country" TEXT NOT NULL,
"IsAnonymous" INTEGER NOT NULL,
"Metadata" TEXT NOT NULL,
CONSTRAINT "FK_BotSessions_Bots_BotId" FOREIGN KEY ("BotId") REFERENCES "Bots" ("Id") ON DELETE CASCADE
);
CREATE TABLE "Products" (
"Id" TEXT NOT NULL CONSTRAINT "PK_Products" PRIMARY KEY,
"Name" TEXT NOT NULL,
"Description" TEXT NOT NULL,
"Price" decimal(18,2) NOT NULL,
"Weight" decimal(18,4) NOT NULL,
"WeightUnit" INTEGER NOT NULL,
"StockQuantity" INTEGER NOT NULL,
"CategoryId" TEXT NOT NULL,
"IsActive" INTEGER NOT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
CONSTRAINT "FK_Products_Categories_CategoryId" FOREIGN KEY ("CategoryId") REFERENCES "Categories" ("Id") ON DELETE RESTRICT
);
CREATE TABLE "BotContacts" (
"Id" TEXT NOT NULL CONSTRAINT "PK_BotContacts" PRIMARY KEY,
"BotId" TEXT NOT NULL,
"TelegramUserId" INTEGER NOT NULL,
"TelegramUsername" TEXT NOT NULL,
"DisplayName" TEXT NOT NULL,
"FirstName" TEXT NOT NULL,
"LastName" TEXT NOT NULL,
"FirstContactDate" TEXT NOT NULL,
"LastContactDate" TEXT NOT NULL,
"TotalInteractions" INTEGER NOT NULL,
"LastKnownLanguage" TEXT NOT NULL,
"Status" INTEGER NOT NULL,
"StatusReason" TEXT NULL,
"CustomerId" TEXT NULL,
"IsRecovered" INTEGER NOT NULL,
"RecoveredFromBotId" TEXT NULL,
"RecoveredAt" TEXT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
"IsActive" INTEGER NOT NULL,
"EncryptedContactData" TEXT NULL,
"Preferences" TEXT NULL,
"Notes" TEXT NULL,
CONSTRAINT "FK_BotContacts_Bots_BotId" FOREIGN KEY ("BotId") REFERENCES "Bots" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_BotContacts_Customers_CustomerId" FOREIGN KEY ("CustomerId") REFERENCES "Customers" ("Id")
);
CREATE TABLE "Orders" (
"Id" TEXT NOT NULL CONSTRAINT "PK_Orders" PRIMARY KEY,
"CustomerId" TEXT NULL,
"IdentityReference" TEXT NULL,
"Status" INTEGER NOT NULL,
"TotalAmount" decimal(18,2) NOT NULL,
"Currency" TEXT NOT NULL,
"ShippingName" TEXT NOT NULL,
"ShippingAddress" TEXT NOT NULL,
"ShippingCity" TEXT NOT NULL,
"ShippingPostCode" TEXT NOT NULL,
"ShippingCountry" TEXT NOT NULL,
"Notes" TEXT NULL,
"TrackingNumber" TEXT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
"PaidAt" TEXT NULL,
"AcceptedAt" TEXT NULL,
"PackingStartedAt" TEXT NULL,
"DispatchedAt" TEXT NULL,
"ExpectedDeliveryDate" TEXT NULL,
"ActualDeliveryDate" TEXT NULL,
"OnHoldAt" TEXT NULL,
"AcceptedByUser" TEXT NULL,
"PackedByUser" TEXT NULL,
"DispatchedByUser" TEXT NULL,
"OnHoldReason" TEXT NULL,
"ShippedAt" TEXT NULL,
CONSTRAINT "FK_Orders_Customers_CustomerId" FOREIGN KEY ("CustomerId") REFERENCES "Customers" ("Id") ON DELETE RESTRICT
);
CREATE TABLE "PushSubscriptions" (
"Id" INTEGER NOT NULL CONSTRAINT "PK_PushSubscriptions" PRIMARY KEY AUTOINCREMENT,
"Endpoint" TEXT NOT NULL,
"P256DH" TEXT NOT NULL,
"Auth" TEXT NOT NULL,
"UserId" TEXT NULL,
"CustomerId" TEXT NULL,
"SubscribedAt" TEXT NOT NULL,
"LastUsedAt" TEXT NULL,
"IsActive" INTEGER NOT NULL,
"UserAgent" TEXT NULL,
"IpAddress" TEXT NULL,
CONSTRAINT "FK_PushSubscriptions_Customers_CustomerId" FOREIGN KEY ("CustomerId") REFERENCES "Customers" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_PushSubscriptions_Users_UserId" FOREIGN KEY ("UserId") REFERENCES "Users" ("Id") ON DELETE CASCADE
);
CREATE TABLE "ProductMultiBuys" (
"Id" TEXT NOT NULL CONSTRAINT "PK_ProductMultiBuys" PRIMARY KEY,
"ProductId" TEXT NOT NULL,
"Name" TEXT NOT NULL,
"Description" TEXT NOT NULL,
"Quantity" INTEGER NOT NULL,
"Price" decimal(18,2) NOT NULL,
"PricePerUnit" decimal(18,2) NOT NULL,
"SortOrder" INTEGER NOT NULL,
"IsActive" INTEGER NOT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
CONSTRAINT "FK_ProductMultiBuys_Products_ProductId" FOREIGN KEY ("ProductId") REFERENCES "Products" ("Id") ON DELETE CASCADE
);
CREATE TABLE "ProductPhotos" (
"Id" TEXT NOT NULL CONSTRAINT "PK_ProductPhotos" PRIMARY KEY,
"ProductId" TEXT NOT NULL,
"FileName" TEXT NOT NULL,
"FilePath" TEXT NOT NULL,
"AltText" TEXT NULL,
"SortOrder" INTEGER NOT NULL,
"CreatedAt" TEXT NOT NULL,
CONSTRAINT "FK_ProductPhotos_Products_ProductId" FOREIGN KEY ("ProductId") REFERENCES "Products" ("Id") ON DELETE CASCADE
);
CREATE TABLE "ProductVariants" (
"Id" TEXT NOT NULL CONSTRAINT "PK_ProductVariants" PRIMARY KEY,
"ProductId" TEXT NOT NULL,
"Name" TEXT NOT NULL,
"VariantType" TEXT NOT NULL,
"SortOrder" INTEGER NOT NULL,
"IsActive" INTEGER NOT NULL,
"StockLevel" INTEGER NOT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
CONSTRAINT "FK_ProductVariants_Products_ProductId" FOREIGN KEY ("ProductId") REFERENCES "Products" ("Id") ON DELETE CASCADE
);
CREATE TABLE "BotActivities" (
"Id" TEXT NOT NULL CONSTRAINT "PK_BotActivities" PRIMARY KEY,
"BotId" TEXT NOT NULL,
"SessionIdentifier" TEXT NOT NULL,
"UserDisplayName" TEXT NOT NULL,
"ActivityType" TEXT NOT NULL,
"ActivityDescription" TEXT NOT NULL,
"ProductId" TEXT NULL,
"ProductName" TEXT NOT NULL,
"OrderId" TEXT NULL,
"CategoryName" TEXT NOT NULL,
"Value" TEXT NULL,
"Quantity" INTEGER NULL,
"Platform" TEXT NOT NULL,
"DeviceType" TEXT NOT NULL,
"Location" TEXT NOT NULL,
"Timestamp" TEXT NOT NULL,
"Metadata" TEXT NOT NULL,
CONSTRAINT "FK_BotActivities_Bots_BotId" FOREIGN KEY ("BotId") REFERENCES "Bots" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_BotActivities_Orders_OrderId" FOREIGN KEY ("OrderId") REFERENCES "Orders" ("Id") ON DELETE SET NULL,
CONSTRAINT "FK_BotActivities_Products_ProductId" FOREIGN KEY ("ProductId") REFERENCES "Products" ("Id") ON DELETE SET NULL
);
CREATE TABLE "CryptoPayments" (
"Id" TEXT NOT NULL CONSTRAINT "PK_CryptoPayments" PRIMARY KEY,
"OrderId" TEXT NOT NULL,
"Currency" INTEGER NOT NULL,
"WalletAddress" TEXT NOT NULL,
"RequiredAmount" decimal(18,8) NOT NULL,
"PaidAmount" decimal(18,8) NOT NULL,
"Status" INTEGER NOT NULL,
"BTCPayInvoiceId" TEXT NULL,
"SilverPayOrderId" TEXT NULL,
"TransactionHash" TEXT NULL,
"CreatedAt" TEXT NOT NULL,
"PaidAt" TEXT NULL,
"ExpiresAt" TEXT NOT NULL,
CONSTRAINT "FK_CryptoPayments_Orders_OrderId" FOREIGN KEY ("OrderId") REFERENCES "Orders" ("Id") ON DELETE CASCADE
);
CREATE TABLE "CustomerMessages" (
"Id" TEXT NOT NULL CONSTRAINT "PK_CustomerMessages" PRIMARY KEY,
"CustomerId" TEXT NOT NULL,
"OrderId" TEXT NULL,
"AdminUserId" TEXT NULL,
"Direction" INTEGER NOT NULL,
"Type" INTEGER NOT NULL,
"Subject" TEXT NOT NULL,
"Content" TEXT NOT NULL,
"Status" INTEGER NOT NULL,
"CreatedAt" TEXT NOT NULL,
"SentAt" TEXT NULL,
"DeliveredAt" TEXT NULL,
"ReadAt" TEXT NULL,
"FailedAt" TEXT NULL,
"FailureReason" TEXT NULL,
"RetryCount" INTEGER NOT NULL,
"NextRetryAt" TEXT NULL,
"ParentMessageId" TEXT NULL,
"ThreadId" TEXT NULL,
"Platform" TEXT NOT NULL,
"PlatformMessageId" TEXT NULL,
"Priority" INTEGER NOT NULL,
"ScheduledFor" TEXT NULL,
"ExpiresAt" TEXT NULL,
"RequiresResponse" INTEGER NOT NULL,
"IsUrgent" INTEGER NOT NULL,
"IsMarketing" INTEGER NOT NULL,
"IsAutoGenerated" INTEGER NOT NULL,
"AutoGenerationTrigger" TEXT NULL,
"IsArchived" INTEGER NOT NULL,
"ArchivedAt" TEXT NULL,
CONSTRAINT "FK_CustomerMessages_CustomerMessages_ParentMessageId" FOREIGN KEY ("ParentMessageId") REFERENCES "CustomerMessages" ("Id") ON DELETE RESTRICT,
CONSTRAINT "FK_CustomerMessages_Customers_CustomerId" FOREIGN KEY ("CustomerId") REFERENCES "Customers" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_CustomerMessages_Orders_OrderId" FOREIGN KEY ("OrderId") REFERENCES "Orders" ("Id") ON DELETE SET NULL,
CONSTRAINT "FK_CustomerMessages_Users_AdminUserId" FOREIGN KEY ("AdminUserId") REFERENCES "Users" ("Id") ON DELETE SET NULL
);
CREATE TABLE "Reviews" (
"Id" TEXT NOT NULL CONSTRAINT "PK_Reviews" PRIMARY KEY,
"ProductId" TEXT NOT NULL,
"CustomerId" TEXT NOT NULL,
"OrderId" TEXT NOT NULL,
"Rating" INTEGER NOT NULL,
"Title" TEXT NULL,
"Comment" TEXT NULL,
"IsVerifiedPurchase" INTEGER NOT NULL,
"IsApproved" INTEGER NOT NULL,
"IsActive" INTEGER NOT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
"ApprovedAt" TEXT NULL,
"ApprovedByUserId" TEXT NULL,
CONSTRAINT "FK_Reviews_Customers_CustomerId" FOREIGN KEY ("CustomerId") REFERENCES "Customers" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_Reviews_Orders_OrderId" FOREIGN KEY ("OrderId") REFERENCES "Orders" ("Id") ON DELETE RESTRICT,
CONSTRAINT "FK_Reviews_Products_ProductId" FOREIGN KEY ("ProductId") REFERENCES "Products" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_Reviews_Users_ApprovedByUserId" FOREIGN KEY ("ApprovedByUserId") REFERENCES "Users" ("Id") ON DELETE SET NULL
);
CREATE TABLE "OrderItems" (
"Id" TEXT NOT NULL CONSTRAINT "PK_OrderItems" PRIMARY KEY,
"OrderId" TEXT NOT NULL,
"ProductId" TEXT NOT NULL,
"ProductMultiBuyId" TEXT NULL,
"SelectedVariant" TEXT NULL,
"Quantity" INTEGER NOT NULL,
"UnitPrice" decimal(18,2) NOT NULL,
"TotalPrice" decimal(18,2) NOT NULL,
CONSTRAINT "FK_OrderItems_Orders_OrderId" FOREIGN KEY ("OrderId") REFERENCES "Orders" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_OrderItems_ProductMultiBuys_ProductMultiBuyId" FOREIGN KEY ("ProductMultiBuyId") REFERENCES "ProductMultiBuys" ("Id") ON DELETE RESTRICT,
CONSTRAINT "FK_OrderItems_Products_ProductId" FOREIGN KEY ("ProductId") REFERENCES "Products" ("Id") ON DELETE RESTRICT
);
CREATE INDEX "IX_BotActivities_ActivityType" ON "BotActivities" ("ActivityType");
CREATE INDEX "IX_BotActivities_BotId_Timestamp" ON "BotActivities" ("BotId", "Timestamp");
CREATE INDEX "IX_BotActivities_OrderId" ON "BotActivities" ("OrderId");
CREATE INDEX "IX_BotActivities_ProductId" ON "BotActivities" ("ProductId");
CREATE INDEX "IX_BotActivities_SessionIdentifier" ON "BotActivities" ("SessionIdentifier");
CREATE INDEX "IX_BotActivities_Timestamp" ON "BotActivities" ("Timestamp");
CREATE INDEX "IX_BotContacts_BotId" ON "BotContacts" ("BotId");
CREATE INDEX "IX_BotContacts_CustomerId" ON "BotContacts" ("CustomerId");
CREATE INDEX "IX_BotMetrics_BotId_RecordedAt" ON "BotMetrics" ("BotId", "RecordedAt");
CREATE INDEX "IX_BotMetrics_MetricType" ON "BotMetrics" ("MetricType");
CREATE UNIQUE INDEX "IX_Bots_BotKey" ON "Bots" ("BotKey");
CREATE INDEX "IX_Bots_Name" ON "Bots" ("Name");
CREATE INDEX "IX_Bots_Status" ON "Bots" ("Status");
CREATE INDEX "IX_BotSessions_BotId_SessionIdentifier" ON "BotSessions" ("BotId", "SessionIdentifier");
CREATE INDEX "IX_BotSessions_LastActivityAt" ON "BotSessions" ("LastActivityAt");
CREATE INDEX "IX_BotSessions_StartedAt" ON "BotSessions" ("StartedAt");
CREATE INDEX "IX_CryptoPayments_BTCPayInvoiceId" ON "CryptoPayments" ("BTCPayInvoiceId");
CREATE INDEX "IX_CryptoPayments_OrderId" ON "CryptoPayments" ("OrderId");
CREATE INDEX "IX_CryptoPayments_WalletAddress" ON "CryptoPayments" ("WalletAddress");
CREATE INDEX "IX_CustomerMessages_AdminUserId" ON "CustomerMessages" ("AdminUserId");
CREATE INDEX "IX_CustomerMessages_CustomerId_CreatedAt" ON "CustomerMessages" ("CustomerId", "CreatedAt");
CREATE INDEX "IX_CustomerMessages_Direction" ON "CustomerMessages" ("Direction");
CREATE INDEX "IX_CustomerMessages_OrderId" ON "CustomerMessages" ("OrderId");
CREATE INDEX "IX_CustomerMessages_ParentMessageId" ON "CustomerMessages" ("ParentMessageId");
CREATE INDEX "IX_CustomerMessages_ScheduledFor" ON "CustomerMessages" ("ScheduledFor");
CREATE INDEX "IX_CustomerMessages_Status" ON "CustomerMessages" ("Status");
CREATE INDEX "IX_CustomerMessages_ThreadId" ON "CustomerMessages" ("ThreadId");
CREATE INDEX "IX_CustomerMessages_Type" ON "CustomerMessages" ("Type");
CREATE INDEX "IX_Customers_CreatedAt" ON "Customers" ("CreatedAt");
CREATE INDEX "IX_Customers_DataRetentionDate" ON "Customers" ("DataRetentionDate");
CREATE INDEX "IX_Customers_Email" ON "Customers" ("Email");
CREATE INDEX "IX_Customers_LastActiveAt" ON "Customers" ("LastActiveAt");
CREATE UNIQUE INDEX "IX_Customers_TelegramUserId" ON "Customers" ("TelegramUserId");
CREATE INDEX "IX_Customers_TelegramUsername" ON "Customers" ("TelegramUsername");
CREATE INDEX "IX_OrderItems_OrderId" ON "OrderItems" ("OrderId");
CREATE INDEX "IX_OrderItems_ProductId" ON "OrderItems" ("ProductId");
CREATE INDEX "IX_OrderItems_ProductMultiBuyId" ON "OrderItems" ("ProductMultiBuyId");
CREATE INDEX "IX_Orders_CreatedAt" ON "Orders" ("CreatedAt");
CREATE INDEX "IX_Orders_CustomerId" ON "Orders" ("CustomerId");
CREATE INDEX "IX_Orders_IdentityReference" ON "Orders" ("IdentityReference");
CREATE INDEX "IX_ProductMultiBuys_IsActive" ON "ProductMultiBuys" ("IsActive");
CREATE UNIQUE INDEX "IX_ProductMultiBuys_ProductId_Quantity" ON "ProductMultiBuys" ("ProductId", "Quantity");
CREATE INDEX "IX_ProductMultiBuys_ProductId_SortOrder" ON "ProductMultiBuys" ("ProductId", "SortOrder");
CREATE INDEX "IX_ProductPhotos_ProductId" ON "ProductPhotos" ("ProductId");
CREATE INDEX "IX_Products_CategoryId" ON "Products" ("CategoryId");
CREATE INDEX "IX_ProductVariants_IsActive" ON "ProductVariants" ("IsActive");
CREATE UNIQUE INDEX "IX_ProductVariants_ProductId_Name" ON "ProductVariants" ("ProductId", "Name");
CREATE INDEX "IX_ProductVariants_ProductId_SortOrder" ON "ProductVariants" ("ProductId", "SortOrder");
CREATE INDEX "IX_PushSubscriptions_CustomerId" ON "PushSubscriptions" ("CustomerId");
CREATE UNIQUE INDEX "IX_PushSubscriptions_Endpoint" ON "PushSubscriptions" ("Endpoint");
CREATE INDEX "IX_PushSubscriptions_IsActive" ON "PushSubscriptions" ("IsActive");
CREATE INDEX "IX_PushSubscriptions_SubscribedAt" ON "PushSubscriptions" ("SubscribedAt");
CREATE INDEX "IX_PushSubscriptions_UserId" ON "PushSubscriptions" ("UserId");
CREATE INDEX "IX_Reviews_ApprovedByUserId" ON "Reviews" ("ApprovedByUserId");
CREATE INDEX "IX_Reviews_CreatedAt" ON "Reviews" ("CreatedAt");
CREATE INDEX "IX_Reviews_CustomerId" ON "Reviews" ("CustomerId");
CREATE UNIQUE INDEX "IX_Reviews_CustomerId_ProductId" ON "Reviews" ("CustomerId", "ProductId");
CREATE INDEX "IX_Reviews_IsActive" ON "Reviews" ("IsActive");
CREATE INDEX "IX_Reviews_IsApproved" ON "Reviews" ("IsApproved");
CREATE INDEX "IX_Reviews_OrderId" ON "Reviews" ("OrderId");
CREATE INDEX "IX_Reviews_ProductId" ON "Reviews" ("ProductId");
CREATE INDEX "IX_Reviews_ProductId_IsApproved_IsActive" ON "Reviews" ("ProductId", "IsApproved", "IsActive");
CREATE INDEX "IX_Reviews_Rating" ON "Reviews" ("Rating");
CREATE UNIQUE INDEX "IX_Users_Username" ON "Users" ("Username");
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20250922025753_AddProductMultiBuysTable', '9.0.9');
CREATE TABLE "SystemSettings" (
"Key" TEXT NOT NULL CONSTRAINT "PK_SystemSettings" PRIMARY KEY,
"Value" TEXT NOT NULL,
"Description" TEXT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL
);
CREATE UNIQUE INDEX "IX_SystemSettings_Key" ON "SystemSettings" ("Key");
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20250922040637_AddSystemSettingsTable', '9.0.9');
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20250928014850_AddVariantCollectionsAndSalesLedger', '9.0.9');
ALTER TABLE "ProductVariants" ADD "Weight" TEXT NULL;
ALTER TABLE "ProductVariants" ADD "WeightUnit" INTEGER NULL;
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20250928155814_AddWeightToProductVariants', '9.0.9');
COMMIT;

181
deploy-db-fix.sh Normal file
View File

@ -0,0 +1,181 @@
#!/bin/bash
# Deployment Database Fix Script
# This script helps fix database schema issues on the deployed server
echo "================================================"
echo "LittleShop Database Schema Fix"
echo "================================================"
echo ""
# Configuration
DB_FILE="littleshop.db"
BACKUP_DIR="db-backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Function to check if database exists
check_database() {
if [ ! -f "$DB_FILE" ]; then
echo -e "${RED}Error: Database file $DB_FILE not found!${NC}"
echo "Please ensure you're running this script in the correct directory."
exit 1
fi
echo -e "${GREEN}✓ Database file found: $DB_FILE${NC}"
}
# Function to create backup
create_backup() {
echo -e "${YELLOW}Creating backup...${NC}"
# Create backup directory if it doesn't exist
mkdir -p "$BACKUP_DIR"
# Create backup with timestamp
BACKUP_FILE="$BACKUP_DIR/littleshop_${TIMESTAMP}.db"
cp "$DB_FILE" "$BACKUP_FILE"
if [ -f "$BACKUP_FILE" ]; then
echo -e "${GREEN}✓ Backup created: $BACKUP_FILE${NC}"
else
echo -e "${RED}Error: Failed to create backup!${NC}"
exit 1
fi
}
# Function to check current schema
check_schema() {
echo -e "${YELLOW}Checking current database schema...${NC}"
# Check if migrations table exists
MIGRATIONS_TABLE=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='__EFMigrationsHistory';")
if [ "$MIGRATIONS_TABLE" -eq "0" ]; then
echo -e "${YELLOW}! Migrations table not found - database may need full initialization${NC}"
else
echo -e "${GREEN}✓ Migrations table exists${NC}"
# List applied migrations
echo ""
echo "Applied migrations:"
sqlite3 "$DB_FILE" "SELECT MigrationId FROM __EFMigrationsHistory ORDER BY MigrationId;"
fi
# Check for key tables
echo ""
echo "Checking core tables..."
TABLES_TO_CHECK=("Products" "Orders" "Users" "Categories" "Customers" "ProductMultiBuys" "SystemSettings" "VariantCollections" "ProductVariants" "SalesLedger" "PushSubscriptions")
for table in "${TABLES_TO_CHECK[@]}"; do
EXISTS=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='$table';")
if [ "$EXISTS" -eq "1" ]; then
COUNT=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM $table;")
echo -e "${GREEN}$table exists (rows: $COUNT)${NC}"
else
echo -e "${YELLOW}$table missing${NC}"
fi
done
}
# Function to apply migration
apply_migration() {
echo ""
echo -e "${YELLOW}Applying migration scripts...${NC}"
# Check which migration file to use
if [ -f "safe-migration.sql" ]; then
echo "Using safe-migration.sql"
MIGRATION_FILE="safe-migration.sql"
elif [ -f "apply-migration.sql" ]; then
echo "Using apply-migration.sql"
MIGRATION_FILE="apply-migration.sql"
elif [ -f "LittleShop/apply-migration.sql" ]; then
echo "Using LittleShop/apply-migration.sql"
MIGRATION_FILE="LittleShop/apply-migration.sql"
else
echo -e "${RED}Error: No migration file found!${NC}"
echo "Please ensure safe-migration.sql or apply-migration.sql is in the current directory."
exit 1
fi
# Apply the migration
echo "Applying $MIGRATION_FILE..."
OUTPUT=$(sqlite3 "$DB_FILE" < "$MIGRATION_FILE" 2>&1)
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Migration applied successfully${NC}"
echo "$OUTPUT"
else
echo -e "${RED}Error applying migration:${NC}"
echo "$OUTPUT"
echo ""
echo -e "${YELLOW}Attempting to restore from backup...${NC}"
cp "$BACKUP_FILE" "$DB_FILE"
echo -e "${GREEN}✓ Database restored from backup${NC}"
exit 1
fi
}
# Function to verify migration
verify_migration() {
echo ""
echo -e "${YELLOW}Verifying migration...${NC}"
# Check migrations table
MIGRATION_COUNT=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM __EFMigrationsHistory;" 2>/dev/null)
if [ -z "$MIGRATION_COUNT" ] || [ "$MIGRATION_COUNT" -eq "0" ]; then
echo -e "${RED}Warning: No migrations found in history${NC}"
else
echo -e "${GREEN}$MIGRATION_COUNT migrations registered${NC}"
fi
# Final schema check
echo ""
echo "Final schema status:"
check_schema
}
# Main execution
main() {
echo "This script will:"
echo "1. Create a backup of your database"
echo "2. Check the current schema"
echo "3. Apply missing migrations"
echo "4. Verify the results"
echo ""
read -p "Continue? (y/n): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 1
fi
# Execute steps
check_database
create_backup
check_schema
apply_migration
verify_migration
echo ""
echo -e "${GREEN}================================================${NC}"
echo -e "${GREEN}Database migration completed successfully!${NC}"
echo -e "${GREEN}================================================${NC}"
echo ""
echo "Next steps:"
echo "1. Test the application to ensure it works correctly"
echo "2. If issues occur, restore from: $BACKUP_FILE"
echo ""
}
# Run main function
main

142
safe-migration.sql Normal file
View File

@ -0,0 +1,142 @@
-- Safe Migration Script for LittleShop Database
-- This script can be safely run on an existing database
-- It will check for existing objects before creating them
-- Create the EF Migrations History table if it doesn't exist
CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
"MigrationId" TEXT NOT NULL CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY,
"ProductVersion" TEXT NOT NULL
);
-- Check and fix any schema issues with existing tables
-- 1. Check if ProductMultiBuys table exists (from migration 20250922025753_AddProductMultiBuysTable)
CREATE TABLE IF NOT EXISTS "ProductMultiBuys" (
"Id" TEXT NOT NULL CONSTRAINT "PK_ProductMultiBuys" PRIMARY KEY,
"ProductId" TEXT NOT NULL,
"Quantity" INTEGER NOT NULL,
"Price" decimal(18,2) NOT NULL,
"Description" TEXT NOT NULL,
"IsActive" INTEGER NOT NULL DEFAULT 1,
CONSTRAINT "FK_ProductMultiBuys_Products_ProductId" FOREIGN KEY ("ProductId") REFERENCES "Products" ("Id") ON DELETE CASCADE
);
-- 2. Check if SystemSettings table exists (from migration 20250922040637_AddSystemSettingsTable)
CREATE TABLE IF NOT EXISTS "SystemSettings" (
"Id" TEXT NOT NULL CONSTRAINT "PK_SystemSettings" PRIMARY KEY,
"Key" TEXT NOT NULL,
"Value" TEXT NOT NULL,
"Type" TEXT NOT NULL,
"Description" TEXT NULL,
"IsReadOnly" INTEGER NOT NULL DEFAULT 0,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL
);
-- Create unique index if it doesn't exist
CREATE UNIQUE INDEX IF NOT EXISTS "IX_SystemSettings_Key" ON "SystemSettings" ("Key");
-- 3. Check if VariantCollections table exists (from migration 20250928014850_AddVariantCollectionsAndSalesLedger)
CREATE TABLE IF NOT EXISTS "VariantCollections" (
"Id" TEXT NOT NULL CONSTRAINT "PK_VariantCollections" PRIMARY KEY,
"Name" TEXT NOT NULL,
"Description" TEXT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
"IsActive" INTEGER NOT NULL DEFAULT 1
);
-- 4. Check if ProductVariants table exists
CREATE TABLE IF NOT EXISTS "ProductVariants" (
"Id" TEXT NOT NULL CONSTRAINT "PK_ProductVariants" PRIMARY KEY,
"CollectionId" TEXT NOT NULL,
"Sku" TEXT NOT NULL,
"Options" TEXT NOT NULL,
"PriceAdjustment" decimal(18,2) NOT NULL DEFAULT 0,
"QuantityInStock" INTEGER NOT NULL DEFAULT 0,
"Weight" TEXT NULL,
"WeightUnit" INTEGER NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
"IsActive" INTEGER NOT NULL DEFAULT 1,
CONSTRAINT "FK_ProductVariants_VariantCollections_CollectionId" FOREIGN KEY ("CollectionId") REFERENCES "VariantCollections" ("Id") ON DELETE CASCADE
);
-- 5. Check if SalesLedger table exists
CREATE TABLE IF NOT EXISTS "SalesLedger" (
"Id" TEXT NOT NULL CONSTRAINT "PK_SalesLedger" PRIMARY KEY,
"OrderId" TEXT NOT NULL,
"TransactionType" INTEGER NOT NULL,
"PaymentMethod" TEXT NULL,
"Amount" decimal(18,2) NOT NULL,
"Tax" decimal(18,2) NOT NULL DEFAULT 0,
"Discount" decimal(18,2) NOT NULL DEFAULT 0,
"NetAmount" decimal(18,2) NOT NULL,
"Currency" TEXT NOT NULL DEFAULT 'GBP',
"ExchangeRate" decimal(18,8) NOT NULL DEFAULT 1,
"TransactionDate" TEXT NOT NULL,
"RecordedAt" TEXT NOT NULL,
"Description" TEXT NULL,
"Reference" TEXT NULL,
"Status" INTEGER NOT NULL,
"ReconciledAt" TEXT NULL,
"ReconciledBy" TEXT NULL,
"Notes" TEXT NULL,
CONSTRAINT "FK_SalesLedger_Orders_OrderId" FOREIGN KEY ("OrderId") REFERENCES "Orders" ("Id") ON DELETE CASCADE
);
-- 6. Add Weight columns to ProductVariants if they don't exist (migration 20250928155814_AddWeightToProductVariants)
-- SQLite doesn't support conditional column addition, so we need to handle this differently
-- This would need to be done programmatically or by checking the schema first
-- 7. Check if PushSubscriptions table exists
CREATE TABLE IF NOT EXISTS "PushSubscriptions" (
"Id" TEXT NOT NULL CONSTRAINT "PK_PushSubscriptions" PRIMARY KEY,
"UserId" TEXT NOT NULL,
"Endpoint" TEXT NOT NULL,
"P256dh" TEXT NOT NULL,
"Auth" TEXT NOT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
"IsActive" INTEGER NOT NULL DEFAULT 1,
CONSTRAINT "FK_PushSubscriptions_Users_UserId" FOREIGN KEY ("UserId") REFERENCES "Users" ("Id") ON DELETE CASCADE
);
-- Insert migration history records if they don't exist
INSERT OR IGNORE INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20250922025753_AddProductMultiBuysTable', '9.0.9');
INSERT OR IGNORE INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20250922040637_AddSystemSettingsTable', '9.0.9');
INSERT OR IGNORE INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20250928014850_AddVariantCollectionsAndSalesLedger', '9.0.9');
INSERT OR IGNORE INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20250928155814_AddWeightToProductVariants', '9.0.9');
-- Add any missing columns to existing tables
-- Note: SQLite has limitations with ALTER TABLE, so some changes may require table recreation
-- Ensure all necessary indexes exist
CREATE INDEX IF NOT EXISTS "IX_ProductMultiBuys_ProductId" ON "ProductMultiBuys" ("ProductId");
CREATE UNIQUE INDEX IF NOT EXISTS "IX_ProductMultiBuys_ProductId_Quantity" ON "ProductMultiBuys" ("ProductId", "Quantity");
CREATE INDEX IF NOT EXISTS "IX_ProductVariants_CollectionId" ON "ProductVariants" ("CollectionId");
CREATE UNIQUE INDEX IF NOT EXISTS "IX_ProductVariants_Sku" ON "ProductVariants" ("Sku");
CREATE INDEX IF NOT EXISTS "IX_SalesLedger_OrderId" ON "SalesLedger" ("OrderId");
CREATE INDEX IF NOT EXISTS "IX_SalesLedger_TransactionDate" ON "SalesLedger" ("TransactionDate");
CREATE INDEX IF NOT EXISTS "IX_PushSubscriptions_UserId" ON "PushSubscriptions" ("UserId");
-- Verify core tables exist
SELECT CASE
WHEN (SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='Products') = 0
THEN RAISE(ABORT, 'Products table missing - database may need initialization')
WHEN (SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='Orders') = 0
THEN RAISE(ABORT, 'Orders table missing - database may need initialization')
WHEN (SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='Users') = 0
THEN RAISE(ABORT, 'Users table missing - database may need initialization')
ELSE 'Schema verification passed'
END;
-- Output success message
SELECT 'Migration completed successfully' AS Result;