Files
podcastdistributiona/app/(marketing)/subprocessors/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

78 lines
3.1 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 = "/subprocessors";
const DESCRIPTION =
"The third-party providers that process data on behalf of Podcast Distribution AI — AI generation, payments, transactional email and hosting.";
export const metadata: Metadata = pageMetadata({
title: "Subprocessors",
description: DESCRIPTION,
path: PATH,
});
const UPDATED = "June 7, 2026";
const SECTIONS: LegalSection[] = [
{
heading: "About this list",
paragraphs: [
"To provide Podcast Distribution AI we use a small number of third-party companies (\"subprocessors\") that process data on our behalf. We share only the data each provider needs to perform its function, and we require appropriate confidentiality and security commitments from them.",
],
},
{
heading: "AI generation",
paragraphs: ["These providers generate the content you request:"],
bullets: [
"OpenAI — script generation, content moderation, and cover-art generation. Receives episode prompts and generated text.",
"ElevenLabs — text-to-speech and multi-speaker dialogue. Receives the script text to be voiced.",
],
},
{
heading: "Payments",
paragraphs: ["These providers process subscriptions and payments:"],
bullets: [
"Stripe — card payments and subscription management. Receives billing and contact details; card data is handled by Stripe directly.",
"PayPal — PayPal payments and subscription management. Receives billing and contact details.",
],
},
{
heading: "Email",
paragraphs: ["This provider delivers transactional email:"],
bullets: [
"Resend — sends verification, password-reset, and episode-ready emails. Receives your name and email address.",
],
},
{
heading: "Infrastructure",
paragraphs: [
"Podcast Distribution AI runs on managed server infrastructure that stores your account data and generated assets to operate the service. Hosting providers process service data only to provide hosting and do not use it for their own purposes.",
],
},
{
heading: "Changes to this list",
paragraphs: [
"We may add or replace subprocessors as the service evolves. When we do, we will update this page and the date above. If you have a data-processing agreement with us that requires advance notice of subprocessor changes, we will honor it.",
],
},
{
heading: "Contact",
paragraphs: ["Questions about our subprocessors or data processing? Email privacy@podcastdistributionai.com."],
},
];
export default function SubprocessorsPage() {
return (
<LegalDoc
title="Subprocessors"
updated={UPDATED}
intro="This page lists the third-party providers Podcast Distribution AI relies on to deliver the service and the data each one processes. It supports our Privacy Policy and is provided for transparency."
sections={SECTIONS}
path={PATH}
description={DESCRIPTION}
/>
);
}