Propozycja A z trzech / 19.08.2026 / do wyboru

Klient wchodzi na listę obiektów

Ten sam ekran co dziś, ta sama nawigacja, te same dane w bazie. Zmienia się jedna rzecz: sekcje listy obiektów przestają nazywać się Twoją firmą, a zaczynają nazywać się klientem. Nad listą pojawia się rząd chipów, którym zawężasz widok do jednego klienta.

Werdykt: to jest wariant najtańszy z trzech i naprawia rzecz, która realnie boli: listę obiektów, która dziś nie niesie żadnej informacji. Dla firmy usługowej z kilkoma klientami i kilkudziesięcioma obiektami to wystarczy. Nic nie przenosimy w drzewie, nie dokładamy nowego ekranu i nie odwracamy żadnej decyzji z 06.08.

01Jedno spojrzenie: dziś kontra po zmianie

Po lewej jest dzisiejsza lista obiektów w Proofixie. Po prawej ta sama lista, te same obiekty, ten sam kod ekranu, tylko z innym kluczem grupowania. Reszta dokumentu to wyjaśnienie tej jednej różnicy i jej ceny.

Obiekty: stan dziś Web 1440px Defekt
Obiekty
Brak klienta: Galeria Robakowo (1)
Galeria Robakowo
Brak klienta
ul. Poznańska 12, Robakowo
Utrzymanie terenów zewnętrznych
3 pracowników
2FSG Sp. z o.o. (14)
Fabryka Formy Malta
2FSG Sp. z o.o.
ul. Baraniaka 88, Poznań
Sprzątanie codzienne, mycie okien 1x/mies
6 pracowników
Strefa cardio
ul. Baraniaka 88, Poznań
2 pracowników
Strefa siłowni
ul. Baraniaka 88, Poznań
2 pracowników
Szatnie i sanitariaty
ul. Baraniaka 88, Poznań
2 pracowników
Fabryka Formy Arena
2FSG Sp. z o.o.
ul. Śniadeckich 15, Poznań
4 pracowników
Basen i strefa mokra
ul. Śniadeckich 15, Poznań
2 pracowników
Fabryka Formy Grunwaldzka
2FSG Sp. z o.o.
ul. Grunwaldzka 104, Poznań
3 pracowników
Fabryka Formy Podolany
2FSG Sp. z o.o.
ul. Strzeszyńska 262, Poznań
2 pracowników
Fabryka Formy Winogrady
2FSG Sp. z o.o.
ul. Serbska 7, Poznań
3 pracowników
Fabryka Formy Luboń
2FSG Sp. z o.o.
ul. Żabikowska 66, Luboń
2 pracowników
Fabryka Formy Swarzędz
2FSG Sp. z o.o.
ul. Poznańska 27, Swarzędz
2 pracowników
Fabryka Formy Komorniki
2FSG Sp. z o.o.
ul. Poznańska 60, Komorniki
2 pracowników
Lidl Poznań Dębiec
2FSG Sp. z o.o.
ul. 28 Czerwca 1956 r. 223, Poznań
2 pracowników
Lidl Poznań Naramowice
2FSG Sp. z o.o.
ul. Naramowicka 154, Poznań
2 pracowników
Lidl Swarzędz
2FSG Sp. z o.o.
ul. Cieszkowskiego 4, Swarzędz
1 pracowników
Student Depot Polonez
2FSG Sp. z o.o.
ul. Obornicka 235, Poznań
3 pracowników
Wspólnota mieszkaniowa Słoneczna 14
2FSG Sp. z o.o.
ul. Słoneczna 14, Poznań
1 pracowników
Biuro 2FSG
2FSG Sp. z o.o.
ul. Św. Michała 43, Poznań
1 pracowników
Obiekty: po zmianie Web 1440px Propozycja
Obiekty
Wszyscy klienci
Benefit System 12
Lidl 3
Bez klienta 4
Benefit System (12 obiektów)
Fabryka Formy Malta
Benefit System
ul. Baraniaka 88, Poznań
Sprzątanie codzienne, mycie okien 1x/mies
6 pracowników
Strefa cardio
ul. Baraniaka 88, Poznań
2 pracowników
Strefa siłowni
ul. Baraniaka 88, Poznań
2 pracowników
Szatnie i sanitariaty
ul. Baraniaka 88, Poznań
2 pracowników
Fabryka Formy Arena
Benefit System
ul. Śniadeckich 15, Poznań
4 pracowników
Basen i strefa mokra
ul. Śniadeckich 15, Poznań
2 pracowników
Fabryka Formy Grunwaldzka
Benefit System
ul. Grunwaldzka 104, Poznań
3 pracowników
Fabryka Formy Podolany
Benefit System
ul. Strzeszyńska 262, Poznań
2 pracowników
Fabryka Formy Winogrady
Benefit System
ul. Serbska 7, Poznań
3 pracowników
Fabryka Formy Luboń
Benefit System
ul. Żabikowska 66, Luboń
2 pracowników
Fabryka Formy Swarzędz
Benefit System
ul. Poznańska 27, Swarzędz
2 pracowników
Fabryka Formy Komorniki
Benefit System
ul. Poznańska 60, Komorniki
2 pracowników
Lidl (3 obiekty)
Lidl Poznań Dębiec
Lidl
ul. 28 Czerwca 1956 r. 223, Poznań
2 pracowników
Lidl Poznań Naramowice
Lidl
ul. Naramowicka 154, Poznań
2 pracowników
Lidl Swarzędz
Lidl
ul. Cieszkowskiego 4, Swarzędz
1 pracowników
Bez klienta (4 obiekty)
Galeria Robakowo
ul. Poznańska 12, Robakowo
Utrzymanie terenów zewnętrznych
3 pracowników
Student Depot Polonez
ul. Obornicka 235, Poznań
3 pracowników
Wspólnota mieszkaniowa Słoneczna 14
ul. Słoneczna 14, Poznań
1 pracowników
Biuro 2FSG
ul. Św. Michała 43, Poznań
1 pracowników
1
Po lewej pierwszy nagłówek brzmi „Brak klienta: Galeria Robakowo (1)", bo nagłówek sekcji bierze surową nazwę wiersza z tabeli firm, a karta pod nim stosuje regułę is_internal i pisze poprawnie „Brak klienta" (objects.tsx:60 kontra :99).
2
Po lewej druga sekcja nazywa się „2FSG Sp. z o.o. (14)" i mieści wszystko pozostałe, więc grupowanie niczego nie dzieli, a linia pod nazwą każdego obiektu powtarza nazwę własnej firmy Franka (objects.tsx:60, :97-101).
3
Po prawej klucz grupowania to klient z rejestru end_clients, sztuczny wiersz „Brak klienta" znika z nagłówka na rzecz sekcji „Bez klienta", a rząd chipów nad listą zawęża widok do jednego klienta jednym kliknięciem.

Uwaga o liczbach przy chipach i w nagłówkach: dziś licznik w nagłówku liczy tylko obiekty korzeniowe (objects.tsx:66), a licznik obiektów klienta na liście Klienci liczy się w przeglądarce z zakresu zalogowanego (EndClientListScreen.tsx:75, lib/utils.ts:258-279). Liczby „12 / 3 / 4" na makiecie to obiekty całych gałęzi. Żeby były takie same dla każdego menedżera, trzeba je policzyć na serwerze. To jest pozycja kosztowa z warstwy 2, nie ozdobnik.

