Selected work

Bemo Buying Guide Platform

A content platform for a product-review and buying-guide site, built on Astro content collections with a validated MDX schema, generated structured data, and a static build deployed behind Docker and Traefik.

Role
Full Stack
Scope
2026 / Website / Content Platform
Stack
Astro, TypeScript, Tailwind CSS, MDX, Docker, Traefik
a laptop and phone mockup of the bemo.cc homepage, with the headline Worth buying, clearly explained, shown on dark blue backdrop

What It Is

Bemo is a content platform for long-form articles, built on Astro content collections instead of a traditional CMS. Every article is an MDX document validated against a schema at build time, which is what drives the listing pages, feeds, and structured data described below.

The full bemo.cc homepage, top to bottom.

Content Model

Articles load through Astro’s content layer with a glob loader over a directory of MDX files, validated against a Zod schema at build time: category, tags, and publish/updated dates are all typed frontmatter, not free text. Reading time isn’t a field anyone fills in either, it’s computed from the article body’s word count at build time. Listing pages, breadcrumbs, and per-article structured data are all generated from that same schema, so a listing page and an article’s JSON-LD can’t drift out of sync the way they would if both were maintained by hand.

Not everything needs to go through that machinery, though. Static pages like the about page are plain Astro pages with hand-written markup rather than collection entries, since they don’t need to appear in a listing, a feed, or search the way an article does. Routing content through a schema it doesn’t need would just be overhead.

The about page: a plain Astro page rather than a content-collection entry.

Built for Both Readers and Crawlers

Each article publishes its own BlogPosting-type JSON-LD linked back to a single Organization entity declared once for the whole site, rather than every page repeating the same entity data. Alongside that, the build generates an RSS feed, a JSON feed, and a sitemap directly from the content collection, so none of those outputs can go stale relative to what’s actually published.

The same content collection also drives an llms.txt file, a plain-text index of the site declared as an alternate representation in the page head. That gives LLM-based crawlers and browsing agents a direct answer to what the site is and what’s on it, instead of forcing them to parse rendered HTML the way a traditional search crawler would.

The guide index, generated from the same content collection as the feeds and sitemap.

The interface is Tailwind CSS on top of Astro’s component model. Category filtering and on-page search run against the same collection data at build time, so there’s no separate search index to keep in sync.

Performance and Accessibility

Bemo ships as a static Astro build with no server-side rendering and no client-side framework runtime, which shows up directly in the numbers. A Lighthouse run against the production site:

Performance Accessibility Best Practices SEO
Mobile 100 100 100 100
Desktop 100 100 100 100

Largest Contentful Paint comes in at 0.8s on desktop and 2.3s on mobile, with 0ms Total Blocking Time and zero Cumulative Layout Shift on both, at a page weight around 230–260 KiB. None of that is accidental: semantic landmarks, correct ARIA usage, alt text on every image, and a well-formed accessibility tree are build-time requirements, not a pass applied after the fact, which is also what lets the same markup serve screen readers and AI browsing agents without extra work.

Deployment

It’s a multi-stage Docker build: one stage installs dependencies and runs the Astro build, the other copies just the static output into a minimal nginx image that serves it. That nginx container sits behind Traefik, which handles TLS and routing, on infrastructure I manage directly rather than a platform-as-a-service. The only runtime piece on top of the static build is the newsletter signup, which posts directly to Brevo rather than through a server route of my own.

Bemo (Bemo’s buying guide platform) has been running in production since 2026. I built it and I still maintain and operate it.