Skip to content

Repository files navigation

Runth — PoC/MVP

Mobilna aplikacja dla biegaczy rekreacyjnych przygotowujących się do dystansów od pierwszego kilometra do maratonu. Produkt łączy plan treningowy, wykonane aktywności ze Stravy oraz dynamiczne zalecenia dotyczące posiłków, nawodnienia i regeneracji.

Status: dokumentacja startowa do budowy PoC/MVP z użyciem GitHub Copilot w Visual Studio Code.

Najważniejsze założenia

  • jedna aplikacja mobilna na iOS i Android,
  • React Native + TypeScript + Expo Development Build,
  • backend jako modularny monolit w .NET 10,
  • PostgreSQL,
  • wdrożenie przez Docker Compose na Mikrusie 3.5 lub 4.1,
  • integracja ze Stravą jako pierwsze źródło treningów,
  • jeden tester w fazie PoC,
  • mały koszt utrzymania i łatwa migracja na większą infrastrukturę,
  • AI wspiera użytkownika, ale nie podejmuje samodzielnie decyzji medycznych.

Od czego zacząć

  1. Przeczytaj wizję produktu.
  2. Przeczytaj zakres MVP.
  3. Zapoznaj się z architekturą i wdrożeniem na Mikrusie.
  4. Uruchom w Copilot Chat prompt bootstrap-repository z katalogu .github/prompts.
  5. Realizuj zadania kolejno z katalogu docs/tasks.

Planowana struktura repozytorium

running-fuel/
├── apps/
│   └── mobile/                   # React Native / Expo
├── services/
│   └── api/                      # .NET 10 modular monolith
├── tests/
│   ├── api.integration/
│   └── architecture/
├── infra/
│   ├── docker/
│   ├── scripts/
│   └── mikrus/
├── docs/
├── .github/
│   ├── workflows/
│   ├── instructions/
│   └── prompts/
├── AGENTS.md
└── README.md

