# OrchardGo Development Instructions

## Project Overview

Multi-brand React Native application for music analytics and catalog management. Supports three brands (Orchard, AWAL, SME) with runtime theme switching.

## Technology Stack

React Native 0.74.2, React 18.2.0, TypeScript 5.0.4, Node.js >=22, Yarn 1.22.19.
Apollo Client 3.7.7 for GraphQL and state management.
React Navigation v6 for navigation.
Redux 5.0.1 (legacy - being phased out, do not add new Redux code).

## Project Structure

`src/components/` - Reusable UI components
`src/componentsDS/` - Design system components
`src/screens/` - Screen components
`src/navigation/` - Navigation configuration
`src/services/` - Business logic and integrations
`src/apollo/` - GraphQL setup and cache
`src/hooks/` - Custom React hooks
`src/mutations/` - GraphQL mutations
`src/queries/` - GraphQL queries
`src/branding/` - Multi-brand theming
`src/redux/` - Redux store (legacy)
`ios/` - iOS native code
`android/` - Android native code
`brands/` - Brand-specific assets

## Component Structure

Every component follows this pattern:

```
ComponentName/
├── ComponentName.tsx
├── index.ts
├── styles.ts (or styles.js for themed styles)
└── types.ts
```

**CRITICAL - Style Files:**