Obiekty na telefonie: dziś kontra po zmianie Mobile 390px Defekt Propozycja
9:41 . . . .|||100%
Obiekty
Brak klienta: Galeria Robakowo (1)
Galeria Robakowo
Brak klienta
ul. Poznańska 12, Robakowo
3 pracowników
2FSG Sp. z o.o. (14)
Fabryka Formy Malta
2FSG Sp. z o.o.
ul. Baraniaka 88, Poznań
6 pracowników
Strefa cardio
ul. Baraniaka 88, Poznań
2 pracowników
Strefa siłowni
ul. Baraniaka 88, Poznań
2 pracowników
Szatnie i sanitariaty
ul. Baraniaka 88, Poznań
2 pracowników
Fabryka Formy Arena
2FSG Sp. z o.o.
ul. Śniadeckich 15, Poznań
4 pracowników
Basen i strefa mokra
ul. Śniadeckich 15, Poznań
2 pracowników
Fabryka Formy Grunwaldzka
2FSG Sp. z o.o.
ul. Grunwaldzka 104, Poznań
3 pracowników
Fabryka Formy Podolany
2FSG Sp. z o.o.
ul. Strzeszyńska 262, Poznań
2 pracowników
9:41 . . . .|||100%
Obiekty
Wszyscy klienci
Benefit System 12
Lidl 3
Bez klienta 4
Benefit System (12 obiektów)
Fabryka Formy Malta
Benefit System
ul. Baraniaka 88, Poznań
6 pracowników
Strefa cardio
ul. Baraniaka 88, Poznań
2 pracowników
Strefa siłowni
ul. Baraniaka 88, Poznań
2 pracowników
Szatnie i sanitariaty
ul. Baraniaka 88, Poznań
2 pracowników
Fabryka Formy Arena
Benefit System
ul. Śniadeckich 15, Poznań
4 pracowników
Basen i strefa mokra
ul. Śniadeckich 15, Poznań
2 pracowników
Fabryka Formy Grunwaldzka
Benefit System
ul. Grunwaldzka 104, Poznań
3 pracowników
Fabryka Formy Podolany
Benefit System
ul. Strzeszyńska 262, Poznań
2 pracowników
1
Na telefonie ta sama zmiana kosztuje jeden rząd chipów przewijany poziomo, bo dolny pasek zakładek i tak zajmuje 80px i nie ma miejsca na nową kolumnę ani nowy ekran.
2
Pod-obiekty zostają wcięte pod swoim rodzicem w obu wersjach, bo wcięcie oznacza fizyczne zawieranie się obiektu w obiekcie, a nie przynależność do klienta.

Uwaga techniczna do wcięcia: dziś wcięcie liczy inline marginLeft: depth * spacing[5], a styl subObjectCard z marginLeft: spacing[6] nigdy nie działa, bo w tablicy stylów przegrywa kolejnością (objects.tsx:80-81, punkt 6 tabeli rozbieżności w audycie). Makieta pokazuje stan realny, czyli 20px na poziom.

Dla kogo i za ile

PytanieOdpowiedź
Co się zmienia Klucz grupowania listy obiektów, treść linii pod nazwą obiektu, rząd chipów nad listą, ścieżka w wyniku szukania, komunikat w formularzu i jeden przycisk na karcie klienta.
Co się NIE zmienia Baza, drzewo, uprawnienia, nawigacja, liczba ekranów. Żaden obiekt nie zmienia rodzica. Żadna decyzja z 06.08 nie zostaje odwrócona.
Dla kogo Firma usługowa z kilkoma klientami i kilkudziesięcioma obiektami, czyli dokładnie dzisiejsze 2FSG. Zarządca (Fikołki, Anfil) dostaje ten sam ekran bez chipów i bez nagłówków, bo rejestr klientów ma pusty.
Ile kosztuje Koszt Najtaniej z trzech propozycji. Warstwa 1 to jedna fala na froncie: hooks/useObjects.ts (jeden join), app/(auth)/(tabs)/objects.tsx (klucz grupowania, chipy, ścieżka), app/(auth)/objects/new.tsx (komunikat), EndClientDetailScreen.tsx (przycisk). Warstwa 2 i 3 są opcjonalne i wyceniane osobno, szczegóły w sekcji 9.
Czego nie załatwia Nie daje przenoszenia obiektów w drzewie, nie porządkuje sześciu znaczeń słowa „klient" w nazewnictwie całej aplikacji i nie robi z rejestru Klienci głównego wejścia do pracy. To jest treść propozycji B i C.

02Co powiedział Franek

Pięć wypowiedzi z dwóch dni. Pod każdą jedno zdanie o tym, co z niej wynika dla tej propozycji.

17.08.2026, 22:32 / d17_v223213

„Zastanawiam się, czy to ja źle myślę, czy źle ułożyłem drzewko. Wchodzę dodaj obiekt, dodam obiekt, i ten obiekt mi wchodzi w to drzewko, którego nie chciałem. Wchodzi mi to w główny, a chciałem to przypisać do terenów zewnętrznych."

Wynika z tego defekt D3: nowy obiekt ląduje na liście głównej, a interfejs tego nie mówi ani przed zapisem, ani po nim. To nie jest błąd Franka, tylko brak komunikatu.
17.08.2026, 22:33 / d17_v223336

„Pod obiektami powinno być napisane nazwa obiektu, adres, miasto, i ta lista byłaby taka mega długa i nie byłoby żadnego drzewka."

„Ja bym chciał zrobić tak, że tutaj Benefit System i tu wtedy siłownia, Fabryka Formy Malta, Fabryka Formy Arena, Fabryka Formy coś tam."

To jest dokładnie obrazek z sekcji 1 po prawej stronie: długa lista, na niej nazwa, adres, miasto, a nad grupami nazwa klienta. Propozycja A daje ten obraz bez ruszania drzewa.
17.08.2026, 22:35 / d17_p223547

„Filipa, który miałby to włożyć do trzystu siłowni. Nie wiem, czy to nie będzie łatwiejsze, jeżeli te wszystkie obiekty będą w jednej linii. Chyba że można to zrobić w ten sposób, że jako obiekt nadrzędny wpisywać klienta. Mamy klienta utworzonego, Benefit System albo Lidl, i wtedy robić nie tak jak ja zrobiłem, że utrzymanie terenów zewnętrznych, tylko jako obiekt nadrzędny robimy Lidl."

Pomysł „klient jako obiekt nadrzędny" został już raz rozpatrzony i odrzucony 06.08 przez samego Franka. Propozycja A daje ten sam obraz na ekranie, ale zbudowany na rejestrze klientów, który już istnieje.
17.08.2026, 22:50 / d17_p225036

„Myślę, że ja to zagmatwałem, bo lepiej jest to zrobić jako każdy obiekt po prostu. Czyli wpisujesz obiekty i później możesz je sobie filtrować. Filip może mieć pięćset za chwilę."

To jest jednozdaniowa definicja propozycji A: płaska lista plus filtr. Cała reszta tego dokumentu to opis, gdzie ten filtr ma stać i skąd bierze dane.
19.08.2026, 14:24 / d19_p142424

„Od strony zarządcy mamy temat zamknięty. Tylko później jest ten temat od strony firmy usługowej, czyli tak jak my jesteśmy 2FSG i mamy tych różnych klientów, te obiekty trzeba podzielić. Szukam łatwego sposobu, czy do każdego obiektu trzeba wpisywać klienta czy co?"

Odpowiedź na to pytanie jest trzyczęściowa i ma osobną sekcję 8. Krótko: u zarządcy nie, u firmy usługowej raz przy tworzeniu, a dla obiektów, które już są, masowo na karcie klienta.
06.08.2026, decyzja już podjęta / migracja 20260806090000:4-8

„Klient to nie jest obiekt. Klient to jest dla mnie numerek."

Ta decyzja obowiązuje i żadna z trzech propozycji jej nie odwraca. Utworzenie klienta nie tworzy żadnego obiektu, a objects.end_client_id jest nullowalne.

