import {
  DocsTitle,
  DocsLead,
  DocsH2,
  DocsP,
  DocsList,
  DocsLi,
  DocsCode,
  Mono,
} from '@/components/docs-page';
import { JsonLd } from '@/components/json-ld';
import { breadcrumbJsonLd, pageMetadata } from '@/lib/seo';

export const metadata = pageMetadata({
  title: 'Self-hosting',
  description:
    'Run the BuildMyMCPServer control plane yourself — bring your own Postgres, Redis and Docker host, plus the production sandboxing flags for generated containers.',
  path: '/docs/self-hosting',
});

export default function SelfHosting() {
  return (
    <>
      <JsonLd
        data={breadcrumbJsonLd([
          { name: 'Home', path: '/' },
          { name: 'Docs', path: '/docs' },
          { name: 'Self-hosting', path: '/docs/self-hosting' },
        ])}
      />
      <DocsTitle kicker="Build">Self-hosting</DocsTitle>
      <DocsLead>
        The control plane and generator are open. Bring your own Postgres, Redis, Docker host and
        Anthropic API key. Production uses Hetzner + Coolify + Traefik; the seams are the same.
      </DocsLead>

      <DocsH2 id="requirements">Requirements</DocsH2>
      <DocsList>
        <DocsLi>Node.js 20+</DocsLi>
        <DocsLi>pnpm 9+</DocsLi>
        <DocsLi>Docker engine reachable from the generator process</DocsLi>
        <DocsLi>Postgres 16+ and Redis 7+ (docker-compose for dev)</DocsLi>
        <DocsLi>Anthropic API key (optional — mock fallback for offline dev)</DocsLi>
      </DocsList>

      <DocsH2 id="dev">Local dev</DocsH2>
      <DocsCode
        label="bash"
        code={`git clone <repo>
cd buildmymcpserver
pnpm install
cp .env.example .env
pnpm dev`}
      />
      <DocsP>
        <Mono>pnpm dev</Mono> loads <Mono>.env</Mono>, brings up Postgres and Redis via
        docker-compose, pushes the Drizzle schema, and starts web (<Mono>:3001</Mono>), api
        (<Mono>:4000</Mono>) and generator concurrently.
      </DocsP>

      <DocsH2 id="env">Environment variables</DocsH2>
      <DocsList>
        <DocsLi><Mono>DATABASE_URL</Mono> — Postgres connection string</DocsLi>
        <DocsLi><Mono>REDIS_URL</Mono> — Redis (BullMQ + pubsub + preview cache)</DocsLi>
        <DocsLi><Mono>ANTHROPIC_API_KEY</Mono> — unset = mock generator</DocsLi>
        <DocsLi><Mono>SECRETS_ENCRYPTION_KEY</Mono> — 32-byte hex, AES-256-GCM key</DocsLi>
        <DocsLi><Mono>CONTROL_PLANE_PUBLIC_URL</Mono> — issuer for OAuth tokens</DocsLi>
        <DocsLi><Mono>OAUTH_KEY_DIR</Mono> — where RS256 keypair lives (auto-generated on boot)</DocsLi>
        <DocsLi><Mono>RUNNER_PORT_RANGE_START/END</Mono> — host port window for generated containers</DocsLi>
      </DocsList>

      <DocsH2 id="prod">Production deployment</DocsH2>
      <DocsP>
        The intended production setup is a Hetzner AX52 running Coolify, Traefik for wildcard SSL
        on <Mono>*.mcp.yourdomain.com</Mono>, and Cloudflare for DNS+DDoS. The runner-deploy
        adapter is the only environment-specific seam — swap the Docker-CLI implementation in
        <Mono>apps/generator/src/lib/deploy.ts</Mono> for the Coolify HTTP API.
      </DocsP>

      <DocsH2 id="sandboxing">Container sandboxing</DocsH2>
      <DocsP>
        Production flags (commented in deploy.ts):
      </DocsP>
      <DocsList>
        <DocsLi><Mono>--read-only</Mono></DocsLi>
        <DocsLi><Mono>--cap-drop=ALL</Mono></DocsLi>
        <DocsLi><Mono>--security-opt=no-new-privileges</Mono></DocsLi>
        <DocsLi><Mono>--cpus=0.5 --memory=512m</Mono></DocsLi>
      </DocsList>
      <DocsP>
        Dev relaxes these for Docker Desktop on Windows compat. Don&apos;t ship dev defaults to
        prod.
      </DocsP>
    </>
  );
}
