From c74ca7f5547c0d600f0335a4658f54852166b6f3fb719d702391495b8a266614 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 26 Apr 2026 20:03:34 -0400 Subject: [PATCH] feat(dedicated): add PCIe NVMe Add-in group (Sabrent adapter combos) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New separate-category config group for stacking high-performance M.2 NVMe storage in any free PCIe slot, on top of the bay-attached drives. Doesn't compete with bay drives — uses PCIe slots independently. Two adapter paths: - Sabrent EC-PCIE (\$17.98) — single M.2 NVMe in any PCIe x4+ slot - Sabrent EC-P4BF (\$99.99) — 4× M.2 NVMe in one PCIe 4.0 x16 slot, requires PCIe bifurcation support (R440/R540/R640/R740 verified; R740xd LFF rear PCIe may need check at build time) 10 curated combos + "None" default. Pricing: 12-month payback × 1.5x markup on (Sabrent retail drive cost + adapter cost). Single-drive (EC-PCIE): 1× 1 TB Rocket 4 Plus +\$35 1× 2 TB Rocket 4 Plus +\$40 1× 4 TB Rocket 4 Plus +\$115 1× 8 TB Rocket 4 Plus +\$465 1× 2 TB Rocket 5 Gen5 +\$65 1× 4 TB Rocket 5 Gen5 +\$180 4-drive bifurcation (EC-P4BF): 4× 1 TB Rocket 4 Plus +\$140 4× 2 TB Rocket 4 Plus +\$160 4× 4 TB Rocket 4 Plus +\$455 4× 8 TB Rocket 4 Plus +\$1,865 (extreme density, ~32 TB raw) Drive prices scraped from Sabrent's Shopify product JSON (/products/{slug}.json) on 2026-04-26. Attached to LFF + SFF chassis (R440 / R540 / R640 / R740 / R740xd SFF / R740xd LFF). Skip on R640 NVMe / R740xd NVMe — those chassis route all PCIe lanes to the U.2 backplane, so no slots are free for add-in cards. Tests: bumped group count to 11; added a test verifying chassis attachment correctness. 15/15 pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../database/seeders/ConfigOptionSeeder.php | 46 +++++++++++++++++++ .../Marketing/DedicatedServersTest.php | 19 +++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/website/database/seeders/ConfigOptionSeeder.php b/website/database/seeders/ConfigOptionSeeder.php index 6580575..8b7641f 100644 --- a/website/database/seeders/ConfigOptionSeeder.php +++ b/website/database/seeders/ConfigOptionSeeder.php @@ -533,6 +533,52 @@ class ConfigOptionSeeder extends Seeder $gen14PrivateNet->plans()->syncWithoutDetaching($gen14AllPlans); + // ─── Dedicated 14th Gen — PCIe NVMe Add-in ────────────────────── + // Separate category from bay-attached drives — uses empty PCIe slots + // via Sabrent EC-PCIE (single-drive) or EC-P4BF (4-drive bifurcation + // x16) adapter cards. Customers can stack this on top of bay drives + // for fast scratch / cache / metadata storage. + // Pricing: 12-month payback × 1.5x markup on (Sabrent retail drive + // cost + adapter cost). Drive prices scraped from sabrent.com on + // 2026-04-26: Rocket 4 Plus 1TB \$249.99 / 2TB \$289.99 / 4TB \$879.99 + // / 8TB \$3,699.99; Rocket 5 Gen5 1TB \$400 / 2TB \$499.99 / 4TB \$1,400. + // Adapters: EC-PCIE \$17.98, EC-P4BF \$99.99. + $gen14PciNvme = PlanConfigGroup::updateOrCreate( + ['name' => 'Dedicated 14th Gen — PCIe NVMe Add-in'], + [ + 'description' => 'Add high-performance M.2 NVMe storage in any free PCIe slot via Sabrent adapter cards. Single-drive (EC-PCIE) fits any x4+ slot; 4-drive (EC-P4BF) needs an x16 slot with bifurcation support.', + 'mode' => 'preset', + 'service_type' => 'dedicated', + 'is_active' => true, + 'sort_order' => 47, + ], + ); + + $gen14PciNvmeOption = $this->seedRadioOption($gen14PciNvme, 'PCIe NVMe Add-in', false, 1); + $this->seedValues($gen14PciNvmeOption, [ + ['label' => 'No PCIe NVMe add-in', 'value' => 'none', 'monthly' => 0, 'is_default' => true], + // Single-drive via EC-PCIE adapter (Gen4) + ['label' => '1× 1 TB Rocket 4 Plus M.2 NVMe (EC-PCIE)', 'value' => '1x1tb-r4p-pcie', 'monthly' => 35.00], + ['label' => '1× 2 TB Rocket 4 Plus M.2 NVMe (EC-PCIE)', 'value' => '1x2tb-r4p-pcie', 'monthly' => 40.00], + ['label' => '1× 4 TB Rocket 4 Plus M.2 NVMe (EC-PCIE)', 'value' => '1x4tb-r4p-pcie', 'monthly' => 115.00], + ['label' => '1× 8 TB Rocket 4 Plus M.2 NVMe (EC-PCIE)', 'value' => '1x8tb-r4p-pcie', 'monthly' => 465.00], + // Single-drive Gen5 via EC-PCIE + ['label' => '1× 2 TB Rocket 5 Gen5 M.2 NVMe (EC-PCIE)', 'value' => '1x2tb-r5-pcie', 'monthly' => 65.00], + ['label' => '1× 4 TB Rocket 5 Gen5 M.2 NVMe (EC-PCIE)', 'value' => '1x4tb-r5-pcie', 'monthly' => 180.00], + // 4-drive bifurcation via EC-P4BF (requires PCIe x16 + bifurcation) + ['label' => '4× 1 TB Rocket 4 Plus M.2 NVMe (EC-P4BF)', 'value' => '4x1tb-r4p-p4bf', 'monthly' => 140.00], + ['label' => '4× 2 TB Rocket 4 Plus M.2 NVMe (EC-P4BF)', 'value' => '4x2tb-r4p-p4bf', 'monthly' => 160.00], + ['label' => '4× 4 TB Rocket 4 Plus M.2 NVMe (EC-P4BF)', 'value' => '4x4tb-r4p-p4bf', 'monthly' => 455.00], + ['label' => '4× 8 TB Rocket 4 Plus M.2 NVMe (EC-P4BF)', 'value' => '4x8tb-r4p-p4bf', 'monthly' => 1865.00], + ]); + + // Attach to LFF + SFF chassis (have free PCIe slots). Skip on the + // U.2 NVMe-native chassis since they don't have PCIe slots free + // for add-in cards (lanes are routed to the U.2 backplane). + $gen14PciNvmeSlugs = ['r440-4lff', 'r540-8lff', 'r640-8sff', 'r740-16sff', 'r740xd-24sff', 'r740xd-12lff']; + $gen14PciNvmePlans = Plan::query()->whereIn('slug', $gen14PciNvmeSlugs)->pluck('id'); + $gen14PciNvme->plans()->syncWithoutDetaching($gen14PciNvmePlans); + // ─── 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 79a2483..4044541 100644 --- a/website/tests/Feature/Marketing/DedicatedServersTest.php +++ b/website/tests/Feature/Marketing/DedicatedServersTest.php @@ -148,13 +148,13 @@ test('1.5 TB RAM is filtered out for chassis with 16 DIMM slots', function (): v } }); -test('seeder creates the 10 dedicated 14th-gen config groups', function (): void { +test('seeder creates the 11 dedicated 14th-gen config groups', function (): void { $names = PlanConfigGroup::query() ->where('name', 'like', 'Dedicated 14th Gen%') ->pluck('name') ->all(); - expect(count($names))->toBe(10); + expect(count($names))->toBe(11); 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'); @@ -162,11 +162,26 @@ test('seeder creates the 10 dedicated 14th-gen config groups', function (): void 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 — PCIe NVMe Add-in'); 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'); }); +test('PCIe NVMe Add-in attaches only to LFF + SFF chassis, not pure-NVMe', function (): void { + foreach (['r440-4lff', 'r540-8lff', 'r640-8sff', 'r740-16sff', 'r740xd-24sff', 'r740xd-12lff'] as $slug) { + $response = $this->get("/dedicated-servers/{$slug}"); + $names = collect($response->viewData('page')['props']['configGroups'])->pluck('name'); + expect($names)->toContain('Dedicated 14th Gen — PCIe NVMe Add-in'); + } + + foreach (['r640-10nvme', 'r740xd-24nvme'] as $slug) { + $response = $this->get("/dedicated-servers/{$slug}"); + $names = collect($response->viewData('page')['props']['configGroups'])->pluck('name'); + expect($names)->not->toContain('Dedicated 14th Gen — PCIe NVMe Add-in'); + } +}); + test('drive bay options are filtered to those that fit chassis bay count', function (): void { // R440 has 4 LFF bays — combos requiring more bays should be hidden. $r440Response = $this->get('/dedicated-servers/r440-4lff');