logicsrc/apps/logicsrc-web/next.config.ts
Anthony Ettinger 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

34 lines
1.3 KiB
TypeScript

import type { NextConfig } from "next";
// The CommandBoard API (boards, tasks, plugins, /health) runs as its own
// service. In the old custom server.js it was mounted in-process; here we proxy
// those paths to it via rewrites. Our own /api routes (hire-us, oauth/coinpay,
// webhooks) are filesystem routes and match before these afterFiles rewrites.
const commandboardApiUrl = process.env.COMMANDBOARD_API_URL;
const securityHeaders = [
// HSTS — site is HTTPS-only behind Railway. No `preload` (irreversible).
{ key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "SAMEORIGIN" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
];
const nextConfig: NextConfig = {
async headers() {
return [{ source: "/:path*", headers: securityHeaders }];
},
async rewrites() {
if (!commandboardApiUrl) return [];
const base = commandboardApiUrl.replace(/\/$/, "");
return {
afterFiles: [
{ source: "/health", destination: `${base}/health` },
{ source: "/api/:path*", destination: `${base}/api/:path*` }
]
};
}
};
export default nextConfig;