|
| 1 | +# AGENTS.md - Discourse Mobile Codebase Guide |
| 2 | + |
| 3 | +This document provides guidance for AI agents working on the Discourse Mobile codebase. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +**Discourse Mobile** is a native iOS and Android application for [Discourse](https://discourse.org) forums, built with React Native. It allows users to connect to multiple Discourse communities, receive push notifications, browse topics, and authenticate via OAuth2. |
| 8 | + |
| 9 | +### Technology Stack |
| 10 | + |
| 11 | +- **Framework**: React Native |
| 12 | +- **JS Engine**: Hermes |
| 13 | +- **Navigation**: React Navigation v6 (Stack + Bottom Tabs) |
| 14 | +- **State**: React hooks, Context (ThemeContext), AsyncStorage |
| 15 | +- **Push Notifications**: Firebase Cloud Messaging (FCM) |
| 16 | +- **Authentication**: OAuth2 via Safari Web Auth with RSA encryption |
| 17 | +- **Testing**: Detox (e2e), Jest (unit) |
| 18 | +- **Languages**: JavaScript, Swift (iOS Share Extension), Kotlin (Android) |
| 19 | + |
| 20 | +## Project Structure |
| 21 | + |
| 22 | +``` |
| 23 | +DiscourseMobile/ |
| 24 | +├── js/ # Main JavaScript source |
| 25 | +│ ├── Discourse.js # Root app component, navigation, lifecycle |
| 26 | +│ ├── site_manager.js # Multi-site management, auth tokens |
| 27 | +│ ├── site.js # Site model, API interactions |
| 28 | +│ ├── DiscourseUtils.js # Notification routing logic |
| 29 | +│ ├── ThemeContext.js # Dark/light theme configuration |
| 30 | +│ ├── screens/ # Screen components |
| 31 | +│ │ ├── HomeScreen.js # Main sites list, topic viewing |
| 32 | +│ │ ├── NotificationsScreen.js |
| 33 | +│ │ ├── DiscoverScreen.js # Site discovery |
| 34 | +│ │ ├── AddSiteScreen.js # Connect to new sites |
| 35 | +│ │ ├── SettingsScreen.js |
| 36 | +│ │ ├── WebViewScreen.js # In-app web content |
| 37 | +│ │ └── *Components/ # Screen-specific sub-components |
| 38 | +│ ├── platforms/ # Platform-specific implementations |
| 39 | +│ │ ├── firebase.ios.js |
| 40 | +│ │ ├── firebase.android.js |
| 41 | +│ │ └── background-fetch.*.js |
| 42 | +│ └── locale/ # 49 language translation files (JSON) |
| 43 | +├── lib/ # Utility libraries |
| 44 | +│ ├── fetch.js # Custom fetch wrapper |
| 45 | +│ ├── jsencrypt.js # RSA encryption |
| 46 | +│ └── random-bytes.js # CSPRNG utility |
| 47 | +├── ios/ # iOS native code |
| 48 | +│ ├── Discourse/ # Main app target |
| 49 | +│ ├── ShareExtension/ # iOS Share Extension (Swift) |
| 50 | +│ └── Podfile # CocoaPods dependencies |
| 51 | +├── android/ # Android native code |
| 52 | +│ └── app/src/main/java/com/discourse/ |
| 53 | +├── e2e/ # Detox e2e tests |
| 54 | +└── fastlane/ # CI/CD automation |
| 55 | +``` |
| 56 | + |
| 57 | +## Key Files |
| 58 | + |
| 59 | +| File | Purpose | |
| 60 | +| -------------------------- | ------------------------------------------------------------- | |
| 61 | +| `js/Discourse.js` | Root component, navigation setup, deep linking, auth handling | |
| 62 | +| `js/site_manager.js` | Manages connected sites, auth tokens, device registration | |
| 63 | +| `js/site.js` | Site model class, API calls, basic info fetching | |
| 64 | +| `js/DiscourseUtils.js` | Maps 37+ notification types to endpoints and icons | |
| 65 | +| `js/ThemeContext.js` | Theme definitions (colors, fonts) for light/dark mode | |
| 66 | +| `js/screens/HomeScreen.js` | Main UI with draggable site list and topic viewing | |
| 67 | + |
| 68 | +## Architecture Patterns |
| 69 | + |
| 70 | +### Platform-Specific Code |
| 71 | + |
| 72 | +Use file suffixes for platform divergence: |
| 73 | + |
| 74 | +- `*.ios.js` - iOS-specific implementation |
| 75 | +- `*.android.js` - Android-specific implementation |
| 76 | + |
| 77 | +The bundler automatically selects the correct file based on platform. |
| 78 | + |
| 79 | +### Component Organization |
| 80 | + |
| 81 | +- Screens in `js/screens/` |
| 82 | +- Screen-specific components in `js/screens/{ScreenName}Components/` |
| 83 | +- Shared components in `js/screens/CommonComponents/` |
| 84 | + |
| 85 | +### State Management |
| 86 | + |
| 87 | +- **Local state**: React `useState` hooks |
| 88 | +- **App-wide theme**: `ThemeContext` (React Context) |
| 89 | +- **Site data**: `SiteManager` singleton class |
| 90 | +- **Persistence**: `AsyncStorage` for local storage |
| 91 | + |
| 92 | +### Authentication Flow |
| 93 | + |
| 94 | +1. User initiates OAuth in `AddSiteScreen` |
| 95 | +2. `SiteManager` generates auth URL with state/challenge |
| 96 | +3. Safari Web Auth opens Discourse authorization page |
| 97 | +4. User approves, redirected to `discourse://auth_redirect` |
| 98 | +5. App exchanges code for token using RSA encryption |
| 99 | +6. Token stored in AsyncStorage |
| 100 | + |
| 101 | +## Development Commands |
| 102 | + |
| 103 | +```bash |
| 104 | +# Install dependencies |
| 105 | +yarn |
| 106 | + |
| 107 | +# iOS setup |
| 108 | +bundle install |
| 109 | +cd ios && pod install && cd .. |
| 110 | + |
| 111 | +# Start Metro bundler |
| 112 | +npx react-native start |
| 113 | + |
| 114 | +# Run on iOS |
| 115 | +npx react-native run-ios |
| 116 | + |
| 117 | +# Run on Android |
| 118 | +npx react-native run-android |
| 119 | + |
| 120 | +# Run e2e tests |
| 121 | +npx detox build --configuration ios.sim.debug |
| 122 | +npx detox test --configuration ios.sim.debug |
| 123 | + |
| 124 | +# Lint |
| 125 | +yarn lint |
| 126 | +``` |
| 127 | + |
| 128 | +## Build Configuration |
| 129 | + |
| 130 | +### iOS |
| 131 | + |
| 132 | +- **Min Deployment**: iOS 15.1 |
| 133 | +- **Targets**: Main app + Share Extension |
| 134 | +- **Capabilities**: Push Notifications, Safari Web Auth, App Groups, Siri Shortcuts |
| 135 | + |
| 136 | +### Android |
| 137 | + |
| 138 | +- **Min SDK**: 26 (Android 8.0) |
| 139 | +- **Target SDK**: 35 (Android 15) |
| 140 | +- **Build**: Gradle with Kotlin DSL |
| 141 | + |
| 142 | +## Testing |
| 143 | + |
| 144 | +### E2E Tests (Detox) |
| 145 | + |
| 146 | +Located in `e2e/`: |
| 147 | + |
| 148 | +- `onboarding.test.js` - Initial app flow tests |
| 149 | +- `topiclist.test.js` - Topic list functionality |
| 150 | + |
| 151 | +### Test Configurations |
| 152 | + |
| 153 | +- iPhone 16 Pro simulator |
| 154 | +- iPad (10th generation) simulator |
| 155 | +- Android emulator |
| 156 | + |
| 157 | +## Internationalization |
| 158 | + |
| 159 | +49 languages supported via JSON files in `js/locale/`. Uses `i18n-js` library. |
| 160 | + |
| 161 | +To add translations, edit the appropriate locale file (e.g., `js/locale/en.json`). |
| 162 | + |
| 163 | +## Common Tasks |
| 164 | + |
| 165 | +### Adding a New Screen |
| 166 | + |
| 167 | +1. Create screen component in `js/screens/NewScreen.js` |
| 168 | +2. Add to navigation in `js/Discourse.js` |
| 169 | +3. Create sub-components in `js/screens/NewScreenComponents/` if needed |
| 170 | + |
| 171 | +### Modifying API Calls |
| 172 | + |
| 173 | +- Site-specific API calls go in `js/site.js` |
| 174 | +- Multi-site operations go in `js/site_manager.js` |
| 175 | +- Use `lib/fetch.js` wrapper for HTTP requests |
| 176 | + |
| 177 | +### Adding Platform-Specific Features |
| 178 | + |
| 179 | +1. Create `*.ios.js` and `*.android.js` files |
| 180 | +2. Export same interface from both |
| 181 | +3. Import without extension: `import X from './platforms/feature'` |
| 182 | + |
| 183 | +### Handling Notifications |
| 184 | + |
| 185 | +Notification type routing is in `js/DiscourseUtils.js`. To add a new notification type: |
| 186 | + |
| 187 | +1. Add case to `getNotificationRoute()` function |
| 188 | +2. Add icon mapping to `getNotificationIcon()` function |
| 189 | + |
| 190 | +## Code Style |
| 191 | + |
| 192 | +- ESLint with React Native config |
| 193 | +- Prettier for formatting |
| 194 | +- No TypeScript (partial adoption in `tsconfig.json` but not enforced) |
| 195 | + |
| 196 | +## CI/CD |
| 197 | + |
| 198 | +### GitHub Actions |
| 199 | + |
| 200 | +- `linting.yml` - ESLint/Prettier checks on PRs |
| 201 | +- `ios-tests.yml` - Detox e2e tests on macOS |
| 202 | + |
| 203 | +### Fastlane |
| 204 | + |
| 205 | +- iOS/Android deployment automation |
| 206 | +- Certificate management via Match |
0 commit comments