# Quality Risks ## Post-apply 20260712-1647 - **Obsłużone:** osobne tokeny urządzeń, hash walidatora, `hash_equals`, selektywne wylogowanie. - **Obsłużone operacyjnie:** tabela utworzona na zdalnej bazie po wykryciu błędu braku migracji. - **Odroczone:** PHPUnit i UAT dwóch profili; brak lokalnego `vendor/` i potwierdzenia użytkownika. ## Plan 20260712-1647 — zapamiętywanie logowania - **Sekret tokenu:** w bazie wyłącznie hash walidatora; porównanie przez `hash_equals`. - **Wiele urządzeń:** nowe logowanie dopisuje token, nie zastępuje aktywnych tokenów. - **Wylogowanie:** unieważnia tylko token bieżącego cookie; sesja i cookie są usuwane. - **Cookie:** 30 dni, HttpOnly, SameSite=Lax, Secure na produkcji. - **Jedno źródło czasu życia:** stała w modelu tokenów. - **YAGNI:** bez panelu urządzeń, harmonogramu i globalnego wylogowania. **Aktualizacja:** 2026-07-06 (post-apply Plan 2 — degraded) ## Zaakceptowane świadomie - **Kopiowanie wzorców zapytań** z `OperationModel` do `InvOperationModel`/`ValuationModel` (filtered/join). Osobna domena (brak type income/expense, dochodzą wyceny) — nie konsolidować w bazowy model, kod krótki. - **Format kwoty** `number_format(...,2,',',' ').' zł'` powtórzony w widokach jako lokalna funkcja `$fmt`. Trywialny, świadomie nie wydzielony do helpera (YAGNI). ## Rozwiązane - Zarobek netto: jedno źródło prawdy `InstrumentModel::withStats` (`net_invested`, `profit`, `percent`); nie liczony w widokach. - Typ operacji inwestycyjnej: ENUM `deposit|withdraw` w DB + walidacja `in_list` w modelu + sanity w kontrolerze. - Integralność: FK RESTRICT na `inv_operations`/`inv_valuations`. ## Odłożone - Pełna indeksacja `codebase-memory-mcp` — `$paul-map-codebase`. - jscpd/ast-grep — wyłączone polityką w `config.md` (skan on-demand). ## Import paragonów (Plan 3) - **Zapis operacji przez `OperationModel`** — bez duplikacji walidacji/logiki; `receipt_id` dodany do `allowedFields`. Jedno źródło prawdy zachowane. - **Format kwoty `$fmt`** powtórzony w widokach `receipts/` — świadomie spójny z resztą (YAGNI, jak w Plan 1/2). - **Podpowiedzi kategorii**: priorytet `receipt_category_map` (nauczone) > propozycja AI; NIC nie księgowane bez `confirm()` użytkownika (wymóg twardy spełniony). - **Klucz OpenAI** czytany z `.env` (`OPEN_AI_API`); nie logowany, nie w repo. Model konfigurowalny (`openai.model`). - **OCR paragonów niedeterministyczny**: wiersze rabatu/gęsty druk bywają źle odczytane (waha się między próbami). Świadomie kryte edytowalnymi kwotami/nazwami w przeglądzie (pół-automat). o4-mini najdokładniejszy z testowanych (suma pozycji = total co do grosza), gpt-4o/4.1 gorzej. - **Mechanizm PDF**: konieczne **Responses API + input_file** — chat-completions `file_data` NIE dostarcza treści PDF (model halucynuje). Rozstrzygnięte i wdrożone. - **Do obserwacji**: `normalize()` robi dokładne dopasowanie surowej nazwy — przy rozbieżnych nazwach tej samej rzeczy podpowiedź się nie pojawi; rozbudować gdy za wąska. Koszt tokenów OpenAI per import (o4-mini). Ewent. zapamiętywanie ładnej nazwy w `receipt_category_map`. ## Do obserwacji - `portfolioTimeline` liczony w PHP O(daty × operacje) — trywialne przy ręcznych wycenach; przy dużej liczbie wpisów rozważyć agregację SQL.