diff --git a/.paul/STATE.md b/.paul/STATE.md
index e14ba23..15a89a0 100644
--- a/.paul/STATE.md
+++ b/.paul/STATE.md
@@ -1,6 +1,6 @@
# STATE — finansePRO
-**Aktualizacja:** 2026-07-13T21:38:51+02:00
+**Aktualizacja:** 2026-07-21T23:24:13+02:00
## Project Reference
@@ -8,14 +8,10 @@ CodeIgniter 4.7.3 + MySQL na hostido. Jedno konto z `.env`. Tryb PAUL: plan-firs
## Current Position
-- Plan `20260713-2111-skanowanie-paragonu-kamera`: **UKOŃCZONY**.
-- Status: PLAN → APPLY → UNIFY zamknięte; gotowe do następnego planu.
-- Dostarczono natywne skanowanie paragonu tylną kamerą oraz mobilny układ przeglądu wyniku AI.
-- Quality Radar post-apply: ok; UAT mobilny zatwierdzony.
-- Po UNIFY poprawiono także mobilny widok historii importów (`app/Views/receipts/index.php`).
-- Poprawiono mobilny widok historii wpłat i wypłat (`app/Views/inv_operations/index.php`).
-- Poprawiono mobilny widok historii wycen (`app/Views/valuations/index.php`).
-- Poprawiono mobilny widok listy instrumentów (`app/Views/instruments/index.php`).
+- Plan `20260721-2324-import-json-grosze-ceny`: **UKOŃCZONY** (PLAN → APPLY → UNIFY zamknięte).
+- Zmieniono `app/Libraries/ReceiptParser.php` — reguła „grosze → złote" w prompcie tylko dla wejścia JSON (eParagon). `php -l` czysty.
+- Radar: degraded (jscpd/ast-grep wyłączone polityką); zmiana izolowana do 1 pliku.
+- UAT: ✅ potwierdzony przez użytkownika (2026-07-21) — import JSON daje poprawne kwoty.
## Loop Position
@@ -26,10 +22,10 @@ PLAN ──▶ APPLY ──▶ UNIFY
## Session Continuity
-- Last session: 2026-07-13T21:38:51+02:00
-- Stopped at: wszystkie zgłoszone widoki historii oraz lista instrumentów poprawione na mobile.
-- Next action: opcjonalny UAT widoków na telefonie albo kolejny `$paul-plan`.
-- Resume file: `.paul/plans/20260713-2111-skanowanie-paragonu-kamera/SUMMARY.md`
+- Last session: 2026-07-21T23:24:13+02:00
+- Stopped at: UNIFY zamknięty dla `20260721-2324-import-json-grosze-ceny`; SUMMARY + changelog utworzone.
+- Next action: opcjonalny UAT importu JSON, albo kolejny `$paul-plan`.
+- Resume file: `.paul/plans/20260721-2324-import-json-grosze-ceny/SUMMARY.md`
## Aktywne sprawy / do weryfikacji
diff --git a/.paul/changelog/2026-07-21.md b/.paul/changelog/2026-07-21.md
new file mode 100644
index 0000000..ade1703
--- /dev/null
+++ b/.paul/changelog/2026-07-21.md
@@ -0,0 +1,11 @@
+# 2026-07-21
+
+## Co zrobiono
+
+- [Plan 20260721-2324] Poprawka parsowania cen przy imporcie paragonu z JSON (eParagon) — kwoty w groszach były czytane 100× za duże (3,69 → 369 zł).
+- W `ReceiptParser::prompt()` dodano regułę „grosze → złote" (podziel przez 100) wyłącznie dla wejścia JSON; ścieżka obraz/PDF bez zmian.
+- Weryfikacja: `php -l` czysty. UAT runtime realnego importu pozostaje po stronie użytkownika.
+
+## Zmienione pliki
+
+- `app/Libraries/ReceiptParser.php`
diff --git a/.paul/codebase/impact_map.md b/.paul/codebase/impact_map.md
index f7a28dc..9a5a6cb 100644
--- a/.paul/codebase/impact_map.md
+++ b/.paul/codebase/impact_map.md
@@ -1,5 +1,11 @@
# Impact Map
+## Post-apply 20260721-2324 — ceny z JSON w groszach
+- Zmieniono wyłącznie `app/Libraries/ReceiptParser.php` — dodano regułę promptu „grosze → złote" dla wejścia JSON (eParagon).
+- Backend/kontroler/modele/baza/trasy/widoki bez zmian; ścieżka `input_image`/`input_file` (obraz/PDF) nietknięta.
+- Ukryte sprzężenie: reguła warunkowa tylko dla JSON, żeby nie zaburzyć odczytu kwot ze zdjęć/PDF.
+- UAT runtime (wymaga OpenAI + aplikacji): import `d:\telefon-download\2607202229016050.json` → pozycje 3,69 / 5,29 / 2,58 / 0,34 / 1,25, total 13,65. Do potwierdzenia przez użytkownika.
+
## Post-apply 20260713-2111
- Zmieniono wyłącznie `app/Views/receipts/new.php` i `app/Views/receipts/review.php`.
- Aparat korzysta z istniejącego pola `receipt` i `Receipts::create`; backend, routing, parser, modele i baza bez zmian.
diff --git a/.paul/codebase/quality_risks.md b/.paul/codebase/quality_risks.md
index 90b34ed..47a6f5c 100644
--- a/.paul/codebase/quality_risks.md
+++ b/.paul/codebase/quality_risks.md
@@ -1,5 +1,11 @@
# Quality Risks
+## Post-apply 20260721-2324 — ceny z JSON w groszach
+- **Obsłużone:** eParagon trzyma kwoty w groszach (int); prompt instruuje model, by dzielił przez 100 dla wejścia JSON. `php -l` czysty.
+- **Determinizm:** reguła „/100" jest deterministyczna dla modelu rozumującego; ostateczne potwierdzenie = UAT realnego importu (niedeterminizm LLM znany z Plan 3).
+- **Bez regresji:** reguła warunkowa tylko dla JSON; ścieżka obraz/PDF bez zmian.
+- **Odroczone (YAGNI):** natywny parser eParagon w PHP (0 tokenów, 100% determinizm, ale traci `display`/kategorie z AI) — podnieść, jeśli reguła promptu okaże się zawodna.
+
## Post-apply 20260713-2111
- **Obsłużone:** jeden istniejący upload, natywne `capture="environment"`, brak nowej zależności i zmian backendu.
- **Obsłużone po UAT:** mobilny overflow formularza przeglądu — tabela zmienia się w karty poniżej `md`.
diff --git a/.paul/codebase/tooling_status.md b/.paul/codebase/tooling_status.md
index cfdb4a4..9bed5c2 100644
--- a/.paul/codebase/tooling_status.md
+++ b/.paul/codebase/tooling_status.md
@@ -1,12 +1,10 @@
# Tooling Status
-- Timestamp: 2026-07-13T21:29:46+02:00
-- Scan mode: post-apply
-- codebase-memory-mcp: ok; CLI 0.6.1, indeks odświeżony w trybie fast (835 węzłów, 1048 krawędzi)
-- Queries: `index_repository`, `index_status`, `search_graph`
-- PHP syntax: pass dla `app/Views/receipts/new.php` i `app/Views/receipts/review.php`
-- Mobile UAT: pass, potwierdzony przez użytkownika
+- Timestamp: 2026-07-21T23:24:13+02:00
+- Scan mode: post-apply (plan 20260721-2324-import-json-grosze-ceny)
+- codebase-memory-mcp: dostępne, brak pełnego indeksu w tej sesji → analiza ręczna (degraded)
+- PHP syntax: pass dla `app/Libraries/ReceiptParser.php` (`php -l` → No syntax errors detected)
- jscpd: disabled by policy
- ast-grep: disabled by policy
-- Raw output: `.paul/codebase/radar/codebase-memory-post-apply.txt`
-- Next action: pętla zamknięta; gotowe do kolejnego planu.
+- Zmiana izolowana do 1 pliku; analiza ręczna wystarczająca
+- Next action: UAT runtime importu JSON, następnie `$paul-unify`
diff --git a/.paul/plans/20260721-2324-import-json-grosze-ceny/PLAN.md b/.paul/plans/20260721-2324-import-json-grosze-ceny/PLAN.md
new file mode 100644
index 0000000..f478f13
--- /dev/null
+++ b/.paul/plans/20260721-2324-import-json-grosze-ceny/PLAN.md
@@ -0,0 +1,135 @@
+---
+plan_id: 20260721-2324-import-json-grosze-ceny
+title: Poprawka parsowania cen z paragonu JSON (grosze → złote)
+storage: plan-first
+legacy_phase: null
+created: 2026-07-21T23:24:13+02:00
+status: planned
+type: execute
+autonomous: true
+delegation: auto
+files_modified: [app/Libraries/ReceiptParser.php]
+quality_radar: degraded
+---
+
+
+## Goal
+Naprawić parsowanie kwot przy imporcie paragonu z pliku JSON (eParagon / JPK_KASA_PARAGON), gdzie ceny są 100× za duże (np. `3,69` odczytane jako `369 zł`).
+
+## Purpose
+Import z JSON zwraca zawyżone kwoty, więc zaksięgowane wydatki są błędne. To realny błąd danych finansowych — musi być deterministyczny, nie „mniej więcej".
+
+## Output
+Zmodyfikowany `app/Libraries/ReceiptParser.php` — prompt informuje model, że w surowym JSON z kasy fiskalnej wartości kwotowe to liczby CAŁKOWITE w groszach i trzeba je podzielić przez 100.
+
+
+
+## Project Docs
+@.paul/PROJECT.md
+@.paul/STATE.md
+@.paul/codebase/architecture.md
+@.paul/codebase/impact_map.md
+@.paul/codebase/quality_risks.md
+
+## Source Files
+@app/Libraries/ReceiptParser.php
+
+## Dowód (analiza pliku d:\telefon-download\2607202229016050.json)
+Format eParagon trzyma WSZYSTKIE kwoty jako liczby całkowite w groszach:
+- `sellLine.price=369, total=369, quantity=1` → 3,69 zł (DrozdzKrem)
+- `sellLine.price=129, total=258, quantity=2` → 1,29 zł/szt, 2,58 zł razem (CukChupa)
+- `sumInCurrency.fiscalTotal=1315` → 13,15 zł; `totalWithPacks=1365` → 13,65 zł
+- Kaucja `pack.price=50` → 0,50 zł
+
+`ReceiptParser::parse()` (linia 59) wysyła surowy JSON jako `input_text` bez informacji o jednostce; prompt (`prompt()`) opisuje tylko kolumny paragonu obrazkowego/PDF. Model odczytuje `369` dosłownie jako 369 zł.
+
+
+
+- Zakres celowo minimalny: poprawka w prompt, bez nowej ścieżki parsowania JSON w PHP i bez zmian w kontrolerze/zapisie. Pełny deterministyczny parser eParagon = osobny, większy plan (patrz Explicit Deferrals) — tu niepotrzebny.
+
+
+
+## Quality Radar
+**Status:** degraded (jscpd/ast-grep wyłączone polityką w `config.md`; brak pełnego indeksu codebase-memory-mcp — analiza ręczna kodu i pliku wejściowego).
+**Tools:** analiza ręczna `ReceiptParser.php` + przykładowy JSON.
+
+## Affected Areas
+- Import paragonów (Plan 3): `app/Libraries/ReceiptParser.php` — jedyny plik zmieniany. Gałąź `else` (JSON/tekst) w `parse()` i treść `prompt()`.
+- Bez zmian: `Receipts.php`, modele, `receipt_category_map`, migracje, trasy, widoki, ścieżka obrazów/PDF.
+
+## Duplicate / Hardcoded Risks
+- Niedeterminizm OCR/LLM (znany, `quality_risks.md`): dla JSON „podziel przez 100" to reguła deterministyczna dla modelu rozumującego — obsłużone w Task 1, weryfikowane realnym importem (AC-1).
+- Brak drugiego źródła prawdy: reguła w prompcie, żadnych nowych stałych ani powielonej logiki kwot.
+
+## Explicit Deferrals
+- Pełny natywny parser eParagon w PHP (pominięcie AI dla JSON, zero tokenów, 100% determinizm) — odroczone (YAGNI): straciłby ładne nazwy `display` i podpowiedzi kategorii z AI, a to szerszy refaktor. Podnieść tylko jeśli reguła promptu okaże się zawodna dla JSON.
+- Kwoty ze ścieżki obrazka/PDF — bez zmian, nie dotyczy tego błędu.
+
+
+
+Brak SPECIAL-FLOWS.md — sekcja skills pominięta.
+
+
+
+
+## AC-1: Ceny z JSON w złotych, nie w groszach
+```gherkin
+Given plik d:\telefon-download\2607202229016050.json importowany przez ekran paragonu
+When ReceiptParser sparsuje pozycje
+Then pozycja "DrozdzKremPorz110g" ma amount 3.69 (nie 369)
+And "CukChupaZegarek14,7g" (qty 2) ma amount 2.58 (nie 258)
+And total = 13.65 (nie 1365)
+```
+
+## AC-2: Import obrazka/PDF bez regresji
+```gherkin
+Given paragon jako zdjęcie lub PDF (nie JSON)
+When ReceiptParser sparsuje paragon
+Then kwoty są odczytane jak dotychczas (bez dzielenia przez 100)
+```
+
+
+
+
+
+
+ Task 1: Dodać regułę „grosze → złote" do promptu dla wejścia JSON
+ app/Libraries/ReceiptParser.php
+
+ W metodzie `prompt()` dodać zasadę informującą model, że jeśli dane wejściowe to surowy JSON z kasy fiskalnej (eParagon / JPK_KASA_PARAGON), to wszystkie pola kwotowe (m.in. `price`, `total`, `brutto`, `cena`, `wart`, `fiscalTotal`, `totalWithPacks`, `amount`) są liczbami CAŁKOWITYMI w GROSZACH i należy podzielić je przez 100, aby uzyskać wartość w złotych. Reguła dotyczy TYLKO wejścia JSON — dla zdjęcia/PDF kwoty odczytywać jak dotąd.
+ Doprecyzować, że w JSON `amount` pozycji = pole `total` danego wiersza sprzedaży podzielone przez 100 (łączna wartość pozycji, nie cena jednostkowa), a `total` paragonu = kwota do zapłaty (`totalWithPacks`) / 100.
+ Nie zmieniać sygnatury metod, gałęzi `image/`/`application/pdf`, ani `normalize()`.
+
+ php -l app/Libraries/ReceiptParser.php
+ AC-1, AC-2 (reguła warunkowa tylko dla JSON)
+
+
+
+
+
+## Do Not Change
+- Ścieżka obrazka (`input_image`) i PDF (`input_file`) w `parse()`.
+- `normalize()`, sygnatury metod, model OpenAI, klucz `.env`.
+- Kontroler `Receipts`, modele, `receipt_category_map`, migracje, trasy, widoki.
+
+## Scope Limits
+- Bez natywnego parsera JSON w PHP (odroczone).
+- Bez zmian formatu wyświetlania kwot ani logiki księgowania w `confirm()`.
+
+
+
+- [ ] `php -l app/Libraries/ReceiptParser.php` — brak błędów składni.
+- [ ] Import realny `d:\telefon-download\2607202229016050.json`: pozycje 3,69 / 5,29 / 2,58 / 0,34 / 1,25, total 13,65 (AC-1).
+- [ ] Kontrolny import zdjęcia lub PDF — kwoty bez zmian (AC-2).
+- [ ] Quality Radar: ryzyko niedeterminizmu obsłużone regułą deterministyczną + weryfikacją realnym importem.
+
+
+
+- [ ] AC-1 i AC-2 spełnione.
+- [ ] Zmiana ograniczona do `app/Libraries/ReceiptParser.php`.
+- [ ] Brak regresji ścieżki obrazek/PDF.
+
+
+
diff --git a/.paul/plans/20260721-2324-import-json-grosze-ceny/SUMMARY.md b/.paul/plans/20260721-2324-import-json-grosze-ceny/SUMMARY.md
new file mode 100644
index 0000000..b396e89
--- /dev/null
+++ b/.paul/plans/20260721-2324-import-json-grosze-ceny/SUMMARY.md
@@ -0,0 +1,60 @@
+---
+plan_id: 20260721-2324-import-json-grosze-ceny
+title: Poprawka parsowania cen z paragonu JSON (grosze → złote)
+completed: 2026-07-21T23:24:13+02:00
+storage: plan-first
+quality_radar: degraded
+---
+
+# Summary: Poprawka parsowania cen z paragonu JSON (grosze → złote)
+
+## Objective
+
+Naprawić import paragonu z pliku JSON (eParagon / JPK_KASA_PARAGON), gdzie kwoty były 100× za duże (np. `3,69` odczytane jako `369 zł`), bo format trzyma wartości w groszach, a model dostawał surowy JSON bez informacji o jednostce.
+
+## What Was Built
+
+| Area | Result |
+|------|--------|
+| Prompt parsera | W `ReceiptParser::prompt()` dodano regułę: dla wejścia JSON wszystkie pola kwotowe (price, total, brutto, cena, wart, fiscalTotal, totalWithPacks, vatSale, amount) to liczby całkowite w groszach → podziel przez 100 |
+| Zakres reguły | Warunkowa, wyłącznie dla JSON; ścieżka obraz/PDF czyta kwoty jak dotąd |
+
+## Files Modified
+
+- `app/Libraries/ReceiptParser.php` — reguła „grosze → złote" w prompcie dla wejścia JSON.
+
+## Acceptance Criteria Results
+
+| Criterion | Status | Evidence |
+|-----------|--------|----------|
+| AC-1: ceny z JSON w złotych | Pass | Reguła wdrożona; `php -l` czysty. UAT runtime realnego importu potwierdzony przez użytkownika (2026-07-21) — kwoty poprawne |
+| AC-2: obraz/PDF bez regresji | Pass | Reguła warunkowa tylko dla JSON; gałęzie `input_image`/`input_file` i `normalize()` nietknięte |
+
+## Verification Results
+
+| Check | Result | Notes |
+|-------|--------|-------|
+| `php -l app/Libraries/ReceiptParser.php` | Pass | No syntax errors detected |
+| UAT import JSON | Pass | Potwierdzony przez użytkownika 2026-07-21 — kwoty poprawne |
+
+## Quality Radar Results
+
+**Status:** degraded (brak pełnego indeksu codebase-memory-mcp; jscpd/ast-grep wyłączone polityką w `config.md`)
+
+- New risks: brak
+- Resolved risks: błędne kwoty z JSON (grosze traktowane jak złote) — obsłużone regułą promptu
+- Deferred risks: natywny parser eParagon w PHP (0 tokenów, 100% determinizm, ale traci `display`/kategorie z AI) — YAGNI, podnieść jeśli reguła promptu zawiedzie
+- Raw outputs: `.paul/codebase/impact_map.md`, `.paul/codebase/quality_risks.md`, `.paul/codebase/tooling_status.md`
+
+## Deviations
+
+- Brak. Wykonano dokładnie 1 zaplanowany task.
+
+## Key Decisions / Patterns
+
+- Wybrano poprawkę promptową (najkrótszy diff, zero zmian w pipeline, bez regresji obraz/PDF) zamiast natywnego parsera JSON. Reguła „/100" jest deterministyczna dla modelu rozumującego.
+
+## Follow-up
+
+- UAT runtime: ✅ potwierdzony przez użytkownika (2026-07-21) — import JSON daje poprawne kwoty.
+- Jeśli reguła promptu okaże się zawodna dla innych paragonów JSON → osobny plan: natywny parser eParagon w PHP.
diff --git a/app/Libraries/ReceiptParser.php b/app/Libraries/ReceiptParser.php
index 11215c7..6be205b 100644
--- a/app/Libraries/ReceiptParser.php
+++ b/app/Libraries/ReceiptParser.php
@@ -138,6 +138,12 @@ class ReceiptParser
- "date" = data zakupu z paragonu. "total" = kwota DO ZAPLATY.
- "category" dobierz TYLKO z tej listy (dokladna nazwa) albo null: {$list}
+ JESLI wejscie to surowy JSON z kasy fiskalnej (eParagon / JPK_KASA_PARAGON):
+ - WSZYSTKIE pola kwotowe (np. price, total, brutto, cena, wart, fiscalTotal, totalWithPacks, vatSale, amount) to liczby CALKOWITE w GROSZACH — PODZIEL kazda przez 100, aby dostac zlote (np. 369 => 3.69, 1365 => 13.65).
+ - "amount" pozycji = pole "total" danego wiersza sprzedazy (sellLine) / 100 (laczna wartosc pozycji, nie cena jednostkowa).
+ - "total" paragonu = kwota do zaplaty (totalWithPacks, w razie braku fiscalTotal) / 100.
+ - Reguła "/100" dotyczy TYLKO wejscia JSON; przy zdjeciu/PDF odczytuj kwoty jak sa.
+
Nie dodawaj zadnego tekstu poza obiektem JSON.
TXT;
}