Aplikacja mobilna bez zasięgu, spięta z ERP: kolejka, konflikty, podpis
Jak zbudować aplikację terenową, która działa bez internetu i nie psuje danych w ERP: lokalny zapis, kolejka zmian, rozwiązywanie konfliktów, zdjęcia i podpis, idempotencja po stronie ERP, monitoring i lista kontrolna.
Serwisant kończy przegląd w kotłowni w piwnicy. Zasięgu nie ma. Klient podpisuje protokół na telefonie, serwisant robi zdjęcie tabliczki znamionowej i jedzie dalej. Godzinę później, gdzieś na trasie, telefon łapie sieć i wszystko ma trafić do systemu: wizyta jako zamknięta, protokół jako PDF, pozycje do faktury, a w firmie z ERP także zużyte części jako rozchód z magazynu.
Pracę bez zasięgu, podpis i protokół obsługuje Aplikacja Serwisanta, którą budujemy dla instalatorów. Ten tekst opisuje, co musi zrobić aplikacja terenowa, żeby praca bez zasięgu nie kończyła się zdublowanymi dokumentami w ERP ani nadpisanymi zmianami z biura.
Za co odpowiada aplikacja, a za co backend
flowchart LR
subgraph TEL["Telefon"]
ui["Ekran wizyty"] --> db[("Lokalna baza")]
db --> q["Kolejka zmian"]
files[("Zdjęcia, podpis, PDF")]
end
q -->|"gdy jest sieć"| api["Backend / API"]
files -->|"upload z ponawianiem"| store[("Magazyn plików")]
api --> out["Outbox do ERP"]
out -->|"dokumenty, rozchody"| erp[("ERP")]
erp -->|"klienci, urządzenia, cennik"| api
api -->|"zlecenia na dziś"| db
Podział, który trzeba ustalić przed pierwszym ekranem:
| Zadanie | Gdzie |
|---|---|
| Zapis wizyty, zdjęć i podpisu bez sieci | telefon, lokalna baza |
| Kolejność i ponawianie wysyłek | telefon (do backendu), backend (do ERP) |
| Reguły: kto może zamknąć wizytę, co trafia na fakturę | backend |
| Numeracja dokumentów | ERP albo backend, nigdy telefon |
| Dane referencyjne (klienci, urządzenia, cennik) | ERP, kopia w telefonie tylko do odczytu |
Ostatni wiersz oszczędza najwięcej problemów. Telefon może mieć kopię kartoteki, żeby szukać klienta bez zasięgu, ale nie jest miejscem, w którym kartoteka się zmienia. Nowy klient założony w terenie idzie do backendu jako propozycja i dostaje identyfikator ERP dopiero po synchronizacji.
Lokalny zapis i kolejka zmian
Każda czynność użytkownika zapisuje się najpierw lokalnie i od razu jest widoczna na ekranie. Równolegle trafia do kolejki jako zmiana z:
- identyfikatorem nadanym w telefonie (UUID), a nie przez serwer, bo serwera w tej chwili nie ma,
- czasem utworzenia i identyfikatorem urządzenia,
- wersją rekordu, którą telefon widział przed zmianą.
Kolejka wysyła zmiany w kolejności, po jednej albo w paczkach. Odpowiedź „przyjęto” usuwa zmianę z kolejki. Timeout nie usuwa niczego: zmiana idzie ponownie, a backend rozpoznaje ją po identyfikatorze i nie zapisuje drugi raz.
W Aplikacji Serwisanta lokalny zapis i kolejkę zapewnia baza Firestore z trwałą pamięcią podręczną na urządzeniu. Przy własnym backendzie (np. Go z PostgreSQL, jak w Gustio) tę samą rolę pełni lokalna baza w telefonie i tabela przyjętych zmian po stronie serwera.
Co widzi użytkownik
Użytkownik musi wiedzieć, co jeszcze nie poszło. Wystarczy prosty wskaźnik: „3 zmiany czekają na wysłanie”. Bez niego serwisant zamyka aplikację, wylogowuje się albo czyści dane telefonu i traci pracę z całego dnia. Wylogowanie z niewysłanymi zmianami musi być zablokowane albo wyraźnie ostrzeżone.
Konflikty: biuro i teren zmieniają to samo
sequenceDiagram participant T as Telefon (offline) participant B as Backend participant O as Biuro O->>B: zmiana terminu wizyty (wersja 4 → 5) T->>T: zamknięcie wizyty na wersji 4 T->>B: zamknij wizytę, widziałem wersję 4 B->>B: wersja na serwerze to 5: konflikt B-->>T: przyjęte, zmiana terminu nadpisana statusem „zamknięta” B->>O: powiadomienie: wizyta zamknięta po zmianie terminu
Reguła „ostatni zapis wygrywa” na całym rekordzie jest najprostsza i najgorsza: zmiana z telefonu, który był offline od rana, nadpisze wszystko, co biuro poprawiło w tym czasie. Lepiej rozstrzygać na poziomie pól:
- Fakty z terenu wygrywają z planem z biura. Wizyta, która się odbyła, jest zamknięta, nawet jeśli biuro w międzyczasie przesunęło jej termin.
- Dane referencyjne wygrywają z telefonem. Cena i dane klienta pochodzą z ERP. Telefon może zaproponować zmianę, ale jej nie nadpisuje.
- Listy łączy się, nie podmienia. Zdjęcia i zużyte części z telefonu dochodzą do tych z serwera, zamiast je zastępować.
- Każdy konflikt zostawia ślad. Wpis w historii rekordu i powiadomienie dla osoby, której zmiana przegrała.
Zdjęcia, skany i podpis
Pliki to osobna kolejka, bo są duże, a mobilny internet na trasie bywa słaby.
- Plik zapisuje się lokalnie z identyfikatorem, a rekord wizyty odwołuje się do tego identyfikatora, nie do adresu w chmurze, którego jeszcze nie ma.
- Upload idzie w tle z ponawianiem. Zdjęcie zmniejszone w telefonie do rozmiaru, który wystarcza w dokumentacji, ładuje się kilka razy szybciej niż oryginał z aparatu.
- Podpis zamyka dane. PDF protokołu z podpisem generuje się w telefonie i zapisuje razem z sumą kontrolną treści. Jeśli ktoś później zmieni pozycje wizyty, protokół musi powstać od nowa, z nowym podpisem. Podpis pod innymi danymi niż te, które klient widział, to problem przy reklamacji.
Idempotencja po stronie ERP
Backend przyjmuje zmianę z telefonu raz, ale do ERP i tak może wysłać ją dwa razy: ERP odpowiedział po czasie, worker padł w połowie, ktoś ręcznie ponowił zadanie. Dlatego do ERP nic nie idzie bezpośrednio z obsługi żądania telefonu.
- Zmiana z telefonu zapisuje się w bazie backendu razem z wpisem w outbox w jednej transakcji.
- Osobny proces bierze wpisy z outbox i wysyła je do ERP z kluczem idempotencji (np. identyfikator wizyty i typ dokumentu).
- Przed utworzeniem dokumentu proces sprawdza, czy dokument z tym kluczem już jest w ERP. Jeśli jest, zapisuje jego numer i kończy.
- ERP niedostępny: wpis zostaje w outbox i wraca z rosnącym odstępem. Telefon o tym nie wie i nie musi, bo jego część pracy jest skończona.
Ten sam wzorzec opisujemy dokładniej przy integracji z KSeF, gdzie podwójna faktura ma skutki podatkowe.
Bezpieczeństwo
- Telefon to urządzenie, które się gubi. Lokalna baza zawiera dane klientów, więc dostęp do aplikacji wymaga logowania, a sesja wygasa. Po zgłoszeniu zgubienia telefonu konto urządzenia blokuje się na serwerze i kolejne synchronizacje są odrzucane.
- Żadnych kluczy do ERP w aplikacji. Klucze API do ERP, KSeF i bramki SMS są tylko w backendzie. Aplikację da się rozpakować, więc wszystko, co jest w niej zapisane, trzeba traktować jak publiczne.
- Weryfikacja aplikacji. Backend sprawdza, czy żądanie pochodzi z prawdziwej aplikacji (w Firebase: App Check), a nie ze skryptu, który podszywa się pod nią.
- Role. Technik widzi swoje zlecenia, właściciel całą firmę, klient tylko link do swojej oferty. Uprawnienia sprawdza serwer, nie ekran aplikacji.
Co monitorować
| Sygnał | Próg |
|---|---|
| Urządzenie z niewysłanymi zmianami | dłużej niż 24 godziny |
| Wpisy w outbox do ERP | starsze niż 30 minut |
| Konflikty na rekordach | każdy, z informacją, kto przegrał |
| Pliki wskazane w rekordach, których nie ma w magazynie | każdy |
| Awarie aplikacji po nowej wersji | wzrost względem poprzedniej wersji |
Pierwszy wiersz wymaga, żeby aplikacja raportowała stan kolejki przy każdym połączeniu. Bez tego telefon, który od tygodnia nie wysłał niczego, wygląda w biurze dokładnie tak samo jak telefon, którego nikt nie używa.
Lista kontrolna przed wydaniem
- Tryb samolotowy: pełna wizyta ze zdjęciami i podpisem, potem włączenie sieci. Wszystko dociera, nic się nie dubluje.
- Ta sama wizyta zmieniona w biurze i w telefonie offline: wynik zgodny z regułami, wpis w historii, powiadomienie.
- Zerwanie połączenia w połowie uploadu zdjęcia: plik dochodzi po wznowieniu.
- ERP wyłączony na godzinę: zmiany czekają w outbox i dochodzą po przywróceniu, każdy dokument raz.
- Próba wylogowania z niewysłanymi zmianami: blokada albo ostrzeżenie.
- Zmiana pozycji wizyty po podpisie wymusza nowy protokół.
- Zablokowane urządzenie nie może zsynchronizować danych.
- W kodzie aplikacji nie ma żadnego klucza do systemów zewnętrznych.
Jeżeli punkt 1 albo 4 wymaga ręcznego poprawiania danych w ERP, aplikacja nie jest gotowa do pracy w terenie.
Powiązane
- Aplikacje mobilne dla firm, spięte z ERP
- Aplikacja Serwisanta: przeglądy, oferty i protokoły dla instalatorów
- Integracja KSeF: architektura, idempotencja, tryb offline
- Audit log w wymianie danych B2B
Opisz, co Twoi ludzie robią w terenie i do jakiego systemu ma to trafić - odpowiem, jak wyglądałaby pierwsza wersja aplikacji i ile by kosztowała.
Co dalej
Rozpoznajesz problem? Sprawdźmy Wasz przepływ danych.
Audyt konta BaseLinker i wymiany danych z partnerami: 2 500 - 6 000 zł. Wynik to konkretny dokument z rekomendacją architektury i orientacyjnym kosztem kolejnego etapu. Bez zobowiązania kontynuacji u nas.