Status implementacji

  • Task 001 (bootstrap) — zrealizowany: szkielet apps/mobile (Expo Router, design system, ekran „Dzisiaj” na danych mockowych) i services/api (health checks, brak modułów biznesowych), Docker Compose, testy.
  • Task 002 (konto, profil, onboarding) — etap 1 — zrealizowany w zakresie opisanym w ADR-011–014: deweloperska sesja (/api/v1/dev/session, EF Core + Postgres, SecureStore po stronie mobile), chronione trasy ((auth)/(protected)), pełny onboarding (dane podstawowe, doświadczenie biegowe, cel, żywienie, bezpieczeństwo, podsumowanie) z lokalnym zapisem postępu, ekran profilu biegacza, przygotowanie architektury połączenia ze Stravą (7 stanów UI, endpointy statusu/connect/sync z jawnym trybem wyłączonym). Pełne ASP.NET Core Identity (rejestracja e-mail/hasło) i realne OAuth Stravy pozostają do zrobienia — patrz docs/tasks/002-auth-profile-onboarding.md i docs/tasks/004-strava-integration.md.
  • Task 003 (kalendarz treningowy) — zrealizowany w zakresie opisanym w ADR-017: deterministyczny, idempotentny seed 12-tygodniowego planu przygotowań do półmaratonu (EF Core + Postgres), ustrukturyzowane kroki treningu (WorkoutStep, nie wolny tekst), endpointy plan/weeks/{weekStart}/workouts/{id} z complete/skip/restore/PATCH, ekran Trening (pasek dni, zakładki Plan/Wykonane, karta najbliższego treningu z wizualizacją interwałów SVG, podsumowanie tygodnia), ekran szczegółów treningu z ręcznym ukończeniem/pominięciem/przywróceniem/edycją, oraz ekran Dzisiaj czytający to samo źródło danych treningowych co ekran Trening. Tworzenie nowego treningu przez użytkownika, dedykowana akcja „Anuluj” i dopasowanie do aktywności Stravy pozostają do zrobienia — patrz docs/tasks/003-training-calendar.md i docs/tasks/004-strava-integration.md.
  • Task 004 (integracja ze Stravą) — zrealizowany w zakresie opisanym w ADR-018: serwerowy OAuth 2.0 (backend jako jedyny posiadacz tokenów, szyfrowanie przez ASP.NET Core Data Protection z kluczami na trwałym wolumenie), import ostatnich 30 dni aktywności i synchronizacja przyrostowa/webhookowa przez generyczną tabelę zadań BackgroundJob w PostgreSQL (FOR UPDATE SKIP LOCKED, bez Redis/RabbitMQ), deterministyczny silnik dopasowania aktywność↔trening (ActivityWorkoutMatcher) z automatycznym ukończeniem powyżej progu pewności i sugestią poniżej, ochrona ręcznie ukończonych treningów przed nadpisaniem, ekran integracji Strava i szczegółu zaimportowanej aktywności z potwierdzeniem/zmianą dopasowania, plakietki źródła ukończenia na ekranach Dzisiaj/Trening/szczegół treningu, odłączenie z zachowaniem historii Runth. Prawdziwe uwierzytelnienie OAuth wobec API Stravy nie zostało zweryfikowane w tym środowisku (brak realnych poświadczeń) — testy backendu używają FakeStravaApiClient; patrz docs/tasks/004-strava-integration.md po kroki ręcznej weryfikacji. Integracja z Garminem pozostaje do zrobienia.
  • Task 005 (Running Nutrition Engine) — zrealizowany w zakresie opisanym w ADR-019: deterministyczny silnik żywieniowy (klasyfikacja dnia, cel energetyczny wg formuły Mifflin-St Jeor + bonus treningowy zależny wyłącznie od typu dnia i czasu trwania — nigdy z kalorii Stravy, makroskładniki periodyzowane, cel nawodnienia, timing posiłków względem godziny treningu), wersjonowana konfiguracja reguł (nutrition-engine-v1), 28 oryginalnych przepisów bez scrapingu z deterministycznym filtrowaniem dietetycznym (twarde wykluczenia alergenów/nietolerancji/nielubianych produktów) i doborem, wersjonowany append-only plan dnia z leniwą idempotentną regeneracją odporną na współbieżność (porównanie hashy wejść treningowych/profilowych), zamiana posiłku i zmiana porcji, ekran Żywienie i szczegół posiłku, integracja z ekranem Dzisiaj i szczegółem treningu (żywienie okołotreningowe). Pełny dziennik jedzenia/logowanie wody i lista zakupów pozostają do zrobienia — patrz docs/tasks/005-nutrition-engine.md.
  • Task 006 (Dziennik i lista zakupów) — zrealizowany w zakresie opisanym w ADR-020: dziennik (własny wpis posiłku ze statusem szacunkowym, nawodnienie, żywienie na biegu, samopoczucie), lista zakupów z agregacją jednostek i kategoryzacją sklepową, przeglądalna/filtrowalna biblioteka przepisów z ulubionymi (zamyka FR-RCP-003). Mobile działa lokalnie-najpierw (SQLite + jeden generyczny outbox) — Dziennik i Lista zakupów są w pełni użyteczne offline; konflikty synchronizacji (współbieżna edycja) są zawsze rozwiązywane jawnym wyborem użytkownika, nigdy cichym nadpisaniem. Arkusz Szybkie Dodaj i check-in samopoczucia na ekranie Dzisiaj są teraz realnie podłączone (wcześniej wizualne stuby). Backend 204/204 i mobile 254/254 testów — patrz docs/tasks/006-journal-shopping.md.
  • Task 007 (Postępy i raport tygodniowy) — zrealizowany w zakresie opisanym w ADR-021: kilometraż tygodniowy, realizacja planu, RPE, energia, realizacja posiłków okołotreningowych, trend masy (z możliwością ukrycia) i deterministyczny raport tygodniowy — wszystko bez AI. Cała agregacja jest czystą, testowaną funkcją mobile nad już istniejącymi endpointami Treningu/Żywienia/Dziennika (rozszerzenie jawnej zasady „weekly math lives on mobile” z Task 003) — jedyny nowy zasób backendu to pomiar masy, lokalny-najpierw jak Dziennik. Każda uśredniona/porównawcza wartość wymaga co najmniej dwóch punktów danych, inaczej pokazuje jawne „za mało danych” zamiast twierdzenia z jednego pomiaru; żadna obserwacja nigdy nie łączy dwóch różnych metryk w jedno zdanie. Backend 214/214 i mobile 280/280 testów — patrz docs/tasks/007-progress-weekly-report.md.
  • Task 008 (Bezpieczne funkcje AI) — zrealizowany w zakresie opisanym w ADR-022: IAiProvider z domyślnym DisabledAiProvider (brak klucza nigdy nie przerywa startu ani nie blokuje głównych funkcji, ten sam wzorzec co Strava) i AnthropicAiProvider (Anthropic Claude przez oficjalny SDK, structured outputs, jedna próba naprawy przy błędzie transportu), cztery endpointy (explain-recommendation, summarize-week, search-recipes, parse-meal-description) zawsze zwracające bezpieczny fallback zamiast błędu, heurystyczny walidator bezpieczeństwa jako druga warstwa obrony nad strukturalnym ograniczeniem promptu (AI nigdy nie dostaje surowych liczb — tylko zamknięte kody powodów/obserwacji, więc nie ma z czego wymyślić fałszywy związek przyczynowy), dzienny limit kosztu i cache (wyjaśnienia globalnie po kodach, raport tygodniowy raz na dobę). Wpięte w Dzisiaj (wyjaśnienie rekomendacji), Postępy (osobna karta AI pod deterministycznymi obserwacjami, nigdy zmieszana), Przepisy (wyszukiwanie opisowe) i Dziennik (propozycja wartości posiłku z opisu, zawsze do zatwierdzenia). Testy nigdy nie wywołują prawdziwego API — FakeAiProvider. Backend 227/227 i mobile 289/289 testów — patrz docs/tasks/008-ai-assistant.md.
  • Task 009 (wdrożenie na Mikrus) — celowo pominięty na tym etapie kolejki zadań; zostanie zrealizowany jako ostatni, po zamknięciu pozostałych zadań funkcjonalnych — patrz docs/tasks/_009-mikrus-deployment.md.
  • Task 010 (cele, priorytety i ścieżki aktywności) — zrealizowany w zakresie opisanym w ADR-023: onboarding rozpoczyna się wyborem ścieżki aktywności (spacer, nordic walking, marszobieg, codzienny ruch, bieganie — nigdy trwale zamknięty wybór) zamiast zakładać biegacza, po czym jeden adaptacyjny ekran oceny możliwości pyta tylko o pola adekwatne do wybranej ścieżki (zod .superRefine() zamiast rozgałęzień schematu, żeby zachować jeden stabilny typ formularza) i ekran celów oferuje katalog celu głównego przefiltrowany per ścieżka plus do trzech celów dodatkowych ze wspólnego katalogu — bez suwaka 0–100, z rangą (główny/ważny/dodatkowy) i deterministycznie wyliczonym miernikiem sukcesu. Przesiew bezpieczeństwa ma teraz cztery wskazówki zamiast dwóch (standardGuidance/conservativeStart/professionalConsultationSuggested/automatedProgressionPaused), wyliczane deterministyczną regułą pierwszeństwa. Profil biegowy sprzed Task 010 (lokalny i w bazie) jest bezstratnie migrowany do ActivityPath.running przy pierwszym odczycie; pola specyficzne dla biegania są zachowane bez zmiany znaczenia dla kompatybilności wstecznej API. Adaptacja generowania planu do nowych ścieżek pozostaje poza zakresem (Task 011). Backend 229/229 i mobile 322/322 testów, w tym dedykowane testy każdej z pięciu ścieżek aktywności — patrz docs/tasks/010-activity-goals-onboarding-v2.md.
  • Task 011 (adaptacyjny silnik priorytetów treningowych i żywieniowych) — zrealizowany w zakresie opisanym w ADR-024: drugi, niezależnie wersjonowany deterministyczny silnik (PriorityEngine, priority-engine-v1) obok NutritionEngine, oba karmiące jeden wiersz DailyPlan — jedyne wspólne źródło priorytetów dla Dzisiaj/Treningu/Żywienia/Postępów. Czternastowartościowa klasyfikacja dnia obejmuje wszystkie pięć ścieżek aktywności (dla biegania redukuje się 1:1 do nietkniętej dotychczasowej klasyfikacji — zero regresji), deterministyczna ocena gotowości (prosty system punktowy, brak danych nigdy nie obniża wyniku) i kaskada propozycji adaptacji z jawną kolejnością (bezpieczeństwo → przeciążenie → gotowość → frekwencja → brama gotowości początkującego → progresja), wymagająca zatwierdzenia użytkownika poza jednym jawnym wyjątkiem bezpieczeństwa. Dziewięć szablonów planu treningowego (był jeden) dobieranych wg ścieżki i poziomu wejściowego, archiwizujących — nie kasujących — niepasujący plan sprzed onboardingu. Postępy zyskały przegląd priorytetów z listą propozycji adaptacji i przyciskami zatwierdź/odrzuć. Podczas implementacji znaleziono i naprawiono rzeczywisty błąd: wielość planów na użytkownika (aktywny + zarchiwizowane) ujawniła brakujące filtrowanie po aktywnym planie w trzech miejscach odpytujących treningi po dacie — zabezpieczone testem regresyjnym. Backend 274/274 i mobile 330/330 testów — patrz docs/tasks/011-adaptive-training-nutrition-priority-engine.md.
  • Task 012 (katalog produktów spożywczych) — zrealizowany w zakresie opisanym w ADR-025: katalog produktów podobny do Fitatu (wyszukiwanie po nazwie/marce/kodzie kreskowym, wybór porcji, prywatne produkty, jawny priorytet i jakość źródeł) osadzony jako pięć encji EF (FoodProduct/FoodBrand/FoodServing/FoodProductRevision/FoodProductFavorite), nie dziesięć nazwanych modeli z dokumentu zadania — reszta to pola/enumy na FoodProduct, tym samym wzorcem co Recipe (Task 005). Jedyny zewnętrzny dostawca to Open Food Facts, wyłącznie dla odczytu po kodzie kreskowym (nigdy wyszukiwania tekstowego), z jawnym priorytetem źródeł przy zapisie — zatwierdzone dane Runth/społeczności nigdy nie są cicho nadpisywane. Moderacja kandydatów to deterministyczne reguły akceptacji (FoodProductValidator), nie kolejka z człowiekiem — dokument zadania to jawnie dopuszcza. Dodawanie produktu do dziennika rozszerza istniejący endpoint i mechanizm offline/outbox (Task 006) o trzy opcjonalne pola zamiast budować drugi mechanizm; serwer zawsze przelicza makra z profilu produktu, nigdy nie ufa wartościom klienta. Backend 309/309 i mobile 340/340 testów — patrz docs/tasks/012-food-product-catalog.md.
  • Task 013 (skanowanie kodu kreskowego i etykiety) — zrealizowany w zakresie opisanym w ADR-026: ILabelRecognitionProvider z dokumentu zadania to istniejący IAiProvider (Task 008) rozszerzony o opcjonalne zdjęcia, nie osobny port — rozpoznawanie etykiety (nazwa, marka, ilość netto, wartości odżywcze na 100 g/ml, składniki, sugerowane alergeny) zwraca structured output z Claude z jawną kategorią pewności (high/medium/low/unknown) na każde pole, nigdy procentem. Skan kodu kreskowego ponownie wykorzystuje endpoint odczytu po kodzie z Task 012 bez nowego endpointu; skan etykiety prowadzi na to samo, w pełni edytowalne rozszerzenie formularza własnego produktu z Task 012 — z podpowiedzią pewności przy polu, banerem ostrzeżeń niespójności i osobnymi grupami „zawiera”/„może zawierać” dla alergenów, nigdy automatycznym zapisem na podstawie samego OCR. Zdjęcia są przetwarzane wyłącznie w pamięci na czas jednego żądania i nigdy nie trafiają na dysk backendu; aparat i galeria wywoływane są z wyłączonym odczytem EXIF, więc metadane lokalizacyjne nigdy nie powstają. Szkic skanu etykiety żyje wyłącznie w lokalnym magazynie urządzenia (Task 006), celowo poza outboxem — analiza to ponawialne żądanie odczytu, nie kolejkowana mutacja. Backend 319/319 i mobile 355/355 testów — patrz docs/tasks/013-barcode-label-ocr.md. Kamera i przepływ zdjęć nie zostały fizycznie zweryfikowane na urządzeniu w tym środowisku (brak dostępu do kamery/Expo Development Build) — sprawdzone statycznie (kompilacja, tsc, testy z zamockowanym expo-camera/expo-image-picker).
  • Task 014 (analiza zdjęcia posiłku i wspomagane logowanie AI) — zrealizowany w zakresie opisanym w ADR-027: IMealVisionProvider z dokumentu zadania to ten sam rozszerzony IAiProvider co Task 013, nie osobna integracja — zdjęcie posiłku (do trzech ujęć) zwraca listę komponentów, każdy z jedną kategorią pewności (nie per pole, jak w Task 013 — dokument zadania wprost tego wymaga), szacowanym zakresem porcji i sugerowanymi niewidocznymi dodatkami (olej, sos...), plus do trzech pytań doprecyzowujących. Dopasowanie komponentu do katalogu dzieje się wyłącznie po stronie mobile przez istniejące wyszukiwanie (Task 012) — endpoint analizy nigdy nie zwraca kandydatów produktu, a energia i makra dla dopasowanego komponentu są zawsze liczone dokładnie tą samą, już przetestowaną ścieżką co ręczne dodanie z katalogu; AI nigdy nie nadpisuje wartości odżywczych. Zapis tworzy jeden FoodJournalEntry na potwierdzony komponent, wszystkie połączone nowym MealPhotoAnalysisId (pełni podwójną rolę znacznika źródła i klucza grupującego — bez nowego pola Source). Zdjęcia nigdy nie trafiają na dysk backendu — jedyna nowa tabela (MealPhotoAnalysis) przechowuje tylko wynik, z hashem obrazu jako kluczem krótkotrwałego cache (identyczne zdjęcie tego samego użytkownika nie jest ponownie wysyłane do AI). Aparat i galeria wywoływane są z wyłączonym odczytem EXIF. Backend 333/333 i mobile 366/366 testów — patrz docs/tasks/014-ai-meal-photo-analysis.md. Kamera i przepływ zdjęć nie zostały fizycznie zweryfikowane na urządzeniu w tym środowisku (to samo ograniczenie co Task 013) — sprawdzone statycznie (kompilacja, tsc, testy z zamockowanym expo-camera/expo-image-picker).
  • Kolejne zadania realizowane po kolei z docs/tasks — patrz też 16-decisions-and-open-questions.md w razie rozbieżności między mockupami a dokumentacją.

