# Dedicated Server Lineup — Design Spec **Date:** 2026-04-26 **Status:** Approved (skip user-review gate per owner override — implementation starting immediately) **Owner:** Andrew **Repo:** `EZSCALE/website` ## Goals 1. Ship the **new Dell 14th-gen dedicated server lineup** (8 chassis SKUs sourced from SaveMyServer per order) on `/dedicated-servers`. 2. Re-surface the **existing 12th/13th-gen rack inventory** (currently `status: hidden` in the seeder) so it's visible alongside the new line as instant-deploy "in stock" SKUs. 3. Build an interactive **per-chassis configurator** at `/dedicated-servers/{slug}` covering CPU, RAM, per-bay drives, OS, bandwidth, networking, IPv4. 4. Add a **5-stage post-order build status tracker** (Ordered → Hardware acquired → Assembly → Racked → Deployed) visible to the customer and editable by admins. 5. Wire **tiered setup fees** that waive automatically on Semi-Annual / Annual cycles. ## Non-goals (deferred) - **C from Q6: Two-preset cards** (`Starter` + `Performance` per chassis) — v1.1, after first-month signal on what people actually buy - **Workload bundles page** — v2 if pricing-positioning-vs-budget-bundlers keeps coming up in support - **Automated SaveMyServer order placement** — admin-driven for v1 - **Live capacity check at order time** — buffer-stock model not in v1 - **Multi-region (currently Atlanta-only)** — `Location` selector renders but only has one option - **Custom-quote builder for non-catalog requests** — uses existing `/contact` form - **Hetzner comparison rows** — placeholder; fills in when separate research lands ## Sources of truth | Asset | Path | Role | |---|---|---| | Catalog JSON | `docs/integrations/savemyserver/dedicated-server-catalog.json` | 27 raw SaveMyServer products, drive options, BOM costs | | Build sheets | `../infrastructure/docs/dedicated-server-configurations.md` | Curated 8-product BOMs, EZSCALE Standard Build (locked baseline) | | Pricing | `../infrastructure/docs/dedicated-server-pricing-2026q2.md` | Customer-facing monthly prices, margin math, drive add-on tables | | Configurator design | `../infrastructure/docs/superpowers/specs/2026-04-24-dedicated-server-gen14-configurator-design.md` | 15 configurable option groups, cross-server compliance matrix | | Competitor research | `../infrastructure/docs/competitors-atlanta-2026.md` | ColoCrossing/GTHost positioning baseline | | Rack reality | `../infrastructure/docs/reference/rack-atl.md` | Existing customer-rentable rack slots | ## EZSCALE Standard Build (locked baseline — applies to all 8 14th-gen chassis) Non-negotiable per `dedicated-server-configurations.md`: | Component | Selection | |---|---| | CPU | 2× Intel Xeon Gold 6230 (40C / 2.10 GHz) | | RAM | 32 GB DDR4-2666 ECC RDIMM (2× 16 GB) | | Boot | Dell BOSS Card with 2× 240 GB M.2 SSDs (mirrored) — **all main bays free for data** | | Storage controller | PERC HBA330 (Non-RAID, IT mode) — N/A on R740xd NVMe (pure-PCIe) | | iDRAC | iDRAC9 Enterprise License | | Power | Dual redundant PSU | | Network | 1× 1 GbE onboard + 1× 10 Gbps SFP+ | | Drive trays | Pre-installed in every bay | | OS | No OS (customer choice via post-provisioning panel) | | Bandwidth | 1 Gbps unmetered uplink | | IPv4 | 1× included | | IPv6 | /64 included | ## The 8 14th-gen chassis | Slug | Title | Form | Bays | Std build cost | Starting $/mo | Setup tier | |---|---|---|---|---|---|---| | `r440-4lff` | R440 4-Bay 3.5" LFF (1U) | 1U | 4× LFF | $1,690.61 | $119 | 2 ($349) | | `r540-8lff` | R540 8-Bay 3.5" LFF (2U) | 2U | 8× LFF | $1,877.03 | $159 | 3 ($549) | | `r640-8sff` | R640 8-Bay 2.5" SFF (1U) | 1U | 8× SFF | $1,411.83 | $179 | 2 ($349) | | `r740-16sff` | R740 16-Bay 2.5" SFF (2U) | 2U | 16× SFF | $1,704.26 | $229 | 3 ($549) | | `r740xd-24sff` | R740xd 24-Bay 2.5" SFF (2U) | 2U | 24× SFF | $1,919.73 | $279 | 3 ($549) | | `r740xd-12lff` | R740xd 12-Bay 3.5" LFF (2U) | 2U | 12× LFF | $2,148.96 | $249 | 3 ($549) | | `r640-10nvme` | R640 10-Bay U.2 NVMe (1U) | 1U | 10× NVMe | $1,606.79 | $239 | 4 ($799) | | `r740xd-24nvme` | R740xd 24-Bay U.2 NVMe (2U) | 2U | 24× NVMe | $2,275.44 | $279 | 4 ($799) | Setup tiers (per Q5 brainstorm): | Tier | Chassis class | Setup fee | |---|---|---| | 1 | Single-socket Budget (R240/R340) — *not in v1 lineup* | $149 | | 2 | Dual-socket 1U | $349 | | 3 | Dual-socket 2U | $549 | | 4 | NVMe / Quad-socket Enterprise | $799 | **Setup fee waived on Semi-Annual (6 mo) and Annual (12 mo) cycles. Non-refundable once hardware is purchased** (typically within 24h of order). Rental fees stay under the 14-day money-back guarantee. ## Architecture ### Routes ``` /dedicated-servers ← catalog landing (chassis grid) /dedicated-servers/{slug} ← per-chassis detail + configurator account./services/{service} ← existing route, gets BuildStatusPanel admin./orders/{order}/build ← admin milestone updater ``` ### Database **1. Migration: `add_setup_fee_to_plans_table`** ```php $table->decimal('setup_fee', 10, 2)->default(0)->after('price'); ``` **2. Migration: `create_service_build_milestones_table`** ```php Schema::create('service_build_milestones', function (Blueprint $table): void { $table->id(); $table->foreignId('subscription_id')->constrained()->cascadeOnDelete(); $table->string('stage'); // 'ordered' | 'hardware_acquired' | 'assembly' | 'racked' | 'deployed' $table->timestamp('reached_at')->nullable(); $table->text('note')->nullable(); $table->foreignId('updated_by')->nullable()->constrained('users'); $table->timestamps(); $table->unique(['subscription_id', 'stage']); }); ``` **3. PlanSeeder updates** - Re-enable existing 12th/13th-gen rows: `status: hidden` → `status: active`. Stock counts preserved. - Insert 8 new 14th-gen rows with: `features` JSON containing `cpu`, `ram`, `storage`, `bays`, `tier` (chassis tier number), `lead_time_days: '7-10'`, `generation: '14th-gen'`. Setup fee per the table above. **4. ConfigOptionSeeder updates** Add a `Dedicated Gen14 Configurator` group cluster per `2026-04-24-dedicated-server-gen14-configurator-design.md`: - `dedicated_server_gen14_cpu` (standard CPU group — R440/R540/R640/R740) - `dedicated_server_gen14_cpu_r740xd` (R740xd-only CPU group) - `dedicated_server_gen14_ram` (RAM tiers) - `dedicated_server_gen14_os` (OS selector) - `dedicated_server_gen14_bandwidth` (bandwidth tiers) - `dedicated_server_gen14_networking` (private networking add-on) - `dedicated_server_gen14_ipv4` (IPv4 block size) - `dedicated_server_gen14_location` (Atlanta only for v1) - `dedicated_server_gen14_lff_bays_1_4` (drive selection bays 1-4 LFF) - `dedicated_server_gen14_lff_bays_5_8` (drive selection bays 5-8 LFF) - `dedicated_server_gen14_r740xd_lff_bays` (R740xd 12-bay LFF) - `dedicated_server_gen14_sff_slots_1_8` (SFF slots 1-8) - `dedicated_server_gen14_sff_slots_9_16` (SFF slots 9-16, R740 only) - `dedicated_server_gen14_sff_slots_17_24` (SFF slots 17-24, R740xd SFF only) - `dedicated_server_gen14_nvme_slots` (U.2 NVMe slots) Attach each sub-group only to applicable chassis per the cross-server compliance matrix. ### Frontend file map ``` resources/ts/Pages/Marketing/ ├─ DedicatedServers.vue (REWRITE) └─ DedicatedServerDetail.vue (NEW) resources/ts/Pages/Account/Services/ └─ Show.vue (extend with BuildStatusPanel) resources/ts/Pages/Admin/Orders/ └─ BuildTracker.vue (NEW) resources/ts/Components/Marketing/Dedicated/ ├─ ChassisCard.vue (NEW) ├─ GenerationFilter.vue (NEW) ├─ DedicatedConfigurator/ │ ├─ index.vue │ ├─ CpuSelector.vue │ ├─ RamSelector.vue │ ├─ DriveBayPicker.vue │ ├─ OsSelector.vue │ ├─ BandwidthSelector.vue │ ├─ NetworkingSelector.vue │ ├─ Ipv4Selector.vue │ └─ ConfiguratorFooter.vue └─ BuildStatusPanel.vue (used by both customer + admin) resources/ts/stores/ └─ dedicatedConfigurator.ts (NEW Pinia store) ``` ### Pinia state ```ts state = { chassis: Plan | null, cpu: string, ramGb: number, // 32, 64, 128, 256, 512, 1024, 1536 bays: Array, os: string, bandwidth: string, privateNetworking: boolean, ipv4: 1 | 5 | 13 | 29, cycle: 'monthly' | 'quarterly' | 'semi_annual' | 'annual', } getters = { baselinePrice, cpuUpgradeCost, ramUpgradeCost, driveCost, bandwidthCost, ipv4Cost, cycleSubtotal, setupFee, cycleTotal, shareUrl, checkoutUrl, } ``` ### URL state contract `/dedicated-servers/{slug}?` and `/checkout/{plan_id}?` share: | Param | Values | Default | |---|---|---| | `cpu` | option value slug | baseline | | `ram` | `32` `64` `128` `256` `512` `1024` `1536` | `32` | | `bays` | comma-list, length = bay count | chassis-specific lean preset | | `os` | `none` `alma9` `ubuntu24` `debian12` `windows-byol` | `none` | | `bw` | `1g-unmetered` `10g-1tb` `10g-10tb` `10g-100tb` `10g-unmetered` | `1g-unmetered` | | `pn` | `0` `1` | `0` | | `ipv4` | `1` `5` `13` `29` | `1` | | `cycle` | `monthly` `quarterly` `semi_annual` `annual` | `monthly` | ### Setup fee flow Setup fee is calculated at checkout based on `plan.setup_fee` and selected cycle: ```php $includesSetupFee = in_array($cycle, ['monthly', 'quarterly']); $setupFee = $includesSetupFee ? $plan->setup_fee : 0; ``` Surfaced as a separate line item on the checkout page with explanatory text. ### Build tracker stages | # | Stage | Triggered by | Customer-visible message | |---|---|---|---| | 1 | `ordered` | Subscription `created` event | "Order received. We're placing the hardware order with our supplier." | | 2 | `hardware_acquired` | Admin click | "Hardware acquired and en route to our datacenter (typically 2-3 days)." | | 3 | `assembly` | Admin click | "Server received in Atlanta. Our DC tech is configuring iDRAC and assembly." | | 4 | `racked` | Admin click | "Server racked, powered up, and online for final QA." | | 5 | `deployed` | Admin click | "Server is live. Root credentials and iDRAC access have been emailed." | The `deployed` milestone flips `subscription.status` from `pending` → `active` and triggers the deployment email. ## Edge cases | Case | Behavior | |---|---| | URL has more bay entries than chassis has bays | Truncate; toast warning | | URL has invalid CPU for the chassis | Fall back to baseline; snackbar | | Subscription cancelled before `hardware_acquired` | Full refund (rental + setup fee) | | Subscription cancelled after `hardware_acquired`, inside 14 days | Pro-rated rental refund; setup fee non-refundable; chassis added to "ready-to-deploy" inventory | | Customer wants off-catalog chassis | "Need something custom?" CTA → `/contact` form | | Mobile (< 768 px) | DriveBayPicker collapses to single-column list; sticky footer docks to viewport bottom | | Browser back/forward | URL hydration restores everything | ## Testing - **Pest** — `tests/Feature/Marketing/DedicatedServersTest.php` and `tests/Feature/Account/BuildTrackerTest.php` - **Vitest** — *deferred (Vitest not currently installed in this project; covered by Playwright + Pest)* - **Playwright** — `tests/e2e/dedicated-configurator.spec.ts` (one happy-path E2E) ## Acceptance criteria - [ ] Migration adds `plans.setup_fee` and `service_build_milestones` table - [ ] PlanSeeder seeds 8 new 14th-gen rows; un-hides existing 12th/13th-gen rows - [ ] ConfigOptionSeeder adds 15 sub-groups under "Dedicated Gen14 Configurator" with chassis-specific attachments - [ ] `/dedicated-servers` lists all dedicated plans (both lines), generation filter works - [ ] `/dedicated-servers/{slug}` works for all 8 new chassis slugs - [ ] Configurator computes correct totals across all option groups - [ ] Setup fee shows on Monthly/Quarterly, hides on Semi-Annual/Annual - [ ] Setup fee non-refundable note on checkout + FAQ - [ ] `Order this configuration` deep-links with all params; checkout pre-selects them - [ ] `Copy share link` works - [ ] BuildStatusPanel renders during build; admin can mark milestones; customer sees timestamps - [ ] `deployed` milestone flips subscription `pending` → `active` - [ ] Pest tests pass - [ ] `npm run build` and `php artisan test --compact` pass - [ ] Mobile layout works without horizontal scroll ## Open implementation questions (deferred to phase work) - Exact RAM upgrade pricing tiers — pull from `dedicated-server-pricing-2026q2.md` at seeder-write time - Exact drive add-on prices per chassis — pull from catalog JSON `drives.drives` array per chassis - Bandwidth tier pricing — pull from `dedicated-server-pricing-2026q2.md` - Hetzner comparison row data — pending separate research