A production-grade React Native mobile application that helps users diagnose and resolve boiler/combi fault codes. Built with TypeScript, featuring a modern architecture with mock data for MVP.
- Smart Search: Find fault codes by code number, brand, or keywords with relevancy-based ranking
- Rich Fault Details: Comprehensive information including severity, causes, safety notices, and step-by-step resolution guides
- Multi-Brand Support: 10+ major boiler brands with 50+ real fault codes
- Freemium Model: Free tier with 10 daily views, Pro tier with unlimited access
- Bilingual: Full support for English and Turkish
- Themeable: Light and dark mode support
- Type-Safe: Full TypeScript with strict mode enabled
- Well-Tested: Jest unit and integration tests included
- React Native: 0.73.6 (pure RN, no Expo)
- React: 18.2.0
- TypeScript: 5.2.2 (strict mode)
- @react-navigation/native: 6.1.9
- @react-navigation/stack: 6.3.20
- @react-navigation/bottom-tabs: 6.5.14
- react-native-screens: 3.30.1
- react-native-safe-area-context: 4.6.3
- Zustand: 4.4.1 (with Immer middleware)
- @tanstack/react-query: 4.29.14
- NativeWind: 2.0.11
- Tailwind CSS: 3.3.2
- react-native-svg: 13.14.0
- i18next: 23.5.1
- react-i18next: 13.2.2
- react-hook-form: 7.45.2
- zod: 3.22.4
- Jest: 29.7.0
- @testing-library/react-native: 12.2.1
- ESLint: 8.52.0
- Prettier: 3.0.3
- Supabase: 2.39.0
- Google Mobile Ads: 11.7.0
- In-App Purchases: 13.9.0
FaultCode/
βββ src/
β βββ app/ # Screens & Navigation
β β βββ navigation/ # Navigation config
β β β βββ RootNavigator.tsx
β β β βββ MainTabNavigator.tsx
β β β βββ SearchStackNavigator.tsx
β β β βββ types.ts
β β βββ screens/ # Screen components
β β βββ SearchHomeScreen.tsx
β β βββ FaultDetailScreen.tsx
β β βββ PaywallScreen.tsx
β β βββ SettingsScreen.tsx
β β
β βββ components/ # Reusable UI components
β β βββ FaultCodeCard.tsx
β β
β βββ data/ # Data layer
β β βββ types.ts # TypeScript types
β β βββ mock/ # Mock JSON data
β β β βββ brands.json (10 brands)
β β β βββ models.json (15 models)
β β β βββ fault_codes.json (50+ codes)
β β β βββ steps.json (Resolution steps)
β β βββ repo/ # Repository layer
β β βββ brandRepo.ts
β β βββ faultRepo.ts
β β
β βββ state/ # Zustand stores
β β βββ useUserStore.ts # User, plan, quota
β β βββ usePrefsStore.ts # Language, theme, settings
β β βββ useAnalyticsStore.ts # Analytics tracking
β β
β βββ lib/ # External integrations
β β βββ supabase.ts # Supabase client
β β βββ env.d.ts # Environment types
β β
β βββ theme/ # Design tokens & theming
β β βββ tokens.ts # Colors, spacing, typography
β β βββ useTheme.ts # Theme hook
β β βββ index.ts
β β
β βββ i18n/ # Internationalization
β β βββ index.ts
β β βββ locales/
β β βββ en.ts # English translations
β β βββ tr.ts # Turkish translations
β β
β βββ utils/ # Utilities
β βββ index.ts # Helpers (debounce, delay, etc.)
β
βββ scripts/ # Database & deployment scripts
β βββ setupSupabaseTables.sql # Bilingual Supabase schema
β βββ README.md # Database setup guide
β
βββ App.tsx # Root component
βββ index.js # RN entry point
βββ package.json # Dependencies (exact versions)
βββ tsconfig.json # TypeScript config
βββ babel.config.js # Babel config
βββ jest.config.js # Jest config
βββ tailwind.config.js # Tailwind config
βββ README.md # This file
- Node.js: >= 18.0.0
- Yarn: >= 1.22.0
- React Native CLI: Installed globally
- Android Studio: For Android development (with Android SDK 33+)
- Xcode: For iOS development (macOS only, version 14+)
-
Clone the repository
cd FaultCode -
Configure environment variables
cp .env.example .env # Edit .env and add your Supabase credentials # Get them from https://app.supabase.com β Project Settings β API
Note: The app currently uses mock data, so Supabase credentials are optional. You can leave the
.envfile with empty values for now. -
Install dependencies
yarn install
-
Install iOS pods (macOS only)
cd ios && pod install && cd ..
-
Start Metro bundler:
yarn start
-
In a new terminal, run Android:
yarn android
Or with a specific device:
yarn android --deviceId=<device-id>
-
Start Metro bundler:
yarn start
-
In a new terminal, run iOS:
yarn ios
Or for a specific simulator:
yarn ios --simulator="iPhone 15"
# Run tests
yarn test
# Run tests in watch mode
yarn test:watch
# Type checking
yarn type-check
# Linting
yarn lint
yarn lint:fix
# Format code
yarn format
# Database migration
yarn db:import # Import mock data to SupabaseThe project includes comprehensive tests:
- Unit tests: Repository functions with search/filter logic
- Integration tests: Screen rendering and component behavior
Run tests:
yarn testExample test files:
src/data/repo/__tests__/brandRepo.test.tssrc/data/repo/__tests__/faultRepo.test.tssrc/app/screens/__tests__/SearchHomeScreen.test.tsxsrc/app/screens/__tests__/FaultDetailScreen.test.tsx
All data access goes through repository functions in src/data/repo/. This abstraction makes it easy to swap mock JSON with real API calls later:
// brandRepo.ts
export async function searchBrands(query: string): Promise<Brand[]> {
// Currently: filter mock JSON
// Future: await axios.get('/api/brands/search', { params: { q: query } })
}- Zustand: Lightweight global state for user plan, quota, and preferences
- React Query: Ready for server-state management when API is integrated
Free users can view 10 fault details per day. The quota resets daily and is tracked in useUserStore:
const { canAccess, remaining, limit } = useCanAccessContent();When limit is reached, users are redirected to the Paywall screen.
This project uses a smart repository layer that automatically switches between Supabase and mock data:
With Supabase configured:
- Fetches data from Supabase with bilingual support (EN/TR)
- Automatically falls back to mock data if Supabase fails
- Provides full translation based on user language preference
Without Supabase:
- Uses local mock JSON files (works 100% offline)
- No network calls, instant responses
- Perfect for development and testing
Key benefit: Your app works offline AND online with the same code!
Advantages:
- Fast development without backend dependency
- Predictable, testable behavior
- Works offline by default
- Easy to demo and iterate
Mock Data Files:
brands.json- 10 major boiler brandsmodels.json- Boiler models per brandfault_codes.json- 50+ real fault codessteps.json- 2-6 resolution steps per fault
When ready to migrate from mock data to Supabase, update only the repository files. The UI layer remains unchanged.
Prerequisites:
- Create a Supabase project at https://app.supabase.com
- Run the database schema:
scripts/setupSupabaseTables.sql(seescripts/README.mdfor details) - Add your credentials to
.envfile - Migrate mock data to Supabase (optional helper scripts coming soon)
- Update repository implementations
Database Schema: The app includes a complete bilingual SQL schema in scripts/setupSupabaseTables.sql with:
- JSONB columns for English/Turkish content
- 7 core tables: brands, boiler_models, fault_codes, resolution_steps, plans, users, analytics_events
- Optimized indexes, foreign keys, and Row Level Security policies
Step 1: Update Repository Implementation
// src/data/repo/faultRepo.ts
// Before (mock):
export const searchFaults = async (params) => {
const faults = require('../mock/fault_codes.json');
return faults.filter(...);
};
// After (Supabase):
import { supabase } from '@lib/supabase';
export const searchFaults = async (params) => {
const { data, error } = await supabase
.from('fault_codes')
.select('*')
.ilike('code', `%${params.q}%`);
if (error) throw error;
return data;
};Step 2: Enable React Query Caching
// App.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 minutes
cacheTime: 10 * 60 * 1000, // 10 minutes
},
},
});
// Use in components
const { data, isLoading } = useQuery({
queryKey: ['faults', query],
queryFn: () => searchFaults({ q: query }),
});Step 3: Add Error Handling
try {
const data = await searchFaults(params);
return data;
} catch (error) {
if (axios.isAxiosError(error)) {
// Handle network errors
throw new Error('Network error. Please check your connection.');
}
throw error;
}Migration Checklist:
- Create Supabase project and get credentials
- Configure
.envwith SUPABASE_URL and SUPABASE_ANON_KEY - Create database tables matching your types
- Update repository implementations to use Supabase client
- Add error handling for network failures
- Implement loading states
- Enable React Query caching
- Keep mock data for tests
- Test with slow/offline network conditions
This project uses exact version pinning (no ^ or ~) for maximum stability.
Why Pinned Versions?
- β Consistent builds across environments
- β Prevents unexpected breaking changes
- β Easier debugging (everyone on same versions)
- β Production-ready stability
Example:
{
"dependencies": {
"react": "18.2.0", // β
Exact version
"react-native": "0.73.6" // β
Exact version
}
}# Check React Native compatibility
# Visit: https://reactnative.directory/
# Ensure package supports React Native 0.73.6# β DON'T: yarn add package-name (uses latest)
# β
DO: Specify exact version
yarn add react-native-package@1.2.3yarn type-check # TypeScript check
yarn lint # Linting
yarn test # All tests
yarn android # Test on device/emulatorgit add package.json yarn.lock
git commit -m "chore: add react-native-package@1.2.3"# Check for outdated packages
yarn outdated
# Update to specific version (test first!)
yarn add package-name@x.y.z
# Run all checks
yarn type-check && yarn lint && yarn testOption 1: Downgrade to Compatible Version (Preferred)
# Prefer downgrading new package over upgrading React Native
yarn add problematic-package@older-compatible-versionOption 2: Wait for Compatibility Update
# Check package issues/PRs for updates
# Consider using alternative packageOption 3: Use Resolutions (Last Resort)
// package.json
{
"resolutions": {
"package-name": "x.y.z"
}
}{
"react": "18.2.0",
"react-native": "0.73.6",
"typescript": "5.2.2"
}Updating these requires extensive testing and may require native code changes.
Full bilingual support (English/Turkish) using i18next:
const { t } = useTranslation();
<Text>{t('search.placeholder')}</Text>Strict TypeScript throughout with shared types in src/data/types.ts:
Brand,BoilerModel,FaultCode,ResolutionStep- Navigation types with full type inference
- Debounced search input
- Brand filter dropdown
- Fault code results list with cards
- Empty states for no results
- Fault code, title, severity badge
- Safety notices (highlighted)
- Possible causes
- Step-by-step resolution guide with time estimates and tool requirements
- Quota indicator for free users
- Free vs Pro comparison
- Mock subscription button
- Quota information
- Language toggle (EN/TR)
- Theme toggle (Light/Dark)
- Analytics opt-in
- Current plan display
When ready to switch from mock data to a real backend:
-
Update repositories in
src/data/repo/:// Before (mock) return brandsData.filter(/* ... */); // After (real API) const response = await axios.get('/api/brands', { params: { q } }); return response.data;
-
Enable React Query caching and invalidation
-
Add authentication using Firebase Auth stubs
-
Implement IAP for real subscriptions
-
Integrate ads for free tier
This project uses GitHub Actions for continuous integration with full Supabase support:
- Automated Testing: Runs on every push and pull request
- Type Checking: TypeScript compilation check
- Linting: ESLint + Prettier checks
- Test Suite: Jest tests with coverage reporting (uses mocks, no network calls)
- Node Version: 18.x
- Caching: Yarn dependencies cached for faster builds
- Supabase Integration: Tests work with or without Supabase credentials
- Checkout code
- Setup Node.js 18 with yarn cache
- Install dependencies with
--frozen-lockfile - Run
yarn type-check(TypeScript) - Run
yarn lint(ESLint + Prettier) - Run
yarn test --ci --coverage(Jest) - Upload coverage to Codecov (optional)
# Run all CI checks locally
yarn type-check # TypeScript check
yarn lint # Linting check
yarn test # Run tests with coverageThe CI badge at the top of this README shows the current build status. Click it to see detailed workflow runs.
Tests use mocks by default and don't require Supabase credentials. However, if you want to test against a real Supabase instance in CI:
- Go to your repository β Settings β Secrets and variables β Actions
- Add these optional secrets:
SUPABASE_URL- Your Supabase project URLSUPABASE_ANON_KEY- Your Supabase anonymous keySUPABASE_SERVICE_ROLE_KEY- Your Supabase service role key (for backend scripts)
Note: These are completely optional. The CI pipeline will use mock data if secrets are not configured.
See GITHUB_ACTIONS_SETUP.md for detailed setup instructions.
Symptom: App crashes or shows blank screen with error about URL.hostname
Cause: React Native doesn't have full URL API support which is required by Supabase
Solution: This is already fixed with the react-native-url-polyfill package. Make sure:
# The polyfill is installed
yarn install
# The app is restarted with cache cleared
yarn start --reset-cacheThe polyfill is imported at the top of index.js before any other code.
Symptom: Infinite recursion error when loading data
Cause: Circular dependency in repository fallback logic
Solution: This is already fixed. The Supabase repositories now import directly from *.mock.ts files instead of the index files to avoid circular dependencies.
If you still see this:
# Clean all caches
yarn start --reset-cache
# On Android
cd android && ./gradlew clean && cd ..
# Rebuild
yarn androidSymptom: Build fails with CMake/ninja errors
Cause: Corrupted native build cache
Solution:
# Clean Android build
cd android
./gradlew clean
cd ..
# Rebuild
yarn androidSymptom: App shows empty lists or blank screens
Cause: Either Supabase connection issue or fallback not working
Solution:
- Check if
.envfile exists with valid Supabase credentials - If you don't have Supabase set up, leave
.envempty to use mock data - Check Metro bundler for errors:
yarn start --reset-cache - Verify mock data files exist in
src/data/mock/
Symptom: Error accessing language preference
Cause: Store not initialized before use
Solution: Make sure usePrefsStore is initialized. The app should initialize it in App.tsx. If issue persists:
// In your store usage
const language = usePrefsStore.getState()?.language || 'en';Symptom: Tests pass but show act() warnings
Cause: React state updates not wrapped in act()
Solution: This is already handled in jest.setup.js with:
global.suppressActWarnings = true;# Full clean rebuild
rm -rf node_modules
yarn install
cd android && ./gradlew clean && cd ..
yarn start --reset-cache
# In another terminal
yarn android
# Check for type errors
yarn type-check
# Check for linting issues
yarn lint
# Run tests to verify everything works
yarn test- Mock Data Only: No real backend or network calls
- No Persistence: State resets on app restart (add AsyncStorage later)
- No Authentication: Login/logout is mocked
- No Real IAP: Subscription is simulated
- No Offline Mode: Though structure supports it
- Basic UI: Production app should use a component library (e.g., React Native Paper)
Symptoms: Favorites show "mock data used" error, nothing is saved, favorites screen is blank.
Root Causes & Solutions:
-
Mock Data Fallback Issue
- Problem: App is using mock fault IDs (fault_001) instead of Supabase UUIDs
- Solution: Ensure fault data comes from Supabase with proper UUIDs
- Check: Look for "Mock data detected" warnings in console
-
Authentication Issues
- Problem: User not logged in or invalid user ID
- Solution: Verify user is logged in with valid Supabase Auth session
- Check:
useUserStore.getState().userIdshould be a valid UUID
-
Premium Plan Issues
- Problem: User has free plan but trying to access favorites
- Solution: Upgrade to Pro plan or check plan status
- Check:
useUserStore.getState().planshould be 'pro'
-
Database Schema Issues
- Problem: Missing favorites table or incorrect column names
- Solution: Run database migrations:
scripts/migrations/002_favorites_monthly_quota.sql - Check: Verify
favoritestable exists with correct columns
-
RLS Policy Issues
- Problem: Row Level Security blocking favorites access
- Solution: Ensure RLS policies allow user to access their own favorites
- Check: Verify
auth.uid()matchesuser_idin favorites table
Debug Steps:
- Check console for "Mock data detected" warnings
- Verify user authentication status
- Confirm user has Pro plan
- Test Supabase connection and table access
- Check RLS policies in Supabase dashboard
Feature Flags:
- Set
USE_MOCK_FALLBACK=falseto disable mock fallback for favorites - Enable debug logs with
ENABLE_DEBUG_LOGS=true - Check
src/config/featureFlags.tsfor configuration
This is a proprietary application. All rights reserved.
- Architecture: Production-grade RN setup
- Data: 50+ real boiler fault codes from Vaillant, Worcester Bosch, Baxi, Viessmann, Ariston, Ideal, Vokera, Baymak, Ferroli, Buderus
For issues or questions, please check:
- Ensure all dependencies are installed:
yarn install - Clear Metro cache:
yarn start --reset-cache - Clean build folders:
cd android && ./gradlew clean - Reinstall pods:
cd ios && pod install
Version: 0.1.0 (MVP with Mock Data)
Last Updated: October 2025