Standardowa odpowiedź brzmi "to zależy" ale ja bym zrobił to tak, że na serwerze postawić jakieś API czy innego pośrednika, który się komunikuje z bazą.
Aplikacja bezpośrednio nie gada z bazą, wiec mamy po pierwsze separację, a po drugie - warstwę abstrakcji. Także jakaś późniejsza zmiana bazy, jakaś migracja itp. z punktu widzenia aplikacji przechodzi bezboleśnie. Ona cały czas wali w ten sam endpoint/odpytuje ten sam adres, a co jest dalej to nie jest problem aplikacji.
Pytanie jest takie - co konkretnie oznaczają dla Ciebie te "niezmienniki biznesowe"? Odnosząc się do Twoich przykładów:
jeden użytkownik z jednym adresem e-mail - tutaj API/pośrednik temat załatwia. Aplikacja wysyła do tego "czegoś" żądanie dodania użytkownika z danym mailem i w odpowiediz dostaje "OK" albo "sorry, mail jest już wykorzystany". Sama aplikacja niczego nie musi robić, nie musi znać zasad dot. emaili itp. po prostu - przekazuje żądanie dalej, a potem patrzy co dostała
jednoczesna edycja - tutaj robimy blokadę danego rekordu/typu danych/określonej kartoteki. W sensie - jak jakiś użytkownik zaczyna edytować kartotekę klienta "4p sp. z o.o." to gdy inny spróbuje zrobić to samo to dodaje info, że aktualnie rekord jest w edycji i pokazujemy tylko w trybie do odczytu.
Tworząc pośrednika (nazwij go jak chcesz, niech to będzie API) zyskujesz to, że masz jedno miejsce trzymania logiki biznesowej.
Oczywiście - dobrze jest mieć tez jakąś podstawową walidację po stronie apki, żeby w polu "wzrost" nie wpisać "45-390 Bytom" albo w miejsce liczby zamówionych sztuk nie wpisać "Tomasz". To są takie podstawowe kwestie, ale bardzie zaawansowana logika (że np. liczba zamówionych sztuk musi być wielokrotnością 15 a także że łączna masa zamówienia nie może przekraczać 400kg) niech będzie jedynie po stronie API a nie aplikacji.
Plusem jest to, że wtedy masz jedno miejsce trzymania takiej logiki. I nieważne, co się z tym łaczy - apka webowa, apka mobilna, desktop, a może jakaś integracja z programem księgowym itp. - masz dokładnie jedno miejsce kontrolujące całość, więc nie ma ryzyka, że logika apki na Androida się rozjedzie z tym, na co pozwala aplikacja desktopowa.
A jeszcze wracając do przykładu z unikalnym emailem:
- trzymanie tego na bazie jest problemem. Bo co w scenariuszu, w którym ktoś miał kilka lat temu konto ma określonego maila, potem je skasował, a teraz chce na nowo. Samo sprawdzenie czy mail jest w bazie spowoduje, że nie da się założyć
- aplikacja (każda - mobilna, desktopowa, webowa itp.) musi więc mieć znajomość struktury bazy i np. wysłać zapytanie
SELECT adres-email WHERE jest-aktywny=TRUE. To po pierwsze powoduje spięcie implementacji apki ze struktura bazy, po drugie - jakby np. baza się zmieniła, ale apka będzie stara to albo nie będzie działać, albo spowoduje błędne/losowe działanie
- mając API - warunki sprawdzania emaili masz tylko tam, a aplikacja wysyła do API prośbę o dodanie usera i patrzy, co się stanie. Aplikacja nie wie i nie powinna sie interesować tym, czy adres jest już wpisany (ale oznaczony jako nieaktywny), czy go nie było, a może nie było ale przed chwilą ktoś dodał itp. Po prostu - podany mail albo moze być, albo nie może.
Cała logika powinna być po stronie serwera ALE NIE baza to ogarnia. Baza (jak pisał @somekind) odpowiada za trzymanie danych i zapewnienie ich spójności. Logika biznesowa leży poza bazą, ale niekoniecznie musi być zaszyta wprost w apce. Uważam, że najlepiej jest dać warstwę pośrednią, która trzyma logikę w oddzieleniu od bazy oraz samej aplikacji/UI.