Commit graph

9 commits

Author SHA1 Message Date
df57b54bde
Breadcrumbs on every page, and a sidebar that unfolds to where you are (#170)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
Anthony: "this needs a cookie crumb navbar, all pages need this with the
new IA" and "broad and drill down, I'm not seeing that in the sidebar".

lib/crumbs.ts derives the trail from the path and the spec registry, so
no page declares it: /openthreat is Home > Specs > Catalogs a site serves
about itself > OpenThreat, /opencpu adds OpenServer before OpenCPU,
/docs/openthreat ends in Specification, /docs/cli is Home > Docs > CLI,
a blog post passes its title as the leaf. components/breadcrumbs.tsx
renders it (server-rendered, with a BreadcrumbList JSON-LD) at the top
of every SiteShell page; the SPA routes rendered by page-markup.ts get
the same trail as a string.

components/side-nav.tsx replaces the flat sidebar: the four groups stay,
and under Specs the family the current page belongs to unfolds to its
specs, and the spec to its blocks, marked active. The home page string
marks the active entry for the SPA routes too.


Claude-Session: https://claude.ai/code/session_014cmNRtR2vL1p89dbVQ7FZJ

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 21:04:02 -07:00
00622f5882
blog: honor canonical_url so guest posts point at their source (#151)
* 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>
2026-09-12 08:25:21 -07:00
d76dd498f2 feat(web): add CrawlProof ad unit to /blog/*
Some checks failed
CI / build (push) Has been cancelled
test / test (push) Has been cancelled
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>
2026-07-08 10:40:04 +00:00
phucnguyen1707
59013cf0af
Sanitize rendered web content (#77) 2026-06-15 01:34:44 -07:00
e47616bf9d fix(web): CI E2E — resilient blog/RSS without Supabase + update stale test
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>
2026-06-08 13:00:51 +00:00
6518dfb4a9 feat(web): AEO foundation — robots, JSON-LD, meta, llms.txt, security headers
Implements the high-signal, content-independent fixes flagged across the
multi-engine AEO audit:

- robots.txt (app/robots.ts): allow mainstream + AI crawlers (GPTBot,
  ClaudeBot, PerplexityBot, Google-Extended, …), disallow /api, link sitemap.
- Organization + WebSite JSON-LD on the root layout; BlogPosting JSON-LD on
  /blog/[slug].
- Richer metadata: descriptive default title, Open Graph + Twitter cards,
  canonical, icons, metadataBase.
- Per-route titles/descriptions for catch-all routes (docs, about, hire-us,
  agent-swarm, …) instead of the generic "LogicSRC".
- /llms.txt (llmstxt.org) and /skill.md capability manifest.
- /.well-known/security.txt (RFC 9116).
- Security headers via next.config: HSTS, X-Content-Type-Options,
  X-Frame-Options, Referrer-Policy, Permissions-Policy (CSP intentionally
  deferred to avoid breaking inline/stats/CoinPay scripts).

Verified in a running build: all routes serve correctly and headers are set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:38:27 +00:00
ce79f02211 fix(web): correct blog colors for the light workspace + thumbnails
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>
2026-06-08 12:21:46 +00:00
7e11130467 feat(web): site chrome on /blog + distinct content link color
- 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>
2026-06-08 12:12:54 +00:00
cf99e93c53 feat(web): blog-post ingestion webhook + /blog, dynamic RSS & sitemap
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>
2026-06-08 11:53:43 +00:00