Uruchomienie lokalne

Wymagania: Node.js 24 LTS, .NET SDK 10, Docker Desktop (Compose v2). Szczegóły w 22-local-development.md.

# 1. Sekrety
cp .env.example .env
cp apps/mobile/.env.example apps/mobile/.env

# 2. Backend + baza (Postgres + API w Dockerze)
docker compose up --build -d
curl http://localhost:8080/health/live
curl http://localhost:8080/health/ready

# 3. Aplikacja mobilna
cd apps/mobile
npm install
npm start        # otwórz w Expo Go / development buildzie

Ekran logowania wymaga działającego backendu (EXPO_PUBLIC_API_BASE_URL w apps/mobile/.env, domyślnie http://localhost:8080). Na fizycznym urządzeniu/emulatorze zamiast localhost wpisz adres IP komputera w sieci lokalnej.

Na Windows bez make użyj ./scripts/dev.ps1 <target> (patrz Makefile dla listy targetów: setup, dev-infra, dev-api, dev-mobile, test, lint, format, build, clean).

Weryfikacja jakości mobile (apps/mobile): npm run format:check, npm run lint, npm run typecheck, npm test, npx expo-doctor. Weryfikacja jakości backendu (root): dotnet format --verify-no-changes, dotnet build, dotnet test (wymaga Dockera — testy Testcontainers).

Dokumenty

Dokument Cel
00-product-vision.md wizja, użytkownik i wartość produktu
01-mvp-scope.md zakres PoC/MVP oraz funkcje odłożone
02-user-flows.md podstawowe przepływy użytkownika
03-functional-requirements.md wymagania funkcjonalne
04-non-functional-requirements.md wydajność, bezpieczeństwo i utrzymanie
05-architecture.md architektura rozwiązania
06-domain-model.md model domenowy i encje
07-api-contract.md kontrakt REST API
08-running-nutrition-engine.md reguły dopasowania żywienia do biegu
09-strava-integration.md OAuth, webhooki i synchronizacja Stravy
10-ai-features.md funkcje AI i ograniczenia bezpieczeństwa
11-security-privacy.md prywatność i bezpieczeństwo danych
12-infrastructure-mikrus.md budżetowe wdrożenie na VPS
13-testing-strategy.md strategia testów
14-roadmap.md kolejność budowy produktu
15-definition-of-done.md wspólne kryteria ukończenia
16-decisions-and-open-questions.md decyzje architektoniczne i pytania
17-ui-ux-spec.md nawigacja i ekrany mobilne
18-observability-backup.md logi, monitoring i kopie zapasowe
19-content-data-policy.md źródła przepisów i danych żywieniowych
20-version-matrix.md wersje startowe technologii
21-environment-configuration.md zmienne i środowiska
22-local-development.md lokalne uruchomienie projektu

Zasady pracy z agentem AI

  • Agent ma realizować jedno zadanie z docs/tasks naraz.
  • Przed kodowaniem agent musi wskazać dokumenty, na których opiera rozwiązanie.
  • Każda zmiana musi zawierać testy lub uzasadnienie ich braku.
  • Agent nie może dodawać nowej usługi infrastrukturalnej bez aktualizacji dokumentacji i ADR.
  • Agent nie może implementować funkcji spoza MVP „przy okazji”.
  • Sekrety nigdy nie trafiają do repozytorium.

About

A mobile app for recreational runners preparing for distances ranging from their first kilometre to a full marathon. The product combines a training plan, completed Strava activities, and dynamic recommendations for nutrition, hydration, and recovery.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages