Commit Graph

110 Commits

Author SHA256 Message Date
dfdef3d7f4 feat: docker compose dev environment
Replaces the bare-metal `composer run dev` workflow with a fully
containerized 9-service stack orchestrated by docker compose. Single
command brings up the full app — three subdomains (marketing /
account / admin) reachable via Traefik with TLS, MariaDB + Valkey
+ Mailpit + Vite HMR + Horizon + scheduler all wired in.

Components:
- docker-compose.yml: traefik, app (php-fpm), web (nginx), mariadb,
  valkey, mailpit, vite, horizon, scheduler.
- docker/: Dockerfiles, nginx config, entrypoint scripts.
- Makefile: convenience targets (up / down / logs / shell / migrate
  / seed / test / pint / etc).
- .env.docker.example: template for Docker-stack environment vars
  (separate from website/.env so bare-metal devs aren't disrupted).
- website/vite.config.ts: server.host / origin / hmr / cors hooks
  driven by VITE_HOST / VITE_ORIGIN / VITE_HMR_HOST so the same
  config serves both bare-metal and Docker.
- website/bootstrap/app.php: redirectGuestsTo() now uses
  request()->getScheme() so http: dev hosts don't get force-https
  redirects.
- composer.json: drops laravel/sail (replaced by this stack).
- docs/superpowers/specs/2026-04-25-docker-compose-dev-environment-design.md:
  full design spec.

Bare-metal `composer run dev` workflow stays usable for anyone who
prefers it — Docker stack reads .env.docker, doesn't fight
website/.env.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 22:10:53 -04:00
4b98e52043 chore: gitignore screenshots, scheduled-tasks lock, playwright cache
Working tree was accumulating debris across sessions:
- Headless-Chrome / visual-companion screenshots in repo root (dozens
  of throwaway PNGs from design iteration)
- .claude/scheduled_tasks.lock from autonomous-loop runs
- .playwright-mcp/ cache from the Playwright MCP server

Adds explicit ignores so these stay local. Intentionally archived
screenshots belong under docs/; the /*.png pattern only catches
root-level debris.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 22:10:27 -04:00
b5a4ba531c feat(dedicated): minimal OS variants, single-open accordion, default Alma 9
Three asks shipped together:

1. Default flipped from AlmaLinux 10 → AlmaLinux 9. Alma 10 stays in
   the picker but isn't pre-selected; 9 is the more battle-tested
   choice for production dedicated workloads.

2. Single-open accordion: openFamilies (Set<string>) → openFamily
   (string). Opening any family closes whichever was previously
   open. Click the open family's header to fully collapse. Watch
   on `props.selected` keeps the active selection's family open on
   first paint and on programmatic selection changes (URL hydration).
   Removed the "Expand all / Collapse all" toggle in the title row —
   redundant under single-open semantics.

3. "Minimal" image variants added for every distro that publishes one
   upstream: AlmaLinux / Rocky / Ubuntu / Debian / Fedora / openSUSE /
   FreeBSD. New labels add a clear "Minimal" suffix; new slugs use
   `-min` suffix (e.g. alma9-min, ubuntu24-min). Proxmox / Windows /
   "No OS" deliberately have no minimal variant — Proxmox is a
   single-flavor hypervisor, Windows is BYOL, "No OS" is a no-op.

Total OS count: 22 → 38 (across 9 families). Reseeded the OS group;
20/20 dedicated tests still pass; npm run build clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 22:07:07 -04:00
bb04a5e3b9 chore(dedicated): refresh OS catalog to April 2026 currents + fix Proxmox color
OS list updated to reflect each project's actual current and supported
versions as of 2026-04 (verified per project release calendars):

Added:
- AlmaLinux 10 (RHEL 10 rebuild, default) — was missing
- Rocky Linux 10 — was missing
- Ubuntu 26.04 LTS (Resolute Raccoon, released Apr 2026) — was missing
- Debian 13 Trixie (current stable since Aug 2025) — was missing;
  bumped from oldstable Debian 12
- openSUSE Leap 16.0 (Oct 2025) — replaces 15.6 (EOLs Apr 30 2026)
- FreeBSD 15.0 (Dec 2025) and 14.4 (Mar 2026) — was a generic "14"
- Proxmox VE 9.1 (Nov 2025) — added alongside 8.4 (security maint
  through Aug 2026)

Removed:
- Debian 11 (LTS ends Aug 2026, dropped to avoid offering near-EOL)
- openSUSE Leap 15.6 (EOLs in 4 days)

Default OS flipped from AlmaLinux 9 → AlmaLinux 10 (current major).

Proxmox logo color: the Wikimedia CoreUI Proxmox SVG was monochrome
(inheriting black). Added fill="#E57000" so the brand orange is
correct.

22 OS options total across 9 distro families. metaFor() in
OsGroupSelector already handles all families via slug prefix —
no component changes needed for the new versions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 21:56:26 -04:00
c5e9bf594f feat(dedicated): authentic OS logos from Wikimedia + expand to 17 distros
Logo source swap:
Replaced all 9 OS brand SVGs with the actual icon-only files mirrored
on Wikimedia Commons (each project's official press kit). The
simple-icons rendering of AlmaLinux specifically was a generic
circles pattern — Wikimedia carries the real multicolor flame mark.
Same correction for Rocky (real green wedge logo), Fedora (proper F
infinity), Debian (bare swirl), Ubuntu (Circle of Friends in orange
hex), FreeBSD (horned daemon mark), Proxmox (CoreUI icon-only),
Windows (4-square 2021 mark), and openSUSE (chameleon button).
Hand-drawn no-os.svg stays — it's a generic terminal indicator,
no brand to source.

OS list expanded 14 → 17 (latest non-EOL versions only):
- Added: AlmaLinux 8, Rocky Linux 8, Ubuntu 22.04 LTS, Debian 11,
  Fedora 43, Fedora 44, openSUSE Leap 15.6, Windows Server 2025,
  Windows Server 2019.
- Removed: Fedora 41 (EOL'd Nov 2025).
- Default flipped from "No OS" to AlmaLinux 9 in the previous commit;
  unchanged here.

OsGroupSelector metaFor() gains an openSUSE family rank between
Fedora and FreeBSD. Reseeded the OS group; 20/20 dedicated tests
still pass; npm run build clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 21:50:00 -04:00
2c85eba156 feat(dedicated): official OS logos + collapsible distro families
Two changes to the OS picker that should be felt together:

1. Swapped my hand-authored SVGs for official brand marks pulled from
   simple-icons (CC0). These are the actual path geometries used in
   each distro's brand kit, just colored to read on dark navy.
   AlmaLinux uses their accent orange (#FA9001) instead of the brand
   navy (#0E1F3D) so it's visible on our dark background.
   Affected: ubuntu, debian, almalinux, rocky, fedora, freebsd,
   proxmox. windows.svg and no-os.svg unchanged (geometric / generic).

2. Each distro family is now a collapsible accordion. The family
   containing the current selection auto-expands on mount; everything
   else collapses to a one-line row showing logo + family name +
   option count + chevron. Header gets a primary-color "selected"
   chip + tinted border when its family contains the active choice.
   "Expand all" / "Collapse all" toggle in the title row for power
   users; collapseAll() keeps the active selection's family open.

Net effect: the picker is ~1/4 of its previous height when only one
family is in use, and the official logos replace my approximations
(AlmaLinux flame mark is now correct, FreeBSD daemon is correct,
Proxmox four-square crown is correct, etc.).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 21:32:53 -04:00
dd8f83a990 polish(dedicated): drive bay title, HDD/SSD optgroups, OS expansion + grouping
Four customer-copy / UX cleanups bundled together:

1. Drive bay title strip — shortGroupLabel() collapses "LFF/SFF/NVMe
   Drive Bays" to just "Drive Bays" everywhere it surfaces (rail
   anchor, configurator section title, BuildSummary line item).
   Each chassis only ever shows one drive bay group, so the
   form-factor prefix was redundant noise.

2. HDD/SSD optgroups in Drive Selection — VSelect now interleaves
   VListSubheader rows ("HDDs", "SSDs", "NVMe") between options.
   Sentinel header values (`__hdr_<cat>`) are filtered in
   onDriveChange so a stray header click can't propagate.

3. OS list expansion — went from 6 entries to 14: added AlmaLinux 8,
   Rocky 8, Ubuntu 22.04 LTS, Debian 11, Fedora Server 41, FreeBSD 14,
   Proxmox VE 8, Windows Server 2019 (BYOL). Default flipped from
   "No OS" → "AlmaLinux 9" (matching what most dedicated buyers
   actually want — flag and revert via seeder if you'd rather keep
   bare-metal as the default).

4. OS picker grouped by distro — OsGroupSelector renders family
   sections (AlmaLinux, Rocky Linux, Ubuntu, Debian, Fedora,
   FreeBSD, Proxmox VE, Windows Server, Other) with a small
   uppercase heading above each row of tiles. metaFor() helper
   maps slug → family + logo path. New SVG logos for fedora,
   freebsd, proxmox; refined geometry on almalinux + rocky + debian.

Reseeded the OS group (deleted old 6 values, recreated 14 with new
ordering). 20/20 dedicated tests still pass. `npm run build` clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 21:21:50 -04:00
f0df110b47 feat(dedicated): 3-column anchor rail layout for configurator
Switches the dedicated server detail page from 2-column (configurator
+ sticky summary) to 3-column (anchor rail | configurator | sticky
summary) — option D from the visual companion exploration. Power-user
shape: every section visible at once, rail tracks completion state,
sticky-on-both-sides keeps navigation + price always in reach.

- New ConfigSectionRail.vue: vertical list of section anchors
  (CPU, RAM, OS, Storage, Network, etc.) with three states
  (untouched, touched ✓, active ●). Click to smooth-scroll.
- Configurator wraps each group in <section :id="cfg-<slug>"> with
  scroll-margin-top: 92px to clear the navbar on scroll-into-view.
- IntersectionObserver in DedicatedConfigurator/index.vue updates
  store.activeAnchorId as sections cross the upper viewport.
  rootMargin '-92px 0px -65% 0px' picks the section nearest the top.
- Store: activeAnchorId reactive ref, isGroupTouched() helper
  (compares selection against seeded default; drive bay groups
  also require quantity > 0 to count), groupAnchorId() and
  shortGroupLabel() helpers.
- Detail-grid CSS: 180px | 1fr | 380px on desktop. Rail hides at
  ≤1280px (tablet keeps the summary). Full stack at ≤1024px.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 21:05:37 -04:00
a224051bde feat(dedicated): dropdowns for radio groups, card-grid OS picker
Replaces stacked radio cards with VSelect dropdowns across CPU, RAM,
Bandwidth, IPv4, Private Networking, PCIe NVMe Add-in, and the Drive
Selection control inside each drive bay group. Major space savings —
the LFF Drive Selection alone goes from 15 stacked cards to one row
on screen, with the active price still visible at a glance via the
selection slot's right-aligned chip.

OS group becomes a tile-grid picker (`OsGroupSelector.vue`): 6 cards
with brand logos, distro name, and price chip. Logos shipped as
hand-authored SVGs at public/img/os/{ubuntu,debian,almalinux,rocky,
windows,no-os}.svg — no new npm dependency.

- Synchronous Pinia store init: moved store.init() out of onMounted
  into setup so children's `selected` props are populated on first
  render. Without this VSelect's selection slot fires with a stub
  item before init completes and the whole tree throws on a
  defensive `.toFixed` access.
- Defensive priceLabel guards in both OptionGroupSelector and
  DriveBayGroupSelector for any future re-render where the slot's
  raw item is incomplete.
- isOperatingSystemGroup() helper alongside isDriveBayGroup() in the
  store; configurator switches OS → OsGroupSelector, drive bays →
  DriveBayGroupSelector, everything else → OptionGroupSelector.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:48:53 -04:00
8be088e22a chore(dedicated): drop carrier jargon and mixed-size ticket copy
The drive bay UX leaked two more pieces of internal detail customers
shouldn't care about:

- "(LFF carrier)" suffix on every LFF SSD label (it's just a tray
  adapter so a 2.5" drive fits a 3.5" bay — internal mechanical
  detail, irrelevant to the customer's storage choice).
- "Mixed-size setups via post-order ticket" tail on the LFF/SFF/NVMe
  group descriptions, plus the entire "Need a custom drive layout?"
  card at the bottom of the detail page. We're not actually offering
  per-bay custom drive layouts as a service, so pitching it as a
  workflow was misleading.

- "No drives — configure via ticket" → "No drives" on the default
  value across all three drive bay groups.

Reseeded with `Drive Selection` value labels deleted+recreated since
the seeder keys on `[option_id, label]`. Internal value slugs
unchanged so share URLs still resolve.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:28:35 -04:00
8cf9526bfc chore(dedicated): scrub vendor names from PCIe NVMe Add-in copy
The PCIe NVMe Add-in description and value labels exposed our adapter
SKUs (EC-PCIE / EC-P4BF), the vendor's product line names (Rocket 4
Plus / Rocket 5 Gen5), and PCIe lane / bifurcation jargon — none of
which the customer needs to see, and our standing rule is no vendor
names on public pages.

- Description rewritten in customer terms: positions the group as
  "fast scratch space or 4-drive bundle for more capacity" instead of
  explaining the adapter card mechanism.
- Value labels collapsed to "1× N TB M.2 NVMe (Gen4)" / "(Gen5)" /
  "(Gen4 bundle)" — keeps the generation distinction (which matters
  to customers) and the count, drops the vendor product names and
  adapter SKUs.

Internal value slugs (`1x1tb-r4p-pcie`, `4x1tb-r4p-p4bf`) left intact
so any in-flight share URLs and the seeder's update path don't break;
they're not customer-visible UI text.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:23:22 -04:00
4833d667e3 feat(dedicated): drive bay Option B restructure (per-drive × quantity)
Replaces the flat-radio combo pattern in LFF/SFF/NVMe drive bay groups
with a Drive Selection (radio, per-drive cost) + Drive Quantity
(stepper) composite. Adds SAS HDD/SSD variants on LFF and SFF, and
collapses NVMe to enterprise U.2 sizes only.

- Seeder: rewrites the 3 drive bay groups; LFF goes from 35 flat combo
  values to 15 per-drive selections, SFF 8 → 8, NVMe 7 → 4. Adds
  SAS HDD (12/16 TB) and SAS SSD (1.92/3.84/7.68 TB) on LFF, SAS SSD
  trio on SFF, and 7.68 TB SATA SSD on both.
- Store: selections become Record<string, string | {drive,quantity}>;
  driveBayCost computed as drive_selection × quantity.
- DriveBayGroupSelector.vue: new composite component with stepper.
- BuildSummary: renders drive bay rows as "N× <drive> = $Y".
- Route filter: clamps Drive Quantity max_qty to chassis bay_count
  instead of filtering value slugs.
- URL contract: drive bay groups serialize as <prefix>_drive +
  <prefix>_qty (lff/sff/nvme).
- Tests: rewrites bay-count filter test, adds 5 new tests covering
  the two-option structure, SAS variants on LFF/SFF, NVMe enterprise
  sizes, and per-drive pricing alignment with the spec table.

Implements docs/superpowers/specs/2026-04-26-dedicated-drive-bays-option-b-design.md.

20/20 dedicated tests pass; 30/30 marketing tests green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:19:41 -04:00
c9e0c8826f docs(spec): drive bay Option B restructure design (deferred)
Captures the full design for splitting LFF/SFF/NVMe drive bay
groups from flat radios into Drive Selection + Drive Quantity
composite controls. Includes the SAS variants user requested,
per-drive pricing table, schema decisions (no migrations needed,
existing schema already supports multi-option groups), Pinia
store changes, new DriveBayGroupSelector component sketch, URL
param contract changes, and migration steps.

Implementation deferred to a focused next session — realistic
4-5 hour build (backend seeder + frontend component + store
rework + test rewrite). Phase A (PCIe NVMe Add-in) shipped
ahead of this in c74ca7f.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:04:48 -04:00
c74ca7f554 feat(dedicated): add PCIe NVMe Add-in group (Sabrent adapter combos)
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) <noreply@anthropic.com>
2026-04-26 20:03:34 -04:00
168b06cd7d feat(dedicated): expand LFF Drive Bays with high-cap HDD + SSD options
Extended the LFF Drive Bays group from 7 → 35 entries to surface
real high-density configurations customers actually order.

High-capacity HDDs (12 new entries, prices set at ~12-month payback
× 1.5x markup on Server Part Deals Seagate Exos pricing scraped
2026-04-26):
  12 TB Enterprise HDD: ×2 \$90, ×4 \$180, ×8 \$360, ×12 \$540
  20 TB Enterprise HDD: ×2 \$110, ×4 \$220, ×8 \$440, ×12 \$660
  24 TB Enterprise HDD: ×2 \$150, ×4 \$300, ×8 \$600, ×12 \$900

LFF SSDs in 3.5" carriers (16 new entries) — 2.5" SATA/SAS SSDs
mounted via SaveMyServer adapters into LFF trays. Same per-drive
pricing model as the SFF group:
  480 GB SATA SSD: ×2 \$20, ×4 \$40, ×8 \$80, ×12 \$120
  1.92 TB SATA SSD: ×2 \$36, ×4 \$72, ×8 \$144, ×12 \$216
  3.84 TB SATA SSD: ×2 \$90, ×4 \$180, ×8 \$360, ×12 \$540
  7.68 TB SAS SSD: ×2 \$200, ×4 \$400, ×8 \$800, ×12 \$1,200

Existing chassis-bay-count filter at the route level keys on the
leading number in each value slug (e.g. "8x12tb-hdd" → 8 bays),
so combos that don't fit a chassis stay hidden — no extra logic
needed for the new entries.

Group description updated to reflect HDDs + SSDs both supported.
14/14 dedicated tests pass; pint clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 19:48:32 -04:00
f464e1ad48 feat(dedicated): bandwidth + private networking restructure
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) <noreply@anthropic.com>
2026-04-26 19:00:50 -04:00
d09224c35c chore(dedicated): bump RAM tier prices to per-stick economics
Recalibrated against Hetzner DX153 configurator data ($78/64GB-DDR5
module monthly) and OVH SYS-5 baseline (~\$0.42/GB monthly, but on
cheaper Silver-tier chassis without iDRAC9 Enterprise / BOSS — not
a 1:1 comp for our Gold-tier line).

New tier pricing at \$65/64GB-equivalent — sits ~17% under Hetzner's
premium tier and ~50% above OVH's budget-floor on a $/GB basis. At
this rate, 1 TB upgrade recoups our $6,240 hardware cost (16x
\$390/stick DDR4-2400 LRDIMM at 2026 Q2 shortage prices) inside
6 months of customer rental, with ~30% ongoing margin.

Per-tier changes:
- 64 GB:    +\$35 → +\$65   (+\$30/mo,  ~85% bump)
- 128 GB:   +\$90 → +\$195  (+\$105/mo, ~115% bump)
- 256 GB:   +\$195 → +\$260 (+\$65/mo,  ~33% bump)
- 512 GB:   +\$380 → +\$520 (+\$140/mo, ~37% bump)
- 1 TB:     +\$580 → +\$1,040 (+\$460/mo, ~80% bump)
- 1.5 TB:   +\$780 → +\$1,560 (+\$780/mo, ~100% bump)

The biggest jumps are at the high-density LRDIMM tiers where DDR4
EOL shortage hits hardest. Original pricing (set during the
brainstorm before the shortage data was researched) would have
left us underwater on hardware-cost recovery.

14/14 dedicated tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:57:37 -04:00
2658576c5b feat(dedicated): filter drive bay options to chassis-compatible combos
Per-chassis page hides drive combos that require more bays than the
chassis has. R440 (4-bay) no longer shows 8× / 12× options; R640
(8-bay SFF) no longer shows 16× / 24×; R640 NVMe (10-bay) hides
16× NVMe.

Implementation:
- routes/marketing.php /dedicated-servers/{slug}: post-load filter
  on configGroups. For any group whose name contains "Drive Bays",
  parses the leading bay-count digit from each value's slug
  (e.g. "8x8tb-hdd" → 8) and drops values where bay_count >
  chassis features.bay_count. Non-quantity values (e.g. "none")
  always pass through.
- ConfigOptionSeeder: dropped the now-redundant "(R740xd LFF
  only)"/"(R740 16-bay only)" parentheticals from the labels —
  the filter handles compatibility, the labels stay clean.

New test asserts:
- R440 (4 bays) drops 8× and 12× LFF combos
- R740xd LFF (12 bays) keeps all combos
- R640 NVMe (10 bays) drops 16× NVMe combo

13/13 dedicated tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:36:57 -04:00
2a9d36270a chore(dedicated): cut setup fees in half — competitive recalibration
Original tiers ($349/$549/$799) drifted into Hetzner Dell US
setup-fee territory ($840-$1,020) — too aggressive for a small
Atlanta provider competing against ColoCrossing ($0 setup) and
OVH SYS ($60-$343). The competitor research at
infrastructure/docs/competitors-atlanta-2026.md and
dedicated-server-pricing-2026q2.md both flagged "no setup fees"
as a documented competitive advantage.

New tiers ($149/$249/$399) preserve a meaningful safety net on
monthly customers (~1 month of rental recoups the fee) while
sitting inside the OVH SYS price band. Annual / Semi-Annual
customers still pay $0 setup.

Per-plan changes:
- R440 / R640 SFF (Tier 2): $349 → $149
- R540 / R740 / R740xd SFF / R740xd LFF (Tier 3): $549 → $249
- R640 NVMe / R740xd NVMe (Tier 4): $799 → $399

Spec doc updated. Test expectations adjusted; 12/12 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:34:30 -04:00
61afa4ed14 feat(dedicated): drive bay configurator + sticky-summary fix + reword setup fee
Three changes bundled:

1. Drive bay configurator (3 new ConfigOptionSeeder groups):
   - LFF Drive Bays (3.5") — 7 starter combos from "None" to
     12× 8 TB SATA HDD; attached to R440 / R540 / R740xd LFF
   - SFF Drive Bays (2.5") — 8 starter combos from "None" to
     24× 1.92 TB SATA SSD; attached to R640 / R740 / R740xd SFF
   - NVMe Drive Bays (U.2) — 7 starter combos from "None" to
     16× 2 TB U.2 NVMe; attached to R640 NVMe / R740xd NVMe
   Combos enforce chassis bay-count constraints via labels
   ("R740xd LFF only"); customers wanting heterogeneous setups
   use the post-order ticket flow.

2. Sticky build-summary fix: previously the BuildSummary card
   slid under the Vuetify navbar at scroll. Moved sticky from
   the inner card to the .detail-grid__summary wrapper, removed
   align-items: start so the right grid cell stretches to the
   configurator column's height (giving sticky a tall enough
   container), and offset top by 80px (64px navbar + 16px
   breathing room). Mobile path drops sticky entirely.

3. Setup fee reword — "Hardware acquisition" was leaking our
   cost structure and making the fee feel like procurement
   passthrough. Now reads "Server provisioning & deployment"
   in BuildSummary, and the FAQ describes what the fee covers
   (build, racking, iDRAC config, deployment) without exposing
   margins. Same shift across the non-refundable note: "once
   your build starts" instead of "once hardware is purchased."

Detail page bay-strategy callout updated: drive selection IS now
self-serve, so the callout pivots to "need a custom drive layout?"
pointing customers with mixed-size / hot-spare / RAID-preference
needs to the contact form.

Tests: updated count assertion to 9 groups, added a new test
verifying drive bay groups attach to chassis by bay type.
22/22 of my session's Pest tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:25:33 -04:00
be3eaba2a1 feat(dedicated): build summary sidebar + expanded CPU/IPv4 options
CPU upgrade ladder (standard, R440/R540/R640/R740) now 6 tiers:
- Gold 6230 (baseline, included)
- Gold 6244 high-clock (16C / 3.6 GHz, +$25/mo) — for per-core
  licensed workloads (MS SQL / Oracle) and single-threaded compute
- Gold 6248 (40C / 2.5 GHz, +$35/mo)
- Gold 6230R sweet-spot (52C / 2.1 GHz, +$50/mo) — Cascade Lake
  Refresh of the 6230, more cores at same clock, bridges baseline
  and 6248R
- Gold 6248R (48C / 3.0 GHz, +$75/mo)
- Gold 6258R (56C / 2.7 GHz, +$145/mo)

R740xd CPU ladder unchanged (6230 / 6248R / 6258R / Platinum 8280).

IPv4 block options extended to /24:
- /29 ($12) · /28 ($36) · /27 ($80) · /26 ($145) · /25 ($275) ·
  /24 ($499). All blocks above /29 require ARIN justification —
  the group description explains the policy and each tier's label
  carries a "justification required" tag.

Build summary sidebar replaces the bottom sticky footer on the
per-chassis page. New 2-column layout (configurator left, summary
right, sticky); collapses to single-column on tablet/mobile with
the summary stacked above the configurator so total stays visible.

The summary fixes the original "Total $468 billed monthly /
includes $349 setup" wording confusion by splitting into clearly
labeled sections:
- RECURRING: per-line itemized breakdown (baseline + each upgrade
  with its actual cycle-priced cost), subtotal in /mo or /yr suffix
- ONE-TIME: setup fee with non-refundable note (or strikethrough +
  "waived" badge when cycle is semi/annual)
- TOTAL: "First invoice $X" + "Then $Y/mo recurring" framing on
  monthly/quarterly cycles; "Total due today" + renewal preview on
  semi/annual

Removed: ConfiguratorFooter.vue (replaced by BuildSummary).
Pinned to top via position:sticky with viewport-height clamp +
internal scroll for tall configs. Order CTA + Copy share link
moved into the summary card.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:19:04 -04:00
017b8b54c1 fix(dedicated): remove vendor name from public FAQ copy
Vendor sourcing is an internal procurement detail. Customer-facing
copy now reads "we source and assemble the chassis at our Atlanta
datacenter" — accurate and protects the supplier relationship.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:08:05 -04:00
2f985ab8f3 test(dedicated): phase 4 — Pest feature tests for the new lineup
11 tests covering:
- Landing page returns 16 plans (8 14th-gen + 8 legacy)
- All 8 14th-gen chassis have correct setup_fee per tier mapping
  (R440 $349, R540 $549, R640 $349, R740 $549, R740xd $549,
   R740xd LFF $549, R640 NVMe $799, R740xd NVMe $799)
- Legacy 12th/13th-gen plans are active with $0 setup fee
- Per-chassis detail page renders for every 14th-gen slug
- 404 for invalid slugs
- R740xd variants get the R740xd-specific CPU group; non-xd
  chassis get the standard CPU group
- All 6 dedicated 14th-gen config groups exist after seeding
- RAM upgrade group standardizes on DDR4-2400 (per Q5 brainstorm)
- Checkout setupFee prop exposed correctly on dedicated plans
- Checkout setupFee is 0 on VPS plans

All 22 of my session's Pest tests pass (11 dedicated + 11 VPS
estimator). Pre-existing project test failures (DOMAIN_* mismatch
between hardcoded test URLs and docker dev env) are unrelated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:02:46 -04:00
311a4e961c feat(dedicated): phase 3 — frontend lineup pages + configurator
New pages:
- /dedicated-servers (rewrite): chassis grid with generation filter
  (All / Build to Order / In Stock — Rack inventory), hardware band,
  ColoCrossing-vs-EZSCALE comparison table, 8-question FAQ, custom-
  build CTA. Uses ChassisCard + GenerationFilter components.
- /dedicated-servers/{slug}: per-chassis page with locked baseline
  spec sidebar, configurator section (4-cycle toggle, 6 option
  groups via OptionGroupSelector, sticky ConfiguratorFooter with
  setup-fee waiver display), bay-strategy reminder card.

New shared components:
- Components/Marketing/Dedicated/
  - ChassisCard.vue — uniform card for both build-to-order and
    in-stock variants; differentiates with badge + border tone
  - GenerationFilter.vue — 3-option chip toggle with counts
  - BuildStatusPanel.vue — 5-stage timeline (Ordered → Hardware
    acquired → Assembly → Racked → Deployed) with editable prop
    for admin use; reused on customer service detail page
  - DedicatedConfigurator/
    - index.vue — orchestrator, mounts store, debounces URL push
    - CycleToggle.vue — 4 cycles (Monthly/Quarterly/Semi/Annual)
      with setup-waived badges on 6+ month tiers
    - OptionGroupSelector.vue — generic radio for any config group
    - ConfiguratorFooter.vue — sticky total + share link + order CTA

Pinia store:
- stores/dedicatedConfigurator.ts: per-chassis state (selections
  keyed by group name, cycle), getters for all sub-totals, setup-
  fee waiver logic, hydrateFromUrl + shareUrl + checkoutUrl. URL
  param shape: ?cycle=&cpu=&ram=&os=&bw=&ipv4= (only non-default
  values serialized).

Comparison rows are sourced from the freshly-landed competitor
research at infrastructure/docs/json/competitors-2026q2.json
and ovh-2026q2.json — focuses on hardware transparency, iDRAC9
inclusion, BOSS boot, setup-fee policy, and engineer-first support.

Drive picker descoped to v1.1 (per design spec): the configurator
captures CPU/RAM/OS/Bandwidth/IPv4 self-serve; drive selection is
handled via post-order ticket in v1. Bay-strategy callout on the
detail page sets that expectation.

npm run build clean; DedicatedServers + DedicatedServerDetail
bundles are 14.7 / 16.3 kB (gzipped 5.8 each). Visually verified
in the docker dev stack.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:01:12 -04:00
9c178f289c chore(dedicated): standardize 14th-gen RAM on DDR4-2400 ECC
Procurement decision: simpler single-DIMM-SKU sourcing across all
RAM tiers. The Gold 6230 IMC supports up to DDR4-2666, but
standardizing on 2400 keeps RDIMM ↔ LRDIMM transitions on the same
speed and means we don't need two separate procurement streams.

The ~10-18% memory bandwidth penalty vs 2666 is invisible for
typical hosting workloads (general compute, web/db, virtualization).
Memory-bandwidth-bound workloads (in-memory caches, ML inference)
can request a custom 2666 build via the contact form.

Updates:
- All 8 14th-gen plan rows: features.ram now reads
  "32 GB DDR4-2400 ECC RDIMM" (was 2666).
- Dedicated 14th Gen — RAM Upgrade group: each value now carries
  its actual DIMM type — RDIMM up through 128 GB, LRDIMM at
  256 GB and above. All speeds DDR4-2400.

Note: this diverges from infrastructure/docs/dedicated-server-
configurations.md which still lists 2666 (matches what
SaveMyServer's configurator ships). Reconcile upstream when
procurement is finalized.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:52:49 -04:00
c7e545601e feat(dedicated): phase 2 — routes, configurator data, checkout setup fee
Routes:
- /dedicated-servers/{slug} (per-chassis detail) added alongside the
  existing /dedicated-servers landing. Landing route now eager-loads
  prices; detail route eager-loads chassis-specific config groups.

ConfigOptionSeeder — 6 new dedicated 14th-gen groups:
- CPU Upgrade (4 tiers; attached to R440/R540/R640/R740)
- CPU Upgrade R740xd (4 tiers, higher-TDP; attached to R740xd variants)
- RAM Upgrade (7 tiers, 32GB → 1.5TB)
- Operating System (6 options incl. Windows BYOL)
- Bandwidth (5 tiers, 1G unmetered → 10G unmetered fair-use)
- IPv4 Block (4 tiers, single → /27)
All idempotent via updateOrCreate, attached per chassis.

HandleSubscriptionCreated listener: build-to-order dedicated
plans (those with features.lead_time_days set) auto-create the
'ordered' build milestone. Other service types unaffected.

CheckoutController + Checkout/Show.vue:
- Pass plan.setup_fee as 'setupFee' Inertia prop
- Vue computes effectiveSetupFee (waived on semi_annual/annual,
  charged on monthly/quarterly per the brainstorm) and adds it
  to total. Display line-item still pending v3 polish.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:49:31 -04:00
c5fd4bcc7e feat(dedicated): phase 1 — backend data layer for new lineup
Migrations:
- add_setup_fee_to_plans_table: new decimal(10,2) default 0
- create_service_build_milestones_table: id, subscription_id,
  stage, reached_at, note, updated_by, timestamps; unique
  (subscription_id, stage); indexed (subscription_id, reached_at)

PlanSeeder:
- Removes the "archive 12th/13th-gen → hidden" block; flips all 8
  legacy slugs (dell-r330-lff..dell-r730-lff) to status=active so
  they surface as in-stock rack inventory alongside the new line.
- Replaces the 5-row 14th-gen placeholder with 8 proper SKUs:
  r440-4lff ($119, $349 setup), r540-8lff ($159, $549),
  r640-8sff ($179, $349), r740-16sff ($229, $549),
  r740xd-24sff ($279, $549), r740xd-12lff ($249, $549),
  r640-10nvme ($239, $799), r740xd-24nvme ($279, $799).
  Setup fees per the brainstorm tier mapping.
- Each new SKU carries full features (chassis, form_factor,
  bay_count, bay_type, locked baseline cpu/ram/boot/idrac/
  network/bandwidth, lead_time_days '7-10', tier).
- All 8 new SKUs have per-cycle prices (M/Q/Semi/A) at 5/10/15%
  discounts.

ServiceBuildMilestone model with STAGES const (ordered →
hardware_acquired → assembly → racked → deployed) and
subscription/updatedBy relations. Queries from this side until
we extend Cashier's Subscription model in a later phase.

Spec: docs/superpowers/specs/2026-04-26-dedicated-server-lineup-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:46:05 -04:00
0d0f6faf40 docs(spec): dedicated server lineup design
Captures the brainstorm: 8 new Dell 14th-gen chassis SKUs alongside
existing rack inventory, per-chassis configurator at
/dedicated-servers/{slug}, 5-stage post-order build tracker,
tiered setup fees waived at Semi-Annual+ cycles.

User approved design + skipped spec-review gate. Implementation
phasing in 4 commits per the spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:33:23 -04:00
e5b445efd5 fix(vps): shorten hardware band — "Dell PowerEdge hypervisors" → "Dell PowerEdge"
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:49:43 -04:00
ffb7f47e7d feat(vps): add hardware transparency band + per-card meta
Adds a "Built on" hardware band above the plan grid and a small
meta line on each plan card so shoppers can see what's actually
running their VPS.

Hardware band lists: Dell PowerEdge hypervisors · Intel Xeon · ECC
memory · Enterprise SSD storage · Atlanta, GA datacenter.

Per-card meta line: "Intel Xeon · ECC memory" in muted small type
under the regular spec list.

Copy is intentionally generic ("Intel Xeon", not Broadwell-EP /
Cascade Lake) to remain accurate across the current mixed pool
(R720xd Ivy Bridge being retired into the new R740xd ATL-04 next
week per infrastructure/docs/hypervisor-consolidation-r740xd-build.md).
Tighten the wording once consolidation lands.

Dropped the originally-proposed "10 Gbps inter-host" row — it's
internal cluster networking (used for live migration + shared
storage), and customers were likely to confuse it with their own
egress bandwidth.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:49:18 -04:00
c688180842 fix(vps): correctly position Ezra in the support story
The differentiator card and comparison row were positioning EZSCALE
as "no chatbots" — but we DO run Ezra, an AI assistant that
extends the support team. Reframed honestly: engineer-first support
where Ezra helps the team triage and respond faster, not the
other way around. That's still differentiated against tier-1
outsourced or AI-only support models the big clouds run.

Also drops in docs/integrations/savemyserver/dedicated-server-catalog.json
— 27 Dell 14th-gen products from SaveMyServer with EZSCALE baseline
config and pricing, generated by a separate scraping session at
/tmp/sms-configurator. Lives next to other vendor integration data
in docs/integrations/. Will feed the dedicated-server PlanSeeder
refresh in a follow-up task.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:39:27 -04:00
28a4ca8d32 feat(vps): rewrite Why Choose section + 5 page improvements
The old "Why Choose EZSCALE VPS?" grid was duplicating the
Included With All Plans card right below it (RAID 10, ZFS Snapshots,
VirtFusion Panel, Full Root Access appeared in both). Replaced with
6 actual differentiators that answer "why us, not Linode/Hetzner/
Vultr": real US humans, ZFS-backed reliability, predictable billing,
optional Pilot tier, 14-day money-back, owner-operated.

Other improvements bundled in this pass:
- Hero subtitle rewritten from feature dump to identity-first one-liner.
- Plans table → responsive PlanCard grid with a "Most popular" badge
  on VPS-4 and a separate "Storage-focused" subgrid for stor-500/1tb.
  Each card carries Order Now + Estimate-this-plan link to the
  estimator (still wired to the prefillEstimator handler).
- Added a 5-row "EZSCALE vs typical big-cloud" comparison table —
  honest differences only, no specific competitor names to avoid
  liability.
- Added an 8-question FAQ section (provisioning time, OS list,
  upgrades, refunds, DDoS roadmap, rDNS, location, migrations) using
  a new reusable Faq accordion component.
- Bottom CTA copy fixed (it was still mentioning DDoS protection as
  current; it's coming-soon upstream): now reads "Real humans on
  support. 14-day money-back if it's not the right fit." Heading
  flipped to "Ready to spin one up?" / "Talk to a Human."

New shared components: Components/Marketing/PlanCard.vue,
Components/Marketing/Faq.vue, Components/Marketing/ComparisonTable.vue.
All three are reusable for the dedicated/web/game pages later.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:35:43 -04:00
66a65263c3 fix(vps): drop Windows License toggle from estimator
Windows BYOL is free and doesn't change the price, so the toggle
was UI clutter. The Included With All Plans card already
communicates the BYOL requirement (line updated to read
"Linux included; Windows supported (bring your own license)" for
clarity), and OS template selection at checkout still lets users
pick a Windows image when they're ready to deploy.

- AddOnsPanel.vue: removed the Windows License switch
- EstimatorSection.vue: removed onWindowsChange handler
- stores/estimator.ts: removed windowsLicense state, dropped from
  share/checkout URL params and hydration
- ConfigOptionSeeder.php: dropped the legacy 'Windows License'
  option from the VPS Add-ons group (deletes existing row)
- CheckoutController.php: removed ?windows=1 query-param handling
  from buildPrefilledSelections
- VpsHosting.vue: tightened the BYOL line in the Included card

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:28:03 -04:00
bc5ccf1731 fix(vps): harmonize estimator palette with rest of marketing site
Replaced --v-theme-surface-bright (auto-generated lighter tone that
clashed with the page's dark navy palette) with --v-theme-surface
across all 10 estimator components. Removed gradient backgrounds in
favor of the existing .glass-card / .section-alt-bg patterns from
resources/styles/_marketing.scss. Bumped contrast on the cycle toggle
discount badges and the EstimatorFooter card so the Copy share link
button reads clearly.

Components touched: EstimatorSection, BillingCycleToggle, WorkloadPicker,
MiniQuizDialog, RecommendedPlanCard, AddOnsPanel, IPv4Stepper,
ManagedSupportSelector, BackupTierSelector, EstimatorFooter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:18:03 -04:00
cfa2e4c8d3 feat(vps): add interactive estimator + refresh Included card
Implements the design captured in
docs/superpowers/specs/2026-04-26-vps-hosting-estimator-design.md.

Estimator (after the hero on /vps-hosting):
- Workload picker (9 chips) recommends a plan; "Not sure" opens a
  mini-quiz with a 12-app catalog and a traffic+priority follow-up.
- Recommended-plan card with "or pick another" alternates dropdown.
- Add-ons panel: IPv4 stepper (1-8, $8/extra), Windows BYOL toggle,
  4-tier Managed Support radio (Self/Basic/Pro/Pilot @ $0/29/79/99),
  5-tier Off-site Backup radio (None/Lite/Standard/Extended/Vault @
  $0/5/12/25/59).
- Pilot tier gated to VPS-8+ via plan.features.tier; auto-fallback to
  Pro on plan downgrade with snackbar warning.
- Billing cycle toggle (Monthly / Quarterly / Annual) reuses
  per-cycle prices already on plan_prices and plan_config_values.
- Sticky footer with live total, "Order this configuration"
  (deep-links to /checkout/{plan} with all params), and "Copy share
  link" (history.replaceState debounced 300ms).
- Plans-table rows get an "Estimate →" link that pre-fills the
  estimator with that plan and scrolls up.

Backend:
- PlanSeeder: each VPS plan gets features.tier (1-32) for gating.
- ConfigOptionSeeder: scope existing Server Management group to
  dedicated only; add VPS Managed Support and Off-site Backup
  groups with full per-cycle prices.
- routes/marketing.php /vps-hosting: pass addOns + workloadMap +
  appExamples Inertia props.
- CheckoutController::show: build prefilledSelections from
  ?ipv4&windows&managed&backup query params; Vue page hydrates
  configSelections from this prop.

Included With All Plans: rewritten to 13 accurate items with
per-line wording (10 Gbps fair-use uplink, ZFS snapshots free,
KVM virtualization, rDNS/PTR control, OOB console/VNC, 99.9%
SLA, etc.) plus a "Coming soon" badge for DDoS protection.

Tests: 10 Pest feature tests in tests/Feature/Marketing/
VpsHostingEstimatorTest.php cover the page props, both new
seeded groups, plan-tier metadata, Server Management dedicated
scope, configGroups attachment, and checkout query-param
pre-fill round-trip. All 10 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:05:01 -04:00
d5f97d1240 docs(spec): VPS hosting estimator + included list refresh design
Design captured from brainstorming: workload-driven estimator with
plan + add-on configurator (managed support + off-site backup tiers),
URL state, share link, checkout pre-fill, and rewritten Included list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 15:44:12 -04:00
Claude Dev
de8ec69ea0 feat: add advanced features — KB, tickets v2, multi-currency, cart, quotes, affiliates, credits, staff RBAC, fraud detection, service panels
Major additions:
- Knowledge base with categories, articles, revisions, and voting
- Enhanced ticket system: departments, SLA policies, canned responses, tags, custom fields, satisfaction ratings, internal notes
- Multi-currency support with exchange rate sync
- Shopping cart and quote system with PDF generation
- Affiliate program with referrals, commissions, and payouts
- Account credits, credit notes, and debit notes
- Staff management with granular role-based permissions
- Fraud detection and order risk assessment
- ServerHunter SEO integration
- Service lifecycle events (suspend/unsuspend/terminate)
- Service management panels for VPS, Dedicated, Hosting, and Game servers
- Plan lifecycle fields and per-customer overrides
- 30+ migrations, 17 factories, 8 feature test suites

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 07:35:10 -04:00
Claude Dev
2bf8a5b6bf docs: update README with current project status, optimize CLAUDE.md
README: reflect completed phases (1-5, 8-9), accurate tech stack
(Vuetify 3 not Tailwind, Passport not Sanctum, standalone tickets
not SupportPal), current codebase counts (59 migrations, 29 models,
85 pages, ~497 tests), and separate implemented vs planned features.

CLAUDE.md: reduce from 281 to 184 lines — trim derivable directory
listings, remove stale counts, cut redundant examples, update all
metrics to current state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:55:01 -04:00
Claude Dev
1d4a9f33f6 chore: clean up repo root — remove obsolete files, organize infra into docs/
Remove 21MB Vuexy theme directory (replaced by custom EZSCALE design system),
old session logs, patch notes, screenshots, and discovery artifacts. Move
infrastructure files (Horizon config, install script, VirtFusion API spec,
discover script) into docs/ subdirectories. Update CLAUDE.md reference docs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:49:07 -04:00
Claude Dev
b4ef90465c 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>
2026-03-16 11:39:25 -04:00
Claude Dev
5be235d35e feat: add billing cycle toggle to pricing page
Eager-load plan prices in the pricing route and add a billing cycle
toggle (monthly/quarterly/semi-annual/annual) with discount badges and
per-month equivalent display for longer cycles. CTA links now pass
the selected cycle as a query param.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 23:38:17 -04:00
Claude Dev
e0e38e47c6 feat: update checkout and API resources for cycle-aware pricing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 23:38:01 -04:00
Claude Dev
d1df4dd8b2 test: add multi-cycle checkout tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 23:37:22 -04:00
Claude Dev
e0c83e36dc feat: add PlanPrice interface and update Plan/Subscription types
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 23:36:44 -04:00
Claude Dev
8fa389f51d feat: add MigrateVpsPlans command for customer migration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 23:34:28 -04:00
Claude Dev
81995079e6 feat: seed new VPS plans with multi-cycle pricing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 23:33:27 -04:00
Claude Dev
82a069304f feat: update billing services for cycle-specific pricing and fix naming
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 23:32:57 -04:00
Claude Dev
c034be820e feat: add plan_prices table, PlanPrice model, and Plan relationship
- Create plan_prices migration with unique(plan_id, billing_cycle)
- PlanPrice model with factory
- Plan::prices() relationship and priceForCycle() helper
- Tests for model relationships, uniqueness, cascade delete

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 23:31:12 -04:00
Claude Dev
b2fd5abc7e Update documentation after full frontend redesign and bug fix session
Updates CLAUDE.md (design system, tech stack, directory structure, conventions),
TASKS.md (redesign and bug fix items checked off), and creates session log for
the 2026-03-14 redesign session covering layout rebuild, SCSS replacement,
component migration, and 12 bug fixes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 19:20:41 -04:00
Claude Dev
0e7c363a04 Fix code review follow-up issues
- EnsureUserNotSuspended: bypass for impersonation stop, also check banned
- FlashProps: add info and new_password keys
- AccountLayout: impersonation stop link uses account domain (not admin)
- withCount alias: billingInvoices as invoices_count for frontend compat
- VPS Show: add secure password dialog with copy button for reset-password

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 19:02:05 -04:00