PHASE 3: Consumer Mobile App (Flutter)

Trigger: "Execute Phase 3 as per masterplan."

Goal: A functional Flutter mobile app for members: register, browse memberships, purchase, view payment history, and use QR code for check-in. 32-language support with language switcher including RTL.

Prerequisite: Phase 2 is completed.

Step 3.0 — Technical Conception

Create doc/developer/conception/phase-3-conception.md.

(reference: Chapter 09 — Frontend Strategy, Chapter 08 — User Journeys)

Content: - Scope: Flutter mobile app, 6 screens (login, register, catalog, purchase, QR, profile) - Component Design: Feature-based architecture with Riverpod providers - API Integration: OpenAPI codegen vs. manual Dio client (decision + rationale) - Offline Strategy: Token caching, QR code offline display, graceful degradation - RTL Layout: Arabic layout verification checklist, Directionality widget - Design Chapter References: Ch08 (Journey 1), Ch09

Result: Technical conception for Phase 3.


Step 3.1 — App Scaffold and Design System

(reference: Chapter 09 — Frontend Strategy, 10 UX/UI Design Principles)

  1. Architecture: lib/core/, lib/features/, lib/shared/, lib/l10n/
  2. Design system: Material 3, MEMBERSHIP colors, dark mode, typography, components
  3. Riverpod, GoRouter, Dio with JWT interceptor
  4. Apply Gestalt Laws: proximity, similarity, continuity

Step 3.2 — Authentication Flow

(reference: Chapter 13 — Security, Chapter 08 — Journey 1)

