buildmymcpserver/apps/web/app/(marketing)/layout.tsx

67 lines
2.9 KiB
TypeScript
Raw Normal View History

import { Logo } from '@/components/logo';
import { MarketingAuthButtons } from '@/components/marketing-auth-buttons';
import { MarketingMobileMenu } from '@/components/marketing-mobile-menu';
import Link from 'next/link';
export default function MarketingLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex min-h-screen flex-col">
<header className="sticky top-0 z-50 border-b border-[--color-border] bg-[--color-bg]/80 backdrop-blur-md">
<div className="mx-auto flex h-12 max-w-6xl items-center justify-between px-5 sm:px-6">
<div className="flex items-center gap-6">
<Logo />
<nav className="hidden items-center gap-5 text-[13px] text-[--color-fg-muted] md:flex">
<Link href="/#how" className="transition-colors hover:text-[--color-fg]">
How it works
</Link>
feat(marketplace): template publish + fork + voting/ranking + admin moderation What this enables: - A user builds an MCP server. If others would benefit, they click 'Publish as template' on their server detail page. The spec + pre-rendered TypeScript snapshot is preserved. - Visitors browse /templates, filter by category, sort by trending/top/newest. Each template card shows fork count + active deployment count as natural manipulation-resistant popularity signal. - /templates/[slug] shows the full plan: tool list with input schemas, required-credential explanations (with 'how to get one' deep links), and a collapsible code preview so users can audit before forking. - Fork is one click → /servers/new?template=slug. The wizard skips Step 1 and pre-fills Step 2 with the template's parsed spec. Forker only fills in their own credentials. mcp_servers.template_id is recorded; template.fork_count is bumped atomically. Each fork gets its own isolated container with its own port, its own AES-256 secrets — the template author has zero visibility into the fork's traffic or data. - Admin /admin/templates moderation: verify quality templates (shows shield badge in marketplace), hide low-effort ones, takedown anything malicious. Takedowns cascade-pause every fork container — owners must re-deploy. Why template+fork instead of shared-container: - Shared containers would mean the publisher's quota + their secrets + their logs are exposed to forkers. Bad ergonomics, bad security, bad ownership. - Templates/forks decouple the spec (shared, vouched-for) from the runtime (isolated per user). Network-effect moat without the trust collapse. Why no 5-star voting in v1: - Manipulation-anfällig, empty lists without adoption. We use fork count + active deploys + verified badge. Trending algorithm: score = (activeDeploys * 3 + forks) / sqrt(ageDays + 1) Real signal, no brigading attack surface. Backend: - New schema: templates table (16 cols incl. tools_schema, generated_code, required_secrets, allowedDomains, status enum, verified, fork_count). - mcp_servers.template_id FK + idx for fork lookup. - @bmm/types: SpecEdit unchanged, CreateServerInput accepts optional templateId. - preview-cache.ts: new cachePrebuiltCode/loadPrebuiltCode for storing the template's full rendered server.ts alongside the spec. Generator worker detects this and skips the render step — uses the audited pre-built code verbatim. Banned-pattern re-scan at publish time. - routes/templates.ts: 5 public/auth routes + 2 admin routes. Banned-pattern re-scan before publish. Slug auto-uniqued. forkCount atomic-increment via SQL. UI: - /templates marketplace with trending/top/newest tabs, category filter, search. Cards show forks + live count + author + verified badge. - /templates/[slug] full detail with tools, credentials-with-hints, expandable code preview, fork CTA, ownership + stats sidebar, 'forking is safe' explainer. - /servers/new?template=slug — wizard auto-jumps to Step 2 with template spec pre-filled, fork banner at top with link back to template. - /servers/[id] new Publish tab with title, category, descriptions, per-secret hint fields (description + howToGetUrl per UPPER_SNAKE_CASE key). - /admin/templates moderation with verify/hide/takedown actions. - Marketing nav now includes /templates. Verified end-to-end: - Published Echo Demo Template from marco@test.local's live server - Marketplace lists it correctly with stats - Detail page renders with all sections - Fork CTA navigates to wizard with ?template= param - Wizard skips Step 1, shows fork banner, pre-fills spec - Build succeeds in ~10s (cached spec + prebuilt code path skips Claude AND render), container live on :4109 with proper OAuth 401 → token → 200 flow - DB: templates.fork_count=1, activeDeployments=1, mcp_servers.template_id populated on the fork - /admin/templates shows the new template with verify/hide/takedown controls
2026-05-19 23:22:35 +02:00
<Link href="/templates" className="transition-colors hover:text-[--color-fg]">
Templates
</Link>
<Link href="/pricing" className="transition-colors hover:text-[--color-fg]">
Pricing
</Link>
<Link href="/docs" className="transition-colors hover:text-[--color-fg]">
Docs
</Link>
<Link href="/changelog" className="transition-colors hover:text-[--color-fg]">
Changelog
</Link>
</nav>
</div>
<div className="flex items-center gap-1.5 sm:gap-2">
<MarketingAuthButtons />
<MarketingMobileMenu />
</div>
</div>
</header>
<main className="flex-1">{children}</main>
<footer className="border-t border-[--color-border] py-8">
<div className="mx-auto flex max-w-6xl flex-col gap-4 px-6 text-[12px] text-[--color-fg-subtle] md:flex-row md:items-center md:justify-between">
<Link
href="/status"
className="flex items-center gap-2 transition-colors hover:text-[--color-fg]"
>
<span className="size-1.5 animate-pulse rounded-full bg-emerald-400" />
<span>System status</span>
</Link>
<div className="flex flex-wrap gap-x-5 gap-y-1">
<Link href="/docs" className="transition-colors hover:text-[--color-fg]">
Docs
</Link>
<Link href="/security" className="transition-colors hover:text-[--color-fg]">
Security
</Link>
<Link href="/privacy" className="transition-colors hover:text-[--color-fg]">
Privacy
</Link>
<Link href="/terms" className="transition-colors hover:text-[--color-fg]">
Terms
</Link>
</div>
<div>&copy; {new Date().getFullYear()} BuildMyMCPServer</div>
</div>
</footer>
</div>
);
}