ginskill-init 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/.wrangler/cache/pages.json +4 -0
  2. package/.wrangler/cache/wrangler-account.json +6 -0
  3. package/DEVELOPMENT.md +510 -0
  4. package/README.md +104 -0
  5. package/agents/developer.md +56 -0
  6. package/agents/frontend-design.md +69 -0
  7. package/agents/mobile-reviewer.md +36 -0
  8. package/agents/review-code.md +49 -0
  9. package/agents/security-scanner.md +50 -0
  10. package/agents/tester.md +72 -0
  11. package/bin/cli.js +461 -0
  12. package/landing/ai-build-ai.png +0 -0
  13. package/landing/index.html +1495 -0
  14. package/landing/logo.png +0 -0
  15. package/package.json +37 -0
  16. package/skills/active-life-dev/SKILL.md +157 -0
  17. package/skills/active-life-dev/docs/auth.md +187 -0
  18. package/skills/active-life-dev/docs/customers.md +216 -0
  19. package/skills/active-life-dev/docs/integrations.md +209 -0
  20. package/skills/active-life-dev/docs/inventory.md +192 -0
  21. package/skills/active-life-dev/docs/modules.md +181 -0
  22. package/skills/active-life-dev/docs/orders.md +180 -0
  23. package/skills/active-life-dev/docs/patterns.md +319 -0
  24. package/skills/active-life-dev/docs/products.md +216 -0
  25. package/skills/active-life-dev/docs/schema.md +502 -0
  26. package/skills/active-life-dev/docs/setup.md +169 -0
  27. package/skills/active-life-dev/docs/vouchers.md +144 -0
  28. package/skills/ai-asset-generator/SKILL.md +247 -0
  29. package/skills/ai-asset-generator/docs/gen-image.md +274 -0
  30. package/skills/ai-asset-generator/docs/genvideo.md +341 -0
  31. package/skills/ai-asset-generator/docs/remove-background.md +19 -0
  32. package/skills/ai-asset-generator/lib/bg-remove.mjs +34 -0
  33. package/skills/ai-asset-generator/lib/env.mjs +48 -0
  34. package/skills/ai-asset-generator/lib/kie-client.mjs +100 -0
  35. package/skills/ai-build-ai/SKILL.md +127 -0
  36. package/skills/ai-build-ai/docs/agent-teams.md +293 -0
  37. package/skills/ai-build-ai/docs/checkpointing.md +161 -0
  38. package/skills/ai-build-ai/docs/create-agent.md +399 -0
  39. package/skills/ai-build-ai/docs/create-mcp.md +395 -0
  40. package/skills/ai-build-ai/docs/create-skill.md +299 -0
  41. package/skills/ai-build-ai/docs/headless-mode.md +614 -0
  42. package/skills/ai-build-ai/docs/hooks.md +578 -0
  43. package/skills/ai-build-ai/docs/memory-claude-md.md +375 -0
  44. package/skills/ai-build-ai/docs/output-styles.md +208 -0
  45. package/skills/ai-build-ai/docs/overview.md +162 -0
  46. package/skills/ai-build-ai/docs/permissions.md +391 -0
  47. package/skills/ai-build-ai/docs/plugins.md +396 -0
  48. package/skills/ai-build-ai/docs/sandbox.md +262 -0
  49. package/skills/ai-build-ai/docs/team-lead-workflow.md +648 -0
  50. package/skills/ant-design/SKILL.md +323 -0
  51. package/skills/ant-design/docs/components.md +160 -0
  52. package/skills/ant-design/docs/data-entry.md +406 -0
  53. package/skills/ant-design/docs/display.md +594 -0
  54. package/skills/ant-design/docs/feedback.md +451 -0
  55. package/skills/ant-design/docs/key-components.md +414 -0
  56. package/skills/ant-design/docs/navigation.md +310 -0
  57. package/skills/ant-design/docs/pro-components.md +543 -0
  58. package/skills/ant-design/docs/setup.md +213 -0
  59. package/skills/ant-design/docs/theme.md +265 -0
  60. package/skills/flutter-performance/SKILL.md +803 -0
  61. package/skills/flutter-performance/references/flutter-patterns.md +595 -0
  62. package/skills/icon-generator/SKILL.md +270 -0
  63. package/skills/mobile-app-review/SKILL.md +321 -0
  64. package/skills/mobile-app-review/references/apple-review.md +132 -0
  65. package/skills/mobile-app-review/references/google-play-review.md +203 -0
  66. package/skills/mongodb/SKILL.md +667 -0
  67. package/skills/mongodb/references/mongoose-patterns.md +368 -0
  68. package/skills/nestjs-architecture/SKILL.md +1086 -0
  69. package/skills/nestjs-architecture/references/advanced-patterns.md +590 -0
  70. package/skills/performance/SKILL.md +509 -0
  71. package/skills/react-fsd-architecture/SKILL.md +693 -0
  72. package/skills/react-fsd-architecture/references/fsd-patterns.md +747 -0
  73. package/skills/react-native-expo/SKILL.md +128 -0
  74. package/skills/react-native-expo/references/data-layer.md +252 -0
  75. package/skills/react-native-expo/references/design-system.md +252 -0
  76. package/skills/react-native-expo/references/navigation.md +199 -0
  77. package/skills/react-native-expo/references/performance.md +229 -0
  78. package/skills/react-native-expo/references/platform-services.md +179 -0
  79. package/skills/react-native-expo/references/state-management.md +209 -0
  80. package/skills/react-native-expo/references/ui-patterns.md +301 -0
  81. package/skills/react-query/SKILL.md +685 -0
  82. package/skills/react-query/references/query-patterns.md +365 -0
  83. package/skills/review-code/SKILL.md +374 -0
  84. package/skills/review-code/references/clean-code-principles.md +395 -0
  85. package/skills/review-code/references/frontend-patterns.md +136 -0
  86. package/skills/review-code/references/nestjs-patterns.md +184 -0
  87. package/skills/security-scanner/SKILL.md +366 -0
  88. package/skills/security-scanner/references/nestjs-security.md +260 -0
  89. package/skills/security-scanner/references/nextjs-security.md +201 -0
  90. package/skills/security-scanner/references/react-native-security.md +199 -0
  91. package/skills/traefik/SKILL.md +105 -0
  92. package/skills/traefik/docs/advanced-routing.md +186 -0
  93. package/skills/traefik/docs/auth-providers.md +137 -0
  94. package/skills/traefik/docs/cicd-devops.md +396 -0
  95. package/skills/traefik/docs/core-config.md +171 -0
  96. package/skills/traefik/docs/distributed-config.md +96 -0
  97. package/skills/traefik/docs/docker-compose.md +182 -0
  98. package/skills/traefik/docs/ha-performance.md +177 -0
  99. package/skills/traefik/docs/kubernetes.md +278 -0
  100. package/skills/traefik/docs/middleware.md +205 -0
  101. package/skills/traefik/docs/monitoring.md +357 -0
  102. package/skills/traefik/docs/security.md +391 -0
  103. package/skills/traefik/docs/tls-acme.md +155 -0
  104. package/skills/ui-ux-pro-max/SKILL.md +377 -0
  105. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  106. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  107. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  108. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  109. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  110. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  111. package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  112. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  113. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  114. package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  115. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  116. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  117. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  118. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  119. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  120. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  121. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  122. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  123. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  124. package/skills/ui-ux-pro-max/data/styles.csv +68 -0
  125. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  126. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  127. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  128. package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
