Potwierdzenie numeru telefonu
Numer telefonu jest jedynym śladem, po którym aplikacja potrafi rozpoznać, że rezerwacja założona na recepcji należy do konkretnego klienta. Konto założone przez Google czy Apple przychodzi bez numeru — a przy logowaniu Apple również bez prawdziwego adresu e-mail (Apple podstawia adres przekierowujący). Bez potwierdzonego numeru takie konto nie ma jak dosięgnąć własnej historii.
👤 Instrukcja dla klienta
- Wejdź w Profil → sekcja Dane osobowe.
- Wpisz numer telefonu w formacie
+48XXXXXXXXX. - Pod polem pojawi się ramka z przyciskiem Wyślij kod SMS. Kliknij go.
- Przepisz sześciocyfrowy kod z SMS-a. Kod sprawdza się sam po wpisaniu ostatniej cyfry.
- Jeśli klub założył wcześniej Twoje rezerwacje na recepcji, zobaczysz komunikat, że konto zostało połączone z istniejącymi danymi — płatności, rezerwacje i saldo portfela pojawią się na koncie od razu.
Numer jest opcjonalny. Możesz zapisać profil bez niego i korzystać z aplikacji normalnie; potwierdzenie jest potrzebne tylko po to, żeby przejąć historię z recepcji i żeby móc logować się numerem telefonu.
Kiedy potwierdzenie się nie uda
| Komunikat | Co się stało | Co zrobić |
|---|---|---|
| Ten numer jest już potwierdzony na innym koncie | Ktoś (być może Ty) potwierdził ten numer na drugim koncie | Zaloguj się na tamto konto albo zgłoś sprawę recepcji |
| Zbyt wiele prób | Limit trzech SMS-ów na 10 minut | Odczekaj kilka minut |
| Nieprawidłowy kod | Kod wygasł (ważny 5 minut) albo został przepisany z błędem | Kliknij Wyślij kod ponownie |
👤 Instrukcja dla pracownika
Klient, który założył konto społecznościowe po tym, jak recepcja wpisała go jako klienta lokalnego, widzi puste konto do momentu potwierdzenia numeru. Jeśli zgłasza, że „nie widzi swojej rezerwacji", poproś go o wejście w Profil i potwierdzenie numeru — historia przeniesie się sama.
Numer wpisany przez pracownika na karcie klienta nie liczy się jako potwierdzony. Recepcja może go poprawić, ale każda zmiana numeru kasuje wcześniejsze potwierdzenie: numer, którego nikt nie potwierdził SMS-em, nie przejmuje żadnych danych.
🔧 Dokumentacja techniczna
Przepływ
Dlaczego route handler, a nie server action
Identyfikator server action jest przypisany do konkretnego builda. Klient,
który ma otwartą starą wersję strony po wdrożeniu, trafiłby na akcję, której
już nie ma — i błąd byłby cichy. Wszystkie wywołania z przeglądarki idą więc
przez app/api/account/phone/route.ts.
Granice bezpieczeństwa
phoneVerified = 1 to dowód tożsamości: claimLocalUserRecords na jego
podstawie przepisuje na konto wszystkie rezerwacje, płatności, faktury i saldo
portfela zapisane pod adresem-zaślepką klienta lokalnego. Dlatego:
- flagi nie da się ustawić przez
updateUserwe własnym imieniu —lib/actions/users.tswycinaapp_metadata.phone_verifiedz aktualizacji klienta na jego własnym koncie. Jedyną drogą jest kod SMS; - zmiana numeru kasuje flagę, niezależnie od tego, kto ją wykonuje;
- numer potwierdzony na innym, niezarchiwizowanym koncie jest odrzucany — sprawdzane dwa razy, przed wysłaniem kodu i po jego weryfikacji, bo okno ważności kodu trwa minuty;
- limity: 3 SMS-y i 10 prób kodu na 10 minut, liczone po numerze przez
Durable Object (
createRateLimiter), więc trzymają się między izolatami.
Zgodność z App Store Review 5.1.1(v)
Numer jest polem opcjonalnym, a nie bramką. Formularz profilu zapisuje się z
pustym polem, nic nie blokuje wejścia do aplikacji i nie ma modala bez
zamknięcia — to były zarzuty, przez które w sierpniu 2026 usunięto poprzedni
mechanizm (components/modal/confirm-phone.tsx). Prośba o numer pojawia się
dopiero wtedy, gdy klient sam zacznie go wpisywać, i jest uzasadniona
konkretną korzyścią widoczną w interfejsie.
Powiązane pliki
| Plik | Rola |
|---|---|
app/api/account/phone/route.ts | wysyłka i weryfikacja kodu, uruchomienie scalenia |
components/forms/userProfile/components/PhoneVerificationCard.tsx | ramka pod polem telefonu w profilu |
lib/local-user-merge.ts | claimLocalUserRecords / mergeLocalUserIntoAccount |
lib/actions/users.ts | strażnik phone_verified w updateUser |
Zobacz też: Klient lokalny.