All checks were successful
Deploy to Production / deploy (push) Successful in 57s
Legal (Swiss minimum, no individual named): - Impressum page (UWG Art. 3 lit. s) — provider, contact via support panel, no email required, jurisdiction = Switzerland - AGB page — subscription terms, payment, cancellation, suspension on payment fail, 14-day money-back, AI-processing-per-tier disclosure, Swiss law + Swiss venue, modeled after typical Schweizer SaaS terms - Privacy: Stripe added as subprocessor with full data-flow disclosure Support panel replaces email contact entirely: - @bmm/db: support_status enum + support_tickets + support_messages tables, migration applied to prod DB - @bmm/api: support routes (user create/list/view/reply, admin list/view/reply /set-status), public /v1/contact for logged-out visitors with per-IP rate limit of 3 submissions/day to prevent spam-flood - Web: /settings/support (list + new), /settings/support/[id] (conversation), /admin/support, /admin/support/[id] - Public /contact form with email collection for guest tickets Data rights (DSG Art. 25 / GDPR Art. 15+20): - /v1/account/export returns user-scoped JSON of profile, org, servers, builds, audit, support tickets and messages — excludes hashes, encrypted secrets, other-user data - /settings/account: download button + deletion-via-ticket workflow Production-readiness gaps closed: - org.suspended now blocks /v1/servers POST and /v1/servers/preview (402); webhook flagged this state but enforcement was missing - Cookie banner: minimal, essential-cookies-only disclosure (Swiss DSG + GDPR compliant without dark-pattern consent UI), mounts on both layouts Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
124 lines
5.4 KiB
TypeScript
124 lines
5.4 KiB
TypeScript
import { pageMetadata } from '@/lib/seo';
|
|
|
|
export const metadata = pageMetadata({
|
|
title: 'Privacy',
|
|
description:
|
|
'BuildMyMCPServer privacy policy — what data we collect, how it is used, and the rights you have over it.',
|
|
path: '/privacy',
|
|
});
|
|
|
|
const SECTIONS = [
|
|
{
|
|
h: 'What we collect',
|
|
p: [
|
|
'Account: email, organization name, the IP address of your sign-in.',
|
|
'Workspace: the prompts you send to the generator, the generated server specifications, build logs, server names and slugs you choose.',
|
|
'Tool-call metrics: counts, latencies, status codes — never the request or response payloads. We only know that a tool was called, how long it took, and whether it succeeded.',
|
|
'Billing: Stripe customer id + subscription metadata for paid plans. Card details never touch our servers.',
|
|
],
|
|
},
|
|
{
|
|
h: 'What we do NOT collect',
|
|
p: [
|
|
'Plaintext credentials. Every secret you save is AES-256-GCM encrypted before it hits storage. We have no ability to read them; only your container at runtime can.',
|
|
'Tool-call payloads. The arguments your AI client sends and the responses our server returns are not stored or logged.',
|
|
'Browsing data, cross-site tracking, advertising identifiers.',
|
|
],
|
|
},
|
|
{
|
|
h: 'Where it lives',
|
|
p: [
|
|
'EU region by default (Hetzner Falkenstein, Germany).',
|
|
'Postgres + Redis + container hosts are all in the same region.',
|
|
'Backups encrypted at rest in Backblaze B2 EU.',
|
|
],
|
|
},
|
|
{
|
|
h: 'Subprocessors',
|
|
p: [
|
|
"Anthropic, USA (Claude AI — used for prompt analysis and code generation on Pro / Team / Enterprise tiers). Only the prompt text and resulting spec are sent. Anthropic's data-retention policy applies.",
|
|
'Zhipu AI, China (GLM model — used for prompt analysis on the free Hobby tier only). Only the prompt text and resulting spec are sent. Upgrade to a paid tier to keep all AI processing within Anthropic (US).',
|
|
'Stripe Payments Europe Ltd., Ireland (billing, invoicing, payment processing, automatic VAT). Stripe receives: email, billing address, payment method details. Card numbers are tokenised by Stripe and never reach our servers. Stripe is GDPR-compliant and Swiss-DSG-aligned via the EU-Swiss adequacy decision.',
|
|
'Hetzner, Germany (compute, Postgres, Redis, runner containers).',
|
|
'Backblaze, EU (encrypted backups).',
|
|
'Cloudflare (DNS + DDoS protection + TLS termination).',
|
|
],
|
|
},
|
|
{
|
|
h: 'AI processing per tier',
|
|
p: [
|
|
'Hobby (free): prompts are sent to Zhipu AI (GLM, China) for analysis. Choose a paid tier if your prompts contain data that must not leave the EU/US.',
|
|
'Pro: prompts are sent to Anthropic (Claude Haiku 4.5, USA).',
|
|
'Team: prompts are sent to Anthropic (Claude Sonnet 4.6, USA).',
|
|
'Enterprise: Anthropic (Claude Sonnet + Opus, USA) with EU-data-residency opt-in available on request.',
|
|
],
|
|
},
|
|
{
|
|
h: 'Retention',
|
|
p: [
|
|
'Active account: all workspace data kept while subscribed.',
|
|
'Cancelled account: 30-day grace period, then full deletion (servers, builds, logs, audit).',
|
|
'Audit log: 1 year on Team+, 30 days on Pro/Hobby.',
|
|
'Tool-call metrics: 30 days, then aggregated to daily counts.',
|
|
],
|
|
},
|
|
{
|
|
h: 'Your rights (GDPR)',
|
|
p: [
|
|
'Access — export everything in JSON via the settings page (Sprint 4) or by email.',
|
|
'Deletion — delete your organization in settings; everything goes within 30 days.',
|
|
'Rectification — change name and email yourself; everything else is editable on request.',
|
|
'Portability — the generated TypeScript source of every server is yours, downloadable.',
|
|
],
|
|
},
|
|
];
|
|
|
|
export default function Privacy() {
|
|
return (
|
|
<div className="mx-auto max-w-3xl px-6 py-16">
|
|
<header className="mb-12">
|
|
<div className="text-[11px] uppercase tracking-[0.16em] text-[--color-fg-subtle]">
|
|
Privacy policy
|
|
</div>
|
|
<h1 className="mt-2 text-[32px] font-semibold tracking-tight">Privacy</h1>
|
|
<p className="mt-3 text-[14px] leading-relaxed text-[--color-fg-muted]">
|
|
Plain language. What we collect, where it lives, how to get it deleted. Last updated
|
|
2026-05-19.
|
|
</p>
|
|
</header>
|
|
|
|
<div className="space-y-9">
|
|
{SECTIONS.map((s) => (
|
|
<section key={s.h}>
|
|
<h2 className="text-[16px] font-semibold tracking-tight">{s.h}</h2>
|
|
<ul className="mt-3 space-y-1.5">
|
|
{s.p.map((p) => (
|
|
<li
|
|
key={p}
|
|
className="relative pl-4 text-[13.5px] leading-relaxed text-[--color-fg-muted] before:absolute before:left-0 before:top-2 before:size-1 before:rounded-full before:bg-[--color-fg-subtle]"
|
|
>
|
|
{p}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
))}
|
|
|
|
<section>
|
|
<h2 className="text-[16px] font-semibold tracking-tight">Contact</h2>
|
|
<p className="mt-3 text-[13.5px] leading-relaxed text-[--color-fg-muted]">
|
|
Data controller: BuildMyMCPServer. Email{' '}
|
|
<a
|
|
className="text-[--color-accent] underline"
|
|
href="mailto:privacy@buildmymcpserver.com"
|
|
>
|
|
privacy@buildmymcpserver.com
|
|
</a>{' '}
|
|
for any of the above.
|
|
</p>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|