Skip to content

feat(blog): add E-E-A-T author profiles with bios and social links - #8037

Merged
ankur-arch merged 5 commits into
mainfrom
feat/blog-author-eeat-bios
Jul 9, 2026
Merged

feat(blog): add E-E-A-T author profiles with bios and social links#8037
ankur-arch merged 5 commits into
mainfrom
feat/blog-author-eeat-bios

Conversation

@ankur-arch

@ankur-arch ankur-arch commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

What

Adds E-E-A-T author profiles to the blog — author biographies plus social profile links (X, LinkedIn, GitHub, Mastodon) rendered as icons with the link embedded. Bios are sourced from the team's Notion "E-E-A-T: Author Biographies" table (19 authors).

Why

Experience, Expertise, Authoritativeness, and Trustworthiness are signals Google (and increasingly AI) use to decide whether to trust and rank content. Surfacing who wrote a post, their background, and verifiable profiles improves those signals.

Changes

  • lib/author-bios.ts — 19 author bios + socials, keyed by slug. Each entry carries a names[] alias list so frontmatter bylines that differ from the canonical bio name resolve correctly (e.g. Will Madden → William Madden, Søren Bramer Schmidt → Søren Schmidt, Josh McLeod → Joshua McLeod).
  • components/AuthorBio.tsx — an "About the author(s)" section for posts, plus a shared AuthorSocialLinks piece rendering FontAwesome brand icons (fa-brands fa-{x-twitter,linkedin,github,mastodon}), matching the existing icon system.
  • Author page (/author/[slug]) — bio + social icons in the header; ProfilePage/Person JSON-LD (sameAs, description, image); meta description now uses the bio.
  • Post page (/[slug]) — "About the author" section, and the BlogPosting author schema enriched with url, sameAs, and description.

Authors without a bio render gracefully with no profile block.

Verification

Ran the dev server and confirmed:

  • Post page renders the section + icons and emits the enriched author schema.
  • Author page renders bio/icons + ProfilePage JSON-LD.
  • The soren-bramer-schmidt alias resolves to the correct bio with sameAs populated.
  • No-bio authors (e.g. Nikolas Burk) render cleanly with no crash.
  • tsc --noEmit passes with 0 errors; lint clean.

Notes

  • Bios cover current team members; long-tail former authors have no bio and simply show no profile block.
  • Bios are copied from Notion (point-in-time); author-bios.ts is the single place to update.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added “About the author(s)” sections to blog posts with author cards, avatars, bios, and social/profile links.
    • Updated author pages to show richer author bio content and embed structured author profile information.
  • Bug Fixes

    • Improved SEO metadata and JSON-LD for both single- and multi-author posts, including richer author details (when available).
    • Applied safer fallbacks so missing author bio details don’t result in incomplete structured data.

Add author biographies and social profile links (X, LinkedIn, GitHub,
Mastodon) to the blog to strengthen E-E-A-T signals.