03Sześć znaczeń słowa „klient"

To jest najważniejsza tabela w całym materiale i jedyny powód, dla którego rozmowa o drzewie jest tak trudna. Słowo „klient" znaczy w Proofixie sześć różnych rzeczy, a napis „Klienci" na pasku nawigacji znaczy co innego u roli owner niż u szefa firmy. Jest dziś

#Nazwa w interfejsieNazwa w kodzieCzym jest naprawdęGdzie to widać
1 Klienci Proofix, Nowy klient Proofix clients z admin_user_id IS NOT NULL Firma najemca, która kupiła Proofixa. Ma limity max_szefs, max_objects, max_object_depth. Panel roli owner, zakładka Klienci
2 Klienci w Zespole u ownera, Dane firmy-klienta w kreatorze clients z admin_user_id IS NULL Klasyczny klient zewnętrzny z modelu sprzed pivotu multi-tenant z 21.04.2026. Model legacy. management.tsx, kreator clients/onboard.tsx
3 Klienci, Karta klienta, Klient (kontrahent) end_clients Klient Twojej firmy, czyli Benefit System albo Lidl. To jest „numerek" Franka i to jest byt, na którym stoi cała propozycja A. /(auth)/klienci, /(klient-admin)/(tabs)/klienci
4 Przedstawiciel klienta w kreatorze, Klient na badge'u profiles.role = 'client' plus wiersz client_users Osoba po stronie klienta: dyrektor, kierownik sklepu, recepcja. Kreator użytkownika, badge roli, stopka sidebara
5 Klient * oraz Klient (opcjonalnie) na jednym ekranie objects.client_id oraz objects.end_client_id Dwa różne pola obiektu pokazane pod tym samym słowem. Pierwsze to firma i granica bezpieczeństwa, drugie to klient i znacznik biznesowy. app/(auth)/objects/new.tsx:507 i :554
6 Szef Klienta na badge'u, Szef firmy na liście Zespół profiles.role = 'klient_admin' Admin firmy najemcy. To w ogóle nie jest klient w żadnym z powyższych znaczeń. UserRoleBadge.tsx:29, szefowie.tsx:36

Siódme, ukryte znaczenie: „Brak klienta"

Defekt objects.client_id jest NOT NULL, więc obiektu bez firmy nie da się zapisać. Interfejs obchodzi to, tworząc sztuczny wiersz w tabeli firm:

.insert({ name: `Brak klienta [tu jest myślnik długi] ${objectName}`, is_internal: true }) w app/(auth)/objects/new.tsx:219-224

Taki wiersz jest odfiltrowany z listy klientów (hooks/useClients.ts:24), nie liczy się do limitu i na karcie obiektu renderuje się jako czyste „Brak klienta". Ale nagłówek sekcji na liście obiektów tej reguły nie stosuje, więc powstaje nagłówek „Brak klienta: Galeria Robakowo (1)". W kodzie separatorem jest tam myślnik długi; w tym dokumencie zastępuje go dwukropek, bo obowiązuje zakaz tego znaku.

Dowód: objects.tsx:60 kontra :99; migracja 20260412000004_internal_client.sql.

Jak z tego wychodzimy w propozycji A

Dokument i interfejs mówią Twoja firma na 2FSG, Klient na Benefit System i Lidla, Przedstawiciel klienta na osobę po stronie klienta. Propozycja A używa wyłącznie znaczenia numer 3, czyli rejestru end_clients. Nie dotyka znaczeń 1, 2 i 6, bo one żyją w panelach, do których szef firmy usługowej i tak nie wchodzi.


04Dlaczego drzewo wyszło dziwnie

Franek nie zbudował złego drzewa. On próbował zbudować jakiekolwiek, bo aplikacja nie pokazywała mu żadnego.

To nie jest zgrabne zdanie, tylko wniosek z trzech faktów z audytu:

  1. Lista obiektów grupuje sekcje po Twojej firmie, nie po kliencie. app/(auth)/(tabs)/objects.tsx:60 bierze (node as any).clients?.name, a hooks/useObjects.ts:31 w ogóle nie pobiera end_client_id. Dla szefa jednego tenantu daje to jedną sekcję z nazwą jego własnej firmy. Defekt
  2. Nazwa klienta nie pojawia się nigdzie poza rejestrem Klienci. Ani na liście obiektów, ani na karcie zlecenia, ani w obecności, ani w raportach. Pełne przeszukanie po app/ i components/ daje 12 plików i żaden z nich to nie jest lista obiektów, zleceń, obecności ani raportów. Defekt
  3. Zero filtrowania po kliencie w całej aplikacji. FilterState w zleceniach ma dokładnie trzy pola: status, priority, objectId (components/ui/FilterBar.tsx:11-27). Defekt

Skoro lista nie pokazywała żadnego podziału, jedynym sposobem, żeby zrobić sobie kategorie, było zrobienie ich z obiektów nadrzędnych. Stąd „utrzymanie terenów zewnętrznych" jako korzeń drzewa.

Reguła, która porządkuje resztę

parent_id znaczy jedno: obiekt fizycznie zawiera się w innym obiekcie. Budynek zawiera piętro. Hala zawiera strefę.

Test: „czy mogę tam wejść i odbić się telefonem o punkt NFC?" TAK, to obiekt. NIE, to cecha obiektu.

  • „Utrzymanie terenów zewnętrznych": nie przechodzi. Nikt się nie odbija o kategorię. To jest cecha, dziś wpisywana w wolne pole service_scope.
  • „Benefit System": nie przechodzi. To firma, nie miejsce. I to jest już w aplikacji rozstrzygnięte decyzją z 06.08: klient to nie obiekt, tylko numerek w rejestrze.
  • „Fabryka Formy Malta": przechodzi. Można tam wejść i odbić kartę.
  • „Strefa cardio": przechodzi, bo mieści się w Malcie i można w niej postawić osobny punkt NFC.

Warto to powiedzieć wprost: pomysł z 22:35, żeby obiektem nadrzędnym był klient, został już raz rozpatrzony i odrzucony 06.08 przez samego Franka. Tryb ?jako=klient został wtedy usunięty (objects/new.tsx:99), a w jego miejsce powstał rejestr end_clients. Propozycja A daje ten sam obraz na ekranie, tylko zbudowany na rejestrze, który już istnieje, a nie na parent_id.

Dlaczego to nie jest kosmetyka

Gdyby klient był obiektem nadrzędnym, to każde odbicie NFC, każde zlecenie i każdy zakres pracownika liczyłyby się po gałęzi, w której siedzi firma. Zmiana klienta oznaczałaby przenoszenie obiektu w drzewie, a tego dziś nie da się zrobić ani z aplikacji, ani bezpiecznie z SQL (brak ochrony przed cyklem, wszystkie triggery głębokości i dziedziczenia firmy są BEFORE INSERT). Rejestr klientów jest znacznikiem, więc zmiana klienta to zmiana jednej kolumny, bez ruszania struktury.


05Pięć rzeczy, które naprawiamy zawsze

Te pięć defektów naprawia każda z trzech propozycji. Różnią się tylko tym, gdzie mieszka klient ze swoimi obiektami. Każdy defekt ma dowód i wskazanie makiety w tym dokumencie, na której go widać.

