Skip to content

refactor(blog): move the 7 TBMQ posts to tbmq.io with 1:1 redirects - #641

Merged
vvlladd28 merged 3 commits into
thingsboard:mainfrom
deaflynx:fix/tbmq-blogs-redirect
Sep 3, 2026
Merged

refactor(blog): move the 7 TBMQ posts to tbmq.io with 1:1 redirects#641
vvlladd28 merged 3 commits into
thingsboard:mainfrom
deaflynx:fix/tbmq-blogs-redirect

Conversation

@deaflynx

@deaflynx deaflynx commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Description

Moves the 7 TBMQ blog posts off thingsboard.io — they now live on tbmq.io under identical slugs (restored there in thingsboard/tbmq.io branch fix/blogs-migration). Follow-up to the TBMQ site migration (#585).

Net changes:

  • Deleted the 7 post .mdx files (6 by dlandiak + 1 Million reasons to choose TBMQ) and their public/images/blog/ directories (~2.7k lines / ~3 MB of assets).
  • Redirects: 7 exact-match 301s added to NON_DOCS_REDIRECTS (/blog/<slug>/https://tbmq.io/blog/<slug>/), pnpm generate:redirects run. Slugs are 1:1, verified against the TBMQ site (200 on its staging mirror for every target), so third-party links keep resolving in one hop.
  • The author pages (/blog/author/dlandiak/, /blog/author/dmytro-shvaika/) intentionally stay local and are not redirected.

No other page in the repo linked to any of the 7 posts (grepped), so nothing internal breaks.

Type of change

  • New / updated documentation page (src/content/docs/**)
  • Shared include file (src/content/_includes/**)
  • Component, layout, or styling change (src/components/**, src/styles/**)
  • Landing / use-case / case-study page (src/pages/**, src/data/**)
  • Redirects (src/data/redirects.ts)
  • Version bump / release (see release skill)
  • Build, CI, scripts, or tooling
  • Other (please describe)

Affected products

TBMQ (blog content only). No docs pages touched.

Related issues

Checklist

  • pnpm check passes (Astro / TypeScript)
  • pnpm lint:eslint passes
  • pnpm lint:slugcheck passes (required if pages were added/renamed/moved across languages)
  • pnpm lint:linkcheck passes locally — required to merge; run it before requesting review (use pnpm lint:linkcheck:nobuild if you already ran a build)
  • Renamed/removed pages have a redirect in src/data/redirects.ts, and pnpm generate:redirects was run
  • No hardcoded versions — values come from src/data/versions.ts
  • Screenshots attached for visual changes

The TBMQ blog posts (6 by dlandiak + 1-million-reasons) now live on
tbmq.io under identical slugs. Delete the local .mdx files and their
public/images/blog/ directories, and add 7 exact 301s to
NON_DOCS_REDIRECTS so third-party links keep resolving.

The author pages (/blog/author/dlandiak/, /blog/author/dmytro-shvaika/)
stay local and are not redirected.

@vvlladd28 vvlladd28 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review summary

Reviewed 50 changed files in refactor(blog): move the 7 TBMQ posts to tbmq.io with 1:1 redirects. Left 1 comment inline.

The mechanics check out. I re-ran node scripts/generate-redirects.ts inside a clean worktree of db832ec and git status came back empty, so pnpm generate:redirects was run and both outputs are in sync — public/redirects.json is absent from the diff only because it carries /docs/* entries and these are NON_DOCS_REDIRECTS. The 7 exact rules land at _redirects:1056-1062, ahead of the /blog/category/... and /blog/{2023..2026}/* dynamic splats at 1123-1130, so nothing shadows them; nothing else in _redirects targets those slugs, so no chains; TBMQ_ORIGIN is https://tbmq.io, not a staging host; and the file sits at 1,100 static + 47 dynamic against Cloudflare's 2,000/100. The PR's grep claim holds — each of the 7 slugs appears nowhere in src/, scripts/, config/ or public/ outside the redirect data — and all 9 BLOG_CATEGORIES still have surviving posts, so no category filter goes empty.

I swept for orphaned artifacts and found almost nothing: the 7 posts imported exactly one component (BlogCTA), still used by 4 surviving posts; they carried no class= attributes and no inline style=, so there are no dead selectors, and nothing in src/styles/ mentions TBMQ; every export in src/models/tbmq.ts still has consumers; no deleted image file is referenced by any surviving page; and no asset outside the 7 slug directories was referenced only by these posts. Post counts per author confirm the rest of the blog is unaffected — 15 of the 18 BLOG_AUTHORS entries keep at least one post, and the per-author counts sum to exactly 49, so no surviving post points at an undeclared author slug.

I also verified the migration is genuinely 1:1 against thingsboard/tbmq.io#15: the seven slugs deleted here match the seven .mdx files added there byte-for-byte, and so do the seven redirect targets, so every rule points at a page that will exist. That repo emits /blog/<slug>/ in the same shape (base: '/', trailingSlash: 'always', params.slug = post.id), and the only /blog/ rules on its side are dev-only WordPress year-archive fallbacks that can't match a post slug, so there's no second hop. The image directories are restored there under identical paths too. The one thing left is inline.

Additional findings

These observations are about existing code outside the PR's diff — spotted while reading surrounding context.

  • src/data/blog/authors.ts:76maryna already has zero posts on main, so the author-page filter suggested inline will drop three routes rather than two. That's intended, not a side effect worth avoiding: the third page is in exactly the same state and has been since before this PR. The same three names in src/data/company/team.ts are separate data for the team page and stay untouched either way.
  • public/images/blog/thingsboard-cli/ — pre-existing orphan asset directory with no matching .mdx in src/content/blog/. Entirely unrelated to this PR and fine to leave; noting it only because it's the one other orphan under public/images/blog/ and blog assets are already open here.

This review was auto-generated. Findings may contain errors — please verify before applying changes.

Comment thread src/data/redirects.ts Outdated
// Demo CA cert removed with the TBMQ docs; the TBMQ site serves its own copy
'/resources/tbmq-demo-root-ca.pem': `${TBMQ_ORIGIN}/resources/tbmq-demo-root-ca.pem`,
// TBMQ blog posts moved to tbmq.io with the same slugs; the local .mdx files
// (and their public/images/blog/ dirs) are deleted. The author pages stay.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two notes on the decisions this comment records — one is fine as-is, the other is worth handling here.

The image dirs going away without a redirect is an acceptable trade-off. Recording it just so the reasoning is on file: [...slug].astro:105 passed ogImage={post.data.featuredImage} and the JSON-LD at lines 51-54 used the same path, so og:image for these seven posts was https://thingsboard.io/images/blog/<slug>/cover.webp, and social platforms cached that URL. But any scraper that follows /blog/<slug>/ now gets the 301 and reads tbmq.io's own og:image, so the blast radius is limited to already-cached share cards and index entries until they recrawl. That's a self-healing, cosmetic degradation on old shares — not worth seven extra splat rules, and no change needed.

The author pages are worth fixing in this PR. dlandiak and dmytro-shvaika have no remaining posts once these seven go, and [author].astro builds a path per BLOG_AUTHORS entry regardless of post count, so both still emit and render an avatar plus "0 posts / No posts by this author yet." — which reads as a bug to anyone arriving from an old bookmark. Since the posts are being removed here, the pages they existed to list belong in the same change.

The fix needs no redirects and breaks nothing. Having getStaticPaths skip authors with zero posts is sufficient on its own: the pages are already noindex (SeoMeta.astro:47 emits noindex, follow), already excluded from the sitemap (config/integrations/sitemap.ts:85 filters on noindex), and /blog/author/<slug>/ is linked only from [...slug].astro (byline :132, bio card :172, JSON-LD :61) — so with no posts left they're fully orphaned, with no rankings, no sitemap presence and no internal link equity to preserve. Nothing else reads those records either: getAuthor() is only ever called for the author of an existing post (rss.xml.ts:15, index.astro:86,145, [...slug].astro:20, BlogCard.astro:22), so it is never invoked for a postless slug.

One thing to pair with it: src/pages/open-graph/_shared/page-data.ts:94 also pushes an OG card per BLOG_AUTHORS entry, so it needs the same predicate or the build will keep rendering cards for routes that no longer exist. Worth deriving the "authors with at least one post" set once and using it in both places rather than writing the filter twice. The BLOG_AUTHORS entries themselves can stay — they're still the source for bylines — so this is a routing change, not a data deletion.

Note this also drops /blog/author/maryna/, which has been in the same postless state since before this PR. That's the right outcome, just worth knowing the diff will show three routes going away rather than two.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in a0026eb. Added getAuthorsWithPosts() in src/data/blog/posts.ts (authors from BLOG_AUTHORS that have at least one post in the blog collection) and used it in both [author].astro getStaticPaths and the author-card loop in page-data.ts, so the predicate lives in one place. The empty-state branch in [author].astro is gone since a page can no longer be postless, and the redirects.ts comment no longer claims the author pages stay. BLOG_AUTHORS is untouched.

Verified with pnpm build:fast: dist/blog/author/ and dist/open-graph/blog/author/ both drop from 18 to 15 entries, and dlandiak, dmytro-shvaika and maryna are absent from both, as you predicted.

deaflynx and others added 2 commits September 3, 2026 12:57
Derive the set of authors that still have at least one post once
(getAuthorsWithPosts) and use it for both the /blog/author/ routes and
their OG cards, so postless authors no longer emit an empty landing page.
BLOG_AUTHORS entries stay as the byline source.
The previous wording justified keeping every BLOG_AUTHORS entry so "old
posts still resolve", but the entries it was describing (dlandiak,
dmytro-shvaika, maryna) now have no posts at all, so nothing resolves
them. It also said "published post", implying a draft/published split
that blogSchema does not have.
@vvlladd28
vvlladd28 merged commit 48fa799 into thingsboard:main Sep 3, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants