Skip to content

Ekrany — Autentykacja

Przegląd

Modul autentykacji obsługuje dwa typy użytkowników: dziecko i rodzic. Dziecko loguje się PINem (4 cyfry) i wybiera profil z listy awatarów zapisanych na urządzeniu. Rodzic loguje się kodem weryfikacyjnym wysyłanym na e-mail (passwordless).

Routing (GoRouter)

dart
final authRoutes = [
  GoRoute(path: '/welcome',       builder: (_, __) => WelcomeScreen()),
  GoRoute(path: '/register/child', builder: (_, __) => ChildRegistrationScreen()),
  GoRoute(path: '/register/parent',builder: (_, __) => ParentRegistrationScreen()),
  GoRoute(path: '/login/child',    builder: (_, __) => ChildLoginScreen()),
  GoRoute(path: '/login/parent',   builder: (_, __) => ParentLoginScreen()),
];

Redirect guard — jeśli brak tokenu w Secure Storage, przekieruj na /welcome.

Riverpod Providers

dart
// Stan autentykacji
final authStateProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
  return AuthNotifier(ref.watch(authRepositoryProvider));
});

// Profile dzieci zapisane na urządzeniu
final deviceProfilesProvider = FutureProvider<List<ChildProfile>>((ref) {
  return ref.watch(authRepositoryProvider).getDeviceProfiles();
});

// Krok rejestracji dziecka (multi-step)
final childRegStepProvider = StateProvider<int>((ref) => 0);

// Dane formularza rejestracji dziecka
final childRegFormProvider = StateNotifierProvider<ChildRegFormNotifier, ChildRegForm>((ref) {
  return ChildRegFormNotifier();
});

// Timer na ponowne wysłanie kodu e-mail
final resendTimerProvider = StateProvider<int>((ref) => 0);

// Walidacja PIN (4 cyfry)
final pinInputProvider = StateProvider<String>((ref) => '');

1. Welcome Screen

Pierwszy ekran po uruchomieniu aplikacji. Dziecko lub rodzic wybiera swoją rolę.

ASCII Wireframe

┌──────────────────────────────────┐
│          ☆ LUMOS ISLANDS ☆       │
│       (logo + animacja tła)      │
│                                  │
│  ┌────────────┐ ┌────────────┐   │
│  │            │ │            │   │
│  │   👧 🧒    │ │    👨 👩    │   │
│  │            │ │            │   │
│  │  DZIECKO   │ │   RODZIC   │   │
│  │            │ │            │   │
│  │ "Chcę się  │ │ "Chcę      │   │
│  │  uczyć!"  │ │  zarządzać"│   │
│  │            │ │            │   │
│  └────────────┘ └────────────┘   │
│                                  │
│     Masz już konto? Zaloguj się  │
│                                  │
└──────────────────────────────────┘

Komponenty

KomponentOpis
AnimatedBackgroundAnimowane tło (cząsteczki / fale)
LumosLogoLogo aplikacji z animacją wejścia
RoleCardDuża karta z ikoną, tytułem i opisem (2 sztuki)
TextLinkButtonLink "Masz już konto? Zaloguj się"

Logika

  • Tap DZIECKO → nawigacja do /register/child (nowy) lub /login/child (istniejący)
  • Tap RODZIC → nawigacja do /register/parent (nowy) lub /login/parent (istniejący)
  • Link "Zaloguj się" → bottom sheet z wyborem: logowanie dziecka / rodzica

Endpointy

Brak — ekran czysto nawigacyjny.


2. Rejestracja Dziecka (multi-step)

Wielokrokowy formularz tworzenia profilu dziecka. Dane zapisywane lokalnie na urządzeniu + wysyłane na serwer.

ASCII Wireframe

Krok 1: Rok urodzenia          Krok 2: Język
┌──────────────────────────┐    ┌──────────────────────────┐
│  ← Cofnij                │    │  ← Cofnij                │
│                          │    │                          │
│  Ile masz lat?           │    │  W jakim języku          │
│                          │    │  chcesz się uczyć?       │
│  ┌────────────────────┐  │    │                          │
│  │  ◀  2018  ▶        │  │    │  ┌──────┐ ┌──────┐      │
│  │  (scroll picker)   │  │    │  │ 🇵🇱   │ │ 🇬🇧   │      │
│  └────────────────────┘  │    │  │Polski │ │Angiel│      │
│                          │    │  └──────┘ └──────┘      │
│  [●○○○] krok 1/4        │    │  ┌──────┐ ┌──────┐      │
│                          │    │  │ 🇩🇪   │ │ 🇪🇸   │      │
│  [ DALEJ ]               │    │  │Niemie│ │Hiszpa│      │
│                          │    │  └──────┘ └──────┘      │
└──────────────────────────┘    │                          │
                                │  [●●○○] krok 2/4        │
                                │  [ DALEJ ]               │
                                └──────────────────────────┘

Krok 3: Wybór awatara          Krok 4: Ustawienie PINu
┌──────────────────────────┐    ┌──────────────────────────┐
│  ← Cofnij                │    │  ← Cofnij                │
│                          │    │                          │
│  Wybierz swój awatar!    │    │  Ustaw swój PIN          │
│                          │    │  (4 cyfry)               │
│     ┌──────────┐         │    │                          │
│     │  👤      │         │    │     ● ● ○ ○              │
│     │(wybrany) │         │    │                          │
│     └──────────┘         │    │  ┌───┬───┬───┐           │
│                          │    │  │ 1 │ 2 │ 3 │           │
│  ◀ ┌────┐┌────┐┌────┐ ▶ │    │  ├───┼───┼───┤           │
│    │ 🧒 ││ 👧 ││ 🧑 │   │    │  │ 4 │ 5 │ 6 │           │
│    └────┘└────┘└────┘   │    │  ├───┼───┼───┤           │
│  (przewiń — 8 presetów) │    │  │ 7 │ 8 │ 9 │           │
│  4 męskie + 4 żeńskie   │    │  ├───┼───┼───┤           │
│                          │    │  │   │ 0 │ ⌫ │           │
│  [●●●○] krok 3/4        │    │  └───┴───┴───┘           │
│  [ DALEJ ]               │    │                          │
└──────────────────────────┘    │  [●●●●] krok 4/4        │
                                │  [ GOTOWE! ]             │
                                └──────────────────────────┘

Komponenty

KomponentOpis
StepIndicatorDots indicator (4 kroki)
YearPickerScroll picker z rokiem urodzenia
LanguageGridSiatka flag z nazwami języków
AvatarPickerHoryzontalny scroll 8 losowych presetów (4 męskie + 4 żeńskie), tap = wybór
PinSetupPadKlawiatura numeryczna 4-cyfrowa z kropkami potwierdzenia
BackButtonPowrót do poprzedniego kroku
LumosButtonPrzycisk "DALEJ" / "GOTOWE!"

Logika

  1. Użytkownik przechodzi przez 4 kroki (PageView z kontrolerem)
  2. Każdy krok walidowany przed przejściem dalej
  3. Na ostatnim kroku (PIN) — wywołanie API rejestracji
  4. Sukces → profil zapisany na urządzeniu (Secure Storage) → nawigacja do onboardingu

Endpointy

MetodaEndpointOpis
POST/app/auth/register/childRejestracja profilu dziecka

Request:

json
{
  "birth_year": 2018,
  "language": "pl",
  "avatar_id": "preset_boy_03",
  "pin": "1234",
  "device_id": "uuid-device"
}

Response:

json
{
  "data": {
    "id": "child-uuid",
    "token": "jwt-token",
    "profile": {
      "display_name": "Odkrywca",
      "avatar_url": "https://..."
    }
  }
}

3. Rejestracja Rodzica

Rejestracja rodzica przez e-mail z kodem weryfikacyjnym (passwordless).

ASCII Wireframe

Krok 1: E-mail                 Krok 2: Kod weryfikacyjny
┌──────────────────────────┐    ┌──────────────────────────┐
│  ← Cofnij                │    │  ← Cofnij                │
│                          │    │                          │
│  Rejestracja Rodzica     │    │  Wpisz kod               │
│                          │    │                          │
│  Podaj swój adres e-mail │    │  Wysłaliśmy 8-znakowy    │
│                          │    │  kod na:                 │
│  ┌────────────────────┐  │    │  anna@example.com        │
│  │ anna@example.com   │  │    │                          │
│  └────────────────────┘  │    │  ┌──┬──┬──┬──┬──┬──┬──┬──┐│
│                          │    │  │ A│ 3│ K│  │  │  │  │  ││
│  Będziemy wysyłać        │    │  └──┴──┴──┴──┴──┴──┴──┴──┘│
│  kody logowania na       │    │                          │
│  ten adres.              │    │  Nie dostałeś kodu?      │
│                          │    │  Wyślij ponownie (42s)   │
│  [ WYŚLIJ KOD ]          │    │                          │
│                          │    │  [ ZWERYFIKUJ ]          │
└──────────────────────────┘    └──────────────────────────┘