NrDefektDowódCo robi propozycja AWidać na
D1 Sekcje listy grupują po Twojej firmie, nie po kliencie, a end_client_id nie jest nawet pobierane. Szef jednego tenantu widzi jedną sekcję z nazwą własnej firmy. objects.tsx:60, hooks/useObjects.ts:31 Jeden join do end_clients w hooku i zmiana klucza grupowania. Nazwa klienta ląduje też w linii pod nazwą obiektu. Ekran 1 i 2
D2 Nagłówek sekcji dla obiektu bez klienta brzmi „Brak klienta: Galeria Robakowo (1)", bo nagłówek bierze surową nazwę wiersza firmy, a karta pod nim stosuje is_internal. objects.tsx:60 kontra :99; migracja 20260412000004_internal_client.sql Sekcja „Bez klienta" na dole listy. Sztuczny wiersz przestaje być kiedykolwiek pokazywany użytkownikowi. Ekran 1
D3 Nowy obiekt ląduje na liście głównej i interfejs tego nie mówi. Komunikat to tylko „Obiekt utworzony!", akordeon rodzica jest zwinięty i nie pokazuje wartości domyślnej. CHECKLISTA_PRZEKLIKANIE_2026-08-19.md:521-530, pozycja S2-012, status FAIL; objects/new.tsx:352 Banner nad formularzem mówi wprost, gdzie obiekt wyląduje, pole obiektu nadrzędnego pokazuje wartość domyślną, a komunikat po zapisie wymienia sekcję. Ekran 4
D4 Szukanie gubi hierarchię. Znaleziony pod-obiekt renderuje się jako korzeń, bo buildObjectTree dostaje już przefiltrowaną listę. Przy 500 obiektach wynik nie mówi, gdzie ta rzecz jest. CHECKLISTA_PRZEKLIKANIE_2026-08-19.md:543-551, pozycja S2-014, status FAIL, zrzut przeklik_S2-014.png; objects.tsx:53-54 Wynik szukania niesie ścieżkę do korzenia nad nazwą obiektu. Ekran 5
D5 Na karcie klienta nie ma przycisku „Dodaj obiekt", mimo że oba formularze obiektu obsługują parametr ?endClient=. Jedyny przycisk to „Dodaj przedstawiciela". audyt sekcja 5.1; EndClientDetailScreen.tsx:365-380; objects/new.tsx:123 Przycisk „Dodaj obiekt" w sekcji Obiekty klienta, prowadzący do istniejącego formularza z wypełnionym klientem. Instalacja jest położona, brakuje kontaktu. Ekran 6

Makiety D1 i D2 są już wyżej, w sekcji 1: to jest ta sama para ramek, po lewej z etykietą DEFEKT. D3, D4 i D5 mają swoje pary ramek w sekcji 6.


06Jak to wygląda

Sześć ekranów, każdy w wersji web i mobilnej. Ekran 1 jest w sekcji 1, bo on decyduje o całej propozycji. Tutaj są ekrany od 2 do 6.

Ekran 2. Lista zawężona do jednego klienta

Kliknięcie chipa zawęża listę. Nic się nie chowa i nic nie znika z bazy, zmienia się tylko to, co widać. Chip z nazwą klienta niesie liczbę obiektów w jego gałęzi, więc skala jest widoczna zanim cokolwiek klikniesz.

Obiekty, chip Benefit System włączony Web 1440px Propozycja
Obiekty
Wszyscy klienci
Benefit System 12 ×
Lidl 3
Bez klienta 4
Benefit System (12 obiektów)
Fabryka Formy Malta
Benefit System
ul. Baraniaka 88, Poznań
Sprzątanie codzienne, mycie okien 1x/mies
6 pracowników
Strefa cardio
ul. Baraniaka 88, Poznań
2 pracowników
Strefa siłowni
ul. Baraniaka 88, Poznań
2 pracowników
Szatnie i sanitariaty
ul. Baraniaka 88, Poznań
2 pracowników
Fabryka Formy Arena
Benefit System
ul. Śniadeckich 15, Poznań
4 pracowników
Basen i strefa mokra
ul. Śniadeckich 15, Poznań
2 pracowników
Fabryka Formy Grunwaldzka
Benefit System
ul. Grunwaldzka 104, Poznań
3 pracowników
Fabryka Formy Podolany
Benefit System
ul. Strzeszyńska 262, Poznań
2 pracowników
Fabryka Formy Winogrady
Benefit System
ul. Serbska 7, Poznań
3 pracowników
Fabryka Formy Luboń
Benefit System
ul. Żabikowska 66, Luboń
2 pracowników
Fabryka Formy Swarzędz
Benefit System
ul. Poznańska 27, Swarzędz
2 pracowników
Fabryka Formy Komorniki
Benefit System
ul. Poznańska 60, Komorniki
2 pracowników
1
Chip zawęża listę, a nie chowa danych: obiekty Lidla i te bez klienta nadal są w bazie i wracają po kliknięciu krzyżyka albo chipa „Wszyscy klienci".
2
Zawężenie nie dotyka zakresu uprawnień, więc menedżer i tak widzi tylko to, co dziś: filtr jest w przeglądarce, nad tą samą listą, którą zwraca useMyObjects.
3
Pod-obiekty zostają razem ze swoim obiektem nadrzędnym, bo dziedziczą klienta przez wyliczenie object_effective_end_client_id, a nie przez własny wpis.

Lista jest ucięta krawędzią ramki celowo. Przy dwunastu obiektach Benefit System i tak nie mieści się na jednym ekranie, a to jest jeszcze mała skala wobec tego, o czym mówi Franek.

Ten sam chip na telefonie, przed i po kliknięciu Mobile 390px Propozycja
9:41 . . . .|||100%
Obiekty
Wszyscy klienci
Benefit System 12
Lidl 3
Bez klienta 4
Benefit System (12 obiektów)
Fabryka Formy Malta
Benefit System
ul. Baraniaka 88, Poznań
6 pracowników
Strefa cardio
ul. Baraniaka 88, Poznań
2 pracowników
Strefa siłowni
ul. Baraniaka 88, Poznań
2 pracowników
Szatnie i sanitariaty
ul. Baraniaka 88, Poznań
2 pracowników
Fabryka Formy Arena
Benefit System
ul. Śniadeckich 15, Poznań
4 pracowników
Basen i strefa mokra
ul. Śniadeckich 15, Poznań
2 pracowników
Fabryka Formy Grunwaldzka
Benefit System
ul. Grunwaldzka 104, Poznań
3 pracowników
9:41 . . . .|||100%
Obiekty
Wszyscy klienci
Lidl 3 ×
Benefit System 12
Bez klienta 4
Lidl (3 obiekty)
Lidl Poznań Dębiec
Lidl
ul. 28 Czerwca 1956 r. 223, Poznań
2 pracowników
Lidl Poznań Naramowice
Lidl
ul. Naramowicka 154, Poznań
2 pracowników
Lidl Swarzędz
Lidl
ul. Cieszkowskiego 4, Swarzędz
1 pracowników
1
Po lewej stan wyjściowy, po prawej ten sam ekran po kliknięciu chipa Lidl: wybrany chip przeskakuje na początek rzędu, żeby na wąskim ekranie był widoczny bez przewijania.
2
Przy krótkiej liście pod spodem staje banner z liczbą widocznych obiektów, żeby nikt nie pomyślał, że reszta zniknęła. To jedyny nowy element mobilny w tej propozycji.

Ekran 3. Zarządca: rejestr klientów jest pusty, więc chipy znikają same

Fikołki to persona zarządcy: firma sprząta własne obiekty i nie ma żadnych klientów w rejestrze. Wtedy grupowanie po kliencie nie ma czego pokazać. Aplikacja sama wybiera stronę: kiedy rejestr klientów jest pusty, rząd chipów i nagłówki sekcji po prostu się nie renderują, a ekran jest zwykłą płaską listą. Franek nie musi niczego ustawiać ani wybierać trybu.

