Propozycja A z trzech / 19.08.2026 / do wyboru
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.
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.
is_internal i pisze poprawnie „Brak klienta" (objects.tsx:60 kontra :99).objects.tsx:60, :97-101).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.
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.
| Pytanie | Odpowiedź |
|---|---|
| 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. |
Pięć wypowiedzi z dwóch dni. Pod każdą jedno zdanie o tym, co z niej wynika dla tej propozycji.
„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."
„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."
„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."
„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ę."
„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?"
„Klient to nie jest obiekt. Klient to jest dla mnie numerek."
objects.end_client_id jest nullowalne.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 interfejsie | Nazwa w kodzie | Czym 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 |
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.
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.
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:
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. Defektapp/ i components/ daje 12 plików i żaden z nich to nie jest lista obiektów, zleceń, obecności ani raportów. DefektFilterState w zleceniach ma dokładnie trzy pola: status, priority, objectId (components/ui/FilterBar.tsx:11-27). DefektSkoro 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.
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.
service_scope.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.
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.
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ć.
| Nr | Defekt | Dowód | Co robi propozycja A | Widać 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.
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.
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.
useMyObjects.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.
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.
EndClientListScreen.tsx:55-66): żadna rola niczego nie traci, a zarządca może kiedyś dodać pierwszego klienta i chipy pojawią się same.objects.tsx:60, :97-101).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.
Obiekt możesz przypisać klientowi teraz lub później (na karcie klienta w Klienci). Pod-obiekty dziedziczą klienta automatycznie.
CHECKLISTA_PRZEKLIKANIE_2026-08-19.md:521-530, S2-012 FAIL).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.
objects/new.tsx, pozycja S2-012 z przeklikania).objects/new.tsx:352).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.
parent_id plus buildObjectTree), więc nie wymaga ani nowego zapytania, ani nowej kolumny.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).
objects.tsx:53-54, S2-014 FAIL).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.
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".
?endClient=, który obsługują dziś oba formularze obiektu (objects/new.tsx:123), tylko nic tam nie nawiguje.20260807103000, błąd 23514); dziś picker ich nie blokuje i nie oznacza, choć powinien.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.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.
Sprząta własne obiekty. Rejestr klientów pusty.
Sprząta u swoich klientów. Rejestr klientów wypełniony.
| Element ekranu | Zarządca (rejestr pusty) | Firma usługowa (rejestr wypełniony) |
|---|---|---|
| Chipy klientów nad listą | nie renderują się | renderują się, z licznikami |
| Nagłówki sekcji | brak, jedna płaska lista | po jednym na klienta plus „Bez klienta" |
| Linia pod nazwą obiektu | brak | nazwa klienta |
| Wcięcie pod-obiektów | bez zmian | bez zmian |
| Pole klienta w formularzu | widoczne, puste, opcjonalne | widoczne, z podpowiedzią ostatnio używanego |
| Przycisk „Dodaj obiekt" na karcie klienta | bez znaczenia, nie ma klientów | tak |
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.
„Szukam łatwego sposobu, czy do każdego obiektu trzeba wpisywać klienta czy co?"
Odpowiedź jest trzyczęściowa, bo pytanie dotyczy trzech różnych sytuacji.
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
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)
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.
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ą.
| Pozycja | Plik | Na 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.
| Pozycja | Dlaczego 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. |
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ę.
Uczciwe granice. Każda pozycja to rzecz, której po tej zmianie nadal nie będzie.
new.tsx:283, [id].tsx:238). Jedyny wyjątek to picker na karcie klienta i on zostaje jedynym wyjątkiem.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.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.client nadal nie ma własnej listy ani karty obiektu i widzi swoje obiekty tylko przez obecność i patrole.owner nadal znaczy co innego niż u szefa firmy, a ekran „Uprawnienia klientów" nadal operuje na tabeli firm, nie na rejestrze klientów.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.
| Źródło | Co z niego pochodzi |
|---|---|
AUDYT_KLIENT_OBIEKTY.md, 19.08.2026, HEAD 5bed4ad | Wszystkie 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.md | Defekty D3 (pozycja S2-012) i D4 (pozycja S2-014), oba ze statusem FAIL. |
zrzuty_przeklikanie_2026-08-19/przeklik_S2-013.png | Wzorzec 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 migracje | Kolumny, klucze obce, triggery i to, czego w bazie nie ma. |
| Nagrania Franka z 17.08 i 19.08 | Cytaty 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.