Create a minimal, focused iOS app that only tracks screen time using Apple’s Family Controls framework and syncs with the existing dreamlauncher-api to enable cross-platform screen time visibility between iOS and macOS devices.
After reviewing the codebase, the current iOS app includes excessive features that add complexity without adding value for screen time tracking:
Bloat Identified:
What We Actually Need:
┌─────────────────────────────────────────────────────────────┐
│ iOS App (Swift/SwiftUI) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Auth Screen │→ │ Screen Time │→ │ Sync Service │ │
│ │ (Apple Sign) │ │ Dashboard │ │ │ │
│ └──────────────┘ └──────────────┘ └──────┬───────┘ │
└───────────────────────────────────────────────┼─────────────┘
│
┌───────────▼───────────┐
│ dreamlauncher-api │
│ (Existing Backend) │
│ │
│ • Apple Auth │
│ • UserScreenTime DB │
│ • Cross-platform API │
└───────────┬───────────┘
│
┌───────────▼───────────┐
│ macOS App │
│ (Displays iOS data) │
└───────────────────────┘
Approach: Use existing dreamlauncher-api Apple Sign-In
// Use existing endpoint: POST /api/v1/apple-auth/sign-in
// Request: { identityToken, authorizationCode, user? }
// Response: { accessToken, refreshToken, user }
UI Flow:
Launch → Apple Sign-In Button → API Auth → Main Dashboard
Implementation:
Authorization Request:
import FamilyControls
// Request authorization
let center = AuthorizationCenter.shared
try await center.requestAuthorization(for: .individual)
Data Collection:
DeviceActivityReport to query usageAPI Endpoint (Already Exists):
POST /api/v1/user-screen-time
Body: {
startDate: "2025-01-01T00:00:00Z",
endDate: "2025-01-01T23:59:59Z",
durationInMinutes: 180,
timeZone: "America/Los_Angeles"
}
Sync Schedule:
Local Storage:
// Core Data entities
ScreenTimeEntry {
id: UUID
startDate: Date
endDate: Date
durationMinutes: Int
synced: Bool
createdAt: Date
}
Single Screen Design:
┌─────────────────────────────────────┐
│ 🌙 DreamLauncher │
├─────────────────────────────────────┤
│ │
│ Today's Screen Time │
│ ┌─────────────────────────────┐ │
│ │ 3h 42m │ │
│ │ ████████████░░░░░ │ │
│ │ iOS: 2h 10m | Mac: 1h 32m │ │
│ └─────────────────────────────┘ │
│ │
│ This Week │
│ ┌─────────────────────────────┐ │
│ │ Mon Tue Wed Thu Fri │ │
│ │ ██ ███ ███ ██ ███ │ │
│ │ 3.2h 4.1h 3.8h 3.0h 4.5h │ │
│ └─────────────────────────────┘ │
│ │
│ Platform Breakdown │
│ ┌─────────────────────────────┐ │
│ │ 📱 iPhone 14.2h (60%) │ │
│ │ 💻 MacBook 9.3h (40%) │ │
│ └─────────────────────────────┘ │
│ │
│ [Settings] [Refresh] │
└─────────────────────────────────────┘
Key Components:
Using BGTaskScheduler:
// Register background task
BGTaskScheduler.shared.register(
forTaskWithIdentifier: "com.dreamlauncher.screentimesync",
using: nil
) { task in
await syncScreenTimeData()
task.setTaskCompleted(success: true)
}
// Schedule next sync (every 4 hours)
let request = BGAppRefreshTaskRequest(
identifier: "com.dreamlauncher.screentimesync"
)
request.earliestBeginDate = Date(timeIntervalSinceNow: 4 * 60 * 60)
try BGTaskScheduler.shared.submit(request)
DreamLauncherLite-iOS/
├── DreamLauncherLite.xcodeproj
├── DreamLauncherLite/
│ ├── App/
│ │ ├── DreamLauncherLiteApp.swift
│ │ └── AppDelegate.swift
│ ├── Models/
│ │ ├── ScreenTimeEntry.swift
│ │ └── User.swift
│ ├── Services/
│ │ ├── AuthService.swift
│ │ ├── ScreenTimeService.swift
│ │ ├── SyncService.swift
│ │ └── APIClient.swift
│ ├── Views/
│ │ ├── AuthView.swift
│ │ ├── DashboardView.swift
│ │ ├── WeekChartView.swift
│ │ └── SettingsView.swift
│ ├── Extensions/
│ │ ├── Date+Extensions.swift
│ │ └── View+Extensions.swift
│ ├── Storage/
│ │ ├── CoreDataStack.swift
│ │ └── DreamLauncher.xcdatamodeld
│ ├── Info.plist
│ └── DreamLauncherLite.entitlements
├── DeviceActivityMonitorExtension/
│ ├── DeviceActivityMonitorExtension.swift
│ ├── Info.plist
│ └── DeviceActivityMonitorExtension.entitlements
└── DeviceActivityReportExtension/
├── TotalActivityReport.swift
├── Info.plist
└── DeviceActivityReportExtension.entitlements
Total Files: ~20 Swift files (vs 200+ in current app) Lines of Code Estimate: ~2,000 (vs 10,000+ in current app)
// ScreenTimeEntry.xcdatamodeld
entity ScreenTimeEntry {
id: UUID
startDate: Date
endDate: Date
durationInMinutes: Int32
deviceType: String // "IOS_PHONE", "IOS_TABLET"
synced: Bool
syncedAt: Date?
createdAt: Date
}
entity User {
id: String
appleId: String
email: String?
name: String?
accessToken: String // Encrypted
refreshToken: String // Encrypted
lastSyncDate: Date?
}
struct CreateScreenTimeDTO: Codable {
let startDate: Date
let endDate: Date
let durationInMinutes: Int
let timeZone: String
}
struct ScreenTimeResponseDTO: Codable {
let success: Bool
let data: [ScreenTimeData]
let pagination: Pagination
}
struct ScreenTimeData: Codable {
let id: String
let userId: String
let startDate: Date
let endDate: Date
let durationInMinutes: Int
let deviceType: String?
let createdAt: Date
}
POST /api/v1/apple-auth/sign-in
POST /api/v1/refresh-token
POST /api/v1/user-screen-time
GET /api/v1/user-screen-time?startDate={date}&endDate={date}
GET /api/v1/user-screen-time/combined // iOS + macOS
class APIClient {
private let baseURL = "https://your-api.railway.app/api/v1"
func signInWithApple(
identityToken: String,
authorizationCode: String
) async throws -> AuthTokens
func refreshToken() async throws -> AuthTokens
func syncScreenTime(
entries: [CreateScreenTimeDTO]
) async throws -> Bool
func fetchScreenTime(
startDate: Date,
endDate: Date
) async throws -> [ScreenTimeData]
func fetchCombinedScreenTime(
startDate: Date,
endDate: Date
) async throws -> CombinedScreenTimeResponse
}
Goal: Basic app that can authenticate and display mock data
Tasks:
Deliverable: App that can log in and show a basic dashboard
Goal: Collect real screen time data from iOS
Tasks:
Deliverable: App shows actual iOS screen time data
Goal: Sync data to backend
Tasks:
Deliverable: iOS data visible in backend and on macOS app
Goal: Show macOS data on iOS
Tasks:
Deliverable: Complete app showing iOS + macOS data
Goal: Production-ready app
Tasks:
Deliverable: App Store ready application
| Feature | Old App (dreamlauncher-ios) | New App (DreamLauncherLite) |
|---|---|---|
| Lines of Code | ~10,000+ | ~2,000 |
| Number of Screens | 20+ | 3 (Auth, Dashboard, Settings) |
| Dependencies | Health, Location, Motion, Beacons | Screen Time only |
| Onboarding Steps | 6 | 1 (Apple Sign-In) |
| App Extensions | 5 | 2 |
| Background Tasks | Multiple complex systems | Single sync task |
| Data Models | 15+ Prisma models | 2 Core Data entities |
| Permissions Required | 6+ | 2 (Sign-In, Family Controls) |
| API Endpoints Used | 20+ | 4 |
| Watch App | Yes | No |
| Social Features | Yes (leaderboard, friends) | No |
| Analytics | Complex weekly reports | Simple aggregation |
<key>NSUserTrackingUsageDescription</key>
<string>We need access to screen time to help you track your device usage across platforms.</string>
Must disclose:
Required Capabilities:
App Review Notes:
// AuthServiceTests.swift
- testAppleSignInSuccess()
- testTokenRefresh()
- testKeychainStorage()
// SyncServiceTests.swift
- testBatchUpload()
- testOfflineQueue()
- testRetryLogic()
// ScreenTimeServiceTests.swift
- testDataCollection()
- testAggregation()
// APIClientTests.swift
- testEndToEndAuth()
- testScreenTimeUpload()
- testCrossPlatformFetch()
Prerequisites:
Build Configuration:
App Store Connect:
Special Considerations:
Phase 2 Features:
Integration Opportunities:
Total: ~7-8 weeks
| Risk | Impact | Mitigation |
|---|---|---|
| Family Controls API changes | High | Monitor beta releases, have fallback plan |
| Background sync limitations | Medium | Implement foreground sync priority |
| API rate limiting | Medium | Batch requests, implement exponential backoff |
| Data sync conflicts | Low | Use timestamps and server-side deduplication |
| Risk | Impact | Mitigation |
|---|---|---|
| App Store rejection | High | Thorough documentation, clear use case |
| User privacy concerns | Medium | Transparent privacy policy, minimal data collection |
| Competition | Low | Unique value prop: cross-platform tracking |
The student-time-tracker iOS monitor is incomplete and follows a similar minimalist approach. Our new app will:
Advantages:
dreamlauncher-api (already built and tested)Key Differences:
DreamLauncherLite-iOSDreamLauncher/
├── dreamlauncher-api/ (existing)
├── student-time-tracker/ (existing - macOS only)
├── dreamlauncher-ios/ (DEPRECATED - legal issues)
└── dreamlauncher-lite-ios/ (NEW - this plan)
This streamlined iOS app will:
dreamlauncher-apiThe app does one thing and does it well: Cross-platform screen time tracking.
No health data. No location tracking. No social features. No bloat.
Just clean, focused screen time monitoring that works seamlessly with your macOS app.