Obiekty u zarządcy, zero klientów w rejestrze Web 1440px Propozycja
Obiekty
Fikołki Poznań Górczyn
ul. Ptasia 10, Poznań
Sprzątanie codzienne po zamknięciu
4 pracowników
Sala zabaw
ul. Ptasia 10, Poznań
2 pracowników
Kuchnia i zaplecze
ul. Ptasia 10, Poznań
1 pracowników
Toalety i szatnia
ul. Ptasia 10, Poznań
1 pracowników
Fikołki Stary Browar
ul. Półwiejska 42, Poznań
3 pracowników
Sala zabaw
ul. Półwiejska 42, Poznań
2 pracowników
Zaplecze i biuro
ul. Półwiejska 42, Poznań
1 pracowników
Fikołki Wrocław Krzyki
ul. Powstańców Śląskich 95, Wrocław
3 pracowników
Sala zabaw
ul. Powstańców Śląskich 95, Wrocław
2 pracowników
Parking i teren zewnętrzny
ul. Powstańców Śląskich 95, Wrocław
1 pracowników
Fikołki Poznań Malta
ul. Baraniaka 8, Poznań
2 pracowników
1
Nie ma chipów i nie ma nagłówków sekcji, bo rejestr klientów jest pusty; to jest ten sam kod ekranu, tylko z zerową liczbą grup.
2
Nie ma też linii z nazwą firmy pod nazwą obiektu, bo u zarządcy powtarzałaby ona własną nazwę przy każdej pozycji, dokładnie tak jak dziś w 2FSG.
3
Zakładka Klienci zostaje w nawigacji z pustym stanem, który już istnieje w kodzie (EndClientListScreen.tsx:55-66): żadna rola niczego nie traci, a zarządca może kiedyś dodać pierwszego klienta i chipy pojawią się same.
Zarządca na telefonie: dziś kontra po zmianie Mobile 390px Jest dziś Propozycja
9:41 . . . .|||100%
Obiekty
Fikołki Sp. z o.o. (4)
Fikołki Poznań Górczyn
Fikołki Sp. z o.o.
ul. Ptasia 10, Poznań
4 pracowników
Sala zabaw
ul. Ptasia 10, Poznań
2 pracowników
Kuchnia i zaplecze
ul. Ptasia 10, Poznań
1 pracowników
Toalety i szatnia
ul. Ptasia 10, Poznań
1 pracowników
Fikołki Stary Browar
Fikołki Sp. z o.o.
ul. Półwiejska 42, Poznań
3 pracowników
Sala zabaw
ul. Półwiejska 42, Poznań
2 pracowników
Zaplecze i biuro
ul. Półwiejska 42, Poznań
1 pracowników
9:41 . . . .|||100%
Obiekty
Fikołki Poznań Górczyn
ul. Ptasia 10, Poznań
4 pracowników
Sala zabaw
ul. Ptasia 10, Poznań
2 pracowników
Kuchnia i zaplecze
ul. Ptasia 10, Poznań
1 pracowników
Toalety i szatnia
ul. Ptasia 10, Poznań
1 pracowników
Fikołki Stary Browar
ul. Półwiejska 42, Poznań
3 pracowników
Sala zabaw
ul. Półwiejska 42, Poznań
2 pracowników
Zaplecze i biuro
ul. Półwiejska 42, Poznań
1 pracowników
Fikołki Wrocław Krzyki
ul. Powstańców Śląskich 95, Wrocław
3 pracowników
1
Po lewej stan dzisiejszy u zarządcy: jeden nagłówek „Fikołki Sp. z o.o. (4)" i pod każdą nazwą obiektu powtórzona ta sama nazwa własnej firmy, czyli dwie linie pikseli bez treści (objects.tsx:60, :97-101).
2
Po prawej ten sam ekran po zmianie: nagłówek i linia firmy znikają, więc na tej samej wysokości ekranu mieści się o jeden obiekt więcej.
3
To jest dowód, że jeden ekran obsługuje obie persony bez przełącznika i bez ustawienia: decyduje zawartość rejestru klientów, a nie wybór Franka.

Ekran 4. Formularz mówi, gdzie obiekt wyląduje (naprawa D3)

To jest ekran, na którym Franek stracił zaufanie do drzewa o 22:32. Obiekt trafił na listę główną, bo formularz w trybie korzeniowym tak działa, ale nie powiedział o tym ani przed zapisem, ani po. Naprawa jest czysto tekstowa: banner nad polami, widoczna wartość domyślna pola nadrzędnego i komunikat po zapisie, który nazywa miejsce.

Nowy obiekt, komunikat przed zapisem Web 1440px Propozycja
Nowy obiekt
Nazwa obiektu * Fabryka Formy Podolany
Obiekt nadrzędny Lista główna, bez obiektu nadrzędnego
Zmień tylko wtedy, gdy ten obiekt fizycznie mieści się w innym obiekcie.
Klient (opcjonalnie)

Obiekt możesz przypisać klientowi teraz lub później (na karcie klienta w Klienci). Pod-obiekty dziedziczą klienta automatycznie.

Bez klienta
Benefit System
Lidl
Adres ul. Strzeszyńska 262
Miasto Poznań
Zakres usług np. sprzątanie codzienne, mycie okien
Utwórz obiekt
1
Banner nazywa miejsce, zanim cokolwiek zostanie zapisane; to jest cała naprawa defektu D3, bo dziś ten sam formularz milczy (CHECKLISTA_PRZEKLIKANIE_2026-08-19.md:521-530, S2-012 FAIL).
2
Pole obiektu nadrzędnego pokazuje wartość domyślną zamiast zwiniętego akordeonu bez treści, więc widać wybór, a nie jego brak.
3
Lista klientów pod spodem to ta sama kontrolka co dziś (objects/new.tsx:554-577) i ten sam tekst pomocniczy; propozycja nic tu nie dokłada, bo to już działa.

Świadomie nie ma tu przycisku „Zmień" przy komunikacie po zapisie. Przeniesienia obiektu w drzewie dziś nie ma: brak kontrolki, brak RPC, brak ochrony przed cyklem, a triggery głębokości i dziedziczenia firmy są BEFORE INSERT. Obiecywanie takiego przycisku byłoby obietnicą bez pokrycia.

Ten sam formularz na telefonie: dziś kontra po zmianie Mobile 390px Defekt Propozycja
9:41 . . . .|||100%
Nowy obiekt
Nazwa obiektu * Fabryka Formy Podolany
Obiekt nadrzędny
Klient (opcjonalnie)
Bez klienta
Benefit System
Lidl
Adres ul. Strzeszyńska 262
Miasto Poznań
Utwórz obiekt
9:41 . . . .|||100%
Nowy obiekt
Nazwa obiektu * Fabryka Formy Podolany
Obiekt nadrzędny Lista główna, bez obiektu nadrzędnego
Zmień tylko wtedy, gdy ten obiekt fizycznie mieści się w innym obiekcie.
Klient (opcjonalnie)
Bez klienta
Benefit System
Lidl
Adres ul. Strzeszyńska 262
Utwórz obiekt
Obiekt utworzony na liście głównej, sekcja Benefit System.
1
Po lewej stan dzisiejszy: akordeon „Obiekt nadrzędny" jest zwinięty i nie pokazuje wartości domyślnej, więc formularz nie mówi, że obiekt idzie na listę główną (objects/new.tsx, pozycja S2-012 z przeklikania).
2
Po prawej ta sama ścieżka po zmianie; dla oszczędności miejsca w jednej ramce pokazany jest i komunikat przed zapisem (banner), i komunikat po zapisie (pasek na dole), które w aplikacji pojawiają się jeden po drugim.
3
Komunikat po zapisie wymienia sekcję, w której obiekt się znajdzie, czyli to samo słowo, którego Franek szuka potem na liście; dziś w panelu firmy usługowej komunikat to samo „Obiekt utworzony!" (objects/new.tsx:352).

Ekran 5. Wynik szukania niesie ścieżkę (naprawa D4)