@@ -0,0 +1,199 @@
1
+ # Navigation — Expo Router v5
2
+
3
+ ## Route Structure
4
+
5
+ ```
6
+ src/app/
7
+ _layout.tsx # Root: providers + auth guards (Stack.Protected)
8
+ +native-intent.tsx # Native deep link handler
9
+ (auth)/
10
+ _layout.tsx # Auth stack (fade animation, no gesture back)
11
+ login.tsx # Apple, Google, email OAuth
12
+ (onboarding)/
13
+ _layout.tsx # Onboarding stack (slide_from_right, no gesture back)
14
+ select-language.tsx # Language selection
15
+ step1-7.tsx # 7-step setup flow
16
+ (main)/
17
+ _layout.tsx # Main stack: registers all push/modal screens
18
+ index.tsx # Main entry redirect
19
+ (tabs)/ # 4 tabs: Home, Wardrobe, Stylist, Profile
20
+ _layout.tsx # Dual-mode: NativeTabs (iOS 26+ Liquid Glass) or ClassicTabs
21
+ home/
22
+ stylist/
23
+ profile/
24
+ (wardrobe)/ # Items + outfits sub-tabs
25
+ (wardrobe)/ # Push screens: item-detail, overview, upload-animation
26
+ (outfits)/ # Modals: maker (slide_from_bottom), save-modal (transparentModal)
27
+ (styling)/ # Modals: tryon, feedback (slide_from_bottom), about-stylist (push)
28
+ (discover)/ # Transparent modal: product-modal
29
+ (calendar)/ # Outfit calendar screens
30
+ (shared)/ # Shared modals: earn-credits, feedback-modal, referral, sty-history
31
+ notifications/
32
+ (global)/ # Transparent modals accessible from anywhere: loading, product-modal
33
+ ```
34
+
35
+ ## Route-Screen Delegation Pattern
36
+
37
+ Route files in `src/app/` are **thin delegators** (under 10 lines). Screen logic lives in `src/screens/` mirroring the same path:
38
+
39
+ ```typescript
40
+ // src/app/(main)/(tabs)/home/index.tsx — THIN DELEGATOR
41
+ import HomeScreen from "@/screens/(main)/(tabs)/home"
42
+ export default function HomeRoute() {
43
+ return <HomeScreen />
44
+ }
45
+ ```
46
+
47
+ Some route files wrap screens with feature dialogs:
48
+
49
+ ```typescript
50
+ // src/app/(main)/(wardrobe)/item-detail.tsx
51
+ import ClosetItemDetailScreen from "@/screens/(main)/(wardrobe)/item-detail"
52
+ import { ItemDialogs } from "@/features/item/_ui/item-dialogs"
53
+ import { useLocalSearchParams } from "expo-router"
54
+
55
+ export default function ClosetItemDetailRoute() {
56
+ const { item_id } = useLocalSearchParams<{ item_id: string }>()
57
+ return (
58
+ <>
59
+ <ClosetItemDetailScreen />
60
+ <ItemDialogs item_id={item_id} />
61
+ </>
62
+ )
63
+ }
64
+ ```
65
+
66
+ Screen folders contain `index.tsx` plus `_components/` for screen-specific sub-components:
67
+
68
+ ```
69
+ src/screens/(main)/(tabs)/home/
70
+ index.tsx
71
+ _components/
72
+ compact-header.tsx
73
+ weather-row.tsx
74
+ todays-picks-section.tsx
75
+ ai-stylist-row.tsx
76
+ ```
77
+
78
+ ## Auth Flow
79
+
80
+ Root `_layout.tsx` uses `Stack.Protected guard={condition}` to gate access:
81
+
82
+ ```typescript
83
+ const isLoggedIn = isAuthenticated && !!user
84
+ const needsOnboarding = isLoggedIn && !user?.is_onboarding_completed
85
+ const isAppReady = !isLoading && isAppInitialized && isOtaReady
86
+
87
+ <Stack>
88
+ <Stack.Protected guard={!isLoggedIn}>
89
+ <Stack.Screen name="(auth)" />
90
+ </Stack.Protected>
91
+ <Stack.Protected guard={isLoggedIn && needsOnboarding}>
92
+ <Stack.Screen name="(onboarding)" />
93
+ </Stack.Protected>
94
+ <Stack.Protected guard={isLoggedIn && !needsOnboarding}>
95
+ <Stack.Screen name="(main)" />
96
+ </Stack.Protected>
97
+ <Stack.Screen name="(global)" />
98
+ </Stack>
99
+ ```
100
+
101
+ Global overlays in root layout: `NetworkErrorOverlay`, `ForceUpdateOverlay`, `DailyCheckInSheet`, `QuotaExceededDialog`, `RemoteDialogContainer`.
102
+
103
+ ## Tab Layout (Dual-Mode)
104
+
105
+ ```typescript
106
+ // iOS 26+ uses NativeTabs (Liquid Glass native zoom + slide animations)
107
+ // Older iOS + Android uses ClassicTabs (custom tab bar)
108
+ const isLiquidGlass = Platform.OS === "ios" && parseInt(Platform.Version, 10) >= 26
109
+
110
+ // Tabs: home, (wardrobe), stylist, profile
111
+ // Tab config loaded from @/screens/(main)/(tabs)/_constants/tabs.const
112
+ ```
113
+
114
+ ## Navigation Patterns
115
+
116
+ ### Typed Routes
117
+
118
+ ```typescript
119
+ import { router } from "expo-router"
120
+ import { ROUTES } from "@/shared/constant/route"
121
+
122
+ // Navigate with typed routes
123
+ router.push(ROUTES.ITEM_DETAIL.path)
124
+ router.push({ pathname: "/(main)/(wardrobe)/item-detail", params: { item_id: "123" } })
125
+ router.back()
126
+ router.replace(ROUTES.LOGIN.path)
127
+ router.setParams({ date: newDate }) // Update current route params
128
+ ```
129
+
130
+ ### Route Params
131
+
132
+ ```typescript
133
+ // Extract params in route/screen files
134
+ const { item_id } = useLocalSearchParams<{ item_id: string }>()
135
+
136
+ // Complex params (JSON-encoded)
137
+ const { productData } = useLocalSearchParams()
138
+ const product = productData ? JSON.parse(productData) : null
139
+ ```
140
+
141
+ ### Modal Presentation
142
+
143
+ ```typescript
144
+ <Stack.Screen
145
+ name="(outfits)/maker"
146
+ options={{ presentation: "modal", animation: "slide_from_bottom", headerShown: false }}
147
+ />
148
+ <Stack.Screen
149
+ name="(discover)/product-modal"
150
+ options={{ presentation: "transparentModal", animation: "fade" }}
151
+ />
152
+ ```
153
+
154
+ ## Creating a New Screen
155
+
156
+ 1. Create screen: `src/screens/(main)/(section)/screen-name/index.tsx`
157
+ 2. Add sub-components: `src/screens/(main)/(section)/screen-name/_components/`
158
+ 3. Create thin route: `src/app/(main)/(section)/screen-name.tsx`
159
+ 4. Register in parent `_layout.tsx` Stack
160
+ 5. Add to `ROUTES` constant in `src/shared/constant/route.ts`
161
+
162
+ ## Screen Component Pattern
163
+
164
+ ```typescript
165
+ export default function HomeScreen() {
166
+ const { t } = useTranslation()
167
+ const { top } = useSafeAreaInsets()
168
+ const queryClient = useQueryClient()
169
+
170
+ const onRefresh = useCallback(async () => {
171
+ await queryClient.invalidateQueries()
172
+ }, [queryClient])
173
+
174
+ useFocusEffect(useCallback(() => {
175
+ logEvent("home_viewed")
176
+ }, []))
177
+
178
+ return (
179
+ <View style={styles.screen}>
180
+ <ScrollView>{/* Content */}</ScrollView>
181
+ </View>
182
+ )
183
+ }
184
+
185
+ const styles = StyleSheet.create({
186
+ screen: { flex: 1, backgroundColor: Theme.color.backgroundSubtle },
187
+ })
188
+ ```
189
+
190
+ ## Best Practices
191
+
192
+ - Keep route files under 10 lines — delegate to screens
193
+ - Use route groups `()` for organization without affecting URL
194
+ - Prefer `router.push()` over `<Link>` for programmatic navigation
195
+ - Use `useLocalSearchParams()` for type-safe params
196
+ - Use `useFocusEffect()` for screen focus side effects (analytics, refresh)
197
+ - Avoid nesting more than 3 levels of stack navigators
198
+ - Use `(shared)` group for screens accessible from multiple tabs
199
+ - Feature dialogs live alongside route files, not inside screens
@@ -0,0 +1,229 @@
1
+ # Performance — Animations, Lists, and Optimization
2
+
3
+ ## React Native Reanimated v4
4
+
5
+ Runs animations on the UI thread for 60fps regardless of JS thread activity. Uses `react-native-worklets` (separate package in v4).
6
+
7
+ ### Shared Values & Animated Styles
8
+
9
+ ```typescript
10
+ import Animated, {
11
+ useSharedValue, useAnimatedStyle,
12
+ withTiming, withSpring, withDelay, withSequence, withRepeat,
13
+ interpolate, Extrapolation, runOnJS,
14
+ } from "react-native-reanimated"
15
+
16
+ const Component = () => {
17
+ const opacity = useSharedValue(0)
18
+ const translateY = useSharedValue(50)
19
+
20
+ const animatedStyle = useAnimatedStyle(() => ({
21
+ opacity: opacity.value,
22
+ transform: [{ translateY: translateY.value }],
23
+ }))
24
+
25
+ const show = () => {
26
+ opacity.value = withTiming(1, { duration: 300 })
27
+ translateY.value = withSpring(0, { damping: 15, stiffness: 150 })
28
+ }
29
+
30
+ return <Animated.View style={animatedStyle} />
31
+ }
32
+ ```
33
+
34
+ ### Animation Functions
35
+
36
+ | Function | Use Case |
37
+ |----------|----------|
38
+ | `withTiming(toValue, { duration })` | Duration-based, predictable |
39
+ | `withSpring(toValue, { damping, stiffness })` | Physics-based, natural |
40
+ | `withDelay(ms, animation)` | Delayed start |
41
+ | `withSequence(anim1, anim2, ...)` | Sequential |
42
+ | `withRepeat(animation, count, reverse)` | Looping |
43
+ | `interpolate(value, inputRange, outputRange)` | Value mapping |
44
+
45
+ ### Spring Presets
46
+
47
+ ```typescript
48
+ const snappy = { damping: 15, stiffness: 200, mass: 0.8 } // Buttons, toggles
49
+ const gentle = { damping: 20, stiffness: 100, mass: 1 } // Modals, panels
50
+ const bouncy = { damping: 8, stiffness: 150, mass: 0.5 } // Playful elements
51
+ ```
52
+
53
+ ### Gesture Handler Integration
54
+
55
+ ```typescript
56
+ import { Gesture, GestureDetector } from "react-native-gesture-handler"
57
+
58
+ const DraggableCard = () => {
59
+ const translateX = useSharedValue(0)
60
+ const translateY = useSharedValue(0)
61
+
62
+ const gesture = Gesture.Pan()
63
+ .onUpdate((e) => {
64
+ translateX.value = e.translationX
65
+ translateY.value = e.translationY
66
+ })
67
+ .onEnd(() => {
68
+ translateX.value = withSpring(0)
69
+ translateY.value = withSpring(0)
70
+ })
71
+
72
+ const style = useAnimatedStyle(() => ({
73
+ transform: [{ translateX: translateX.value }, { translateY: translateY.value }],
74
+ }))
75
+
76
+ return (
77
+ <GestureDetector gesture={gesture}>
78
+ <Animated.View style={style}>{/* content */}</Animated.View>
79
+ </GestureDetector>
80
+ )
81
+ }
82
+ ```
83
+
84
+ ### Entering/Exiting Layout Animations
85
+
86
+ ```typescript
87
+ import Animated, { FadeIn, FadeOut, SlideInRight, SlideOutLeft } from "react-native-reanimated"
88
+
89
+ <Animated.View entering={FadeIn.duration(300)} exiting={FadeOut.duration(200)}>
90
+ {/* content */}
91
+ </Animated.View>
92
+
93
+ // Staggered list items
94
+ <Animated.View entering={FadeIn.delay(index * 50).duration(300)}>
95
+ {/* item */}
96
+ </Animated.View>
97
+ ```
98
+
99
+ ### Performance Limits
100
+
101
+ - Max **100 animated components** on low-end Android
102
+ - Max **500 animated components** on iOS
103
+ - Never read shared values on JS thread — only in worklets/useAnimatedStyle
104
+ - For complex visuals, use `react-native-skia` instead of many animated components
105
+
106
+ ## FlashList v2 — High-Performance Lists
107
+
108
+ FlashList v2 is New Architecture only, uses recycling for near-native perf. **Always use FlashList, never FlatList.**
109
+
110
+ ### Basic Usage
111
+
112
+ ```typescript
113
+ import { FlashList } from "@shopify/flash-list"
114
+
115
+ <FlashList
116
+ data={items}
117
+ renderItem={({ item }) => <ItemCard item={item} />}
118
+ estimatedItemSize={120} // Required: approximate item height
119
+ keyExtractor={(item) => item._id}
120
+ />
121
+ ```
122
+
123
+ ### Optimized Pattern
124
+
125
+ ```typescript
126
+ const renderItem = useCallback(({ item }: { item: ItemRes }) => (
127
+ <MemoizedItemCard item={item} />
128
+ ), [])
129
+
130
+ const MemoizedItemCard = React.memo(({ item }: { item: ItemRes }) => (
131
+ <View><Typography variant="b2">{item.name}</Typography></View>
132
+ ))
133
+
134
+ <FlashList
135
+ data={items}
136
+ renderItem={renderItem}
137
+ estimatedItemSize={120}
138
+ keyExtractor={(item) => item._id}
139
+ drawDistance={250} // Pre-render distance
140
+ onEndReached={onEndReached} // Infinite scroll
141
+ onEndReachedThreshold={0.5}
142
+ numColumns={2} // Grid layout
143
+ getItemType={(item) => item.type} // CRITICAL for mixed item types
144
+ ListFooterComponent={isFetchingNextPage ? <ActivityIndicator /> : null}
145
+ ListEmptyComponent={<EmptyState />}
146
+ />
147
+ ```
148
+
149
+ ### Key Rules
150
+
151
+ 1. **Never use `key` prop** inside item components — defeats recycling
152
+ 2. **Use `getItemType`** for heterogeneous lists
153
+ 3. **Always provide `estimatedItemSize`** — measure one item
154
+ 4. **Profile in release mode** — dev mode perf is misleading
155
+ 5. **Memoize `renderItem`** with `useCallback`
156
+ 6. **Memoize item components** with `React.memo`
157
+
158
+ ## expo-image — Optimized Image Loading
159
+
160
+ ```typescript
161
+ import { Image } from "expo-image"
162
+
163
+ <Image
164
+ source={{ uri: imageUrl }}
165
+ style={{ width: 100, height: 100 }}
166
+ contentFit="cover"
167
+ transition={200} // Fade-in ms
168
+ cachePolicy="memory-disk" // Default, recommended
169
+ placeholder={blurhash} // Optional blurhash
170
+ recyclingKey={item._id} // For list recycling
171
+ />
172
+
173
+ // Prefetch
174
+ await Image.prefetch(urls)
175
+ // Clear cache
176
+ await Image.clearDiskCache()
177
+ ```
178
+
179
+ | Cache Policy | Description |
180
+ |-------------|-------------|
181
+ | `memory-disk` | Default. Memory + disk |
182
+ | `memory` | Memory only |
183
+ | `disk` | Disk only |
184
+ | `none` | No caching |
185
+
186
+ ## General Performance Best Practices
187
+
188
+ ### Component Optimization
189
+
190
+ ```typescript
191
+ // Memoize expensive components
192
+ const ExpensiveChild = React.memo(({ data }) => { /* ... */ })
193
+
194
+ // Memoize callbacks passed as props
195
+ const handlePress = useCallback(() => { /* ... */ }, [dep])
196
+
197
+ // Memoize computed values
198
+ const filtered = useMemo(() => items.filter(i => i.category === selected), [items, selected])
199
+ ```
200
+
201
+ ### Avoid Common Pitfalls
202
+
203
+ ```typescript
204
+ // BAD: Inline styles (new object every render)
205
+ <View style={{ padding: 16, backgroundColor: "#fff" }}>
206
+
207
+ // GOOD: StyleSheet.create (cached)
208
+ const styles = StyleSheet.create({
209
+ container: { padding: Spacing.lg, backgroundColor: Theme.color.backgroundElevated },
210
+ })
211
+
212
+ // BAD: Arrow in render (new reference)
213
+ <Button onPress={() => handlePress(item._id)} />
214
+
215
+ // GOOD: Memoized callback
216
+ const onPress = useCallback(() => handlePress(item._id), [item._id])
217
+ ```
218
+
219
+ ### Metro Optimization
220
+
221
+ - `inlineRequires: true` in `metro.config.js` — defers module loading, improves cold start
222
+ - `.lottie` and `.cjs` added as asset/source extensions
223
+ - SVG support via `react-native-svg-transformer`
224
+
225
+ ### Platform-Specific
226
+
227
+ - **Shimmer**: `shimmer.ios.tsx` / `shimmer.android.tsx` (platform file extensions)
228
+ - **Android**: `removeClippedSubviews={true}` on large lists
229
+ - **Lottie**: Keep files under 100KB; for complex animations use Skia
@@ -0,0 +1,179 @@
1
+ # Platform Services — Auth, Push, Deep Links, i18n, Analytics
2
+
3
+ ## Authentication
4
+
5
+ ### OAuth Providers
6
+
7
+ - **Apple**: `expo-apple-authentication` → `src/features/auth/sign-in-with-apple.service.ts`
8
+ - **Google**: `@react-native-google-signin/google-signin` → `src/features/auth/sign-in-with-google.service.ts`
9
+ - **Facebook**: `react-native-fbsdk-next` (auto-initialized via app.config.ts)
10
+ - **Sign out**: `src/features/auth/sign-out.service.ts`
11
+
12
+ ### Auth Bootstrap (`src/shared/hooks/use-auth-init.ts`)
13
+
14
+ Runs once in root layout:
15
+ 1. Wait for Zustand hydration (`isHydrated`)
16
+ 2. Validate token integrity (`validateTokenIntegrity()`)
17
+ 3. If valid → `setAuthenticated(true)`, else → `logout()`
18
+ 4. Fetch user profile → set `useUserStore`
19
+ 5. Init Adapty (subscriptions) + sync Adapty user ID
20
+ 6. Sync Sty balance + retry pending verifications
21
+ 7. **15-second timeout guard** → force sign-out if user never loads
22
+
23
+ Error handling: Network errors keep auth state; 401/404 triggers `handleAuthFailure()` → sign out.
24
+
25
+ ### Token Management
26
+
27
+ ```typescript
28
+ import { storeTokens, getAccessToken, clearTokens, hasValidTokens } from "@/shared/libs/token-storage"
29
+
30
+ await storeTokens({ accessToken, refreshToken }) // After login
31
+ // Auto-injected by api-client interceptor
32
+ // 401 → auto-refresh (single-flight, max 2 retries) → if fails, sign out
33
+ ```
34
+
35
+ ## Push Notifications
36
+
37
+ ```typescript
38
+ import * as Notifications from "expo-notifications"
39
+ import { usePushNotifications } from "@/shared/hooks/use-push-notifications"
40
+
41
+ // Hook handles: permission request, token registration, notification handlers
42
+ Notifications.setNotificationHandler({
43
+ handleNotification: async () => ({
44
+ shouldShowAlert: true, shouldPlaySound: true, shouldSetBadge: true,
45
+ }),
46
+ })
47
+ ```
48
+
49
+ ## Deep Linking
50
+
51
+ ### Branch.io
52
+
53
+ ```typescript
54
+ import branch from "react-native-branch"
55
+
56
+ branch.subscribe(({ error, params }) => {
57
+ if (params["+clicked_branch_link"]) {
58
+ router.push({ pathname: params.screen, params: { id: params.id } })
59
+ }
60
+ })
61
+ ```
62
+
63
+ ### Airbridge
64
+
65
+ Configured via `airbridge-expo-sdk` plugin in `app.config.ts`. Associated domains for universal links.
66
+
67
+ ### Native Intent
68
+
69
+ `src/app/+native-intent.tsx` processes incoming URLs.
70
+
71
+ ## Internationalization (i18n)
72
+
73
+ 9 languages via `i18next` + `react-i18next`. Config in `src/features/multi-languages/`.
74
+
75
+ ```typescript
76
+ import { useTranslation } from "react-i18next"
77
+
78
+ const { t } = useTranslation()
79
+ <Typography variant="b1">{t("home.welcome")}</Typography>
80
+ ```
81
+
82
+ Language stored in MMKV for instant startup access. Locale JSON files in `src/features/multi-languages/locales/`.
83
+
84
+ ## Analytics
85
+
86
+ ### Airbridge (Primary) + Facebook
87
+
88
+ ```typescript
89
+ import { logEvent } from "@/shared/utils/log-event"
90
+
91
+ logEvent("item_created", { category: "tops", source: "camera" })
92
+ logEvent("outfit_saved", { itemCount: 3 })
93
+ logEvent("subscription_started", { plan: "premium" })
94
+ ```
95
+
96
+ ### User Properties
97
+
98
+ ```typescript
99
+ import { setUserProperty } from "@/shared/utils/set-user-property"
100
+ setUserProperty("subscription_tier", "premium")
101
+ ```
102
+
103
+ ## Subscriptions — Adapty
104
+
105
+ ```typescript
106
+ import { adapty } from "react-native-adapty"
107
+ // Managed via createAdaptySlice in app-store
108
+ // Paywall presentation, subscription status, receipt validation
109
+ ```
110
+
111
+ ### Store Review
112
+
113
+ ```typescript
114
+ import * as StoreReview from "expo-store-review"
115
+ if (await StoreReview.hasAction()) await StoreReview.requestReview()
116
+ ```
117
+
118
+ ## Live Activity (iOS)
119
+
120
+ ```typescript
121
+ import { useLiveActivityManager } from "@/shared/live-activity"
122
+ // Start/update/end live activities for long-running tasks (e.g., outfit generation)
123
+ // Uses expo-live-activity with push notification support
124
+ ```
125
+
126
+ ## Location
127
+
128
+ ```typescript
129
+ import { useLocation } from "@/features/location"
130
+ // Flow: permission → device location → sync to backend → weather recommendations
131
+ // Services in src/features/location/_services/
132
+ ```
133
+
134
+ ## Haptics
135
+
136
+ ```typescript
137
+ import * as Haptics from "expo-haptics"
138
+ Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light) // Buttons
139
+ Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium) // Toggles
140
+ Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success) // Confirmations
141
+ ```
142
+
143
+ ## Clipboard / Linking / Browser
144
+
145
+ ```typescript
146
+ import * as Clipboard from "expo-clipboard"
147
+ import * as WebBrowser from "expo-web-browser"
148
+ import * as Linking from "expo-linking"
149
+
150
+ await Clipboard.setStringAsync("text")
151
+ await WebBrowser.openBrowserAsync(url) // In-app browser
152
+ await Linking.openURL(url) // System browser
153
+ await Linking.openSettings() // App settings
154
+ ```
155
+
156
+ ## Environment Configuration
157
+
158
+ ```
159
+ .env.local → Development (default)
160
+ .env.staging → Staging/Preview
161
+ .env.prod → Production
162
+ ```
163
+
164
+ Key env vars: `EXPO_PUBLIC_API_URL`, `EXPO_PUBLIC_APP_NAME`, `APP_VARIANT=development` (appends `.dev` to bundle IDs), `EXPO_ENV` (controls env file loading).
165
+
166
+ `app.config.ts` loads env files based on `EXPO_ENV`. Production builds set `SKIP_LOCAL_ENV=1`.
167
+
168
+ ## Logging
169
+
170
+ ```typescript
171
+ import { Logger } from "@/shared/utils/logger"
172
+
173
+ Logger.info("User signed in", { userId })
174
+ Logger.warn("Slow response", { endpoint, duration })
175
+ Logger.error("Upload failed", { error: err.message })
176
+ // Dev: console with emojis/colors. Prod: errors shipped via clientLogger (batched, with backoff)
177
+ ```
178
+
179
+ Client logger (`src/shared/services/client-logger.service.ts`): max 200 entries queue, batch flush at 20 or every 10s, 429 backoff, connectivity check before flush.