Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
000d966
Add first-launch onboarding flow with premium CTA
beaux-riel Jul 4, 2026
a52ba2e
Move crew roles off member profiles with per-event migration
beaux-riel Jul 4, 2026
9856186
Assign multiple crew roles per event across crew and event screens
beaux-riel Jul 4, 2026
5921775
Add tests for onboarding completion flag
beaux-riel Jul 4, 2026
60be1c3
Preserve local race plans across failed saves and relationship changes
beaux-riel Sep 6, 2026
5c7b6ab
Ship a truthful free local planner with offline privacy and support
beaux-riel Sep 6, 2026
9c440f8
Preserve GPX routes across updates and make PDF omissions explicit
beaux-riel Sep 6, 2026
4e687ad
Prepare native build 3 and reproducible release verification
beaux-riel Sep 6, 2026
da41aee
Document build 3 evidence, release gates, and fictional native smoke …
beaux-riel Sep 6, 2026
14c2e71
Redesign planner with graphite field guide and race-first home
beaux-riel Sep 6, 2026
380eacb
design: align app icon with field guide identity
beaux-riel Sep 6, 2026
7288d44
release: prepare build 4 for internal TestFlight
beaux-riel Sep 6, 2026
a27c97e
feat: reusable drop bag templates and race packing workflows
beaux-riel Sep 6, 2026
a93d785
release: prepare build 5 TestFlight candidate
beaux-riel Sep 6, 2026
a1b2052
Fix crew role editing and import GPX checkpoints into race plans
beaux-riel Sep 6, 2026
680a023
Accept GPX XML exports and verify original Fat Dog import
beaux-riel Sep 6, 2026
1cabd6e
Import KML courses and verify Fat Dog export parity
beaux-riel Sep 6, 2026
0618d57
Bump iOS build to 6 for crew and course import fixes
beaux-riel Sep 6, 2026
ad9094a
Add race operations planning and private live team timing
beaux-riel Sep 6, 2026
b2991f8
Bump iOS build to 7 for race operations and live team timing
beaux-riel Sep 6, 2026
9aadd0b
Improve race planning inputs, mandatory gear, photos and race guides
beaux-riel Sep 6, 2026
f1cd849
Bump iOS build to 8 for athlete feedback improvements
beaux-riel Sep 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 14 additions & 40 deletions .github/workflows/code-review.yml
Original file line number Diff line number Diff line change
@@ -1,53 +1,27 @@
name: Claude Code Review
name: Manual Review Checklist

on:
pull_request:
branches: [main]

permissions:
contents: read
pull-requests: write

jobs:
claude-review:
review-checklist:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Get PR diff
id: diff
# The previous third-party action no longer exists. This job records the
# required human gate; a green checklist job does not certify code review.
- name: Record required release review
run: |
git fetch origin ${{ github.base_ref }}
DIFF=$(git diff origin/${{ github.base_ref }}...HEAD -- '*.ts' '*.tsx' '*.js' '*.jsx' | head -c 50000)
echo "diff<<EOF" >> $GITHUB_OUTPUT
echo "$DIFF" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

- name: Claude Code Review
uses: anthropics/anthropic-cookbook/.github/actions/claude-code-review@main
if: ${{ steps.diff.outputs.diff != '' }}
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
model: claude-sonnet-4-20250514
max_tokens: 4096
continue-on-error: true
cat >> "$GITHUB_STEP_SUMMARY" <<'CHECKLIST'
## Human review required
This job publishes a checklist only. It does not perform or approve code review.

- name: Fallback - Basic Review Comment
if: failure()
uses: actions/github-script@v7
with:
script: |
const diff = `${{ steps.diff.outputs.diff }}`.slice(0, 1000);
if (diff) {
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## 🔍 Code Review Pending\n\nClaude code review action encountered an issue. Please ensure:\n- \`ANTHROPIC_API_KEY\` secret is configured in repository settings\n- The PR contains reviewable code changes\n\n<details>\n<summary>Files changed</summary>\n\n\`\`\`\n${diff}\n\`\`\`\n</details>`
});
}
- Review changed behavior and failure/recovery tests.
- Check CI and the candidate commit used for native verification.
- Exercise affected runner/crew journeys on the Release iOS build.
- For release work, complete docs/release/V1-RELEASE-PACKAGE.md gates.
- Obtain owner approval before publishing or changing production services.
CHECKLIST
45 changes: 14 additions & 31 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,18 @@
import { StatusBar } from 'expo-status-bar';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import * as Sentry from '@sentry/react-native';

