Service Integrations
show.fm integrates with multiple third-party services to provide a complete podcasting platform. This section documents the configuration, API patterns, and implementation details for each integration.
Architecture Overview
┌─────────────────────────────────────────────────────────────────────────┐
│ SERVICE INTEGRATION LAYER │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ show.fm Application │ │
│ │ (SvelteKit + Hono API Layer) │ │
│ └───────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────┼──────────────────────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │ │
│ ┌──────────┐ ┌──────────────────┐ ┌──────────────────────────┐ │ │
│ │Cloudflare│ │ Supabase │ │ Third-Party APIs │ │ │
│ │ Services │ │ PostgreSQL │ │ │ │ │
│ │ │ │ Auth │ │ • Google Calendar │ │ │
│ │ • Pages │ │ RLS │ │ • Stripe (Payments) │ │ │
│ │ • Workers│ │ │ │ • Resend (Email) │ │ │
│ │ • R2 │ │ │ │ │ │ │
│ │ • Queues │ │ │ │ │ │ │
│ │ • KV │ │ │ │ │ │ │
│ └──────────┘ └──────────────────┘ └──────────────────────────┘ │ │
│ │ │
└───────────────────────────────────────────────────────────────────────┘ │
│
└──────────────────────────────────────────────────────────────────────────┘Service Documentation
| Service | Purpose | Status |
|---|---|---|
| Cloudflare | Infrastructure - Pages, Workers, R2, Queues, KV, Hyperdrive | Production |
| Supabase | Database, authentication, RLS policies, real-time | Production |
| Google Calendar | OAuth, availability checking, event creation | Production |
| Stripe | Subscriptions, checkout, webhooks, billing portal | Production |
| Resend | Transactional email, templates, audience management | Production |
| Search System | Fuse.js (client) + PostgreSQL FTS (server) | Production |
Service Categories
Infrastructure Services
Cloudflare provides the edge computing infrastructure:
- Pages: Hosts the main SvelteKit application
- Workers: Runs RSS feed generation, automation execution, scheduled publishing
- R2: Object storage for audio files and media
- Queues: Async message processing for automation and cache invalidation
- KV: Global key-value storage for RSS feed caching
- Hyperdrive: Connection pooling for Workers → PostgreSQL
Data Services
Supabase provides the data layer:
- PostgreSQL: Primary database with multi-tenant schema
- Auth: User authentication with email/password and OAuth
- RLS Policies: Row-level security for multi-tenancy
- Admin Client: Service role access for Workers and webhooks
Scheduling & Calendar
Google Calendar powers the guest booking system:
- OAuth 2.0: Secure calendar access with refresh tokens
- FreeBusy API: Real-time availability checking across multiple calendars
- Events API: Automatic calendar event creation with Google Meet links
- Multi-Account: Support for multiple connected Google accounts
Payments & Billing
Stripe handles all payment processing:
- Checkout Sessions: Subscription signup flow
- Customer Portal: Self-service subscription management
- Webhooks: Real-time subscription state synchronization
- Tier Management: Price ID → subscription tier mapping
Search & Discovery
Search System provides two-layer search:
- Client-Side (Fuse.js): Instant fuzzy search for in-memory data (<10K items)
- Server-Side (PostgreSQL FTS): Full-text search with GIN indexes and trigram matching
- Command Palette: Global
Cmd+Ksearch across the application
Email & Communications
Resend handles all transactional and automation emails:
- Email Client: Type-safe Resend SDK wrapper with error handling
- Templates: Pre-built booking flow emails (request, confirm, decline, host notification)
- Audience Management: Contact creation and topic subscriptions for marketing
- Automation Integration: Sends emails triggered by the automation engine
Integration Patterns
Environment Configuration
All services use environment variables for configuration:
bash
# Cloudflare (set via wrangler.toml and wrangler secret)
CLOUDFLARE_ACCOUNT_ID=...
# Supabase
PUBLIC_SUPABASE_URL=https://xxx.supabase.co
PUBLIC_SUPABASE_ANON_KEY=...
SUPABASE_SECRET_KEY=... # Server-only
# Google Calendar
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=... # Server-only
GOOGLE_REDIRECT_URI=...
# Stripe
PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_...
STRIPE_SECRET_KEY=sk_... # Server-only
STRIPE_WEBHOOK_SECRET=whsec_...
# Resend
RESEND_API_KEY=re_... # Server-only
RESEND_FROM_EMAIL=[email protected]
RESEND_AUDIENCE_ID=aud_... # For marketing contactsAPI Route Pattern
Service integrations follow the Hono API pattern:
typescript
// src/api/routes/service-name/index.ts
import { Hono } from 'hono';
import type { Env } from '$api/types';
const serviceRoutes = new Hono<Env>().post('/action', async (c) => {
// Access secrets from environment
const apiKey = c.env?.SERVICE_API_KEY;
// Initialize service client
const client = new ServiceClient(apiKey);
// Perform action
const result = await client.doSomething();
return c.json({ data: result });
});
export { serviceRoutes };Webhook Pattern
External services call back via webhook endpoints:
typescript
// src/api/routes/webhooks/service.ts
webhookRoutes.post('/service', async (c) => {
// 1. Verify signature
const signature = c.req.header('x-signature');
const body = await c.req.text();
if (!verifySignature(body, signature, secret)) {
return c.json({ error: 'Invalid signature' }, 400);
}
// 2. Parse event
const event = JSON.parse(body);
// 3. Handle event
await handleEvent(event);
// 4. Acknowledge (always return 200 to prevent retries)
return c.json({ received: true });
});Security Considerations
Token Storage
| Service | Token Type | Storage | Refresh |
|---|---|---|---|
| Google Calendar | Refresh Token | Database (encrypted) | On-demand |
| Stripe | API Key | Environment variable | N/A |
| Supabase | Service Role Key | Environment variable | N/A |
| Resend | API Key | Environment variable | N/A |
Secret Management
- Local Development:
.envfile (gitignored) - Production:
wrangler secret putfor Cloudflare - Never commit: API keys, webhook secrets, service role keys
Rate Limiting
| Service | Limits | Handling |
|---|---|---|
| Google Calendar | 1M queries/day | Caching, batch requests |
| Stripe | 100 requests/second | Webhook queuing |
| Supabase | 500 requests/second | Connection pooling via Hyperdrive |
| Resend | 10 requests/second | Queue-based automation sends |
Error Handling
All service integrations follow consistent error handling:
typescript
try {
const result = await serviceClient.action();
return c.json({ data: result });
} catch (error) {
// Log with context
console.error(
JSON.stringify({
event: 'service_error',
service: 'service-name',
error: error instanceof Error ? error.message : String(error)
})
);
// Return generic error (don't expose internals)
return c.json({ error: 'Service unavailable' }, 500);
}Related Documentation
- Architecture Overview - System design context
- Workers Documentation - Cloudflare Workers using these services
- API Reference - Hono API routes that expose service functionality
- Testing Mocks - Mock factories for service testing