Files
podcastdistributiona/app/(marketing)/privacy/page.tsx
T
Leon SerfatyandClaude Opus 5 3e9ba07175 feat: Cloudflare Turnstile on auth, CSP fixes, admin/SEO/analytics additions
Turnstile bot protection (sign-in, sign-up, password-reset):
- Register Better Auth's captcha plugin with the cloudflare-turnstile
  provider; endpoints listed explicitly rather than relying on defaults.
  /reset-password is intentionally excluded — it is reached only via a
  single-use emailed token.
- Add an explicit-render Turnstile widget component. Tokens are single-use,
  so each form resets the challenge after a failed submit; submit stays
  disabled until a token is held.
- Read the site key server-side and pass it down as a prop, so rotating it
  does not require a rebuild.
- Fail fast in production when TURNSTILE_SECRET_KEY is missing, and when a
  secret is set without a site key (that combination would demand a token
  no form can produce, locking every user out).
- Pass a throwaway secret during `next build` in the Dockerfile, mirroring
  the existing BETTER_AUTH_SECRET treatment, so image builds don't need it.

CSP fixes in middleware (these blocked Turnstile entirely):
- Add frame-src for challenges.cloudflare.com. Without it the widget's
  iframe fell back to default-src 'self' and was blocked outright.
- Allow 'unsafe-eval' and websockets in DEVELOPMENT only. `next dev`
  compiles with eval(), so the strict policy threw EvalError and killed
  hydration — no client JS ran at all, which also meant form submit
  handlers never fired. Production policy is unchanged and still strict.

Also included (concurrent work in the tree):
- Admin organizations pages and lib/admin/orgs.
- Episode moderation migration, SEO metadata (sitemap, robots, JSON-LD,
  OG/Twitter images, manifest), Umami analytics, not-found page.

Local dev database: docker-compose.dev.yml provisions Postgres 18 on port
5443 (5432-5442 are in use by other local projects).

Note: `npx tsc --noEmit` currently fails in app/(app)/team/page.tsx — an
`invitations` prop the component does not accept. This predates the commit
and will fail `next build` until fixed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 11:10:55 -04:00

120 lines
5.8 KiB
TypeScript

import type { Metadata } from "next";
import { LegalDoc, type LegalSection } from "@/components/marketing/legal-doc";
import { pageMetadata } from "@/lib/seo";
/** Shared by the page metadata and the document's structured data. */
const PATH = "/privacy";
const DESCRIPTION =
"How Podcast Distribution AI collects, uses, stores and protects your personal data and generated content — and the rights you have over it.";
export const metadata: Metadata = pageMetadata({
title: "Privacy Policy",
description: DESCRIPTION,
path: PATH,
});
const UPDATED = "June 7, 2026";
const SECTIONS: LegalSection[] = [
{
heading: "Information we collect",
paragraphs: ["We collect the following categories of information to operate Podcast Distribution AI:"],
bullets: [
"Account information you provide — your name, email address, and password (passwords are stored only as salted hashes).",
"Content you create — episode topics, prompts, configuration (tone, format, language, voices), generated scripts, audio, cover art, and repurposed content.",
"Billing information — your plan, subscription status, and payment-provider customer IDs. Card and bank details are handled by our payment processors and are never stored on our servers.",
"Usage and technical data — feature usage, monthly generation counts, API-key activity, IP address, browser/user-agent, and server logs used for security and debugging.",
],
},
{
heading: "How we use your information",
paragraphs: [
"We use your information to provide and improve the service: to authenticate you, generate and store your episodes, enforce plan limits, process payments, send transactional email, prevent abuse, and meet legal obligations. We do not sell your personal data, and we do not use your private content to train our own models.",
],
},
{
heading: "AI processing and sub-processors",
paragraphs: [
"Generating an episode requires sending the content you submit (and content derived from it) to our AI sub-processors so they can produce your script, audio, and artwork:",
],
bullets: [
"OpenAI — script generation, content moderation, and cover-art generation.",
"ElevenLabs — text-to-speech and multi-speaker dialogue synthesis.",
"These providers process your prompts and generated text under their own terms and security commitments. Only the data needed to perform the requested generation is shared.",
],
},
{
heading: "Payments",
paragraphs: [
"Subscriptions are processed by Stripe and PayPal. When you check out you interact with the provider directly; we receive only confirmation of your subscription status and identifiers needed to manage it. Please review the privacy policies of Stripe and PayPal for how they handle your payment data.",
],
},
{
heading: "Email",
paragraphs: [
"Transactional email (account verification, password resets, and episode-ready notifications) is delivered through Resend. We send only the information necessary to deliver these messages.",
],
},
{
heading: "Data retention",
paragraphs: [
"We retain your account and content for as long as your account is active. Generated assets (audio and artwork) are stored so we can deliver your episodes. When you delete an episode it is removed from our systems; when you delete your account, your personal data and content are deleted or anonymized except where we must retain records to comply with legal, tax, or accounting obligations.",
],
},
{
heading: "Your rights",
paragraphs: [
"Depending on where you live, you may have rights to access, correct, export, or delete your personal data, and to object to or restrict certain processing. You can edit your profile and delete your content from within the app, or contact us to exercise any of these rights. We will not discriminate against you for exercising them.",
],
},
{
heading: "Cookies and sessions",
paragraphs: [
"We use strictly-necessary cookies to keep you signed in and to secure your session. We do not use third-party advertising cookies.",
],
},
{
heading: "Security",
paragraphs: [
"We protect your data with encryption in transit, hashed credentials and API keys, scoped access controls, signed billing webhooks, and least-privilege storage. No method of transmission or storage is perfectly secure, but we work to protect your information and to respond promptly to any incident.",
],
},
{
heading: "Children",
paragraphs: [
"Podcast Distribution AI is not directed to children under 13 (or the minimum age required in your jurisdiction), and we do not knowingly collect their personal data.",
],
},
{
heading: "International transfers",
paragraphs: [
"We and our sub-processors may process your data in countries other than your own. Where required, we rely on appropriate safeguards for such transfers.",
],
},
{
heading: "Changes to this policy",
paragraphs: [
"We may update this policy from time to time. Material changes will be reflected by updating the date above and, where appropriate, by notifying you.",
],
},
{
heading: "Contact",
paragraphs: [
"Questions about this policy or your data? Email privacy@podcastdistributionai.com and we'll be glad to help.",
],
},
];
export default function PrivacyPage() {
return (
<LegalDoc
title="Privacy Policy"
updated={UPDATED}
intro="This Privacy Policy explains what information Podcast Distribution AI collects, how we use it, who we share it with, and the choices you have. It applies to your use of the Podcast Distribution AI website and application."
sections={SECTIONS}
path={PATH}
description={DESCRIPTION}
/>
);
}