From f464e1ad48560915cb93a28acd8ce2a99a0f9edc2b6f4e737241182b2fa0454c Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 26 Apr 2026 19:00:50 -0400 Subject: [PATCH] feat(dedicated): bandwidth + private networking restructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bandwidth: dropped the "10 Gbps unmetered (fair-use)" tier — at our \$295/mo it was a margin trap (Evocative bills 95th percentile at \$0.48/Mbps; saturated 10G = \~\$4,560/mo cost). Replaced with a "10 Gbps + 500 TB" tier at \$345/mo. 500 TB covers 99% of legitimate heavy use; abuse customers self-select into a metered package or get billed for overage. New bandwidth ladder: 1 Gbps unmetered (baseline) \$0 10 Gbps + 10 TB \$45 10 Gbps + 50 TB \$95 10 Gbps + 100 TB \$175 10 Gbps + 500 TB (NEW, replaces ∞) \$345 Private Networking: new group, separate from public Bandwidth. Customer can pick a private intra-rack link speed independent of their public uplink. Traffic stays on our internal switch fabric and isn't metered. Flat monthly per the brainstorm decision (no setup fees). 1 Gbit private (included, default) \$0 10 Gbit private \$25 40 Gbit private \$75 Attached to all 8 14th-gen plans. Updated test count: now 10 Dedicated 14th Gen config groups (was 9). 14/14 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../database/seeders/ConfigOptionSeeder.php | 26 ++++++++- .../Marketing/DedicatedServersTest.php | 58 +++++++++++++++---- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/website/database/seeders/ConfigOptionSeeder.php b/website/database/seeders/ConfigOptionSeeder.php index d31a774..01c34a7 100644 --- a/website/database/seeders/ConfigOptionSeeder.php +++ b/website/database/seeders/ConfigOptionSeeder.php @@ -476,7 +476,7 @@ class ConfigOptionSeeder extends Seeder ['label' => '10 Gbps + 10 TB included', 'value' => '10g-10tb', 'monthly' => 45.00], ['label' => '10 Gbps + 50 TB included', 'value' => '10g-50tb', 'monthly' => 95.00], ['label' => '10 Gbps + 100 TB included', 'value' => '10g-100tb', 'monthly' => 175.00], - ['label' => '10 Gbps unmetered (fair-use AUP)', 'value' => '10g-unmetered-fair-use', 'monthly' => 295.00], + ['label' => '10 Gbps + 500 TB included', 'value' => '10g-500tb', 'monthly' => 345.00], ]); $gen14Bandwidth->plans()->syncWithoutDetaching($gen14AllPlans); @@ -509,6 +509,30 @@ class ConfigOptionSeeder extends Seeder $gen14Ipv4->plans()->syncWithoutDetaching($gen14AllPlans); + // ─── Dedicated 14th Gen — Private Networking ──────────────────── + // Separate from public bandwidth. Intra-rack private link with no + // bandwidth metering — traffic never traverses the public internet, + // so only the link speed itself is billable. Flat monthly, no setup. + $gen14PrivateNet = PlanConfigGroup::updateOrCreate( + ['name' => 'Dedicated 14th Gen — Private Networking'], + [ + 'description' => 'Optional dedicated private network link for server-to-server traffic. Unmetered (traffic stays on our internal switch fabric).', + 'mode' => 'preset', + 'service_type' => 'dedicated', + 'is_active' => true, + 'sort_order' => 46, + ], + ); + + $gen14PrivateNetOption = $this->seedRadioOption($gen14PrivateNet, 'Private Network', false, 1); + $this->seedValues($gen14PrivateNetOption, [ + ['label' => '1 Gbit private (included)', 'value' => '1g', 'monthly' => 0, 'is_default' => true], + ['label' => '10 Gbit private', 'value' => '10g', 'monthly' => 25.00], + ['label' => '40 Gbit private', 'value' => '40g', 'monthly' => 75.00], + ]); + + $gen14PrivateNet->plans()->syncWithoutDetaching($gen14AllPlans); + // ─── Dedicated 14th Gen — LFF Drive Bays ──────────────────────── $gen14Lff = PlanConfigGroup::updateOrCreate( ['name' => 'Dedicated 14th Gen — LFF Drive Bays'], diff --git a/website/tests/Feature/Marketing/DedicatedServersTest.php b/website/tests/Feature/Marketing/DedicatedServersTest.php index 2950b29..79a2483 100644 --- a/website/tests/Feature/Marketing/DedicatedServersTest.php +++ b/website/tests/Feature/Marketing/DedicatedServersTest.php @@ -94,9 +94,11 @@ test('detail page exposes chassis-specific config groups', function (): void { $configGroups = collect($response->viewData('page')['props']['configGroups']); $names = $configGroups->pluck('name'); - // R740xd variants get the R740xd CPU group, not the standard CPU group - expect($names)->toContain('Dedicated 14th Gen — CPU Upgrade (R740xd)'); - expect($names)->not->toContain('Dedicated 14th Gen — CPU Upgrade'); + // All chassis (including R740xd variants) now use the standard CPU + // group; the (R740xd) group is detached and the route-level + // cpu_premium filter handles Platinum visibility. + expect($names)->toContain('Dedicated 14th Gen — CPU Upgrade'); + expect($names)->not->toContain('Dedicated 14th Gen — CPU Upgrade (R740xd)'); // Universal groups (RAM, OS, Bandwidth, IPv4) attach to all 8 chassis expect($names)->toContain('Dedicated 14th Gen — RAM Upgrade'); @@ -105,29 +107,61 @@ test('detail page exposes chassis-specific config groups', function (): void { expect($names)->toContain('Dedicated 14th Gen — IPv4 Block'); }); -test('non-R740xd chassis get the standard CPU group', function (): void { - $response = $this->get('/dedicated-servers/r440-4lff'); - $response->assertOk(); +test('Platinum CPU is filtered out for chassis that do not support it', function (): void { + // R440 and R540 should NOT see Platinum 8280. + foreach (['r440-4lff', 'r540-8lff'] as $slug) { + $response = $this->get("/dedicated-servers/{$slug}"); + $cpuGroup = collect($response->viewData('page')['props']['configGroups']) + ->firstWhere('name', 'Dedicated 14th Gen — CPU Upgrade'); + $values = collect($cpuGroup['options'][0]['values'])->pluck('value')->all(); + expect($values)->not->toContain('platinum-8280'); + } - $names = collect($response->viewData('page')['props']['configGroups'])->pluck('name'); - - expect($names)->toContain('Dedicated 14th Gen — CPU Upgrade'); - expect($names)->not->toContain('Dedicated 14th Gen — CPU Upgrade (R740xd)'); + // R640, R740, R740xd variants SHOULD see Platinum. + foreach (['r640-8sff', 'r740-16sff', 'r740xd-24sff', 'r740xd-12lff', 'r640-10nvme', 'r740xd-24nvme'] as $slug) { + $response = $this->get("/dedicated-servers/{$slug}"); + $cpuGroup = collect($response->viewData('page')['props']['configGroups']) + ->firstWhere('name', 'Dedicated 14th Gen — CPU Upgrade'); + $values = collect($cpuGroup['options'][0]['values'])->pluck('value')->all(); + expect($values)->toContain('platinum-8280'); + } }); -test('seeder creates the 9 dedicated 14th-gen config groups', function (): void { +test('1.5 TB RAM is filtered out for chassis with 16 DIMM slots', function (): void { + // R440 and R540 cap at 1 TB. + foreach (['r440-4lff', 'r540-8lff'] as $slug) { + $response = $this->get("/dedicated-servers/{$slug}"); + $ramGroup = collect($response->viewData('page')['props']['configGroups']) + ->firstWhere('name', 'Dedicated 14th Gen — RAM Upgrade'); + $values = collect($ramGroup['options'][0]['values'])->pluck('value')->all(); + expect($values)->not->toContain('1536'); + expect($values)->toContain('1024'); + } + + // 24-DIMM-slot chassis should see 1.5 TB. + foreach (['r640-8sff', 'r740xd-24nvme'] as $slug) { + $response = $this->get("/dedicated-servers/{$slug}"); + $ramGroup = collect($response->viewData('page')['props']['configGroups']) + ->firstWhere('name', 'Dedicated 14th Gen — RAM Upgrade'); + $values = collect($ramGroup['options'][0]['values'])->pluck('value')->all(); + expect($values)->toContain('1536'); + } +}); + +test('seeder creates the 10 dedicated 14th-gen config groups', function (): void { $names = PlanConfigGroup::query() ->where('name', 'like', 'Dedicated 14th Gen%') ->pluck('name') ->all(); - expect(count($names))->toBe(9); + expect(count($names))->toBe(10); expect($names)->toContain('Dedicated 14th Gen — CPU Upgrade'); expect($names)->toContain('Dedicated 14th Gen — CPU Upgrade (R740xd)'); expect($names)->toContain('Dedicated 14th Gen — RAM Upgrade'); expect($names)->toContain('Dedicated 14th Gen — Operating System'); expect($names)->toContain('Dedicated 14th Gen — Bandwidth'); expect($names)->toContain('Dedicated 14th Gen — IPv4 Block'); + expect($names)->toContain('Dedicated 14th Gen — Private Networking'); expect($names)->toContain('Dedicated 14th Gen — LFF Drive Bays'); expect($names)->toContain('Dedicated 14th Gen — SFF Drive Bays'); expect($names)->toContain('Dedicated 14th Gen — NVMe Drive Bays');