Part 2: The 7-Day Launch Roadmap
A realistic day-by-day plan to go from idea to App Store.
Before You Start
Prerequisites Checklist
- Apple Developer Account ($99/year)
- Google Play Developer Account ($25 one-time)
- Node.js 18+ installed
- Expo account (free)
- Convex account (free)
Pro Tip: Apple review can take 24-48 hours. Submit early, iterate later.
Day 1: Foundation
Morning (2-3 hours)
1. Project Setup
npx create-expo-app@latest my-app
cd my-app
npx expo install expo-router2. Configure Expo Router
- Create app/ directory
- Set up basic navigation structure
- Add index.tsx and _layout.tsx
3. Set Up Convex
.env
CONVEX_URL=https://xxxxx.convex.co
CONVEX_AUTH_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...lib/convex.ts
import { ConvexReactClient } from 'convex/react';
import AsyncStorage from '@react-native-async-storage/async-storage';
export const convex = createClient(
process.env.CONVEX_URL!,
process.env.CONVEX_AUTH_TOKEN!,
{
auth: {
storage: AsyncStorage,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
}
);Afternoon (2-3 hours)
4. Design System Foundation
constants/theme.ts
export const colors = {
light: {
primary: '#7C3AED',
background: '#FFFFFF',
surface: '#F9FAFB',
text: '#111827',
textSecondary: '#6B7280',
border: '#E5E7EB',
error: '#EF4444',
success: '#22C55E',
},
dark: {
primary: '#A78BFA',
background: '#111827',
surface: '#1F2937',
text: '#F9FAFB',
textSecondary: '#9CA3AF',
border: '#374151',
error: '#F87171',
success: '#4ADE80',
},
};
export const spacing = {
xs: 4,
sm: 8,
md: 16,
lg: 24,
xl: 32,
};components/ui/Button.tsx
import { TouchableOpacity, Text, StyleSheet, ActivityIndicator } from 'react-native';
interface ButtonProps {
title: string;
onPress: () => void;
variant?: 'primary' | 'secondary' | 'outline';
loading?: boolean;
disabled?: boolean;
}
export function Button({
title,
onPress,
variant = 'primary',
loading,
disabled
}: ButtonProps) {
return (
<TouchableOpacity
style={[styles.base, styles[variant], disabled && styles.disabled]}
onPress={onPress}
disabled={disabled || loading}
>
{loading ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={[styles.text, styles[`${variant}Text`]]}>{title}</Text>
)}
</TouchableOpacity>
);
}Day 1 Deliverable: Running app with navigation and basic theming
Day 2: Authentication
Morning (2-3 hours)
- Enable Email auth in Convex dashboard
- Configure OAuth providers (Google, Apple)
- Set up redirect URLs
Auth Store
stores/useAuthStore.ts
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { convex } from '@/lib/convex';
interface AuthState {
user: User | null;
session: Session | null;
isLoading: boolean;
signIn: (email: string, password: string) => Promise<void>;
signUp: (email: string, password: string) => Promise<void>;
signOut: () => Promise<void>;
initialize: () => Promise<void>;
}
export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
user: null,
session: null,
isLoading: true,
initialize: async () => {
const { data: { session } } = await convex.auth.getSession();
set({
session,
user: session?.user ?? null,
isLoading: false,
});
convex.auth.onAuthStateChange((_event, session) => {
set({ session, user: session?.user ?? null });
});
},
signIn: async (email, password) => {
const { error } = await convex.auth.signInWithPassword({
email,
password,
});
if (error) throw error;
},
signUp: async (email, password) => {
const { error } = await convex.auth.signUp({
email,
password,
});
if (error) throw error;
},
signOut: async () => {
await convex.auth.signOut();
set({ user: null, session: null });
},
}),
{
name: 'auth-storage',
storage: createJSONStorage(() => AsyncStorage),
}
)
);Day 2 Deliverable: Users can sign up, log in, and log out
Day 3: Core Feature
This is YOUR app's unique feature. Examples:
- AI image generation
- Habit tracking
- Expense logging
- Recipe saving
Data Model Example
SQL
-- Example: AI generations table
CREATE TABLE generations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES auth.users(id),
prompt TEXT NOT NULL,
result_url TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- Enable document-level access control
ALTER TABLE generations ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view own data"
ON generations FOR SELECT
USING (auth.uid() = user_id);Day 3 Deliverable: Core feature is functional and testable
Day 4: Monetization
npx expo install react-native-purchasesapp/paywall.tsx
import { useState, useEffect } from 'react';
import { View, Text, Alert, ScrollView } from 'react-native';
import Purchases, { PurchasesPackage } from 'react-native-purchases';
import { router } from 'expo-router';
import { Button } from '@/components/ui/Button';
export default function PaywallScreen() {
const [packages, setPackages] = useState<PurchasesPackage[]>([]);
const [selectedPackage, setSelectedPackage] = useState<PurchasesPackage | null>(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
loadOfferings();
}, []);
const loadOfferings = async () => {
const offerings = await Purchases.getOfferings();
if (offerings.current?.availablePackages) {
setPackages(offerings.current.availablePackages);
const yearly = offerings.current.availablePackages.find(
p => p.packageType === 'ANNUAL'
);
setSelectedPackage(yearly || offerings.current.availablePackages[0]);
}
};
const handlePurchase = async () => {
if (!selectedPackage) return;
try {
setLoading(true);
const { customerInfo } = await Purchases.purchasePackage(selectedPackage);
if (customerInfo.entitlements.active['pro']) {
Alert.alert('Success!', 'Welcome to Pro!');
router.back();
}
} catch (error) {
if (!error.userCancelled) {
Alert.alert('Error', error.message);
}
} finally {
setLoading(false);
}
};
return (
<ScrollView>
<Text>Upgrade to Pro</Text>
{/* Package selection UI */}
<Button
title={`Subscribe ${selectedPackage?.product.priceString || ''}`}
onPress={handlePurchase}
loading={loading}
/>
</ScrollView>
);
}Day 4 Deliverable: Users can upgrade to premium
Day 5: Polish & Settings
- Settings Screen (theme, notifications, language)
- Profile Screen (user info, usage stats)
- Onboarding Flow (3-4 screens)
- Error Handling (Sentry setup)
- Performance Optimization (image caching, lazy loading)
- Haptic Feedback
Day 5 Deliverable: App feels complete and polished
Day 6: App Store Assets
Screenshots
| Device | Size | Required |
|---|---|---|
| iPhone 6.7" | 1290 x 2796 | Yes |
| iPhone 6.5" | 1284 x 2778 | Yes |
| iPad Pro 12.9" | 2048 x 2732 | If iPad support |
Day 6 Deliverable: All marketing assets ready
Day 7: Submit & Launch
Build & Submit
# Install EAS CLI
npm install -g eas-cli
# Configure
eas build:configure
# Build for both platforms
eas build --platform all --profile production
# Submit to stores
eas submit --platform ios
eas submit --platform androidDay 7 Deliverable: App submitted to both stores!
Time Investment
| Day | Focus | Hours |
|---|---|---|
| 1 | Foundation | 5-6 |
| 2 | Authentication | 5-6 |
| 3 | Core Feature | 6-8 |
| 4 | Monetization | 5-6 |
| 5 | Polish | 4-5 |
| 6 | Assets | 5-6 |
| 7 | Submit | 4-5 |
| Total | — | 35-42 |
Ship in Hours, Not Days
Or launch today with everything built
Why spend 7 days building when you can start with production-ready code?
Day 1-7 already done
Auth & payments ready
Just add your features
Get ShipReactNative
Save 40+ hours of setup