// Theme & Fonts
import { ThemeProvider, useTheme } from './src/theme';
import { useFonts } from './src/hooks/useFonts';

// Data Providers
import { AuthProvider } from './src/context/AuthContext';
import { MoverProvider } from './src/context/MoverContext';
import { EventProvider } from './src/context/EventContext';
import { CheckpointProvider } from './src/context/CheckpointContext';
import { GearProvider } from './src/context/GearContext';
import { CrewProvider } from './src/context/CrewContext';
import { DropBagProvider } from './src/context/DropBagContext';
import { SubscriptionProvider } from './src/context/SubscriptionContext';

// Navigation
import AppNavigator from './src/navigation/AppNavigator';
Expand All @@ -36,7 +33,7 @@
// Loading screen while fonts load
function LoadingScreen() {
const { theme } = useTheme();

Check warning on line 36 in App.tsx

View workflow job for this annotation

GitHub Actions / ci

Trailing spaces not allowed
return (
<View style={[styles.loading, { backgroundColor: theme.colors.parchment }]}>
<ActivityIndicator size="large" color={theme.colors.forest} />
Expand All @@ -62,48 +59,34 @@
);
}

const SENTRY_DSN = process.env.EXPO_PUBLIC_SENTRY_DSN;

if (SENTRY_DSN) {
Sentry.init({
dsn: SENTRY_DSN,
enabled: !__DEV__,
tracesSampleRate: 0.2,
});
}

// Root component with all providers
function App() {
return (
<ErrorBoundary>
<GestureHandlerRootView style={styles.root}>
<SafeAreaProvider>
<ThemeProvider>
<AuthProvider>
<SubscriptionProvider>
<MoverProvider>
<EventProvider>
<CheckpointProvider>
<GearProvider>
<CrewProvider>
<DropBagProvider>
<AppContent />
</DropBagProvider>
</CrewProvider>
</GearProvider>
</CheckpointProvider>
</EventProvider>
</MoverProvider>
</SubscriptionProvider>
</AuthProvider>
<MoverProvider>
<EventProvider>
<CheckpointProvider>
<GearProvider>
<CrewProvider>
<DropBagProvider>
<AppContent />
</DropBagProvider>
</CrewProvider>
</GearProvider>
</CheckpointProvider>
</EventProvider>
</MoverProvider>
</ThemeProvider>
</SafeAreaProvider>
</GestureHandlerRootView>
</ErrorBoundary>
);
}

export default SENTRY_DSN ? Sentry.wrap(App) : App;
export default App;