Screens:

  1. Login Screen: - Email + password fields, "Remember me" toggle, "Forgot password?" link - Biometric login (fingerprint/face) after initial login (flutter_secure_storage for token) - Error handling: invalid credentials, account locked (brute-force), email not verified - Auto-refresh: Dio interceptor detects 401, refreshes token via /api/auth/refresh, retries request

  2. Registration Screen: - Fields: first name, last name, email, password (strength indicator), confirm password, accept terms checkbox - Validation: real-time email format, password min 8 chars + uppercase + number - On submit: POST /api/auth/register → success screen with "Check your email" message

  3. Email Verification: Deep link handler (membership://verify?token=...), success → auto-login

  4. Forgot Password Flow: - Screen 1: enter email → POST /api/auth/forgot-password - Screen 2: enter code (6-digit OTP from email) + new password → POST /api/auth/reset-password

  5. Token Storage: - flutter_secure_storage for JWT access token (15min) and refresh token (30 days) - Encrypted keychain (iOS) / encrypted shared preferences (Android) - Auto-logout on refresh token expiry

  6. Widget tests: login success, login error, registration validation, token refresh interceptor


Step 3.3 — Membership Browsing and Purchase

(reference: Chapter 08 — Journey 1: Member Registration and First Purchase)

Screens:

  1. Catalog Screen: - Card list of available membership templates (from GET /api/membership-templates/catalog/{entityId}) - Each card: template name, price, billing cycle, description (truncated), features list, "Select" button - Filter by category (if applicable), sort by price

  2. Membership Detail Screen: - Full description, features (checklist), price with VAT breakdown, terms (minimum duration, cancellation notice) - "Purchase" button → starts purchase flow

  3. Purchase Flow (3-step wizard): - Step 1 — Bank Account: enter IBAN (auto-format), account holder, SEPA mandate consent checkbox, date auto-filled - Step 2 — Terms: display contract terms (scrollable), cancellation policy, "I agree" checkbox - Step 3 — Sign: digital signature (tap-to-sign), IP + user agent recorded, summary of what is being signed - Confirmation: success animation, contract PDF download link, "View your QR code" CTA

  4. Widget tests: catalog loading, purchase wizard navigation, IBAN validation, signature recording


Step 3.4 — QR Code Access

(reference: Chapter 08 — Journey 13: QR Door Access, Chapter 12 — QR Access)

Screens:

  1. QR Code Screen (bottom navigation item): - Full-screen QR code display (high contrast, max brightness auto-set) - QR content: encrypted JWT containing memberId, entityId, contractId, timestamp, hash - Time-limited: QR regenerates every 60 seconds (countdown timer shown) - Immutable after generation (security requirement: QR content cannot be modified by member) - Offline capable: last valid QR cached locally, valid for 5 minutes without network - Pull-to-refresh for manual regeneration

  2. Backend validation endpoint: POST /api/checkin/qr-validate - Decrypt QR token, verify signature, check: contract active, not suspended, access zone allowed - Return: GRANTED / DENIED + reason

  3. Widget tests: QR generation, countdown timer, offline fallback, brightness control


Step 3.5 — Payment History and Profile

(reference: Chapter 08 — Journey 1)

Screens:

  1. Transaction History: - List view: date, description, amount (green = paid, red = overdue, gray = pending), status chip - Filter by date range, status - Tap → detail: full transaction info, linked contract, payment method, download invoice PDF

  2. Profile Screen: - Personal data: name, email, phone, address, birthday, photo (camera/gallery picker) - Active contracts: list with status, renewal date - Bank accounts: list with IBAN (masked: DE89 * 3000), default indicator - Notification preferences: email on/off, push on/off, per category - Language selector (32 languages, native names, flag icons) - GDPR Actions:*

    • "Export my data" button → POST /api/members/me/data-export → JSON download (Art. 20)
    • "Delete my account" button → confirmation dialog → POST /api/members/me/deletion-request (Art. 17, 30-day grace period)
    • Logout, app version info
  3. Widget tests: transaction list loading, profile edit, GDPR export trigger, language switch


Step 3.6 — Internationalization (i18n)

(reference: Chapter 09 — Frontend Strategy, Rule 11, Rule 18)

Approach:

  1. ARB Files: 32 app_{locale}.arb files in lib/l10n/: - EU (24): app_bg, app_hr, app_cs, app_da, app_nl, app_en, app_et, app_fi, app_fr, app_de, app_el, app_hu, app_ga, app_it, app_lv, app_lt, app_mt, app_pl, app_pt, app_ro, app_sk, app_sl, app_es, app_sv - Non-EU (8): app_tr, app_ar, app_ru, app_uk, app_sr, app_sq, app_zh, app_he - All strings via AppLocalizations.of(context).key
  2. Language Switcher: - Bottom sheet with all 32 languages, displayed in native names (e.g., "Deutsch", "العربية", "עברית") - Persist selection in shared_preferences + send to backend via PUT /api/users/me/locale - Backend Accept-Language header for API error messages
  3. RTL Support: - Directionality widget wraps app root, auto-detects from locale (Arabic, Hebrew) - All screens tested in RTL: login, catalog, purchase wizard, QR, transactions, profile - RTL-specific fixes: icon mirroring, text alignment, padding reversal, navigation direction
  4. Date/Time/Currency Formatting: - intl package DateFormat per locale - Currency formatting: NumberFormat.currency(locale: locale, symbol: currency) - Relative dates: "2 days ago", "in 3 hours" per locale

Validation: flutter gen-l10n && flutter analyze && flutter test --dart-define=FORCE_RTL=true


Step 3.7 — Phase 3 Documentation

  1. doc/enduser/consumer-manual.md (mobile app guide)
  2. doc/developer/frontend-guide.md (Flutter architecture)

Step 3.8 — Update Intranet

Run python doc/intranet/build.py.


Phase 3 — Quality Gate

# Check Target
1 Conception exists
2 flutter analyze 0 issues
3 flutter test all pass
4 Full flow register -> verify -> login -> browse -> purchase -> QR -> transactions
5 German switch all UI text changes
6 Arabic switch RTL layout correct
7 32 ARB files all keys present
8 Documentation consumer-manual, frontend-guide exist
9 Intranet regenerated
10 CLAUDE.md updated

Report: "Phase 3 completed."

---