A Blog in One Evening
Friday evening. The site exists, the content exists - eight LinkedIn posts about Planq. But no blog. Search engines see a landing page with three pages and have no idea why they should show it to anyone. Google Search Console is connected, Yandex Webmaster is connected, but there’s nothing to index.
Decided to fix that. In one evening.

Stack
The site runs on Astro 5, Tailwind, Cloudflare Pages. Three locales - Russian by default, English and Kazakh with /en/ and /kk/ prefixes. Static generation, no server. Everything through content collections and getStaticPaths().
For the blog I needed:
- A content collection with a schema (title, description, locale, pubDate, tags, keywords)
- List and article pages for each locale (6 files)
- Card and post components
- SEO on every page - JSON-LD BlogPosting, og:type=article, meta keywords
- Header navigation
- Sitemap
Eight posts in an hour
The content was already there. Seven posts from LinkedIn about Planq and one about chatbot security. Wrapped them in markdown with frontmatter, cleaned up the LinkedIn formatting, replaced em-dashes with normal hyphens, removed colons from headings. Eight files in src/content/blog/.
Astro picked them up automatically. getCollection('blog', e => e.data.locale === 'ru') - done. Each article got its own slug from the filename, its own tags and keywords.
OG images on the fly
When you share a link on LinkedIn or Telegram, you want a nice card with the title to appear, not a bare URL. That’s what Open Graph images are for. You could design eight images in Figma. Or you could generate them at build time.
Satori by Vercel takes JSX-like markup and turns it into SVG. @resvg/resvg-js renders SVG to PNG. The result is an endpoint src/pages/og/[slug].png.ts - at build time Astro generates a PNG for each article. Dark background, title, description, tags at the bottom. 1200 by 630 pixels, as social platforms require.
Eight images generate in two seconds. The first one takes a bit longer - loading the font. The rest are about 120 ms each.
Sharing buttons
Each article got three buttons - LinkedIn, Threads, Telegram. Each one builds the right URL with text and link. LinkedIn via sharing/share-offsite, Threads via intent/post, Telegram via t.me/share/url. Icons from Lucide, Threads is a custom SVG.
SEO
Every article gets:
<title>and<meta description>from frontmatter<meta keywords>for search enginesog:type=articleinstead of the defaultwebsiteog:imagepointing to the generated PNG- JSON-LD
BlogPostingwith author, date, keywords - JSON-LD
BreadcrumbListfor navigation - Canonical URL and hreflang for all three locales
Updated the sitemap manually - it’s static in public/sitemap.xml. Nine new URLs.
The chatbot knows too
The site has an AI chatbot - a virtual clone that answers visitor questions. Updated its system prompt - now it knows about all the blog posts and can recommend them in conversation. “By the way, Ilyas has a post about this” - casual, on topic.
The bottom line
Nine posts. Six pages. Two components. Eight OG images. Three sharing buttons. Navigation. SEO. Sitemap. Updated chatbot.
One evening. One terminal. Claude Code alongside as a partner - reading code, suggesting solutions, writing, committing. I review and steer.
Tomorrow Google will index nine new pages instead of three. And I’ll write about it on LinkedIn - short, with a link to the blog. Full circle.