Ten ekran jest pokazany na personie Filipa z Anfila, czyli na skali, o którą Franek pyta: kilkaset obiektów, po kilka pod-obiektów w każdym. Szukanie „cardio" znajduje pod-obiekty w kilkunastu siłowniach naraz. Dziś wszystkie wyglądają identycznie, bo znaleziony pod-obiekt renderuje się jako korzeń i nie ma przy nim żadnej informacji o tym, gdzie leży.

Szukanie „cardio" u Anfila, wynik ze ścieżką Web 1440px Propozycja
Obiekty
Anfil Poznań Rataje Strefa cardio
Strefa cardio
ul. Piłsudskiego 4, Poznań
2 pracowników
Anfil Poznań Winogrady Parter Strefa cardio
Strefa cardio
ul. Serbska 7, Poznań
1 pracowników
Anfil Poznań Grunwald Strefa cardio
Strefa cardio
ul. Bukowska 12, Poznań
2 pracowników
Anfil Wrocław Krzyki Strefa cardio
Strefa cardio
ul. Powstańców Śląskich 95, Wrocław
2 pracowników
Anfil Wrocław Psie Pole Strefa cardio
Strefa cardio
ul. Krzywoustego 40, Wrocław
1 pracowników
Anfil Kraków Podgórze Strefa cardio
Strefa cardio
ul. Kalwaryjska 66, Kraków
2 pracowników
Anfil Gdańsk Przymorze Strefa cardio
Strefa cardio
al. Grunwaldzka 411, Gdańsk
2 pracowników
Anfil Katowice Centrum Strefa cardio
Strefa cardio
ul. Chorzowska 107, Katowice
1 pracowników
Anfil Łódź Widzew Strefa cardio
Strefa cardio
ul. Rokicińska 8, Łódź
2 pracowników
Anfil Szczecin Pogodno Strefa cardio
Strefa cardio
ul. Mickiewicza 45, Szczecin
1 pracowników
1
Ścieżka nad nazwą jest liczona z tych samych danych, które lista już ma w pamięci (parent_id plus buildObjectTree), więc nie wymaga ani nowego zapytania, ani nowej kolumny.
2
Wynik zostaje płaski i nie udaje drzewa, bo przy szukaniu drzewo i tak jest niepełne; ścieżka zastępuje wcięcie i mówi to samo, tylko słowami.

Skala na tej makiecie to skala, o której mówi Franek (Filip, 300 do 500 siłowni), a nie stan bazy z 18.08.2026. W bazie jest dziś 28 obiektów, 12 z rodzicem i maksymalna głębokość 2 (audyt sekcja 9.12).

To samo szukanie na telefonie: dziś kontra po zmianie Mobile 390px Defekt Propozycja
9:41 . . . .|||100%
Obiekty
Anfil Sp. z o.o. (10)
Strefa cardio
Anfil Sp. z o.o.
ul. Piłsudskiego 4, Poznań
2 pracowników
Strefa cardio
Anfil Sp. z o.o.
ul. Serbska 7, Poznań
1 pracowników
Strefa cardio
Anfil Sp. z o.o.
ul. Bukowska 12, Poznań
2 pracowników
Strefa cardio
Anfil Sp. z o.o.
ul. Powstańców Śląskich 95, Wrocław
2 pracowników
Strefa cardio
Anfil Sp. z o.o.
ul. Krzywoustego 40, Wrocław
1 pracowników
Strefa cardio
Anfil Sp. z o.o.
ul. Kalwaryjska 66, Kraków
2 pracowników
9:41 . . . .|||100%
Obiekty
Anfil Poznań Rataje Strefa cardio
Strefa cardio
ul. Piłsudskiego 4, Poznań
2 pracowników
Anfil Poznań Winogrady Parter Strefa cardio
Strefa cardio
ul. Serbska 7, Poznań
1 pracowników
Anfil Poznań Grunwald Strefa cardio
Strefa cardio
ul. Bukowska 12, Poznań
2 pracowników
Anfil Wrocław Krzyki Strefa cardio
Strefa cardio
ul. Powstańców Śląskich 95, Wrocław
2 pracowników
Anfil Wrocław Psie Pole Strefa cardio
Strefa cardio
ul. Krzywoustego 40, Wrocław
1 pracowników
1
Po lewej stan dzisiejszy: sześć identycznych kart „Strefa cardio", każda z nazwą własnej firmy pod spodem, i jedyna różnica to adres; znaleziony pod-obiekt jest rysowany jako korzeń, bo drzewo buduje się z już przefiltrowanej listy (objects.tsx:53-54, S2-014 FAIL).
2
Po prawej ta sama lista ze ścieżką; przy dwóch poziomach zagnieżdżenia ścieżka pokazuje oba, więc widać nie tylko siłownię, ale i piętro.

Ekran 6. Karta klienta z przyciskiem „Dodaj obiekt" (naprawa D5)

Na karcie klienta jest dziś sekcja Obiekty klienta z pickerem, który pozwala masowo zaznaczyć istniejące obiekty. Nie ma za to żadnego sposobu, żeby stamtąd utworzyć nowy obiekt, mimo że oba formularze obiektu obsługują już parametr ?endClient= i robią preselect klienta. Brakuje jednego przycisku.

Karta klienta Benefit System Web 1440px Propozycja
Benefit System
Dane klienta
Nazwa klienta * Benefit System
Adres pl. Europejski 2
Miasto Warszawa
Obiekty klienta Dodaj obiekt

Zaznacz istniejące obiekty, które należą do tego klienta. Pod-obiekty zaznaczonego obiektu dziedziczą klienta automatycznie. Nowy obiekt możesz utworzyć od razu stąd przyciskiem „Dodaj obiekt".

Fabryka Formy Malta
Strefa cardio
dziedziczy z gałęzi
Strefa siłowni
dziedziczy z gałęzi
Szatnie i sanitariaty
dziedziczy z gałęzi
Fabryka Formy Arena
Basen i strefa mokra
dziedziczy z gałęzi
Fabryka Formy Grunwaldzka
Fabryka Formy Podolany
Fabryka Formy Winogrady
Lidl Poznań Dębiec
inny klient
Galeria Robakowo
Student Depot Polonez
Przedstawiciele klienta
Anna Kowalczyk
Dyrektor
Dodaj przedstawiciela
Zapisz zmiany
1
Jedyna nowa rzecz na tym ekranie to przycisk „Dodaj obiekt": prowadzi do istniejącego formularza z parametrem ?endClient=, który obsługują dziś oba formularze obiektu (objects/new.tsx:123), tylko nic tam nie nawiguje.
2
Pod-obiekty są tu pokazane jako dziedziczące gałąź i zablokowane, bo trigger integralności i tak nie pozwoli dać im innego klienta niż ma najbliższy otagowany przodek (migracja 20260807103000, błąd 23514); dziś picker ich nie blokuje i nie oznacza, choć powinien.
3
Notka nad listą zostaje w treści, którą aplikacja już ma, bo mówi prawdę: lista pokazuje wyłącznie obiekty z zakresu zalogowanego, a klient może mieć obiekty przypisane przez administratora firmy.
Karta klienta na telefonie: dziś kontra po zmianie Mobile 390px Defekt Propozycja
9:41 . . . .|||100%
Benefit System
Dane klienta
Nazwa klienta * Benefit System
Miasto Warszawa
Obiekty klienta
Fabryka Formy Malta
Strefa cardio
Strefa siłowni
Szatnie i sanitariaty
Fabryka Formy Arena
Basen i strefa mokra
Galeria Robakowo
Przedstawiciele klienta
Anna Kowalczyk
Dyrektor
Dodaj przedstawiciela
9:41 . . . .|||100%
Benefit System
Dane klienta
Nazwa klienta * Benefit System
Miasto Warszawa
Obiekty klienta Dodaj obiekt
Fabryka Formy Malta
Strefa cardio
dziedziczy z gałęzi
Strefa siłowni
dziedziczy z gałęzi
Szatnie i sanitariaty
dziedziczy z gałęzi
Fabryka Formy Arena
Basen i strefa mokra
dziedziczy z gałęzi
Galeria Robakowo
Przedstawiciele klienta
Anna Kowalczyk
Dyrektor
Dodaj przedstawiciela
1
Po lewej stan dzisiejszy: jedyny przycisk na tej karcie to „Dodaj przedstawiciela" (EndClientDetailScreen.tsx:365-380), a pod-obiekty w pickerze są zwykłymi, odznaczalnymi pozycjami, mimo że zapis na nich i tak odbije się na całej gałęzi.
2
Po prawej dochodzi „Dodaj obiekt" i oznaczenie dziedziczenia; to są dwie zmiany w jednym pliku komponentu, bez ruszania bazy.