- author-bios.ts: 19 author bios + socials, keyed by slug with name
  aliases so frontmatter bylines (e.g. "Will Madden", "Søren Bramer
  Schmidt", "Josh McLeod") resolve to their canonical bio.
- AuthorBio.tsx: "About the author(s)" section for posts + a shared
  AuthorSocialLinks piece rendering FontAwesome brand icon links.
- Author page: bio + social icons in the header, plus ProfilePage/Person
  JSON-LD (sameAs, description, image). Meta description uses the bio.
- Post page: "About the author" section, and BlogPosting author schema
  enriched with url, sameAs, and description.

Authors without a bio render gracefully with no profile block.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
blog Ready Ready Preview, Comment Jul 9, 2026 2:27pm
docs Ready Ready Preview, Comment Jul 9, 2026 2:27pm
eclipse Ready Ready Preview, Comment Jul 9, 2026 2:27pm
site Ready Ready Preview, Comment Jul 9, 2026 2:27pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e8053028-0465-4ad5-8618-2150fce839b2

📥 Commits

Reviewing files that changed from the base of the PR and between 7b127b1 and f1dd517.

📒 Files selected for processing (1)
  • apps/blog/src/components/AuthorBio.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/blog/src/components/AuthorBio.tsx

Walkthrough

This PR adds author bio data and lookup helpers, renders author bio content in blog and author pages, and upgrades both pages’ JSON-LD and metadata to include richer author details.

Changes

Author bios feature

Layer / File(s) Summary
Author bio dataset and lookup helpers
apps/blog/src/lib/author-bios.ts
Adds AuthorSocial/AuthorBio types, the static AUTHOR_BIOS dataset, an internal slug map, and exported bio/social lookup helpers.
AuthorBio and AuthorSocialLinks components
apps/blog/src/components/AuthorBio.tsx
Adds icon metadata, social-link rendering, and the author bio section that normalizes authors, deduplicates profiles, and renders cards.
Blog post page JSON-LD and AuthorBio rendering
apps/blog/src/app/(blog)/[slug]/page.tsx
Adds richer author Person schema generation, replaces inline author JSON-LD mapping, and renders an “About the author(s)” section.
Author profile page JSON-LD, layout, and metadata
apps/blog/src/app/(blog)/author/[slug]/page.tsx
Adds ProfilePage JSON-LD, renders author social links and bio text, adjusts header layout, and prefers bio text in metadata descriptions.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: blog author profiles with bios and social links.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@argos-ci

argos-ci Bot commented Jul 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - Jul 9, 2026, 2:34 PM

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
apps/blog/src/app/(blog)/[slug]/page.tsx (1)

86-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse getAuthorSameAs instead of re-deriving sameAs inline.

author-bios.ts already exports getAuthorSameAs(name) for exactly this purpose, but Line 93 reimplements bio.socials.map((s) => s.url). The same pattern is duplicated again in author/[slug]/page.tsx's buildAuthorJsonLd. Worth consolidating into a single shared "Person schema from author name/slug" helper (e.g. in author-bios.ts) so url/description/sameAs derivation only needs to change in one place across both pages.

♻️ Proposed simplification
 function buildAuthorSchema(name: string): PersonSchema {
   const author: PersonSchema = { "`@type`": "Person", name };
   const slug = toAuthorSlug(name);
   const bio = getAuthorBioByName(name);
   if (slug) author.url = toAbsoluteUrl(withBlogBasePath(`/author/${slug}`));
   if (bio) {
     author.description = bio.bio;
-    if (bio.socials.length > 0) author.sameAs = bio.socials.map((s) => s.url);
+    const sameAs = getAuthorSameAs(name);
+    if (sameAs.length > 0) author.sameAs = sameAs;
   }
   return author;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/blog/src/app/`(blog)/[slug]/page.tsx around lines 86 - 97, The author
Person schema logic is re-deriving sameAs inline instead of using the shared
helper. Update buildAuthorSchema to call getAuthorSameAs(name) from
author-bios.ts, and consider extracting the repeated url/description/sameAs
assembly into a shared Person schema helper used by both buildAuthorSchema and
buildAuthorJsonLd so the author metadata stays centralized.
apps/blog/src/lib/author-bios.ts (1)

226-232: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Heads up: this helper isn't used anywhere in this cohort.

getAuthorSameAs was clearly built for populating sameAs in structured data, but both [slug]/page.tsx and author/[slug]/page.tsx reimplement bio.socials.map((s) => s.url) inline instead of calling it. See the corresponding comments in those files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/blog/src/lib/author-bios.ts` around lines 226 - 232, The sameAs URL
mapping is duplicated instead of using the shared helper. Update the
structured-data code in the relevant page components to call
getAuthorSameAs(name) from author-bios.ts rather than reimplementing
bio.socials.map((s) => s.url) inline, and remove any now-redundant local mapping
logic so the helper is actually used consistently.
apps/blog/src/app/(blog)/author/[slug]/page.tsx (1)

61-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Same duplicate sameAs derivation as the blog post page.

Line 76 reimplements bio?.socials.map((s) => s.url) ?? [] instead of calling getAuthorSameAs(profile.name) from author-bios.ts. This mirrors the identical inline logic in [slug]/page.tsx's buildAuthorSchema. Consider extracting a shared "build Person schema" helper (used by both pages) so the url/description/sameAs/@id shape stays consistent — right now this page's Person includes @id while the blog post page's doesn't.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/blog/src/app/`(blog)/author/[slug]/page.tsx around lines 61 - 85, The
author JSON-LD builder is duplicating `sameAs` logic instead of using the shared
author-bios helper, which can drift from the blog post page schema. Update
`buildAuthorJsonLd` to derive `sameAs` via `getAuthorSameAs(profile.name)` (or
extract a shared person-schema helper used by both `buildAuthorJsonLd` and the
blog post page’s `buildAuthorSchema`) so `url`, `description`, `sameAs`, and
`@id` are built consistently from one source.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/blog/src/components/AuthorBio.tsx`:
- Around line 57-68: AuthorBio currently assumes authors is always an array, so
a null or non-array value will make the filter/map chain throw and break post
rendering. Update AuthorBio to defensively normalize the incoming authors prop
before using it, similar to the Array.isArray check used in [slug]/page.tsx, and
only run the existing Set-based dedupe and slug/bio mapping on a verified array.
Keep the fix centered in AuthorBio and its authors handling so the rest of the
profile-building logic remains unchanged.

---

Nitpick comments:
In `@apps/blog/src/app/`(blog)/[slug]/page.tsx:
- Around line 86-97: The author Person schema logic is re-deriving sameAs inline
instead of using the shared helper. Update buildAuthorSchema to call
getAuthorSameAs(name) from author-bios.ts, and consider extracting the repeated
url/description/sameAs assembly into a shared Person schema helper used by both
buildAuthorSchema and buildAuthorJsonLd so the author metadata stays
centralized.

In `@apps/blog/src/app/`(blog)/author/[slug]/page.tsx:
- Around line 61-85: The author JSON-LD builder is duplicating `sameAs` logic
instead of using the shared author-bios helper, which can drift from the blog
post page schema. Update `buildAuthorJsonLd` to derive `sameAs` via
`getAuthorSameAs(profile.name)` (or extract a shared person-schema helper used
by both `buildAuthorJsonLd` and the blog post page’s `buildAuthorSchema`) so
`url`, `description`, `sameAs`, and `@id` are built consistently from one
source.

In `@apps/blog/src/lib/author-bios.ts`:
- Around line 226-232: The sameAs URL mapping is duplicated instead of using the
shared helper. Update the structured-data code in the relevant page components
to call getAuthorSameAs(name) from author-bios.ts rather than reimplementing
bio.socials.map((s) => s.url) inline, and remove any now-redundant local mapping
logic so the helper is actually used consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e301f649-0d80-457b-be4e-995a18973b24

📥 Commits

Reviewing files that changed from the base of the PR and between 2212ee6 and 23a98b9.

📒 Files selected for processing (4)
  • apps/blog/src/app/(blog)/[slug]/page.tsx
  • apps/blog/src/app/(blog)/author/[slug]/page.tsx
  • apps/blog/src/components/AuthorBio.tsx
  • apps/blog/src/lib/author-bios.ts

Comment thread apps/blog/src/components/AuthorBio.tsx
- Surface the "About the author" card near the top of each post (right
  after the byline, before the body) so readers and LLM/agent crawlers
  encounter author credentials early; restyle it as a self-contained
  bordered card.
- Render social links with the eclipse Action icon-button treatment used
  by the footer and share row, so the icons read as a consistent, tightly
  spaced set instead of drifting apart.
- Use fa-square-linkedin (the variant shipped in the FA kit) so the
  LinkedIn icon renders instead of showing a blank box.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the defensive Array.isArray handling used in [slug]/page.tsx so a
null or non-array page.data.authors cannot crash post rendering.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant