Skip to main content

Historia logowań w panelu

Kafelek Liczba logowań i wiersz Ostatnie logowanie na profilu klienta oraz pracownika w panelu administracyjnym.

👤 Instrukcja dla pracownika

Na karcie klienta (Klienci → profil) i pracownika (Pracownicy → profil) widać dwie informacje o korzystaniu z konta:

  • Liczba logowań — ile razy właściciel konta się zalogował,
  • Ostatnie logowanie — data i godzina ostatniego wejścia, albo „Nigdy".

Przydaje się przy pytaniu „czy ten klient w ogóle używa aplikacji?" — na przykład zanim wyśle się mu instrukcję albo zanim uzna się, że nie odbiera powiadomień, bo nigdy nie wszedł na konto.

Dwa zastrzeżenia, o których warto wiedzieć:

  • Klient bez konta (kartoteka założona przez recepcję, rezerwacja z publicznego kalendarza) pokazuje 0 i „Nigdy" — i to jest prawda, bo takie konto nie istnieje, więc nie ma się czym logować. Rozpoznasz go po plakietce „Brak konta".
  • Licznik sięga do migracji logowania (koniec lipca 2026). Konto założone wcześniej ma policzone tylko logowania od tamtej pory, więc dla starych klientów liczba bywa zaniżona. Data ostatniego logowania jest dokładna.

🔧 Dokumentacja techniczna

Skąd biorą się liczby

Better Auth zakłada jeden wiersz w tabeli session na każde zalogowanie (session.createdAt; updatedAt zmienia się przy odświeżeniu sesji, ale nowego wiersza nie tworzy). To jedyna historia logowań, jaką aplikacja ma.

Od września 2026 cotygodniowy cron usuwa sesje wygasłe ponad 30 dni temu, więc wiersze nie zostają w nieskończoność. Żeby licznik tego nie odczuł, sprzątanie najpierw dopisuje sumę usuwanych logowań do tabeli session_login_archive (migracja 0253), a odczyt sumuje archiwum z tym, co wciąż jest w session — patrz Czas trwania sesji.

lib/actions/users-db.ts:

  • getSessionActivityByUserIds(userIds) — jedno zapytanie GROUP BY userId nad UNION ALL żywych sesji (COUNT(*), MAX(createdAt)) i zarchiwizowanego salda, korzysta z istniejącego indeksu session_userId_idx. Gdy session_login_archive jest niedostępne (worker wdrożony przed migracją, baza bez niej), zapytanie schodzi do samych żywych sesji i loguje ostrzeżenie — licznik jest wtedy zaniżony, ale lista klientów i pracowników nadal się otwiera, zamiast zwracać 500,
  • getSessionActivity(userId) — wariant dla jednego konta,
  • withSessionActivity(users) — dokleja logins_count i last_login do całej strony listy jednym zapytaniem (używane przez getUsers i getEmployees).

Dlaczego to w ogóle powstało

Do sierpnia 2026 oba pola były zahardkodowane na logins_count: 0 i last_login: null — pozostałość po Auth0, które dostarczało je w tokenie. Panel pokazywał więc „0 logowań / Nigdy" dla każdego użytkownika, łącznie z takimi, którzy logowali się co tydzień. Wartość nie była pusta, tylko nieprawdziwa, co jest gorsze: na jej podstawie dało się wyciągnąć wniosek, że klient nigdy nie wszedł do aplikacji.

Puste wartości zostały tam, gdzie są prawdziwe — w gałęziach budujących profil użytkownika lokalnego i klienta bez konta.

Pliki

PlikRola
lib/actions/users-db.tsodczyt z session
app/(dashboard)/dashboard/user/[email]/profile/page.tsxprofil klienta
app/(dashboard)/dashboard/employee/[employeeId]/profile/page.tsxprofil pracownika
lib/actions/users.tsgetUsers, getEmployees — listy
lib/session-cleanup.tssprzątanie sesji + zapis do archiwum

Testy

__tests__/lib/actions/session-activity.test.ts — liczba i data z sesji, konto bez sesji, konto nieistniejące, jedno zapytanie na całą stronę listy.

__tests__/lib/session-cleanup.test.ts — regresja na prawdziwym SQLite: licznik logowań przeżywa sprzątanie, także przy kolejnych przebiegach.