07Dwie persony na jednym ekranie

Franek sam nazwał przyczynę całego zamieszania 17.08 o 22:48: „Patrzę sobie od dwóch stron. Czy to weźmie zarządca, czy weźmie ta firma usługowa. I to jest największy błąd w tej sytuacji." Propozycja A nie każe wybierać. Ten sam ekran obsługuje obie persony, a o tym, którą wersję widzisz, decyduje zawartość rejestru klientów.

Zarządca: Fikołki, Anfil

Sprząta własne obiekty. Rejestr klientów pusty.

  • Brak chipów nad listą.
  • Brak nagłówków sekcji.
  • Brak linii z nazwą firmy pod nazwą obiektu.
  • Płaska lista z nazwą, adresem, miastem i liczbą pracowników, czyli dokładnie to, o co Franek prosił o 22:33.
  • Pole „Klient (opcjonalnie)" w formularzu nowego obiektu jest puste i nie przeszkadza; można je pominąć.
  • Zakładka Klienci zostaje z pustym stanem, który już istnieje w kodzie.

Firma usługowa: 2FSG

Sprząta u swoich klientów. Rejestr klientów wypełniony.

  • Rząd chipów nad listą, po jednym na klienta plus „Bez klienta".
  • Sekcje nazwane klientem, sekcja „Bez klienta" na końcu.
  • Nazwa klienta w linii pod nazwą obiektu.
  • Ścieżka w wyniku szukania.
  • Przycisk „Dodaj obiekt" na karcie klienta.
  • Wszystko to znika samo w dniu, w którym rejestr klientów byłby pusty.
Element ekranuZarządca (rejestr pusty)Firma usługowa (rejestr wypełniony)
Chipy klientów nad listąnie renderują sięrenderują się, z licznikami
Nagłówki sekcjibrak, jedna płaska listapo jednym na klienta plus „Bez klienta"
Linia pod nazwą obiektubraknazwa klienta
Wcięcie pod-obiektówbez zmianbez zmian
Pole klienta w formularzuwidoczne, puste, opcjonalnewidoczne, z podpowiedzią ostatnio używanego
Przycisk „Dodaj obiekt" na karcie klientabez znaczenia, nie ma klientówtak

Uwaga uczciwa: decyzja W9 z audytu (kto jest gospodarzem aplikacji: firma usługowa czy zarządca) wracała trzy razy przez 13 dni i brzmi tak: wariantu zarządcy nie budujemy teraz, ale nie wolno niczego zahardcodować tak, żeby go zamknąć. Propozycja A tego nie łamie, bo nie wprowadza żadnego trybu ani przełącznika, tylko reaguje na dane.


08Odpowiedź na pytanie z 19.08

19.08.2026, 14:24 / d19_p142424

„Szukam łatwego sposobu, czy do każdego obiektu trzeba wpisywać klienta czy co?"

Odpowiedź jest trzyczęściowa, bo pytanie dotyczy trzech różnych sytuacji.

1. U zarządcy: NIE, w ogóle

Rejestr klientów jest pusty, więc pole nie ma czego zaproponować, a lista nie ma czego grupować. Fikołki i Anfil nigdy nie wpisują klienta. Propozycja

2. U firmy usługowej, nowe obiekty: TAK, raz, przy tworzeniu

Jedno kliknięcie w formularzu, na obiekcie korzeniowym. Pod-obiekty klienta nie dostają, bo dziedziczą go z gałęzi przez wyliczenie object_effective_end_client_id. Czyli wpisujesz klienta na budynku, nie na piętrze. Jest dziś (pole istnieje, objects/new.tsx:554) Propozycja (podpowiedź ostatnio używanego klienta i wejście z karty klienta)

3. U firmy usługowej, obiekty, które już są: masowo, na karcie klienta

To już istnieje i działa. Na karcie klienta jest picker, który pokazuje pełne drzewo i zapisuje dwoma masowymi operacjami naraz. To jedyna ścieżka w całej aplikacji, która pozwala otagować także pod-obiekt. Franek nie musi otwierać kilkunastu obiektów po kolei, tylko raz zaznacza listę. Jest dziś (EndClientDetailScreen.tsx:311-317, hooks/useEndClients.ts:180-214)

Jeszcze krócej: klienta wpisuje się raz na gałąź, nie raz na obiekt. Przy dwunastu siłowniach Benefit System to dwanaście kliknięć w pickerze albo dwanaście razy jedno kliknięcie w formularzu. Nie ma trzeciej drogi, w której aplikacja zgadnie klienta sama, bo nazwa obiektu nie mówi nic o tym, kto za niego płaci.


09Co to kosztuje

Trzy warstwy. Warstwa 1 to cała propozycja A i tylko ona jest potrzebna, żeby lista zaczęła cokolwiek mówić. Warstwy 2 i 3 są osobnymi decyzjami z osobną ceną.

Warstwa 1: sam widok Koszt mały

PozycjaPlikNa czym stoi
Join do rejestru klientów w liście obiektów hooks/useObjects.ts:31 Dziś zapytanie pobiera clients(name, rate_enabled, is_internal) i nie pobiera end_client_id. Dochodzi jedno pole i jeden join.
Zmiana klucza grupowania i treści linii pod nazwą app/(auth)/(tabs)/objects.tsx:53-69, :97-101 SectionList i buildObjectTree już są; zmienia się to, po czym liczy się klucz grupy. Sekcja „Bez klienta" zamiast surowej nazwy sztucznego wiersza.
Rząd chipów nad listą app/(auth)/(tabs)/objects.tsx Nowy element, ale filtrowanie odbywa się na już pobranej liście, tak samo jak dzisiejsze szukanie po nazwie i adresie.
Ścieżka w wyniku szukania app/(auth)/(tabs)/objects.tsx:41-54 Ścieżkę można policzyć z parent_id, które lista już ma; dziś przepada, bo drzewo buduje się z przefiltrowanej listy.
Komunikaty w formularzu obiektu app/(auth)/objects/new.tsx Banner, widoczna wartość domyślna pola nadrzędnego i tekst komunikatu po zapisie. Zero zmian w zapisie.
Przycisk „Dodaj obiekt" na karcie klienta components/endclients/EndClientDetailScreen.tsx Nawigacja do istniejącego formularza z parametrem ?endClient=, który jest już obsługiwany.
Blokada i oznaczenie dziedziczących pod-obiektów w pickerze components/ui/ObjectMultiPicker.tsx, wywołanie w EndClientDetailScreen.tsx:311 Komponent ma już propy inheritFromAncestors i cascadeDescendants, tylko nie są tu podane. To jest przekazanie dwóch propów, nie nowa funkcja.

