# Product Requirements Document (PRD) ## SelfieCam - Professional Selfie Camera App **Version:** 1.0 **Platform:** iOS 18.0+ **Language:** Swift 6 with strict concurrency **Framework:** SwiftUI --- ## Executive Summary SelfieCam is a professional-grade selfie camera app featuring a customizable screen-based ring light overlay, premium camera controls, and beautiful branding. The app targets content creators, makeup artists, video call professionals, and anyone who needs flattering lighting for selfies. --- ## Target Audience - Content creators and influencers - Makeup artists and beauty professionals - Video call and streaming professionals - Casual users seeking better selfie lighting - Portrait photographers needing on-the-go lighting --- ## Technical Requirements ### Platform & Tools | Requirement | Specification | |-------------|---------------| | iOS Deployment Target | iOS 18.0+ | | Swift Version | Swift 6 with strict concurrency checking | | UI Framework | SwiftUI (primary) | | Persistence | iCloud via CloudSyncManager | | Subscriptions | RevenueCat SDK | | Camera | MijickCamera framework | | Design System | Bedrock (local package) | ### Architecture Principles 1. **Protocol-Oriented Programming (POP)** - All shared capabilities defined via protocols before concrete types 2. **MVVM-lite** - Views are "dumb" renderers; all logic lives in `@Observable` view models 3. **Bedrock Design System** - Centralized design tokens, no magic numbers 4. **Full Accessibility** - Dynamic Type, VoiceOver labels/hints/traits/announcements 5. **Modern Swift & SwiftUI** - Swift 6 concurrency, `@MainActor`, modern APIs 6. **Testable & Reusable Design** - Protocols enable mocking and future package extraction --- ## Feature Requirements ### FR-100: Core Camera System #### FR-101: Camera Preview - **Priority:** P0 (Critical) - **Description:** Full-screen camera preview with real-time display - **Acceptance Criteria:** - [ ] Smooth, low-latency camera preview - [ ] Supports both front and back camera - [ ] Camera switching via UI button - [ ] Prevents screen dimming during camera use - [ ] Uses MijickCamera framework for SwiftUI-native handling #### FR-102: Photo Capture - **Priority:** P0 (Critical) - **Description:** High-quality photo capture with multiple trigger methods - **Acceptance Criteria:** - [ ] Capture button triggers photo capture - [ ] Volume buttons trigger capture (hardware shutter) - [ ] Camera Control button full press triggers capture (iPhone 16+) - [ ] Post-capture preview with share functionality - [ ] Auto-save option to Photo Library #### FR-103: Zoom Control - **Priority:** P1 (High) - **Description:** Pinch-to-zoom gesture support - **Acceptance Criteria:** - [ ] Smooth pinch-to-zoom interpolation - [ ] Zoom level persists during session - [ ] Zoom resets on camera switch (optional behavior) #### FR-104: Camera Control Button Support - **Priority:** P2 (Medium) - **Description:** iPhone 16+ Camera Control button integration - **Acceptance Criteria:** - [ ] Full press triggers photo capture - [ ] Light press locks focus/exposure (if API available) - [ ] Uses `AVCaptureEventInteraction` (iOS 17.2+) - **Known Limitations:** - Light press may be restricted to first-party apps - Swipe-to-zoom is Apple-exclusive API --- ### FR-200: Ring Light System #### FR-201: Ring Light Overlay - **Priority:** P0 (Critical) - **Description:** Screen-based ring light effect using colored border - **Acceptance Criteria:** - [ ] Configurable border thickness (10-120pt range) - [ ] Border renders around camera preview - [ ] Quick enable/disable toggle - [ ] Smooth transition animations #### FR-202: Ring Light Colors - **Priority:** P0 (Critical) - **Description:** Multiple color temperature presets - **Free Colors:** - Pure White - Warm Cream - **Premium Colors:** - Ice Blue - Soft Pink - Warm Amber - Cool Lavender - **Acceptance Criteria:** - [ ] Color picker UI with visual swatches - [ ] Premium colors show lock indicator for free users - [ ] Premium users can access custom color picker #### FR-203: Ring Light Brightness - **Priority:** P1 (High) - **Description:** Adjustable ring light opacity/brightness - **Acceptance Criteria:** - [ ] Slider control for brightness (10%-100%) - [ ] Real-time preview of brightness changes - [ ] Debounced saving (300ms) to prevent excessive iCloud writes --- ### FR-300: Flash System #### FR-301: Flash Modes - **Priority:** P1 (High) - **Description:** Multiple flash options for photo capture - **Modes:** - Off - On - Auto - **Acceptance Criteria:** - [ ] Mode selector in camera UI - [ ] Flash fires during capture when enabled - [ ] Auto mode uses ambient light detection #### FR-302: Front Flash - **Priority:** P1 (High) - **Description:** Screen brightness-based flash for front camera - **Acceptance Criteria:** - [ ] Screen brightness increases to maximum during front camera capture - [ ] Returns to original brightness after capture #### FR-303: Flash Sync (Premium) - **Priority:** P2 (Medium) - **Description:** Match flash color with ring light color - **Acceptance Criteria:** - [ ] Premium feature with appropriate gating - [ ] Screen color matches current ring light color during flash - [ ] Toggle in settings to enable/disable --- ### FR-400: Self-Timer System #### FR-401: Timer Options - **Priority:** P1 (High) - **Description:** Countdown timer before photo capture - **Free Options:** - Off - 3 seconds - **Premium Options:** - 5 seconds - 10 seconds - **Acceptance Criteria:** - [ ] Visual countdown indicator - [ ] Audio feedback (optional) - [ ] Cancel option during countdown - [ ] VoiceOver announces countdown --- ### FR-500: Display & Enhancement Features #### FR-501: Grid Overlay - **Priority:** P2 (Medium) - **Description:** Rule-of-thirds composition guide - **Acceptance Criteria:** - [ ] Toggle in settings to show/hide - [ ] Semi-transparent grid lines - [ ] Does not interfere with tap gestures #### FR-502: True Mirror Mode (Premium) - **Priority:** P2 (Medium) - **Description:** Horizontally flipped preview like a real mirror - **Acceptance Criteria:** - [ ] Premium feature with appropriate gating - [ ] Live preview is mirrored - [ ] Captured photo reflects mirror setting #### FR-503: Skin Smoothing (Premium) - **Priority:** P2 (Medium) - **Description:** Real-time subtle skin smoothing filter - **Acceptance Criteria:** - [ ] Premium feature with appropriate gating - [ ] Toggle in settings - [ ] Subtle, natural-looking effect - [ ] Applied to both preview and captured photo #### FR-504: Center Stage (Premium) - **Priority:** P3 (Low) - **Description:** Automatic subject tracking/centering - **Acceptance Criteria:** - [ ] Premium feature with appropriate gating - [ ] Uses Apple's Center Stage API if available - [ ] Graceful fallback on unsupported devices --- ### FR-600: Photo Quality Options #### FR-601: HDR Mode (Premium) - **Priority:** P2 (Medium) - **Description:** High Dynamic Range photo capture - **Modes:** - Off - On - Auto - **Acceptance Criteria:** - [ ] Premium feature with appropriate gating - [ ] HDR indicator in UI when enabled - [ ] Uses system HDR capture capabilities #### FR-602: Photo Quality Settings (Premium) - **Priority:** P2 (Medium) - **Description:** Resolution/quality selection - **Options:** - Medium (Free) - High (Premium) - **Acceptance Criteria:** - [ ] Premium feature for High quality - [ ] Clear indication of current quality setting - [ ] Maximum resolution output for High setting --- ### FR-700: Settings & Synchronization #### FR-701: iCloud Sync - **Priority:** P1 (High) - **Description:** Automatic settings synchronization across devices - **Acceptance Criteria:** - [ ] Available to all users (free and premium) - [ ] Real-time sync status with last sync timestamp - [ ] Manual "Sync Now" option - [ ] Uses Bedrock's CloudSyncManager #### FR-702: Settings Persistence - **Priority:** P0 (Critical) - **Description:** All user preferences stored in SyncedSettings model - **Settings Include:** - Ring light: size, color ID, custom color RGB, opacity, enabled - Camera: position, flash mode, HDR mode, photo quality - Display: mirror flip, skin smoothing, grid visible - Capture: timer, capture mode, auto-save - Premium features: flash sync, center stage - **Acceptance Criteria:** - [ ] Settings persist across app launches - [ ] Debounced saves for slider values - [ ] Settings sync via iCloud --- ### FR-800: Branding & Launch Experience #### FR-801: Animated Launch Screen - **Priority:** P2 (Medium) - **Description:** Beautiful branded launch experience - **Acceptance Criteria:** - [ ] Animated launch with configurable duration - [ ] Customizable colors, patterns, and layout - [ ] Seamless transition to main app - [ ] Uses Bedrock's LaunchScreenConfig #### FR-802: App Icon - **Priority:** P2 (Medium) - **Description:** Consistent branded app icon - **Acceptance Criteria:** - [ ] Generated via Bedrock icon system - [ ] Matches launch screen branding - [ ] Icon generator available in DEBUG builds --- ### FR-900: Premium & Monetization #### FR-901: Freemium Model - **Priority:** P0 (Critical) - **Description:** Free tier with optional Pro subscription - **Free Features:** - Basic ring light (2 colors) - Photo capture - 3-second timer - Grid overlay - Zoom - iCloud sync - **Premium Features:** - Full color palette + custom colors - HDR mode - High quality photos - Flash sync - True mirror mode - Skin smoothing - Center stage - Extended timers (5s, 10s) #### FR-902: RevenueCat Integration - **Priority:** P0 (Critical) - **Description:** Subscription management via RevenueCat - **Acceptance Criteria:** - [ ] PremiumManager wraps RevenueCat SDK - [ ] PremiumGate utility for consistent feature gating - [ ] Entitlement named `pro` - [ ] Settings automatically fall back to free defaults when not premium #### FR-903: Paywall - **Priority:** P1 (High) - **Description:** Pro subscription purchase flow - **Acceptance Criteria:** - [ ] Clear presentation of premium features - [ ] Monthly and yearly subscription options - [ ] Restore purchases functionality - [ ] Accessible and localized #### FR-904: Debug Premium Mode - **Priority:** P3 (Low) - **Description:** Testing premium features without subscription - **Acceptance Criteria:** - [ ] Environment variable `ENABLE_DEBUG_PREMIUM=1` - [ ] Only works in DEBUG builds - [ ] Unlocks all premium features for testing --- ## Non-Functional Requirements ### NFR-100: Accessibility #### NFR-101: VoiceOver Support - **Priority:** P0 (Critical) - **Acceptance Criteria:** - [ ] All interactive elements have meaningful `.accessibilityLabel()` - [ ] Dynamic state uses `.accessibilityValue()` - [ ] Actions described with `.accessibilityHint()` - [ ] Appropriate traits via `.accessibilityAddTraits()` - [ ] Decorative elements hidden with `.accessibilityHidden(true)` - [ ] Important events trigger accessibility announcements #### NFR-102: Dynamic Type - **Priority:** P0 (Critical) - **Acceptance Criteria:** - [ ] All text supports Dynamic Type - [ ] Custom dimensions use `@ScaledMetric` - [ ] UI remains usable at largest text sizes --- ### NFR-200: Performance #### NFR-201: Camera Performance - **Priority:** P0 (Critical) - **Acceptance Criteria:** - [ ] Smooth, real-time camera preview (30+ fps) - [ ] Minimal latency on capture - [ ] No UI blocking during photo processing #### NFR-202: Battery Efficiency - **Priority:** P1 (High) - **Acceptance Criteria:** - [ ] Efficient camera usage - [ ] Debounced saves reduce iCloud writes - [ ] Screen dimming prevention is intentional (user is actively using camera) --- ### NFR-300: Privacy & Security #### NFR-301: Data Collection - **Priority:** P0 (Critical) - **Acceptance Criteria:** - [ ] No data collection - [ ] No analytics - [ ] No tracking - [ ] Privacy policy reflects minimal data usage #### NFR-302: API Key Security - **Priority:** P0 (Critical) - **Acceptance Criteria:** - [ ] API keys stored in `.xcconfig` files - [ ] `Secrets.xcconfig` is gitignored - [ ] Template file provided for setup --- ### NFR-400: Localization #### NFR-401: String Catalogs - **Priority:** P1 (High) - **Acceptance Criteria:** - [ ] Uses `.xcstrings` files for localization - [ ] All user-facing strings in String Catalog - [ ] Minimum supported languages: English (en), Spanish-Mexico (es-MX), French-Canada (fr-CA) --- ## Project Structure ``` SelfieCam/ ├── App/ # App entry point with launch screen ├── Configuration/ # xcconfig files (API keys) ├── Features/ │ ├── Camera/ # Main camera UI │ │ ├── ContentView.swift # Main screen coordinator │ │ ├── Views/ # Camera UI components │ │ │ ├── CustomCameraScreen.swift │ │ │ ├── RingLightOverlay.swift │ │ │ ├── CaptureButton.swift │ │ │ ├── ExpandableControlsPanel.swift │ │ │ ├── CaptureEventInteraction.swift │ │ │ └── ... │ │ ├── GridOverlay.swift │ │ └── PostCapturePreviewView.swift │ ├── Paywall/ # Pro subscription flow │ │ └── ProPaywallView.swift │ └── Settings/ # Configuration screens │ ├── SettingsView.swift │ ├── SettingsViewModel.swift │ └── ... ├── Shared/ │ ├── BrandingConfig.swift # App icon & launch screen config │ ├── DesignConstants.swift # Design tokens (uses Bedrock) │ ├── Color+Extensions.swift # Ring light color presets │ ├── Models/ # Data models │ │ ├── CameraFlashMode.swift │ │ ├── CameraHDRMode.swift │ │ ├── PhotoQuality.swift │ │ └── ... │ ├── Protocols/ # Shared protocols │ │ ├── RingLightConfigurable.swift │ │ ├── CaptureControlling.swift │ │ ├── CaptureEventHandling.swift │ │ └── PremiumManaging.swift │ ├── Premium/ # Subscription management │ │ └── PremiumManager.swift │ ├── Services/ # App services │ │ └── PhotoLibraryService.swift │ └── Storage/ # Persistence │ └── SyncedSettings.swift └── Resources/ # Assets, localization ├── Assets.xcassets/ │ ├── AppIcon.appiconset/ │ ├── LaunchBackground.colorset/ │ └── ... └── Localizable.xcstrings ``` --- ## Dependencies | Dependency | Purpose | Integration | |------------|---------|-------------| | **Bedrock** | Design system, branding, cloud sync | Local Swift package | | **MijickCamera** | Camera capture and preview | SPM dependency | | **RevenueCat** | Subscription management | SPM dependency | --- ## Premium Feature Gating Pattern All premium features use centralized `PremiumGate` utility: ```swift // Getter pattern - returns free default if not premium var isMirrorFlipped: Bool { get { PremiumGate.get(cloudSync.data.isMirrorFlipped, default: false, isPremium: isPremiumUnlocked) } set { guard PremiumGate.canSet(isPremium: isPremiumUnlocked) else { return } updateSettings { $0.isMirrorFlipped = newValue } } } ``` --- ## Premium Feature Matrix | Feature | Free Value | Premium Value | |---------|-----------|---------------| | Ring light colors | Pure White, Warm Cream | All presets + custom | | Timer options | Off, 3s | Off, 3s, 5s, 10s | | Photo quality | Medium | Medium, High | | HDR mode | Off | Off, On, Auto | | True mirror | Off | Configurable | | Skin smoothing | Off | Configurable | | Flash sync | Off | Configurable | | Center stage | Off | Configurable | --- ## Known Limitations ### Camera Control Button Light Press **Status:** Not Working - Needs Investigation The Camera Control button (iPhone 16+) full press works for photo capture, but the light press (secondary action) does not work. **What Works:** - Camera Control full press → triggers photo capture - Volume up/down → triggers capture **What Doesn't Work:** - Camera Control light press → no event received - Camera Control swipe gestures (zoom) → Apple-exclusive API **Possible Causes:** 1. Light press may be restricted to first-party apps 2. MijickCamera session may interfere with light press detection 3. Accessibility settings may need explicit enablement **User Workaround:** Check Settings > Accessibility > Camera Control: - Ensure Camera Control is enabled - Ensure Light-Press is turned ON - Adjust Light-Press Force if needed --- ## Future Enhancements Potential areas for expansion: - [ ] Real-time filters (beauty, color grading) - [ ] Gesture-based capture (smile detection) - [ ] Widget for quick camera access - [ ] Apple Watch remote trigger - [ ] Export presets (aspect ratios, watermarks) - [ ] Social sharing integrations - [ ] Camera Control button swipe-to-zoom (if Apple makes API public) --- ## Required Permissions | Permission | Reason | |------------|--------| | Camera | Photo preview and capture | | Photo Library | Save captured photos | | Microphone | May be requested by camera framework (not actively used) | | iCloud | Settings synchronization (optional) | --- ## Development Setup ### 1. Clone and Configure ```bash git clone https://github.com/yourusername/SelfieCam.git cd SelfieCam cp SelfieCam/Configuration/Secrets.xcconfig.template SelfieCam/Configuration/Secrets.xcconfig ``` ### 2. Add API Key Edit `Secrets.xcconfig`: ``` REVENUECAT_API_KEY = appl_your_actual_api_key_here ``` ### 3. RevenueCat Setup 1. Create RevenueCat account and project 2. Connect to App Store Connect 3. Create products and entitlement named `pro` 4. Copy Public App-Specific API Key to `Secrets.xcconfig` ### 4. Test Premium Features Set environment variable in scheme: - **Name:** `ENABLE_DEBUG_PREMIUM` - **Value:** `1` --- ## Code Quality Standards - **No magic numbers**: All values from Design constants - **Full accessibility**: Every interactive element has VoiceOver support - **Protocol-first**: Shared behavior defined via protocols - **Separation of concerns**: Views are dumb, ViewModels contain logic - **Modern APIs**: Swift 6, async/await, @Observable - **Documentation**: Code comments, README, PRD --- *This PRD serves as the primary requirements document for SelfieCam development.*