- Always create a separate style file - never define styles inline in component files
- Use `ThemedStyleSheet.create()` for components that need theme colors
- The `ThemedStyleSheet.create()` factory receives the full theme - destructure `colors`, `typography` (and `images`) and apply them **inside the style file**, not in the component. Spread typography in styles (`{ ...typography.label3DS, color: colors.midnight850 }`), never inline in JSX (`style={[styles.label, { ...typography.label3DS }]}`). Only keep a theme value in the component when it must be passed as a prop (e.g. an icon's `color`), not as a style.
- Reuse spacing tokens from `src/branding/utils/spacing.ts` (`spacing` = `{ xs: 2, s: 4, ms: 8, m: 10, ml: 12, l: 20, xl: 36 }`) for `padding`, `margin` and `gap` when the Figma value matches a token, instead of hardcoding the number - e.g. `gap: spacing.ms` not `gap: 8`. Use a raw number only when no token matches (border radius, fixed element sizes, shadow offsets).
- Name the file `styles.js` (for ThemedStyleSheet) or `styles.ts` (for regular StyleSheet)
- Import styles at the end of the component file
- Example pattern:

    ```typescript
    // ComponentName.tsx
    import styles from './styles';

    // styles.js
    import { ThemedStyleSheet } from '../../branding';
    const styles = ThemedStyleSheet.create(({ colors }) => ({
        container: {
            backgroundColor: colors.midnight900
        }
    }));
    export default styles;
    ```

## Naming Conventions

Components: PascalCase (ParticipantOverview)
Files/Directories: kebab-case (participant-overview)
Functions/Variables: camelCase (getParticipantData)
Constants: SCREAMING_SNAKE_CASE (MAX_RETRY_COUNT)

### Detailed Naming Rules

- **PascalCase**: Components and React components only
- **camelCase**: Any files/modules importing `react-native` or `react`
- **kebab-case**:
    - Utilities and functions that are JS/TS only
    - GraphQL queries
    - Formatters
    - Pure JavaScript/TypeScript modules without React dependencies

## TypeScript Requirements

Use TypeScript (.ts/.tsx) for all new files.
When making substantial changes to existing JavaScript files, consider migrating them to TypeScript.
For minor changes to JavaScript files, migration to TypeScript is optional and can be done opportunistically.
Define interfaces/types for all props, state, and function parameters in TypeScript files.
Avoid `any` type - use proper types or `unknown`.
Export types/interfaces that other files might need.

## React Patterns - CRITICAL

Use function components with hooks exclusively - never create class components.
Use custom hooks for logic reuse - never create Higher-Order Components (HOCs).
For touchable elements use the shared `TouchableOpacity` from `src/components/TouchableOpacity` (it debounces presses) - never `Pressable` or React Native's `TouchableOpacity` directly.
Never use Redux Saga - use React hooks or Apollo for async operations.
If Redux is needed for legacy code, use useSelector/useDispatch hooks, never connect().

## State Management

Server state: Use Apollo Client for API data.
Client state: Use Apollo Reactive Variables or React Context.
Local component state: Use React hooks (useState, useReducer).
Legacy Redux: Do not add new Redux code - migrate to Apollo/Context when refactoring.
Do not use `useSelector`, `connect`, or any Redux in new code. Use `getCurrentLanguage()` from `i18n.js` for language. Check the utility layer before reaching for the store.

## GraphQL Best Practices

Create custom hooks for all queries/mutations.
Implement proper error handling with error boundaries.
Use cache-and-network fetch policy for fresh data.
Leverage Apollo cache for optimistic updates.
Use fragments for reusable query parts.

## Multi-Brand Support

Use `useBrand()` hook to get current brand.
Use `useTheme()` hook with `safeWithTheme` HOC for themed styles.
Place brand-specific assets in `/brands/{brand}/`.
Never hardcode colors or dimensions - always use theme values.
Test with all brand themes.

## Import Order

1. React/React Native imports
2. Third-party libraries
3. Apollo/Redux imports
4. Local components
5. Hooks
6. Utils/Constants
7. Styles
8. Types

## Testing

Write tests for new components using React Native Testing Library.

- **Assertion style**: Never assert on hook return values, internal objects, or component state. Always assert on what the user sees: rendered text, visible elements, labels. Pattern: **user action → visible output**. Never: function call → object contains value.
- **Test file structure**: Do not create per-feature test files (e.g. `Component.featureName.spec.js`). All tests for a component live in its single spec file.
- **Mock scope**: Mocks that apply to more than one test belong in `beforeEach`, not inside individual tests.
- **Fixture naming**: Name test fixtures after their role, not their value: `existingCountry` not `usCountry`, `CHARTS_EXISTING_COUNTRY_CODE` not `CHARTS_US_COUNTRY_CODE`. Names must stay valid if the underlying value changes.
- **No scaffold comments**: Do not emit `// arrange`, `// act`, `// assert` or similar structural comments in test files.
- Use snapshot testing for UI components.
- Mock external dependencies in `__mocks__/`.
- Run `yarn test` before committing.
- Update snapshots with `yarn test:update:snapshots`.

## Feature Flags

Feature flags are managed in **Harness** (not GrowthBook). The mobile app reads flags via `useHasFeature(CONSTANT)` from `src/hooks/auth/useHasFeature.ts`, where `CONSTANT` is defined in `src/constants/features.ts`.

**Naming convention — critical**: All flag string values in `features.ts` use the `mobile_` prefix (e.g. `mobile_brand_filters_native`, `mobile_internal_user_data`). The Harness flag name **must exactly match** this string — the backend serves `profile.features` keyed by the Harness flag name, so a mismatch means `getHasFeature` always returns `false`.

When creating a new flag:

1. Name it `mobile_<description>` in Harness
2. Set the constant: `export const MOBILE_<DESCRIPTION> = 'mobile_<description>';`
3. Configure targeting rules in Harness (not in code)

## Hooks

Before adding a feature-flag guard or `skip` condition around a hook, read its implementation. Hooks in this codebase often handle their own flags and return safe defaults (empty arrays, `null`) when disabled. Wrapping them adds redundant logic.

## Error Handling

Wrap screens with error boundaries.
Log errors to Sentry with context.
Show user-friendly error messages.
Handle offline scenarios gracefully.

## Performance Optimization

### When NOT to optimize:

❌ Don't add `useMemo` for simple object lookups (`styles[theme]`, `config.value`)
❌ Don't memoize every style object "just in case"
❌ Don't add `useCallback` to every function without clear purpose
❌ Don't optimize without measuring first

### When TO optimize:

✅ Fix incorrect `useEffect` dependencies causing unwanted re-runs
✅ Use `React.memo` when profiling shows a component re-renders unnecessarily with same props
✅ Use `useCallback` for callbacks passed to native components (Image `onLoad`, FlatList `renderItem`)
✅ Use `useCallback` for callbacks passed to memoized child components
✅ Lazy load non-critical screens
✅ Virtualize long lists with FlatList
✅ Use FastImage for cached images
✅ Implement pagination for large datasets
✅ Debounce search inputs

### Reanimated-specific:

- Use `useAnimatedStyle` for Reanimated animations (NOT `useMemo`)
- Reanimated already optimizes internally - don't add extra memoization layers

### Process:

1. Identify the actual performance problem (profile/measure first)
2. Find the root cause (incorrect dependencies, unnecessary re-renders, expensive calculations)
3. Apply the minimal fix needed
4. Don't add "preventive" optimizations without evidence of benefit

Trust the framework. React and React Native are already highly optimized. Over-optimization adds complexity without real benefit. Measure first, optimize only when necessary, and keep solutions simple.

## Code Quality

Code must pass ESLint rules.
TypeScript must compile without errors.
All tests must pass.
Format code with Prettier.

## Code Clarity

Prefer creating meaningful variables instead of adding comments to explain code.
When logic is complex or unclear, extract it into well-named variables or functions rather than adding inline comments.
Only use comments for complex business logic that cannot be expressed through naming, non-obvious workarounds, or "why" explanations when the "what" is not self-evident.

## Accessibility

Add `accessibilityLabel` to interactive elements.
Use `accessibilityRole` appropriately.
Ensure proper contrast ratios.
Support dynamic font sizes where possible.

## Critical DO's

✅ Use TypeScript for all new code (.ts/.tsx files)
✅ Use function components with hooks exclusively
✅ Use custom hooks for logic reuse (never HOCs)
✅ Consider migrating JavaScript files to TypeScript when making substantial changes
✅ Migrate Redux/Saga to Apollo or Context when refactoring
✅ Define proper interfaces for all data structures
✅ Handle loading and error states
✅ Test with all three brands
✅ Keep components small and focused
✅ Export types that might be needed by other files
✅ Create separate style files (styles.js/styles.ts) - never define styles in component files

## Critical DON'Ts

❌ Create new JavaScript files (always use TypeScript)
❌ Create class components (use function components)
❌ Create Higher-Order Components (use custom hooks)
❌ Add new Redux Saga code (use hooks or Apollo)
❌ Add new Redux actions/reducers (use Apollo or Context)
❌ Use Redux connect (use hooks if Redux needed)
❌ Use `any` type (use proper types or `unknown`)
❌ Hardcode colors or dimensions
❌ Ignore TypeScript errors
❌ Commit console.logs
❌ Define styles in component files (use StyleSheet.create in separate styles.js/styles.ts files)
❌ Use inline style objects in JSX (move to dedicated style files)
❌ Skip writing tests

## Environment Configuration

Environments: prod, qa
Brands: orchard, awal, sme
Run command: `yarn start --platform [ios|android] --brand [brand] --env [env]`

## Common Commands

Setup: `yarn setup`
Test: `yarn test`
Lint: `yarn lint`
Clean: `yarn clean`
Reset: `yarn reset`

## Metro MCP Debugging

On this RN setup, `mcp__metro__get_network_requests`, `mcp__metro__search_network`, and `mcp__metro__get_response_body` return empty even right after a request fires — network interception isn't wired up. Use `mcp__metro__get_console_logs` instead: the Apollo logger link (`[GQL]`-prefixed groups) prints every request/response to console, including operation name, variables, and full data payload. Search by ISRC/ID, field name, or operation name (e.g. `search: "USSM19902991"` or `search: "streams1Day"`) rather than by URL. If the tool returns a file path for large payloads, use grep or a small Python script on that file for the specific field rather than reading it whole.
