← Tasks
[SC-01] Expo project initialization with TypeScript + Expo Router
completedcode_genP0
Description
## SC-01: Expo project initialization with TypeScript + Expo Router
Section: Scaffold | Milestone: M1 | Owner: AG Lu
### Failing Tests
- **package_json_exists** (file_exists): File `c8-audio/package.json` must exist
- **app_json_exists** (file_exists): File `c8-audio/app.json` must exist
- **tsconfig_exists** (file_exists): File `c8-audio/tsconfig.json` must exist
- **expo_router_dep** (grep): Pattern `expo-router` in `c8-audio/package.json` (need 1+ matches)
### Acceptance Criteria
- File `c8-audio/package.json` must exist
- File `c8-audio/app.json` must exist
- File `c8-audio/tsconfig.json` must exist
- File matching `c8-audio/package.json` must contain pattern `expo-router`
### Codebase Conventions
- Trilingual comments: // EN: ... // VI: ... // ES: ...
- SPEC section refs in comments
- Zod at module level with .safeParse()
- (supabase as any) with eslint-disable
- NextResponse.json() responses
- Error format: { error: 'message' }
Assignee
-
Claimed By
Cloud Lu → Claude Sonnet
Created
22d ago
Completed
19d ago
Quality
Overall
79%
Pass
PASS
Graded By
-
Graded At
-
Cost
Input Tokens
-
Output Tokens
-
Est. USD
-
Result
{
"cost": {
"input_tokens": 23,
"estimated_usd": 0.044499,
"output_tokens": 2962
},
"model": "claude-sonnet-4-20250514",
"status": "success",
"transport": "anthropic_api",
"latency_ms": 31179,
"response_text": "I'll help you initialize an Expo project with TypeScript and Expo Router. Here's a step-by-step guide:\n\n## 1. Create New Expo Project with TypeScript\n\n```bash\n# Create a new Expo project with TypeScript template\nnpx create-expo-app@latest MyApp --template blank-typescript\n\n# Navigate to the project directory\ncd MyApp\n```\n\n## 2. Install Expo Router\n\n```bash\n# Install Expo Router and required dependencies\nnpx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar\n```\n\n## 3. Update Configuration Files\n\n### `app.json`\n```json\n{\n \"expo\": {\n \"name\": \"MyApp\",\n \"slug\": \"myapp\",\n \"version\": \"1.0.0\",\n \"orientation\": \"portrait\",\n \"icon\": \"./assets/icon.png\",\n \"userInterfaceStyle\": \"light\",\n \"splash\": {\n \"image\": \"./assets/splash.png\",\n \"resizeMode\": \"contain\",\n \"backgroundColor\": \"#ffffff\"\n },\n \"assetBundlePatterns\": [\n \"**/*\"\n ],\n \"ios\": {\n \"supportsTablet\": true\n },\n \"android\": {\n \"adaptiveIcon\": {\n \"foregroundImage\": \"./assets/adaptive-icon.png\",\n \"backgroundColor\": \"#ffffff\"\n }\n },\n \"web\": {\n \"bundler\": \"metro\",\n \"output\": \"static\",\n \"favicon\": \"./assets/favicon.png\"\n },\n \"plugins\": [\n \"expo-router\"\n ],\n \"scheme\": \"myapp\"\n }\n}\n```\n\n### `package.json` (update the main entry point)\n```json\n{\n \"main\": \"expo-router/entry\",\n \"scripts\": {\n \"start\": \"expo start\",\n \"android\": \"expo start --android\",\n \"ios\": \"expo start --ios\",\n \"web\": \"expo start --web\"\n }\n}\n```\n\n## 4. Create App Directory Structure\n\nCreate the following directory structure:\n\n```\napp/\n├── (tabs)/\n│ ├── _layout.tsx\n│ ├── index.tsx\n│ └── explore.tsx\n├── modal.tsx\n└── _layout.tsx\n```\n\n## 5. Root Layout (`app/_layout.tsx`)\n\n```typescript\nimport FontAwesome from '@expo/vector-icons/FontAwesome';\nimport { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';\nimport { useFonts } from 'expo-font';\nimport { Stack } from 'expo-router';\nimport * as SplashScreen from 'expo-splash-screen';\nimport { useEffect } from 'react';\nimport { useColorScheme } from 'react-native';\n\nexport {\n // Catch any errors thrown by the Layout component.\n ErrorBoundary,\n} from 'expo-router';\n\nexport const unstable_settings = {\n // Ensure that reloading on `/modal` keeps a back button present.\n initialRouteName: '(tabs)',\n};\n\n// Prevent the splash screen from auto-hiding before asset loading is complete.\nSplashScreen.preventAutoHideAsync();\n\nexport default function RootLayout() {\n const [loaded, error] = useFonts({\n SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),\n ...FontAwesome.font,\n });\n\n // Expo Router uses Error Boundaries to catch errors in the navigation tree.\n useEffect(() => {\n if (error) throw error;\n }, [error]);\n\n useEffect(() => {\n if (loaded) {\n SplashScreen.hideAsync();\n }\n }, [loaded]);\n\n if (!loaded) {\n return null;\n }\n\n return <RootLayoutNav />;\n}\n\nfunction RootLayoutNav() {\n const colorScheme = useColorScheme();\n\n return (\n <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>\n <Stack>\n <Stack.Screen name=\"(tabs)\" options={{ headerShown: false }} />\n <Stack.Screen name=\"modal\" options={{ presentation: 'modal' }} />\n </Stack>\n </ThemeProvider>\n );\n}\n```\n\n## 6. Tab Layout (`app/(tabs)/_layout.tsx`)\n\n```typescript\nimport React from 'react';\nimport FontAwesome from '@expo/vector-icons/FontAwesome';\nimport { Link, Tabs } from 'expo-router';\nimport { Pressable, useColorScheme } from 'react-native';\n\nimport Colors from '../../constants/Colors';\n\n/**\n * You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/\n */\nfunction TabBarIcon(props: {\n name: React.ComponentProps<typeof FontAwesome>['name'];\n color: string;\n}) {\n return <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;\n}\n\nexport default function TabLayout() {\n const colorScheme = useColorScheme();\n\n return (\n <Tabs\n screenOptions={{\n tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,\n }}>\n <Tabs.Screen\n name=\"index\"\n options={{\n title: 'Tab One',\n tabBarIcon: ({ color }) => <TabBarIcon name=\"code\" color={color} />,\n headerRight: () => (\n <Link href=\"/modal\" asChild>\n <Pressable>\n {({ pressed }) => (\n <FontAwesome\n name=\"info-circle\"\n size={25}\n color={Colors[colorScheme ?? 'light'].text}\n style={{ marginRight: 15, opacity: pressed ? 0.5 : 1 }}\n />\n )}\n </Pressable>\n </Link>\n ),\n }}\n />\n <Tabs.Screen\n name=\"explore\"\n options={{\n title: 'Tab Two',\n tabBarIcon: ({ color }) => <TabBarIcon name=\"code\" color={color} />,\n }}\n />\n </Tabs>\n );\n}\n```\n\n## 7. Home Screen (`app/(tabs)/index.tsx`)\n\n```typescript\nimport { StyleSheet, Text, View } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\n\nexport default function TabOneScreen() {\n return (\n <SafeAreaView style={styles.container}>\n <View style={styles.content}>\n <Text style={styles.title}>Tab One</Text>\n <View style={styles.separator} />\n <Text>This is the first tab screen.</Text>\n </View>\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: '#fff',\n },\n content: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n padding: 20,\n },\n title: {\n fontSize: 20,\n fontWeight: 'bold',\n },\n separator: {\n marginVertical: 30,\n height: 1,\n width: '80%',\n backgroundColor: '#eee',\n },\n});\n```\n\n## 8. Explore Screen (`app/(tabs)/explore.tsx`)\n\n```typescript\nimport { StyleSheet, Text, View } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\n\nexport default function TabTwoScreen() {\n return (\n <SafeAreaView style={styles.container}>\n <View style={styles.content}>\n <Text style={styles.title}>Tab Two</Text>\n <View style={styles.separator} />\n <Text>This is the second tab screen.</Text>\n </View>\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: '#fff',\n },\n content: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n padding: 20,\n },\n title: {\n fontSize: 20,\n fontWeight: 'bold',\n },\n separator: {\n marginVertical: 30,\n height: 1,\n width: '80%',\n backgroundColor: '#eee',\n },\n});\n```\n\n## 9. Modal Screen (`app/modal.tsx`)\n\n```typescript\nimport { StatusBar } from 'expo-status-bar';\nimport { Platform, StyleSheet, Text, View } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\n\nexport default function ModalScreen() {\n return (\n <SafeAreaView style={styles.container}>\n <View style={styles.content}>\n <Text style={styles.title}>Modal</Text>\n <View style={styles.separator} />\n <Text>This is a modal screen.</Text>\n </View>\n\n {/* Use a light status bar on iOS to account for the black space above the modal */}\n <StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: '#fff',\n },\n content: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n padding: 20,\n },\n title: {\n fontSize: 20,\n fontWeight: 'bold',\n },\n separator: {\n marginVertical: 30,\n height: 1,\n width: '80%',\n backgroundColor: '#eee',\n },\n});\n```\n\n## 10. Constants File (`constants/Colors.ts`)\n\n```typescript\nconst tintColorLight = '#2f95dc';\nconst tintColorDark = '#fff';\n\nexport default {\n light: {\n text: '#000',\n background: '#fff',\n tint: tintColorLight,\n tabIconDefault: '#ccc',\n tabIconSelected: tintColorLight,\n },\n dark: {\n text: '#fff',\n background: '#000',\n tint: tintColorDark,\n tabIconDefault: '#ccc',\n tabIconSelected: tintColorDark,\n },\n};\n```\n\n## 11. Add Font File\n\nCreate an `assets/fonts/` directory and add the SpaceMono font file, or remove the font loading from the root layout if you don't want custom fonts.\n\n## 12. Update Metro Configuration (`metro.config.js`)\n\n```javascript\nconst { getDefaultConfig } = require('expo/metro-config');\n\nconst config = getDefaultConfig(__dirname);\n\nmodule.exports = config;\n```\n\n## 13. TypeScript Configuration (`tsconfig.json`)\n\n```json\n{\n \"extends\": \"expo/tsconfig.base\",\n \"compilerOptions\": {\n \"strict\": true,\n \"baseUrl\": \".\",\n \"paths\": {\n \"@/*\": [\"./*\"]\n }\n }\n}\n```\n\n## 14. Start the Development Server\n\n```bash\nnpx expo start\n```\n\nThis setup provides:\n- ✅ TypeScript support\n- ✅ Expo Router with file-based routing\n- ✅ Tab navigation\n- ✅ Modal presentation\n- ✅ Safe area handling\n- ✅ Dark/light theme support\n- ✅ Proper project structure\n\nYou can now press `i` for iOS simulator, `a` for Android emulator, or `w` for web development."
}Task ID: 7ee4becc-736b-4f8b-b31b-ab78d150ebcd