feat: complete pre-launch audit — frontend polish, churn prevention, login history, financial reports, configurable checkout

Includes all work from phases 6-9+ and frontend polish rounds 1 & 2:

- Login history with device trust, new device notifications, session management
- Churn prevention: cancellation surveys, winback campaigns with email sequences
- Financial reports: revenue, P&L, tax, aging, refund, subscription reports with PDF/CSV/JSON export
- Configurable checkout: plan config groups/options, build-your-own VPS
- Frontend polish: fix broken legal links, add SEO meta tags, favicon, font display=swap,
  Head titles on all 14 marketing pages, mobile responsive fixes, AuthLayout legal footer,
  remove false 24/7 claims, hide empty stats, correct uptime SLA to 99.9%,
  GameServers notify buttons linked to /contact, 301 redirects for /terms and /privacy
- WHMCS migration scripts
- Update legal page effective dates to March 16, 2026

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Dev
2026-03-16 11:39:25 -04:00
parent 5be235d35e
commit b4ef90465c
187 changed files with 27317 additions and 1840 deletions

View File

@@ -0,0 +1,163 @@
<?php
declare(strict_types=1);
namespace WhmcsMigrate;
final class StatusMapper
{
/**
* Map WHMCS client status to EZSCALE user status.
*/
public static function mapClientStatus(string $whmcsStatus): string
{
return match ($whmcsStatus) {
'Active' => 'active',
'Inactive' => 'suspended',
'Closed' => 'banned',
default => 'suspended',
};
}
/**
* Map WHMCS service/hosting status to EZSCALE service status.
*/
public static function mapServiceStatus(string $whmcsStatus): string
{
return match ($whmcsStatus) {
'Active' => 'active',
'Suspended' => 'suspended',
'Terminated' => 'terminated',
'Cancelled' => 'terminated',
'Pending' => 'pending',
default => 'pending',
};
}
/**
* Map WHMCS invoice status to EZSCALE invoice status.
*/
public static function mapInvoiceStatus(string $whmcsStatus): string
{
return match ($whmcsStatus) {
'Paid' => 'paid',
'Unpaid' => 'pending',
'Overdue' => 'overdue',
'Cancelled' => 'void',
'Refunded' => 'refunded',
'Draft' => 'draft',
default => 'pending',
};
}
/**
* Map WHMCS billing cycle to EZSCALE billing cycle.
*/
public static function mapBillingCycle(string $whmcsCycle): string
{
return match ($whmcsCycle) {
'Monthly' => 'monthly',
'Quarterly' => 'quarterly',
'Semi-Annually' => 'semi_annual',
'Annually' => 'annual',
'Biennially' => 'annual',
'Triennially' => 'annual',
'Free Account' => 'monthly',
'One Time' => 'monthly',
default => 'monthly',
};
}
/**
* Map WHMCS service status to Stripe subscription status.
*/
public static function mapStripeStatus(string $whmcsServiceStatus): string
{
return match ($whmcsServiceStatus) {
'Active' => 'active',
'Suspended' => 'past_due',
'Terminated' => 'canceled',
'Cancelled' => 'canceled',
'Pending' => 'incomplete',
default => 'incomplete',
};
}
/**
* Map WHMCS payment gateway module name to EZSCALE gateway identifier.
*/
public static function mapGateway(string $whmcsGateway): string
{
$normalized = strtolower(trim($whmcsGateway));
return match (true) {
str_contains($normalized, 'paypal') => 'paypal',
str_contains($normalized, 'stripe') => 'stripe',
str_contains($normalized, 'bank') => 'stripe',
str_contains($normalized, 'transfer') => 'stripe',
str_contains($normalized, 'credit') => 'stripe',
$normalized === '' => 'stripe',
default => 'stripe',
};
}
/**
* Heuristically map a WHMCS product group name (and optionally product name) to an EZSCALE service type.
*/
public static function mapServiceType(string $groupName, string $productName = ''): string
{
// Try group name first
$normalized = strtolower(trim($groupName));
if ($normalized !== '' && $normalized !== 'none') {
return match (true) {
str_contains($normalized, 'mysql') => 'mysql',
str_contains($normalized, 'veeam') || str_contains($normalized, 'backup') => 'backups',
str_contains($normalized, 'vps') || str_contains($normalized, 'cloud') || str_contains($normalized, 'virtual') => 'vps',
str_contains($normalized, 'dedicated') => 'dedicated',
str_contains($normalized, 'web') || str_contains($normalized, 'hosting') || str_contains($normalized, 'cpanel') => 'hosting',
str_contains($normalized, 'game') || str_contains($normalized, 'minecraft') || str_contains($normalized, 'rust') => 'game_server',
default => 'vps',
};
}
// Fall back to product name heuristics
$name = strtolower(trim($productName));
return match (true) {
// MySQL hosting
str_contains($name, 'mysql') => 'mysql',
// Backup services (Veeam, etc.)
str_contains($name, 'veeam') || str_contains($name, 'backup') => 'backups',
// Dedicated servers: Dell, HP, Storage Server with bay counts
str_contains($name, 'dell r') || str_contains($name, 'hp dl') || str_contains($name, 'storage server') => 'dedicated',
// VPS products
str_contains($name, 'vps') || str_contains($name, 'cloud') || str_contains($name, 'virtual') => 'vps',
// Game server related
str_contains($name, 'battlefield') || str_contains($name, 'procon') || str_contains($name, 'game') || str_contains($name, 'minecraft') => 'game_server',
// Managed dedicated
str_contains($name, 'managed dedicated') => 'dedicated',
// Web hosting tiers
str_contains($name, 'hosting') || str_contains($name, 'cpanel') => 'hosting',
default => 'other',
};
}
/**
* Map an EZSCALE service type to its provisioning platform.
*
* Returns null for service types that have no auto-provisioning platform.
*/
public static function mapPlatform(string $serviceType): ?string
{
return match ($serviceType) {
'vps' => 'virtfusion',
'dedicated' => 'synergycp',
'hosting' => 'enhance',
'game_server' => 'pterodactyl',
'mysql' => null,
'backups' => null,
default => 'virtfusion',
};
}
}