AURIX is a Flutter-based strength-training and nutrition companion app: workout planning, active session logging, progress analytics, nutrition/water tracking, weekly performance reports, and an AI coach — all backed by Supabase (auth + Postgres + RLS) with Riverpod for state and GoRouter for navigation.
- Client: Flutter (Dart SDK
^3.12.2), targets Android, iOS, macOS, Windows, Linux, and Web. - Backend: Supabase (Postgres, Auth, Row Level Security).
- AI: Groq API (chat + vision models) for coaching, meal-photo estimation, post-workout feedback, and weekly report narratives.
- What the app does
- Tech stack
- Project structure
- Navigation
- Data model
- Getting started
- Supabase setup
- AI / Groq configuration
- Notifications
- Platform notes
- Android release signing
- Known behaviors worth knowing about
- Useful references
AURIX is a full training companion rather than a single-purpose workout log:
- Auth & onboarding — splash/session gate, email sign-up/sign-in, and a guided onboarding flow that collects goal, experience level, gym access, and body data before creating a profile.
- Dashboard — current training status, a "Quick Start" card (including resume-in-progress-workout support), recent activity, and streak tracking.
- Workout planning — plan templates, custom plan creation/editing, weekly schedules, and multi-day program grouping (e.g. Push/Pull/Legs saved and shown as one program).
- Active workouts — set-by-set logging with rest timers, RPE per set, the ability to minimize/leave and resume a workout without losing progress, and an explicit Cancel Workout action.
- Post-workout AI feedback — every completed session is reviewed by the AI coach (wins, improvements, a focus for next time) on the Workout Summary screen.
- Exercise library & detail views — browsing by muscle/equipment/difficulty with per-exercise detail pages.
- Progress tracking — personal records, activity history, adaptive training-streak calculation, and a body-weight log/trend chart.
- Nutrition tracking — meal logging by free-text description or by scanning a photo of a meal (both AI-estimated), plus water intake logging and calorie/macro targets (auto-calculated from BMR/TDEE or manually overridden).
- Weekly reports — an automatically generated, scored (consistency / nutrition / progress) Mon–Sun recap with an AI-written narrative summary, wins, improvements, and a focus for the next week.
- AI Coach screen — a guided chat experience, with history persisted per user.
- Achievements and utility tools (plate calculator).
- Profile & settings — units (kg/lb), notification preferences, and a Danger Zone "Clear All Workout Data" option that wipes plans/sessions/PRs/streak data/body-weight log while keeping the account and profile.
| Concern | Package |
|---|---|
| State management | flutter_riverpod |
| Navigation | go_router |
| Backend | supabase_flutter |
| Local secrets | flutter_dotenv |
| Local notifications | flutter_local_notifications |
| Charts | fl_chart |
| Fonts / UI polish | google_fonts, flutter_animate, shimmer, flutter_svg |
| Images (nutrition scan) | image_picker |
| Sharing | share_plus |
| Misc | intl, uuid, shared_preferences, http, path_provider |
| Lints | flutter_lints |
See pubspec.yaml for exact version constraints.
lib/
├── main.dart # Bootstraps Flutter, loads .env, initializes Supabase & notifications, starts the app
├── app.dart # Root MaterialApp.router + global theme
├── app_router.dart # GoRouter route tree (see Navigation below)
├── app_const.dart # Typed accessors over .env (throws if required keys are missing)
├── Supabase/
│ └── supabase_service.dart # Supabase client init/session helpers
├── services/
│ └── notification_service.dart # Local notification channel setup
├── data/
│ └── app_data.dart # In-memory app-wide cache/state, synced with Supabase
├── theme/ # app_colors.dart, app_text.dart, app_theme.dart
├── widgets/ # ff_nav.dart (bottom nav shell), ff_widgets.dart (shared UI)
├── utils/ # nutrition_calc.dart, progressive_overload.dart, streak_utils.dart, units.dart
└── features/
├── auth/ # splash, login, signup, onboarding flow
│ ├── data/ # auth_repository.dart, auth_mock_data.dart (static UI copy, not fake data)
│ └── models/, presentation/
├── dashboard/ # home dashboard + profile/settings screen
│ ├── data/dashboard_repository.dart
│ └── models/, presentation/
├── workout/ # hub, active session, plan creation, library, detail,
│ │ # progress, weekly schedule, template customize, session edit, summary
│ ├── data/workout_repository.dart
│ └── models/, presentation/
├── nutrition/ # meal/water logging, AI photo & text estimation
│ ├── data/nutrition_repository.dart, nutrition_ai_service.dart
│ └── models/, presentation/
├── reports/ # weekly report scoring, AI narrative, screen
│ └── data/, models/, presentation/
├── AI_Coach/ # AI coach chat screen + post-workout feedback service
│ ├── ai_coach_screen.dart
│ └── data/workout_feedback_service.dart
├── achievements/ # models/, presentation/
└── tools/
└── plate_calculator_screen.dart
Platform folders (android/, ios/, macos/, windows/, linux/, web/) contain the standard Flutter-generated native runners plus the app's icons and platform config. Supabase SQL lives in supabase/, and test/widget_test.dart holds the starter widget test.
Routing is defined in lib/app_router.dart using GoRouter:
- Entry routes:
/splash,/login,/signup,/onboarding. - Full-screen routes (pushed above the bottom nav, on the root navigator):
/active-workout,/workout-summary,/create-workout(accepts an existingWorkoutPlanviaextrato edit in place),/schedule,/template-customize,/exercise/:id,/profile,/plate-calculator,/achievements,/edit-session,/weekly-report. - Shell routes (nested under the bottom-nav
FFShell):/home(Dashboard),/workouts(Workout Hub),/nutrition,/exercises(Exercise Library),/progress,/ai(AI Coach).
The Supabase schema (see DB_SCHEMA.md for the full reference, informational only — not meant to be executed as-is) covers:
| Table | Purpose |
|---|---|
profiles |
User settings, goal/level, body data, macro targets, notification & unit preferences |
exercises |
Global exercise catalog (name, muscle, equipment, difficulty, description) |
workout_plans / plan_exercises |
User-created plans and their exercises; program_id/program_name group multi-day programs |
plan_templates / template_exercises |
Built-in template library used to seed new plans |
workout_sessions / session_exercises |
Logged workouts and their per-set data (includes RPE) |
personal_records |
PR tracking per exercise |
daily_activity |
Per-day activity used for streak/progress calculations |
body_metrics |
Body-weight log entries (Progress → Body tab trend chart) |
coach_messages |
AI Coach chat history |
meal_logs / water_logs |
Nutrition tracking (event-based: one row per logged meal / per water addition) |
weekly_reports |
One row per Mon–Sun week: deterministic scores plus an AI-generated narrative |
All weights are stored in kg regardless of the user's display-unit preference (profiles.weight_unit is display-only).
Row Level Security is enabled on every user-data table (supabase/rls_policies.sql), scoping all access to auth.uid(). exercises, plan_templates, and template_exercises are shared catalog data and get public read-only access instead.
-
Install Flutter and make sure your environment is set up for your target platform(s) (
flutter doctor). -
Clone and install packages:
flutter pub get
-
Create your local secrets file:
cp .env.example .env # macOS/Linux copy .env.example .env # Windows
-
Fill in
.env:SUPABASE_URL=https://your-project-ref.supabase.co SUPABASE_ANON_KEY=your-supabase-anon-key GROQ_API_KEY=your-groq-api-key GROQ_MODEL=llama3-8b-8192 GROQ_VISION_MODEL=meta-llama/llama-4-scout-17b-16e-instruct
SUPABASE_URLandSUPABASE_ANON_KEYare required at startup — the app throws a clear error on launch if either is missing (seelib/app_const.dart).GROQ_API_KEYis only required when an AI feature (AI Coach, nutrition photo scan, post-workout feedback, weekly report narrative) is actually used. -
Set up your Supabase project — see Supabase setup below.
-
Run the app:
flutter run
The AI Coach screen, the nutrition photo-scan estimator, the post-workout feedback card, and the weekly report narrative all call the Groq API using the same key from .env:
GROQ_API_KEY— your Groq API key.GROQ_MODEL— text model used for chat/coaching/report narrative (default:llama3-8b-8192).GROQ_VISION_MODEL— multimodal model used only by nutrition's "Scan Photo" feature (default:meta-llama/llama-4-scout-17b-16e-instruct). Groq's vision lineup changes more often than its text models — if this stops working, check console.groq.com/docs/vision for a current model and update.env; no code changes needed.
This key ships inside the compiled app bundle, so it is not a production-safe secret — anyone can extract it from a release build. For a real production deployment, proxy these requests through a backend (e.g. a Supabase Edge Function) that holds the real key server-side, and call that function from the app instead of calling Groq directly.
lib/services/notification_service.dart configures local notification channels for:
- Workout reminders
- Rest-timer completion
- Weekly training summaries
Channels are initialized at startup, but the OS permission prompt is only requested when the user enables the corresponding toggle in Profile settings — not on first launch.
- The app launches in portrait orientation only.
- The app uses an always-dark theme (status bar icons are set to light to stay visible against it).
- The app runs in immersive/fullscreen mode (system status/navigation bars hidden) and re-hides them if the user swipes them back into view.
- The nutrition photo-scan feature requests camera and photo-library access on first use of "Scan Photo" — see
NSCameraUsageDescription/NSPhotoLibraryUsageDescriptioninios/Runner/Info.plistand theCAMERApermission inandroid/app/src/main/AndroidManifest.xml. - Android
applicationId/namespace:com.aurix.fitness(seeandroid/app/build.gradle.kts).
Release builds are unsigned (fall back to debug signing) until you configure your own keystore:
-
Generate a keystore once:
keytool -genkey -v -keystore ~/aurix-release.jks \ -keyalg RSA -keysize 2048 -validity 10000 \ -alias aurixKeep the resulting
.jksfile and its passwords safe and backed up — whoever holds it can publish updates to the app, and losing it means you can never update the app under the same listing again. -
Copy
android/key.properties.exampletoandroid/key.properties(already gitignored) and fill in:storePassword=<your keystore password> keyPassword=<your key password> keyAlias=aurix storeFile=/absolute/path/to/aurix-release.jks
-
flutter build appbundle --releasewill then sign with your real key automatically. Untilkey.propertiesexists,flutter run --releasestill works locally with debug signing, but a debug-signed build will be rejected by the Play Store.
A few intentional design choices and open items, so they aren't mistaken for bugs:
- Adaptive training streaks (
lib/utils/streak_utils.dart,computeTrainingStreak) infer your typical training frequency from the last 4 weeks and tolerate that many rest days between sessions without resetting the streak — a genuine multi-day lapse still resets it. Dashboard, Progress, and Profile all share this one implementation. - Resumable active workouts: in-progress session state (checked sets, weights, elapsed time) lives in
AppData, not screen-local state, so minimizing an active workout (▾ button or Android back) and returning later restores exactly where you left off. Elapsed time is computed from a wall-clockstartedAt, so it keeps counting even while the screen isn't mounted. - Optimistic plan creation:
AppData.addPlan()falls back to a temporary client-side id if the Supabase insert fails, so the UI doesn't appear broken on a flaky connection — but this means a failed write can silently diverge from the database until the next full reload. - Exercise Library reads from a static in-app list, not the
exercisestable, even thoughWorkoutRepository.fetchExerciseCatalog()exists — functionally fine since it's read-only reference data, but editing the catalog currently requires a code change rather than a database update. - "Clear All Workout Data" (Profile → Danger Zone) deletes plans, session history, PRs, streak/daily-activity data, and the body-weight log, but keeps the account and profile — so the user lands on a clean dashboard rather than back in onboarding.