Cała warstwa 1 to jedna fala na froncie, cztery pliki plus jeden hook. Żadnej migracji, żadnej zmiany polityk RLS, żadnej zmiany w danych.

Warstwa 2: dane i serwer Koszt średni, do decyzji

PozycjaDlaczego to kosztuje
Licznik obiektów klienta liczony na serwerze Dziś liczy się w przeglądarce z zakresu zalogowanego (EndClientListScreen.tsx:75, lib/utils.ts:258-279), więc dwóch menedżerów widzi dla tego samego klienta różne liczby. Funkcja SQL get_end_client_object_closure nie istnieje: sprawdzone przeszukaniem całego repozytorium. Jeśli liczby przy chipach mają być wiążące, trzeba ją napisać.
Filtr po kliencie w zleceniach Tabela zleceń nie ma kolumny klienta, orders.object_id jest NOT NULL. Filtr wymaga joina przez obiekt. Poza zakresem propozycji A, wyceniane osobno.
Opcja dodatkowa: grupowanie po rodzaju usługi service_scope to wolny tekst: bez słownika, bez CHECK, bez klucza obcego, bez indeksu i bez ani jednego miejsca w kodzie, które po nim filtruje, grupuje albo sortuje (audyt 9.4). Grupowanie po nim wymaga nowego pola słownikowego, migracji, pola w formularzu, filtru i przepisania istniejących wpisów. To jest osobna pozycja z osobną ceną, a nie część propozycji A.

Warstwa 3: osobna fala z testem PRZED i PO Koszt duży, nie teraz

Przepięcie obiektów, które dziś siedzą pod korzeniami-kategoriami w rodzaju „utrzymanie terenów zewnętrznych", wymaga zmiany parent_id. Dziś nie ma na to ani kontrolki, ani RPC, a sama ścieżka jest nieosłonięta: trigger dziedziczenia firmy, kontrola głębokości i limit liczby obiektów są BEFORE INSERT, ochrony przed cyklem nie ma w ogóle, a trigger integralności klienta milczy, gdy przenoszony obiekt ma pusty znacznik. To zawsze osobna fala z pomiarem przed i po, nigdy „jedna linia".

Ważne: propozycja A nie potrzebuje warstwy 3, żeby zadziałać. Stare korzenie-kategorie zostają tam, gdzie są, a lista i tak zaczyna grupować po kliencie. Warstwa 3 tylko sprząta historię.


10Czego to NIE robi

Uczciwe granice. Każda pozycja to rzecz, której po tej zmianie nadal nie będzie.

  1. Nie daje przenoszenia obiektu w drzewie. Nie ma kontrolki, nie ma RPC, nie ma ochrony przed cyklem, a triggery głębokości, limitu i dziedziczenia firmy są BEFORE INSERT. Dlatego na makiecie formularza nie ma przycisku „Zmień" przy komunikacie po zapisie.
  2. Nie pozwala ustawić klienta na pod-obiekcie z formularza. Klienta ustawia się z interfejsu tylko na obiekcie korzeniowym (new.tsx:283, [id].tsx:238). Jedyny wyjątek to picker na karcie klienta i on zostaje jedynym wyjątkiem.
  3. Nie zmienia niczego w uprawnieniach. Są dwa rozłączne tory liczenia zakresu: role firmowe po parent_id, przedstawiciel klienta po znaczniku klienta. Propozycja A dotyka wyłącznie warstwy widoku i nie miesza tych torów. Zakaz z nagłówka migracji 20260807210000 zostaje nienaruszony.
  4. Nie robi z liczb przy chipach liczb wiążących. Dopóki licznik liczy się w przeglądarce z zakresu zalogowanego, dwóch menedżerów zobaczy dla tego samego klienta różne liczby. Notka o tym jest dziś na karcie klienta, ale nie na liście, i tak zostaje do czasu warstwy 2.
  5. Nie grupuje po rodzaju usługi. service_scope to wolny tekst bez słownika i bez ani jednego miejsca, które po nim filtruje. Grupowanie i nawigacja po nim to osobna, wyceniona opcja dodatkowa, nie część tej propozycji.
  6. Nie daje przedstawicielowi klienta listy obiektów. Rola client nadal nie ma własnej listy ani karty obiektu i widzi swoje obiekty tylko przez obecność i patrole.
  7. Nie porządkuje sześciu znaczeń słowa „klient" w całej aplikacji. Napis „Klienci" u roli owner nadal znaczy co innego niż u szefa firmy, a ekran „Uprawnienia klientów" nadal operuje na tabeli firm, nie na rejestrze klientów.
  8. Nie filtruje po kliencie w zleceniach, obecności ani raportach. Zmiana dotyczy listy obiektów i karty klienta. Zlecenia nie mają nawet kolumny klienta.
  9. Nie odwraca żadnej decyzji z 06.08. Klient dalej nie jest obiektem, utworzenie klienta dalej nie tworzy żadnego obiektu, a znacznik klienta dalej jest nullowalny.

11Co to odblokowuje

Ten sam join, którym lista obiektów dostaje nazwę klienta, jest jedynym brakującym elementem w kilku innych miejscach. Gdy nazwa klienta raz pojawi się w danych ekranu, można ją potem pokazać na karcie zlecenia, w nagłówku raportu i w widoku obecności, bez żadnej nowej kolumny w bazie. Domyka się przy tym rzecz, która dziś wygląda jak przeoczenie: przedstawiciel klienta nie widzi nigdzie nazwy klienta, którego reprezentuje, mimo że kolumna end_client_id fizycznie przychodzi do aplikacji w useMyClientUser przez select('*'), tylko nie jest zadeklarowana w typie i nikt jej nie renderuje. To jest jedno pole tekstowe w nagłówku jego pulpitu.

Drugą rzeczą, którą to otwiera, jest rozmowa handlowa z wątku z 19.08 o 15:17: skoro klient jest w systemie osobnym bytem z własnymi obiektami i własnymi przedstawicielami, to w przyszłości mógłby kupić Proofixa na swoje pozostałe obiekty, te, których 2FSG nie sprząta. To jest decyzja handlowa do podjęcia później i nic w propozycji A jej nie przesądza, ale też nic jej nie zamyka.


12Na czym to jest oparte

ŹródłoCo z niego pochodzi
AUDYT_KLIENT_OBIEKTY.md, 19.08.2026, HEAD 5bed4adWszystkie twierdzenia o stanie dzisiejszym: sześć znaczeń słowa klient, model danych, dwa tory zakresu, twarde ograniczenia, luki.
CHECKLISTA_PRZEKLIKANIE_2026-08-19.md oraz WYNIKI_PRZEKLIKANIE_2026-08-19.mdDefekty D3 (pozycja S2-012) i D4 (pozycja S2-014), oba ze statusem FAIL.
zrzuty_przeklikanie_2026-08-19/przeklik_S2-013.pngWzorzec wyglądu listy obiektów na web: układ, karty, wcięcia, nagłówek sekcji, sidebar.
Zrzut schematu db_schema_2026-08-18_pre_fala_z2z8.sql plus trzy późniejsze migracjeKolumny, klucze obce, triggery i to, czego w bazie nie ma.
Nagrania Franka z 17.08 i 19.08Cytaty w sekcji 2, z datą i godziną.

Nic z tego nie jest wdrożone. Wszystko, co ma etykietę PROPOZYCJA, istnieje wyłącznie na tych makietach. Etykiety JEST DZIŚ i DEFEKT opisują stan aplikacji z 19.08.2026 i mają dowód przy sobie. Wybór między propozycją A, B i C należy do Franka i żadna z nich nie jest lepsza z definicji: A jest najtańsza i naprawia listę, B robi z klienta wejście do pracy, C odpowiada na skalę Filipa.