Generated: 2025-11-26
This backlog contains prioritized recommendations from the comprehensive code review. Critical issues have been resolved. Items below are prioritized for future development.
Confidence: 90%
Effort: 1 day
Files: app/_layout.tsx
Issue: Error Boundaries only catch synchronous render errors, not async operations (API calls, SSE events, event handlers).
Solution:
// app/_layout.tsx - Add global error handler
useEffect(() => {
const previousHandler = ErrorUtils.getGlobalHandler()
ErrorUtils.setGlobalHandler((error, isFatal) => {
console.error('Global error:', error, 'isFatal:', isFatal)
if (isFatal) {
Alert.alert('Fatal Error', 'The app needs to restart.', [
{ text: 'Restart', onPress: () => RNRestart.Restart() },
])
}
previousHandler?.(error, isFatal)
})
return () => {
ErrorUtils.setGlobalHandler(previousHandler)
}
}, [])Dependencies: react-native-restart package
Confidence: 85%
Effort: 1 day
Files: hooks/useRealtimeSession.ts:50-73
Issue: SSE events update React Query cache with wildcard query key matching, causing updates to be applied to filtered queries incorrectly.
Current Code:
queryClient.setQueriesData<Session[]>({ queryKey: ['sessions'] }, (old) => {
// Updates ALL sessions queries, including filtered ones
})Improved Solution:
const handleProgressUpdate = useCallback(
(data: SessionProgressData) => {
// Update all sessions cache entries
queryClient.setQueriesData<Session[]>({ queryKey: ['sessions'] }, (old) => {
if (!old) {
queryClient.invalidateQueries({ queryKey: ['sessions'] })
return undefined
}
const sessionIndex = old.findIndex((s) => s.id === data.sessionId)
if (sessionIndex === -1) {
return old // Don't update if session not in this cache
}
const updated = [...old]
updated[sessionIndex] = {
...updated[sessionIndex],
progress: data.progress,
currentTask: data.currentTask || updated[sessionIndex].currentTask,
updatedAt: new Date(),
}
return updated
})
// Also update individual session detail cache
queryClient.setQueryData<Session>(['session', data.sessionId], (old) => {
if (!old) return undefined
return {
...old,
progress: data.progress,
currentTask: data.currentTask || old.currentTask,
updatedAt: new Date(),
}
})
},
[queryClient]
)Confidence: 85%
Effort: 2 days
Files: hooks/useAuth.tsx, app/_layout.tsx
Issue: Offline detection exists (useOffline hook) but isn't used to prevent critical operations or inform users.
Solution:
- Prevent login when offline:
// hooks/useAuth.tsx
const login = async () => {
const netInfo = await NetInfo.fetch()
if (!netInfo.isConnected) {
throw new Error('Cannot log in while offline. Please check your internet connection.')
}
// ... existing login logic
}- Show offline banner:
// app/_layout.tsx
import { useOffline } from '@/hooks/useOffline'
function RootLayoutNav() {
const { isOffline } = useOffline()
return (
<>
{isOffline && (
<View style={styles.offlineBanner}>
<Text>You're offline. Some features may not work.</Text>
</View>
)}
<Stack>...</Stack>
</>
)
}Confidence: 100% Effort: 2-3 days Priority: HIGH (Technical Debt)
Issue: Zero test coverage creates significant risk for regressions.
Action Items:
- Install testing dependencies:
npm install --save-dev @testing-library/react-native @testing-library/jest-native jest-
Priority test files:
__tests__/services/auth/token-manager.test.ts- Token expiration, refresh logic__tests__/services/api/client.test.ts- Token refresh interceptor, request queueing__tests__/hooks/useAuth.test.tsx- Auth flow, error handling__tests__/services/api/realtime.test.ts- SSE reconnection, exponential backoff
-
Test coverage goals:
- Auth flows: 90%+
- API client: 85%+
- Realtime service: 80%+
Confidence: 75%
Effort: 4 hours
Files: services/api/realtime.ts:140-162
Issue: EventSource.close() may not remove event listeners in all polyfill implementations.
Current Cleanup:
private cleanup(): void {
if (this.eventSource) {
this.eventSource.close() // Doesn't explicitly remove listeners
this.eventSource = null
}
}Improved Solution:
private eventListeners = new Map<string, (event: MessageEvent) => void>()
private setupEventListeners(): void {
if (!this.eventSource) return
const sessionUpdatedListener = (event: MessageEvent) => {
this.handleEvent(event, RealtimeEventType.SESSION_UPDATED)
}
this.eventListeners.set(RealtimeEventType.SESSION_UPDATED, sessionUpdatedListener)
this.eventSource.addEventListener(RealtimeEventType.SESSION_UPDATED as never, sessionUpdatedListener)
// ... repeat for other events
}
private cleanup(): void {
if (this.eventSource) {
// Remove all listeners explicitly
this.eventListeners.forEach((listener, eventType) => {
this.eventSource?.removeEventListener(eventType as never, listener)
})
this.eventListeners.clear()
this.eventSource.close()
this.eventSource = null
}
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout)
this.reconnectTimeout = null
}
}Confidence: 95%
Effort: 1 day
Files: utils/errorHandler.ts, components/ErrorBoundary.tsx, app/_layout.tsx, package.json
Issue: Error handler infrastructure exists but doesn't send errors to tracking service. Production errors are lost.
Solution:
- Install Sentry SDK:
npm install @sentry/react-native
npx @sentry/wizard -i reactNative- Initialize Sentry in app root:
// app/_layout.tsx
import * as Sentry from '@sentry/react-native'
if (!__DEV__) {
Sentry.init({
dsn: process.env.EXPO_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
environment: __DEV__ ? 'development' : 'production',
})
}- Integrate with error handler:
// utils/errorHandler.ts
import * as Sentry from '@sentry/react-native'
private trackError(error: Error, context?: ErrorContext): void {
if (!__DEV__) {
Sentry.captureException(error, {
extra: context,
tags: {
source: context?.source || 'unknown',
},
})
}
}- Wrap ErrorBoundary:
// components/ErrorBoundary.tsx
import * as Sentry from '@sentry/react-native'
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('ErrorBoundary caught:', error, errorInfo)
if (!__DEV__) {
Sentry.captureException(error, {
contexts: {
react: {
componentStack: errorInfo.componentStack,
},
},
})
}
if (this.props.onError) {
this.props.onError(error, errorInfo)
}
}Prerequisites:
- Create Sentry account and obtain DSN
- Add
EXPO_PUBLIC_SENTRY_DSNto.env - Test error tracking in staging environment first
Validation:
- Trigger test error in app
- Verify error appears in Sentry dashboard
- Confirm context (componentStack, source) is captured
Confidence: 75%
Effort: 1-2 days
Files: components/session/ApprovalActions.tsx, components/PerformanceMonitor.tsx
Issue: Frequent slow frame warnings (20-40 FPS) during modal open/close animations and optimistic updates.
Observed Warnings:
WARN 🐌 Slow frame detected: 38.4 FPS (26.06ms)
WARN 🐌 Slow frame detected: 21.4 FPS (46.70ms)
Root Causes:
- Modal animations + React Query cache updates happening simultaneously
- 300ms loading state + 800ms mock delay may cause layout thrashing
- Multiple re-renders during optimistic update flow
Solutions:
- Use native driver for modal animations:
// ApprovalActions.tsx - Modal animation
<Modal
animationType="fade"
transparent
hardwareAccelerated // Add this
>- Debounce optimistic updates:
// useUpdateSession.ts - Batch state updates
onMutate: async ({ id, request }) => {
// Use startTransition for non-urgent updates
startTransition(() => {
queryClient.setQueriesData(...)
})
}- Profile with React DevTools:
- Identify which components re-render during mutations
- Add more
memo()boundaries if needed - Check if Toast component causes layout shifts
Priority: Medium - App is functional but UX could be smoother
Confidence: 100%
Effort: 5 minutes
Files: package.json, components/PerformanceMonitor.tsx
Issue: Warning on every app start due to missing optional dependency.
Warning:
WARN ⚠️ Could not initialize why-did-you-render:
[Error: Cannot find module '@welldone-software/why-did-you-render']
Solution:
Either:
- Remove the code (recommended if not actively debugging):
# Find and remove why-did-you-render initialization code
grep -r "why-did-you-render" components/- Or install the dependency (if needed for debugging):
npm install --save-dev @welldone-software/why-did-you-renderRecommendation: Remove the code - this tool is for React development debugging and shouldn't be in the production codebase unless actively being used.
Confidence: 70% Effort: 1-2 days
Issue: Currently using custom performance monitoring (utils/performanceMonitor.ts, utils/fpsMonitor.ts, utils/renderTracker.ts). The @shopify/react-native-performance library is already installed but not actively used. Need to evaluate if it provides better performance monitoring capabilities.
Action Items:
-
Research the library:
- Review documentation: https://github.com/Shopify/react-native-performance
- Understand capabilities vs. current custom implementation
- Check maintenance status and community support
-
Compare features:
- Memory monitoring (current:
performanceMonitor.ts) - FPS tracking (current:
fpsMonitor.ts) - Render performance (current:
renderTracker.ts) - Additional features from Shopify library
- Memory monitoring (current:
-
Decision criteria:
- Better accuracy/features than custom implementation?
- Active maintenance (library currently marked as "unmaintained")
- New Architecture compatibility
- Integration effort vs. value gained
-
Possible outcomes:
- Replace custom monitoring with Shopify library
- Keep custom implementation and remove Shopify dependency
- Hybrid approach using both
Files to review:
utils/performanceMonitor.ts- Current memory monitoringutils/fpsMonitor.ts- Current FPS trackingutils/renderTracker.ts- Current render performanceapp/_layout.tsx:131-171- Where performance monitoring is initialized
Note: Library is flagged as "Unmaintained" and "Untested on New Architecture" by Expo doctor. Consider this in the evaluation.
Confidence: 90% Effort: 2-3 days
Issue: No telemetry/analytics to understand user behavior, feature usage, or performance metrics in production.
Action Items:
-
Choose telemetry provider:
- Expo Analytics (built-in, simple)
- Segment (multi-destination)
- Mixpanel (product analytics)
- PostHog (open source, self-hostable)
-
Track key events:
- User sessions (start, end, duration)
- Feature usage (sessions viewed, notifications checked, actions taken)
- Performance metrics (screen load times, API response times)
- Errors and crashes (complement Sentry)
- User flows (navigation paths, drop-off points)
-
Implementation example with Expo Analytics:
// utils/analytics.ts
import * as Analytics from 'expo-analytics'
export const analytics = {
trackEvent: (name: string, properties?: Record<string, any>) => {
if (!__DEV__) {
Analytics.logEvent(name, properties)
}
},
trackScreen: (screenName: string) => {
if (!__DEV__) {
Analytics.setCurrentScreen(screenName)
}
},
setUserProperties: (properties: Record<string, any>) => {
if (!__DEV__) {
Analytics.setUserProperties(properties)
}
},
}
// Usage in components
analytics.trackEvent('session_viewed', { sessionId, status })
analytics.trackScreen('SessionDetail')- Privacy considerations:
- Update Privacy Manifest with data collection disclosure
- Implement opt-out mechanism
- Anonymize sensitive data (no tokens, no PII)
- GDPR/CCPA compliance
Benefits:
- Understand which features users actually use
- Identify performance bottlenecks in production
- Data-driven product decisions
- Track adoption and retention metrics
Confidence: 80% Effort: 4 hours
Issue: No visibility into app bundle size or what's contributing to it.
Action Items:
npm install --save-dev react-native-bundle-visualizer// package.json
{
"scripts": {
"analyze:ios": "EXPO_PUBLIC_ANALYZE=true expo export:ios && npx react-native-bundle-visualizer",
"analyze:android": "EXPO_PUBLIC_ANALYZE=true expo export:android && npx react-native-bundle-visualizer"
}
}Monitoring Goals:
- Track bundle size over time
- Identify large dependencies (consider replacing
axioswithfetch) - Verify tree-shaking is working
- Monitor unused Expo modules
Confidence: 80% Effort: 1 hour Files: Multiple
Issue: Some files don't use import type for type-only imports despite ESLint rule.
Solution:
npm run lint:fixThis should auto-fix most instances. Review and commit.
Confidence: 95%
Effort: 2-3 weeks
Files: See SECURITY_AUDIT_SUMMARY.md
Remaining Critical Items (Pre-App Store Submission):
- Missing Privacy Manifest data declarations - App Store blocker
- Missing SSL pinning - Legitimate security gap
- Insecure deep links - OAuth vulnerability
- Code verifier in memory - PKCE security violation
Refer to: SECURITY_AUDIT_SUMMARY.md for detailed remediation steps.
✅ TypeScript Strict Mode - tsconfig.json has "strict": true
✅ Zod Schema Validation - Comprehensive runtime API validation
✅ Error Boundary Defense-in-Depth - Triple-nested error boundaries
✅ Expo Router File-Based Routing - Clean navigation structure
✅ Separation of Concerns - Services, hooks, components layers
✅ SecureStore for Tokens - Proper sensitive data storage
✅ Mock Data Infrastructure - Environment-based feature flags
✅ Pre-commit Hooks - Husky + lint-staged configured
File: services/api/realtime.ts:219-223
const delay = Math.min(
this.reconnectionConfig.initialDelay *
Math.pow(this.reconnectionConfig.backoffMultiplier, this.reconnectAttempts),
this.reconnectionConfig.maxDelay
)Recommendation: Already configurable via reconnectionConfig, no action needed.
File: components/ErrorBoundary.tsx:34-46
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('ErrorBoundary caught:', error, errorInfo)
// TODO: Send to error tracking service
}Recommendation: Integrate error tracking service (Sentry, Bugsnag) when ready.
✅ Missing Zod Dependency - Added zod@^4.1.13
✅ JWT Token Expiration Handling - TokenManager.isAuthenticated() now clears expired tokens
✅ SecureStore Error Handling - All operations have try/catch blocks
✅ Proactive Token Refresh - API client refreshes 5 minutes before expiration
✅ Production Debug Logging - Created logger utility, wrapped all console.log calls
✅ Hardcoded Mock User Data - Replaced with AuthAPI.getUserProfile()
✅ Type Error Fix - Fixed performanceMonitor.ts setInterval type
- Week 1: Complete security audit items (SSL pinning, Privacy Manifest, deep link validation)
- Week 2: Set up test infrastructure + write critical path tests (auth, token refresh)
- Week 3: Add global error handling, fix React Query cache race conditions
- Week 4: Bundle size optimization, offline mode UI, final QA
These items represent the original roadmap for the ACP Mobile app:
- OAuth with Red Hat SSO - Replace mock authentication with real OAuth flow
- ACP Backend API Connection - Connect to production API for sessions and repositories
- GitHub OAuth + Notifications - Implement GitHub integration for notifications
- Push Notifications - Firebase Cloud Messaging / Apple Push Notification Service
- Data Persistence - Implement robust offline storage (AsyncStorage/SQLite)
- Real-time Updates - Complete SSE implementation (partially done)
- Error Handling - Comprehensive error handling and loading states
- TestFlight / Google Play Internal Testing - Beta testing program
- App Store / Google Play Submission - Production release
The initial implementation used a single-file mockup (app/(tabs)/index.tsx, ~1800 lines) with StyleSheet for all styling. This has been refactored into a proper component-based architecture.
Backlog Maintained By: Code Review Agent Last Updated: 2025-11-26 Review Frequency: After each major feature/sprint