GScopy website built with Next.js on our own VPS
Bilingual website for GScopy built with Next.js 15 and Tailwind 4, with trial downloads served from a Hetzner VPS.

We built the presentation website for GScopy, our desktop application for medical clinics, at gscopy.gxasolutions.com. The site presents the platform and each application, has pricing and contact pages, and hosts the 7-day trial download for Windows and macOS.

Next.js 15, Tailwind 4 and framer-motion, with statically generated pages
The stack is:
• Next.js 15 with the App Router and React 19.1 • TypeScript 5.8 • Tailwind CSS 4.1, configured through @theme in globals.css • framer-motion 12, with our own primitives (Reveal, Stagger, LiftCard, CountUp, FadeIn) that respect prefers-reduced-motion • Geist fonts through next/font, so there is no external request for them
All content pages are statically generated.
Applications are data, not pages
The registry in products.ts describes each application: its slug per language, status (available or coming-soon), accent color, file names and versions. Navigation, sitemap, JSON-LD, product pages, downloads and pricing are all generated from it. For a new specialty I add an id, a registry entry and the texts in both dictionaries, and TypeScript flags any missing translation.

Romanian and English, with translated slugs only for products
Products have different addresses per language, /ro/endoscopie and /en/endoscopy, while the other routes use the same slug in both, so existing URLs stay stable. Each page has its own metadata, hreflang for RO, EN and x-default, a canonical URL, and the OpenGraph image is generated at /api/og. In July 2026 we moved from a single product to a platform with one application per specialty, and the old /features and /download now redirect permanently (301) to the endoscopy page.
Each application has its own JSON-LD
The site publishes Organization, WebSite, a separate SoftwareApplication for each application with its own id, URL, description and availability, plus ItemList, Product with price offers, BreadcrumbList and FAQPage. We kept FAQPage for extraction by LLMs, since Google no longer shows FAQ rich results as of May 2026.

Download buttons switch on when the file lands on the server
The /api/downloads route checks at runtime whether the installer exists in the server folder and returns its URL and size. There are three variants: Windows, macOS Apple Silicon and macOS Intel. Caddy serves them with accept-ranges, so downloads can resume. File names change in .env and apply at runtime, while the version shown on the card needs a redeploy. A product marked coming-soon stays locked even if the file exists.
It runs on a Hetzner VPS behind Caddy and pm2
The code lives in /home/deploy/gscopy, the pm2 process is called gscopy and listens on port 3100, and Caddy obtains the Let's Encrypt certificate automatically. The scripts/deploy.sh script does rsync, npm ci, build and a pm2 restart, then requests /ro from 127.0.0.1:3100 with curl.
The launch price is not shown as a struck-through price
The Omnibus Directive rules out fake discounts, so 1,000 EUR appears as a launch price with the standard price of 2,000 EUR beside it. The bundle costs 1,600 EUR against 2,199 EUR standard, and the "bought separately" reference (4,000 EUR) is calculated from the standard price, so it never goes stale. The footer carries ANPC and SAL. SOL/ODR is missing on purpose, because the EU platform was shut down on 20 July 2025.

The contact form is gone, the phone and email stayed
The first version, from 23 June 2026, had a contact API on Resend. The current version shows the phone and email with tel: and mailto: buttons, read from CONTACT in site.ts.
The source has 47 files in src and about 6,300 lines. The Git history has 11 commits, between 23 June and 13 July 2026.