RevenueCat Shipyard 2026 — Eitan Bernath Brief
Technical Docs
Architecture, tech stack, and RevenueCat implementation.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ iOS App (Swift/SwiftUI) │
│ @Observable state │ NavigationStack │
│ Share Extension │ Cooking Mode │ RevenueCat SDK │
└──────────────┬──────────────────────────────┬───────────────┘
│ │
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────────┐
│ Nuxt 4 API (Railway) │ │ RevenueCat Dashboard │
│ │ │ │
│ /api/recipes/import │ │ Entitlements: "pro" │
│ /api/recipes/[id]/stream│ │ Products: monthly + annual │
│ /api/extract │ │ Offerings: default │
└─────────┬────────────────┘ └──────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Extraction Pipeline │
│ │
│ yt-dlp / TikWM → Captions + Metadata │
│ Groq Whisper → Audio transcription (when no captions) │
│ Claude Sonnet → Structured recipe JSON extraction │
│ Supabase Storage → Image persistence │
└─────────┬────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Supabase (PostgreSQL) │
│ │
│ Auth: Anonymous sign-in (device-based) │
│ Storage: recipe-images bucket │
│ Realtime: grocery list sync │
└──────────────────────────────────────────────────────────────┘Tech Stack
iOS App
- Language: Swift 6.0
- UI: SwiftUI (iOS 17+)
- State: @Observable pattern
- Navigation: NavigationStack
- Payments: RevenueCat SDK
- Backend client: supabase-swift
Web & API
- Framework: Nuxt 4 (Vue 3)
- UI: Nuxt UI v3 + Tailwind CSS
- Hosting: Railway
- Domain: getcooked.today
- Code quality: oxlint + oxfmt
Backend / Data
- Database: Supabase (PostgreSQL)
- Auth: Supabase Anonymous Auth
- Storage: Supabase Storage (images)
- Realtime: Supabase Realtime (grocery sync)
AI / Extraction
- LLM: Claude Sonnet 4.5
- Transcription: Groq Whisper
- Video metadata: yt-dlp + TikWM API
- Output: Structured JSON (json_schema mode)
Recipe Import Pipeline
The hero feature. Share a link from any platform and get a structured recipe in seconds.
1. URL Detection
User shares a URL via iOS Share Extension or pastes it in-app. Platform is detected (TikTok, Instagram, YouTube, or generic website).
2. Metadata Extraction
TikTok uses TikWM API for reliable extraction (including video text overlays). YouTube and Instagram use yt-dlp. Quick metadata is returned immediately, full extraction continues in background.
3. Transcription
If the video has no captions, audio is extracted and transcribed using Groq Whisper. Captions + video text overlays are combined for maximum context.
4. LLM Extraction
All content is sent to Claude Sonnet 4.5 with a structured JSON schema. Returns title, ingredients (with quantities and categories), ordered steps, and tags. Metrics tracked per extraction.
5. SSE Progress
Real-time progress streamed to the iOS app via Server-Sent Events. User sees each stage as it completes. Recipe is saved to Supabase with image persisted to Storage.
RevenueCat Implementation
SDK Integration
RevenueCat purchases-ios SDK added via Swift Package Manager. Configured at app launch with API key. User identified via Supabase anonymous auth ID for consistent tracking across sessions.
Products & Offerings
| Product | ID | Price |
|---|---|---|
| Monthly | cooked_pro_monthly | $4.99/mo |
| Annual | cooked_pro_annual | $29.99/yr |
Single entitlement: "pro". Default offering with $rc_monthly and $rc_annual packages. Products created in App Store Connect and linked to RevenueCat dashboard.
SubscriptionState (@Observable)
Centralized subscription state injected via SwiftUI environment. Handles entitlement checks, offering loading, usage tracking, and paywall presentation.
@Observable class SubscriptionState {
var isPro: Bool // Active "pro" entitlement
var currentOffering: Offering?
var annualPackage: Package?
var monthlyPackage: Package?
// Usage tracking (synced with Supabase)
var videoImportsUsed: Int
var totalRecipesImported: Int
// Limit checks
func canAddRecipe() -> Bool
func canImportVideo() -> Bool
// Paywall
func showPaywall()
func purchase(_ package: Package) async
func restorePurchases() async
}Entitlement Gating
Limits are enforced at multiple touchpoints:
- Recipe import: Free users get 10 video imports/month. Limit check before extraction starts. Paywall shown when exceeded.
- Recipe library: Free users limited to 8 recipes. Recipes beyond the limit are shown with a blur overlay and lock icon.
- Menu history: Free users see last 3 menus. Upgrade prompt shown inline for older history.
- Server-side:
user_settings.subscription_statussynced for backend validation.
Paywall UI
Native SwiftUI paywall presented as a sheet. Shows pro benefits, monthly/yearly toggle (defaults to yearly for better conversion), real-time prices fetched from RevenueCat offerings, and restore purchases option. Triggered contextually when users hit limits.
Feature Summary
Multi-platform recipe import
TikTok, Instagram, YouTube, recipe websites
iOS Share Extension
Import from any app without switching
Menu planning system
State machine: planning → to_cook → archived
Smart grocery list generation
Consolidated, categorized, shareable via QR
Real-time grocery list sync
Family can check items off together via web link
Cooking mode
Step-by-step with timers, wake lock, haptic feedback
Menu history & reuse
Cook favorites again with one tap
Bold Swiss design system
Consistent across iOS app and web