* blog: honor canonical_url so guest posts point at their source
A post syndicated from another blog carries the original URL in
blog_posts.canonical_url (the autoblog webhook already stores it). The post
page ignored it and always self-canonicalized, so a guest post would
compete with its source for the same words. Now the page selects
canonical_url and author, sets rel=canonical to the original when present
(self otherwise), points JSON-LD mainEntityOfPage at it, and shows readers
an "Originally published on <host>" line with the author byline.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MxNif5tsYq4LczgG7aE8Jp
* blog: author is jsonb, render a name not [object Object]
The blog_posts.author column is jsonb (e.g. { name, url }), not text.
Extract a display name for the byline and JSON-LD instead of rendering the
object directly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MxNif5tsYq4LczgG7aE8Jp
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Reusable AdUnit component (div[data-cp-ad] + ad.js via next/script) placed
in-content on the blog index and post pages, scoped to /blog/* only.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The dynamic /blog/rss.xml returned 500 in CI (no Supabase env) and the E2E
still asserted the old static feed's hand-written items.
- /blog, /blog/[slug], and /blog/rss.xml now degrade gracefully (empty feed/
list, HTTP 200) when Supabase is unavailable, instead of throwing.
- E2E: assert the always-present channel <title>LogicSRC Blog</title> and a
looser xml content-type, dropping the removed static post titles.
Verified with `next dev` and no Supabase env (CI conditions): rss/blog/sitemap
all return 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Only the .rail sidebar is dark; the .workspace content area is on the
light (#f6f7f4) page background. The previous blog styling assumed a dark
workspace, so text was light-grey on white (unreadable) and the link
green was too light.
- Darken the global link color to #0a7d59 (readable on white); content
links only — rail nav stays inherited.
- Repaint .blog-content (post HTML) for a light surface: dark body text,
light code/pre, light borders.
- Blog index/post: dark titles, readable grey meta, light row borders;
light-themed footer.
- Add post thumbnails to the /blog index from featured_image.url.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add SiteShell (rail nav + workspace + footer) and wrap /blog and
/blog/[slug] in it so they share the site's dark chrome instead of
rendering as bare standalone pages.
- Style rendered post HTML (.blog-content) for the dark workspace.
- Links were `color: inherit` everywhere, so content-area links matched
body text and were invisible. Give links a distinct accent (#5ac8a6);
keep the rail nav and buttons on their own colors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an autoblog webhook receiver and a Supabase-backed blog to logicsrc-web
(the app had no Supabase usage before).
- Migration: blog_posts table (RLS: public reads published, service-role
writes). Applied to the linked project.
- POST /api/webhooks/blog: verifies the Standard Webhooks signature against
BLOG_WEBHOOK_SECRET via @profullstack/autoblog verifyAndParse (no admin
user — shared secret only) and upserts the post by slug.
- /blog index + /blog/[slug] render published posts from the table.
- /blog/rss.xml and /sitemap.xml are now dynamic, generated from the table;
removed the static public/sitemap.xml and public/blog/rss.xml.
- BLOG_WEBHOOK_SECRET added to .env.example.
Verified end-to-end: a signed sample post delivered 200 and appeared in the
index, post page, RSS, and sitemap; build + typecheck pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>