Komponenty

KomponentOpis
EmailInputPole e-mail z walidacją formatu
CodeInput8 pól na znaki kodu alfanumerycznego (auto-focus, auto-submit)
ResendTimerOdliczanie do ponownego wysłania kodu
LumosButtonPrzycisk "WYŚLIJ KOD" / "ZWERYFIKUJ"

Logika

  1. Rodzic wpisuje e-mail → API wysyła kod
  2. Rodzic wpisuje 8-znakowy kod → API weryfikuje
  3. Sukces → token JWT → nawigacja do głównego ekranu (panel rodzica)
  4. Błąd → komunikat "Nieprawidłowy kod" + możliwość ponownego wysłania

Endpointy

MetodaEndpointOpis
POST/app/auth/register/parentWysyłka kodu na e-mail
POST/app/auth/verify-emailWeryfikacja kodu

Register Request:

json
{
  "email": "anna@example.com"
}

Verify Request:

json
{
  "email": "anna@example.com",
  "code": "A3K7M2X9"
}

Verify Response:

json
{
  "data": {
    "id": "parent-uuid",
    "token": "jwt-token",
    "is_new": true
  }
}

4. Login Dziecka

Dziecko wybiera swój profil (awatar) z listy zapisanych na urządzeniu, następnie wpisuje 4-cyfrowy PIN.

ASCII Wireframe

Krok 1: Wybór profilu          Krok 2: Wpisanie PINu
┌──────────────────────────┐    ┌──────────────────────────┐
│                          │    │  ← Cofnij                │
│  Kto się dzisiaj uczy?   │    │                          │
│                          │    │  Cześć, Kacper!           │
│  ┌──────┐ ┌──────┐      │    │                          │
│  │ 🧒   │ │ 👧   │      │    │     ┌──────────┐         │
│  │      │ │      │      │    │     │   🧒     │         │
│  │Kacper│ │Zosia │      │    │     └──────────┘         │
│  └──────┘ └──────┘      │    │                          │
│  ┌──────┐ ┌──────┐      │    │  Wpisz swój PIN          │
│  │ 🧒   │ │  +   │      │    │                          │
│  │      │ │ Nowy │      │    │     ● ○ ○ ○              │
│  │ Jan  │ │profil│      │    │                          │
│  └──────┘ └──────┘      │    │  ┌───┬───┬───┐           │
│                          │    │  │ 1 │ 2 │ 3 │           │
│                          │    │  ├───┼───┼───┤           │
│  Zaloguj się jako rodzic │    │  │ 4 │ 5 │ 6 │           │
│                          │    │  ├───┼───┼───┤           │
└──────────────────────────┘    │  │ 7 │ 8 │ 9 │           │
                                │  ├───┼───┼───┤           │
                                │  │   │ 0 │ ⌫ │           │
                                │  └───┴───┴───┘           │
                                │                          │
                                │  Zapomniałem PIN         │
                                └──────────────────────────┘

Komponenty

KomponentOpis
ProfileGridSiatka awatarów (z urządzenia) + karta "Nowy profil"
ProfileCardKarta z awatarem i imieniem dziecka
PinPadKlawiatura numeryczna z 4 kropkami statusu
AddProfileCardKarta "+" do dodawania nowego profilu
TextLinkButtonLink "Zaloguj się jako rodzic" / "Zapomniałem PIN"

Logika

  1. Pobranie listy profili z urządzenia (Secure Storage) + opcjonalnie z API
  2. Dziecko tapuje swój awatar → przejście do ekranu PIN
  3. Wpisanie 4 cyfr → automatyczna weryfikacja (bez przycisku)
  4. Sukces → token JWT → nawigacja do globusa (lub onboardingu)
  5. Błędny PIN → animacja potrząsania + reset pól

Endpointy

MetodaEndpointOpis
GET/app/auth/profilesLista profili na urządzeniu
POST/app/auth/login/childLogowanie dziecka (PIN)

