# Teknisk Beskrivning - Flutter Frontend Detta dokument beskriver vad som ar byggt, arkitekturval och teknisk kontext for Flutter-frontenden. Malgrupp: utvecklare och AI-assistent i denna chat. Relaterade dokument: - [next_steps_flutter.md](next_steps_flutter.md) - [flutter/README.md](flutter/README.md) - [teknisk_beskrivning.md](teknisk_beskrivning.md) (for backend-kontekst) ## Syfte - Isolerad Flutter-baserad frontend i separat Docker-service. - Web forst, men med arkitektur som kan ateranvandas for Android/iOS. - Stegvis migrering av funktioner fran befintlig Next.js-frontend. ## Vad som ar gjort - Ny compose override: [compose.flutter.yml](compose.flutter.yml). - Ny Flutter-service: `recipe-flutter`. - Service ansluten till natverk: - `recipe-internal` (backend access) - `proxy` (external Caddy reachability) - Flutter-container serverar web build via intern Caddy. - Exponering via extern Caddy med site `test.gynther.se` -> `recipe-flutter:5000`. - API anrop gar same-origin via `/api` och proxas internt till `recipe-api:8080`. ## Arkitektur ### Lager - Presentation: skarmar och widgets i `flutter/lib/features/*/presentation`. - State/Application: Riverpod providers/notifiers i `flutter/lib/features/*/data`. - Data/API: `ApiClient` i `flutter/lib/core/api`. - Platform abstraction: token storage interface i `flutter/lib/core/platform`. ### Routing - GoRouter i [flutter/lib/core/router/app_router.dart](flutter/lib/core/router/app_router.dart). - Nuvarande routes: - `/login` — loginskarm - `/recipes` — receptlista (ShellRoute med AppShell) - `/recipes/create` — nytt recept, utanfor ShellRoute - `/recipes/:id` — receptdetalj, utanfor ShellRoute - `/recipes/:id/edit` — redigera recept, utanfor ShellRoute - `/profile` — profil (ShellRoute med AppShell) - `/recipes/create` maste vara listad fore `/recipes/:id` i routelistan for att undvika konflikt. - Detaljsidor (detalj, skapa, redigera) ligger utanfor ShellRoute for att fa full-screen med automatisk back-knapp. ### Auth - Login endpoint: `POST /api/auth/login`. - Backend kontrakt anvander `username` + `password`. - Token-falt i svar: `accessToken`. - Token lagras via `ITokenStorage` (web implementation med SharedPreferences). - Auth-gate i router: utloggad anvandare redirectas till `/login`, inloggad redirectas fran `/login` till `/recipes`. - Splash-skarm (`/`) visas medan auth-state lases fran storage vid app-start. - `guardedApiCall()` i `flutter/lib/core/api/guarded_api_call.dart` hanterar automatisk logout vid 401. ### API-lager - `ApiClient` i `flutter/lib/core/api/api_client.dart` exponerar: `getJson`, `postJson`, `patchJson`, `putJson`, `deleteJson`. - Centralicerad HTTP-felklassning: 401 -> `ApiErrorType.unauthorized`, 403 -> `forbidden`, 5xx -> `server`, natverksfel -> `network`. - `ApiException` i `flutter/lib/core/api/api_exception.dart` ar den enda feltypen som propageras fran repositories. - `mapErrorToUserMessage()` i `flutter/lib/core/api/api_error_mapper.dart` oversatter fel till svenska anvandarmedddelanden. ### Recipes - `GET /api/recipes` — receptlista. - `GET /api/recipes/:id` — receptdetalj inkl. ingredienser. - `POST /api/recipes` — skapa recept. - `PATCH /api/recipes/:id` — uppdatera recept (OBS: PATCH, inte PUT). - `DELETE /api/recipes/:id` — ta bort recept (returnerar 204, ingen body). - `POST /api/recipes/parse-markdown` — tolka Markdown, returnerar ParsedRecipe med ingrediensforslagslistor. - Flutter Recipe-model: `name`-fallback till `title`, null-safe parsing av Decimal-strang till double. ### Gemensamma UI-komponenter - `LoadingStateView`, `EmptyStateView`, `ErrorStateView` i `flutter/lib/core/ui/async_state_views.dart`. - `AppShell` i `flutter/lib/core/ui/app_shell.dart`: responsiv NavigationRail (bred) / NavigationBar (smal), delad AppBar med logout. ## Kanda API-fallgropar (viktigt!) > **Regel: Kontrollera alltid HTTP-metod i [TEKNISK_BESKRIVNING.md](TEKNISK_BESKRIVNING.md) innan en ny repository-metod implementeras.** | Operation | Korrekt metod | Fel som gjorts | |-----------|--------------|----------------| | Uppdatera recept | `PATCH /api/recipes/:id` | `PUT` — ger 404 | | Uppdatera inventariepost | `PATCH /api/inventory/:id` | Anvand PATCH | | Uppdatera matplan | `POST /api/meal-plan` (upsert) | Ingen PUT/PATCH | Generell regel: NestJS-backenden anvander `PATCH` for partiella uppdateringar, inte `PUT`. `PUT` exponeras inte pa nagra resurser i detta projekt. ## Drift och deploy ### Build/run - Build argument i compose: `API_BASE_URL=/api`. - Build command: - `docker compose -f compose.yml -f compose.flutter.yml build recipe-flutter` - Run command: - `docker compose -f compose.yml -f compose.flutter.yml up -d --no-deps recipe-flutter` ### Viktiga verifieringar - Compose merge valid: - `docker compose -f compose.yml -f compose.flutter.yml config` - Container reachable from external Caddy: - `docker exec caddy wget -S -O- http://recipe-flutter:5000` - Public endpoint: - `curl -I https://test.gynther.se` ## Viktiga beslut - `compose.yml` lamnas orord; Flutter ligger i separat override-fil. - Flutter-web anvander same-origin API (`/api`) for att undvika mixed-content. - Intern Caddy i Flutter-container hanterar static hosting + `/api` proxy. - Feature migration sker stegvis enligt [next_steps_flutter.md](next_steps_flutter.md). ## Kanda fallgropar - Om `recipe-flutter` inte ar i `proxy` natverket blir det 502 fran extern Caddy. - Om browser visar gammal JS kan gamla API-URL:er leva kvar i cache/service worker. - Login med email fungerar inte om backend forvantar username. ## Nasta tekniska steg Fortsatt migrering enligt prioritering i [next_steps_flutter.md](next_steps_flutter.md): 1. Auth parity (session behavior refinements). 2. Recipes parity (list -> detail -> create/edit). 3. Inventory and meal plan pages. 4. Profile/admin parity.