const styles = StyleSheet.create({
root: {
Expand Down
147 changes: 23 additions & 124 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,145 +1,44 @@
# UltraEdge

<img align="center" width="100%" height="30%" src="assets/logo.png">
UltraEdge is an open-source race preparation app for ultramarathon runners and crews. The V1 release scope is a **free planner on one device**, with PDF sharing for crew handoffs. Release readiness and device verification are tracked in [the release package](docs/release/V1-RELEASE-PACKAGE.md).

**UltraEdge** is an open-source mobile application designed specifically for ultra marathon runners and their support crews. Plan your races, manage aid stations, coordinate your crew, and optimize your performance - all in one comprehensive app.
## Plan your event

> Created by an ultra runner, for ultra runners.
- Create events and checkpoints with distances, cutoffs, access details and notes.
- Organize gear and weights, food and hydration supplies, and drop bags.
- Keep crew contacts and assign roles for each event.
- Import GPX routes and inspect the route and elevation profile.
- Export an event's race plan as a PDF to share with your crew.

## Recent Updates
Editable planning data lives on the device. Export a PDF before travel and keep a copy outside the app. PDFs are readable copies, not restorable backups. Deleting the app can remove local plans. Map backgrounds may require a connection; download/import your route before heading out.

- **2025-04-08**: Fixed profile data backup issue by adding missing columns to the Supabase database schema
Cloud sync, automatic backups, crew invitations/notifications, live tracking/predictions, and paid subscriptions are outside V1. Nutrition and hydration are packing/notes tools, not a timed fueling prescription. Supabase and RevenueCat integration code remains in the repository for future work; its presence does not mean those services are enabled or verified for release.

## Latest Features
## Development

### Race Planning & Management
- **Create detailed race plans** for ultra marathons and endurance events
- **Customize distance units** (miles/kilometers) and elevation units (feet/meters)
- **Track key race metrics** including distance, elevation gain, and cut-off times
- **Edit and update race plans** as your training and strategy evolve
The app uses Expo SDK 54, React Native 0.81.5, React 19 and TypeScript. Use Node.js 20 as in CI, npm, and Xcode for local iOS builds.

### Aid Station Management
- **Configure comprehensive aid station details**:
- Precise location and distance markers
- Cut-off times and pacing calculations
- Available supplies and nutrition options
- Medical support availability
- Required equipment checks
- **Edit existing aid stations** to refine your race strategy

### Crew Coordination
- **Manage your support crew** with detailed profiles and contact information
- **Assign crew members to specific aid stations** for seamless race-day coordination
- **Add crew instructions** with meeting points, driving directions, and responsibilities
- **Optimize crew logistics** to maximize their effectiveness during your event

### User Experience
- **Personalized user profiles** with customizable preferences
- **Dark mode support** for comfortable viewing in any lighting condition
- **Intuitive navigation** designed for quick access during race planning and execution
- **Responsive design** that works across different device sizes

### Premium Features
- **Cloud synchronization** of all race data across devices
- **Automatic backup** to secure cloud storage after every edit
- **Restore race data** from cloud backups
- **Advanced analytics** and performance insights
- **Unlimited race plans** and aid station configurations
- **Priority support** and early access to new features

## Screenshots

*Note: Screenshots will be added as the app development progresses.*

<!--
<div style="display: flex; flex-wrap: wrap; justify-content: space-between;">
<img src="assets/screenshots/home_screen.png" alt="Home Screen" width="30%" />
<img src="assets/screenshots/race_details.png" alt="Race Details" width="30%" />
<img src="assets/screenshots/aid_station.png" alt="Aid Station Setup" width="30%" />
</div>
-->

The app includes screens for:
- Home dashboard with upcoming races
- Race creation and editing
- Aid station setup and management
- Crew coordination and assignment
- User profile customization
- Premium subscription management

## Technical Details

- Built with **React Native** for cross-platform compatibility (iOS and Android)
- Implements **React Navigation** for seamless app navigation
- Uses **React Native Paper** for beautiful, consistent UI components
- Stores data locally using **AsyncStorage** for offline functionality
- Integrates with **Supabase** for secure cloud storage and authentication
- Implements **RevenueCat** for subscription management and in-app purchases

## Getting Started

### Prerequisites

- Node.js (v14 or newer)
- npm or yarn
- Expo CLI

### Installation

1. Clone the repository
```bash
```sh
git clone https://github.com/beaux-riel/UltraEdge.git
cd UltraEdge
npm ci
npm start
```

2. Install dependencies
```bash
npm install
# or
yarn install
```

3. Configure Supabase (for premium features)
```bash
# See instructions in /supabase/README.md
```sh
npm run typecheck
npm test -- --runInBand
npm run lint
```

4. Configure RevenueCat (for subscription management)
```bash
# Update API keys in src/context/RevenueCatContext.js
```
For the native iOS development build, use `npm run ios` after setting up Xcode. Release work uses the committed iOS project and [Fastlane](fastlane/README.md). Read the lane before running it: even a build can install pods and change signing settings. The beta lane uploads externally and requires release-owner approval. EAS is not the verified release route.

5. Start the development server
```bash
npx expo start
```
Never commit credentials or copy production secrets into test fixtures. Backend migrations and billing setup require a separate validated deployment plan; do not apply legacy migrations to production as a development setup step.

## Contributing

UltraEdge is an open-source project, and we welcome contributions from the community! Whether you're an ultra runner with ideas for new features, a developer looking to contribute code, or someone who wants to improve documentation, we'd love your help.

### Ways to Contribute

- **Feature Development**: Help build new features or enhance existing ones
- **Bug Fixes**: Identify and fix issues in the codebase
- **Documentation**: Improve README, add code comments, or create user guides
- **Testing**: Test the app in different environments and report issues
- **Design**: Suggest UI/UX improvements or create assets

### Getting Started with Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

This project is licensed under the MIT License - see the LICENSE file for details.

## Contact
Prefer small changes tied to an athlete journey. Test failure and restart behavior for persistence changes, and verify critical journeys in release-mode iOS: JavaScript checks alone do not certify device behavior. Report what you exercised, the build/device, and what remains unverified. Preserve existing user data.

Beaux - [GitHub](https://github.com/beaux-riel)
## License and contact

Project Link: [https://github.com/beaux-riel/UltraEdge](https://github.com/beaux-riel/UltraEdge)
MIT; see [LICENSE](LICENSE). Maintained by [Beaux](https://github.com/beaux-riel). Report reproducible issues in [GitHub Issues](https://github.com/beaux-riel/UltraEdge/issues). Include app version and reproduction steps; do not post private routes, contacts or credentials.
Binary file modified android/app/src/main/res/drawable-hdpi/splashscreen_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/drawable-mdpi/splashscreen_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions android/app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<resources>
<color name="splashscreen_background">#ffffff</color>
<color name="iconBackground">#ffffff</color>
<color name="splashscreen_background">#171C20</color>
<color name="iconBackground">#171C20</color>
<color name="colorPrimary">#023c69</color>
<color name="colorPrimaryDark">#ffffff</color>
<color name="colorPrimaryDark">#171C20</color>
</resources>
11 changes: 4 additions & 7 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,29 @@
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"splash": {
"image": "./assets/splash.png",
"image": "./assets/icon.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
"backgroundColor": "#171C20"
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.beaux.ultraedge",
"usesAppleSignIn": true
"bundleIdentifier": "com.beaux.ultraedge"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
"backgroundColor": "#171C20"
},
"package": "com.beaux.ultraedge"
},
"web": {
"favicon": "./assets/favicon.png"
},
"plugins": [
"expo-apple-authentication",
"expo-secure-store",
"@sentry/react-native",
"expo-font",
"expo-web-browser"
],
Expand Down
Binary file modified assets/adaptive-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/alpine-backdrop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Alpine backdrop

Generated with OpenAI image generation on September 5, 2026 for UltraEdge's approved field-guide design. Fictional alpine landscape, decorative only; not a photograph or map of Fat Dog. Bundled locally so the home screen requires no image network request. Source PNG retains content provenance metadata.
Binary file added assets/alpine-backdrop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/splash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions docs/design/app-icon.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# App icon

The field-guide identity now uses a trail-lime alpine silhouette with a negative-space ascending trail on graphite. Generated using the built-in imagegen tool, then resized with macOS sips.

Production assets: `assets/icon.png` and the matching native `ios/UltraEdge/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png`; both are opaque 1024×1024 PNGs. Android's adaptive foreground has extra safe-area padding with a graphite background configured in app.json. The web favicon uses the same mark at 48×48.

Generation prompt: Create one production app icon for UltraEdge, a premium ultramarathon race-planning app. Square full bleed opaque cool graphite #171C20 background. Center a bold geometric alpine ridge / ascending trail emblem in trail lime #C3E76B. Two sharp mountain summits with an angular ascending negative-space trail cut through the lower form as one cohesive compact symbol. Premium outdoor equipment brand, disciplined Swiss graphic design, crisp silhouette with generous clear space for OS masks. No text, letters, border, rounded outer corners, shadows, glow, gradients, texture, mockup, or scenery.

Validation: Apple's actool successfully compiled the native asset catalog for iPhone and iPad Simulator. Native and Expo icon files are byte-identical; dimensions and lack of alpha verified. The 60×60 rendering was visually inspected. Android configuration updated, but no Android runtime build was tested. No app logic changed; no new TestFlight upload in this change.
Loading
Loading