WitPit
A gamified iOS app that trains quick-wittedness through AI-scored daily challenges, unlimited practice scenarios, and a community voting arena
More screenshots
Short description
WitPit is a native iOS app that helps users build verbal agility and quick thinking through timed wit challenges scored by AI across three dimensions: creativity, relevance, and humor. It features a freemium model with StoreKit 2 subscriptions, a community leaderboard, a structured Academy, and a 22-level XP progression system. The backend is a self-built REST API deployed on Railway, with Sign in with Apple and JWT auth.
Full description
The problem
Quick-wittedness is a learnable skill — but there's no structured way to practice it. Most people freeze when they need a fast, clever response in conversation. WitPit gives them a daily challenge to sharpen that reflex, immediate AI feedback to understand why a response lands, and a community arena to see how they stack up.
What I built
A full-stack product from scratch: native iOS app, REST API, and admin panel. The iOS app is the primary product — a SwiftUI app built with MVVM and the @Observable macro, targeting iOS 17+.
Core features:
- Daily challenge — one timed (45s) wit challenge per day, AI-scored on creativity, relevance, and humor (1–10 each), with XP awarded and streak tracked
- Practice mode — unlimited (Pro) or 5/day (free) AI-generated scenarios with full coaching feedback, no persistence
- Community arena — ranked leaderboard of today's responses with community voting; one vote per response, enforced server-side
- Wit Academy — 5 structured lessons on timing, wordplay, callbacks, and social reading; lessons 3–5 gated behind Pro
- Progression system — 22 levels from "Wit Newbie" to "Comedy Deity", XP formula
(overall × 10) + (creativity × 2) + (humor × 2), daily streak tracking - Freemium / StoreKit 2 — monthly ($4.99) and annual ($34.99) subscriptions; paywall sheet triggered contextually from Practice, Academy, and Settings; entitlements synced on every launch
Technical highlights:
iOS
- SwiftUI +
@Observablefor reactive state without@StateObject/@Publishedboilerplate - Two environment objects (
AuthState,StoreManager) injected at the app root and consumed anywhere in the tree - StoreKit 2 for subscriptions: local JWS transaction verification (no server receipt validation needed), entitlement sync on launch, purchase flow with backend sync on
.verified - Sign in with Apple via
ASAuthorizationAppleIDCredential; identity token sent to backend for server-side Apple public key verification - JWT tokens stored in Keychain;
APIClientis anactorto avoid data races; 401 responses trigger silent token refresh - Client-side daily practice counter (
@AppStorage) with date-keyed reset — simple and sufficient for an indie freemium gate - Local StoreKit test configuration (
WitPit.storekit) for full sandbox purchase testing in Simulator
Backend
- Express + TypeScript REST API deployed to Railway; Drizzle ORM against Neon PostgreSQL
- Apple identity token verification using Apple's public keys (JWKS endpoint), audience-checked for both iOS and web clients
- Refresh token rotation: tokens stored hashed (SHA-256), rotated on each use, revoked on logout
- Rate limiting on auth (
express-rate-limit) and response submission endpoints - Admin panel with LLM switcher, prompt editor, user management, arena moderation, and daily challenge override — all DB-backed via a
settingstable POST /api/premium/activate|deactivate— auth-guarded endpoints that flipis_premiumon the user record after StoreKit verification on the client
AI
- OpenAI API for response scoring and challenge/scenario generation
- Scoring prompt returns structured JSON with per-dimension scores and a coaching paragraph
- Fallback scores (6/6/6) on API failure so the user flow never breaks
- Model and system prompts are runtime-configurable via the admin panel without a deploy
Stack
| Layer | Tech |
|---|---|
| iOS | SwiftUI, StoreKit 2, AuthenticationServices, Observation |
| Backend | Node.js, Express, TypeScript, Drizzle ORM |
| Database | PostgreSQL (Neon serverless) |
| AI | OpenAI API |
| Auth | Sign in with Apple, JWT (access + refresh), bcrypt |
| Deployment | Railway (API), Codemagic (iOS CI/CD) |
| Web client | React, TypeScript, shadcn/ui, TanStack Query, Vite |
What I'm proud of
- Shipping a complete freemium iOS product end-to-end: ideation → SwiftUI app → backend → StoreKit subscriptions → App Store submission pipeline
- The StoreKit 2 integration: clean
@ObservableStoreManagerthat handles purchase, restore, and entitlement sync in ~80 lines, with no server-side receipt validation complexity - The admin panel — a full operator tool that lets me change AI prompts, swap models, manage users, and override daily challenges without touching code
- Keeping the architecture simple enough to move fast: one
Models.swift, oneAPIClientactor, two environment objects — no over-engineering