Profiles Response:

json
{
  "data": [
    {
      "id": "child-1",
      "display_name": "Kacper",
      "avatar_url": "https://..."
    },
    {
      "id": "child-2",
      "display_name": "Zosia",
      "avatar_url": "https://..."
    }
  ]
}

Login Request:

json
{
  "profile_id": "child-1",
  "pin": "1234",
  "device_id": "uuid-device"
}

Login Response:

json
{
  "data": {
    "token": "jwt-token",
    "profile": {
      "id": "child-1",
      "display_name": "Kacper",
      "avatar_url": "https://...",
      "level": 5,
      "xp": 1240
    },
    "onboarding_completed": true
  }
}

5. Login Rodzica

Logowanie rodzica przez e-mail + kod weryfikacyjny (passwordless, identyczny flow jak rejestracja).

ASCII Wireframe

Krok 1: E-mail                 Krok 2: Kod weryfikacyjny
┌──────────────────────────┐    ┌──────────────────────────┐
│  ← Cofnij                │    │  ← Cofnij                │
│                          │    │                          │
│  Logowanie Rodzica       │    │  Wpisz kod               │
│                          │    │                          │
│  Podaj swój adres e-mail │    │  Wysłaliśmy 8-znakowy    │
│                          │    │  kod na:                 │
│  ┌────────────────────┐  │    │  anna@example.com        │
│  │ anna@example.com   │  │    │                          │
│  └────────────────────┘  │    │  ┌──┬──┬──┬──┬──┬──┬──┬──┐│
│                          │    │  │  │  │  │  │  │  │  │  ││
│                          │    │  └──┴──┴──┴──┴──┴──┴──┴──┘│
│  Nie masz konta?         │    │                          │
│  Zarejestruj się         │    │  Nie dostałeś kodu?      │
│                          │    │  Wyślij ponownie (58s)   │
│  [ WYŚLIJ KOD ]          │    │                          │
│                          │    │  [ ZALOGUJ SIĘ ]         │
└──────────────────────────┘    └──────────────────────────┘

Komponenty

KomponentOpis
EmailInputPole e-mail z walidacją formatu (reuse z rejestracji)
CodeInput8 pól na znaki kodu alfanumerycznego (reuse z rejestracji)
ResendTimerOdliczanie do ponownego wysłania kodu
LumosButtonPrzycisk "WYŚLIJ KOD" / "ZALOGUJ SIĘ"
TextLinkButtonLink "Nie masz konta? Zarejestruj się"

Logika

  1. Rodzic wpisuje e-mail → API wysyła kod weryfikacyjny
  2. Rodzic wpisuje 8-znakowy kod → API weryfikuje
  3. Sukces → token JWT → nawigacja do ekranu rodzica (zarządzanie dziećmi)
  4. Jeśli e-mail nie istnieje → komunikat z linkiem do rejestracji

Endpointy

MetodaEndpointOpis
POST/app/auth/login/parentWysyłka kodu na e-mail
POST/app/auth/verify-emailWeryfikacja kodu

Login Request:

json
{
  "email": "anna@example.com"
}

Verify Request:

json
{
  "email": "anna@example.com",
  "code": "B5T8N3P1"
}

Verify Response:

json
{
  "data": {
    "id": "parent-uuid",
    "token": "jwt-token",
    "children": [
      { "id": "child-1", "display_name": "Kacper" },
      { "id": "child-2", "display_name": "Zosia" }
    ]
  }
}

Wspólne Elementy UI

KomponentWykorzystanie
LumosButtonWszystkie ekrany — primary, secondary, text variant
BackButtonNawigacja wstecz w GoRouter (context.pop())
LoadingOverlayWyświetlany podczas requestów API
ErrorSnackbarKomunikaty błędów (walidacja, serwer)
AnimatedBackgroundWelcome screen, tło logowania

Bezpieczeństwo

  • PIN przechowywany wyłącznie na serwerze (hash + salt)
  • Token JWT w Flutter Secure Storage (Keychain / Keystore)
  • Device ID generowany przy pierwszym uruchomieniu i zapisywany w Secure Storage
  • Kod e-mail ważny 10 minut, max 3 próby
  • Rate limiting na endpointach autentykacji (429 Too Many Requests)

Lumos Islands v2 - Dokumentacja Projektowa