--- plan_id: 20260706-1248-fundament-wydatki-przychody title: Fundament finansePRO + moduł wydatków/przychodów bieżących storage: plan-first legacy_phase: null created: 2026-07-06T12:48:27+02:00 status: planned type: execute autonomous: false delegation: auto files_modified: - composer.json - .env - app/Config/Database.php - app/Config/Routes.php - app/Config/Filters.php - app/Filters/AuthFilter.php - app/Controllers/BaseController.php - app/Controllers/Auth.php - app/Controllers/Categories.php - app/Controllers/Operations.php - app/Controllers/Dashboard.php - app/Models/CategoryModel.php - app/Models/OperationModel.php - app/Database/Migrations/*_create_categories.php - app/Database/Migrations/*_create_operations.php - app/Database/Seeds/DefaultCategoriesSeeder.php - app/Views/layout/main.php - app/Views/auth/login.php - app/Views/categories/* - app/Views/operations/* - app/Views/dashboard/index.php quality_radar: degraded --- ## Cel Postawić fundament aplikacji finansePRO na CodeIgniter 4 (MySQL z `.env`), logowanie jednego użytkownika oraz kompletny moduł finansów bieżących: kategorie (hierarchiczne, typ przychód/wydatek), operacje (CRUD + filtry) i dashboard z wykresami ApexCharts. ## Po co To pierwsza, uruchamialna wersja narzędzia do analizy finansów osobistych. Daje działający szkielet (auth + DB + layout), na którym Plan 2 dołoży moduł inwestycji. Wzorzec domenowy (kategorie/operacje) świadomie czerpie z modułu finansów crmPRO, ale kod pisany jest od zera w CI4 — bez przenoszenia frameworka crmPRO. ## Wynik Działająca aplikacja CI4: logowanie → dashboard z wykresami → zarządzanie kategoriami i operacjami. Migracje tworzą schemat, seeder wrzuca startowe kategorie. ## Dokumenty projektu @.paul/PROJECT.md @.paul/STATE.md @.paul/config.md @.paul/codebase/impact_map.md @.paul/codebase/quality_risks.md ## Referencja (NIE modyfikować — tylko wzorzec domenowy) @C:/visual-studio-code/crmPRO/autoload/Domain/Finances/FinanceRepository.php @C:/visual-studio-code/crmPRO/templates/finances/main-view.php @C:/visual-studio-code/crmPRO/templates/finances/operations-list.php ## Konfiguracja środowiska @.env - Stack: **CodeIgniter 4** (użytkownik zna go z innej aplikacji, wdrożenie na hostido OK). - Logowanie: **jeden użytkownik wprost z `.env`** (`user_email` + `user_password`), bez tabeli users, bez rejestracji, bez remember-tokenów. - Zakres tego planu: **fundament + moduł bieżących wydatków/przychodów**. Moduł inwestycji to osobny Plan 2 (ręczne snapshoty wartości). - Kategorie: hierarchiczne (`parent_id`), z typem przychód/wydatek — wzorzec jak `finance_categories` w crmPRO. - Wykresy: **ApexCharts** (znane z crmPRO). - Hasło w `.env` jest jawne — logowanie porównuje wprost (narzędzie jednoosobowe). Podniesienie do hasha zostawione jako możliwa późniejsza zmiana. ## Quality Radar **Status:** degraded (finansePRO to greenfield — brak kodu do skanowania; codebase-memory-mcp nie ma czego indeksować) **Tools:** codebase-memory-mcp (brak indeksu — projekt pusty); jscpd/ast-grep wyłączone polityką ## Obszary objęte planem - fundament CI4 — `app/Config/*`, `composer.json`, bootstrap - auth (jeden user z .env) — `app/Filters/AuthFilter.php`, `app/Controllers/Auth.php` - domena finansów bieżących — `app/Models/{Category,Operation}Model.php`, `app/Controllers/{Categories,Operations,Dashboard}.php`, migracje, widoki - config DB — `app/Config/Database.php` czyta klucze z istniejącego `.env` ## Ryzyka duplikacji / hardcode - **Drugie źródło prawdy dla configu DB** — istniejący `.env` używa własnych kluczy (`db_host`, `db_user`, `db_name`, `db_password`), NIE standardowych CI4 (`database.default.*`). Obsłużone w Task 1: `Database.php` czyta te klucze przez `env('db_host')` itd., bez dublowania wartości i bez zmiany `.env`. - **Typ operacji (przychód/wydatek)** — nie utrwalać go w dwóch miejscach niespójnie. Obsłużone w Task 2: `type` jest kolumną enum na kategorii i na operacji; walidacja spójności w `OperationModel`. - **Wzorzec z crmPRO** — czerpiemy schemat domenowy, ale nie kopiujemy kodu 1:1 (inny framework). Brak ryzyka copy-paste między repo. ## Świadome odroczenia - Hashowanie hasła użytkownika — odroczone (jawne `.env`, narzędzie jednoosobowe). - Pełny skan radaru (codebase-memory-mcp index) — po zbudowaniu kodu, w `$paul-apply`/`$paul-map-codebase`. - Moduł inwestycji — Plan 2. Brak SPECIAL-FLOWS.md — sekcja skills pominięta. ## AC-1: Aplikacja startuje i łączy się z bazą z .env ```gherkin Given świeżo zainstalowany CodeIgniter 4 z konfiguracją z .env When uruchomię `php spark serve` i otworzę stronę główną Then aplikacja ładuje się bez błędu połączenia z MySQL, używając db_host/db_user/db_name/db_password z .env ``` ## AC-2: Logowanie jednego użytkownika z .env ```gherkin Given niezalogowany użytkownik wchodzi na dowolną chronioną trasę When zostaje przekierowany na /login i poda email oraz hasło zgodne z user_email/user_password z .env Then zostaje zalogowany (sesja) i przekierowany na dashboard; błędne dane pokazują komunikat, a /logout kończy sesję ``` ## AC-3: Zarządzanie kategoriami (hierarchia + typ) ```gherkin Given zalogowany użytkownik w widoku kategorii When doda/edytuje/usunie kategorię z nazwą, typem (przychód/wydatek) i opcjonalnym rodzicem Then kategoria zapisuje się w tabeli categories, respektuje parent_id, a usunięcie kategorii z operacjami jest zablokowane lub przenosi operacje zgodnie z regułą (patrz Task 3) ``` ## AC-4: CRUD operacji z filtrami ```gherkin Given zalogowany użytkownik w widoku operacji When doda operację (data, kwota, typ, kategoria, opis) i użyje filtra po zakresie dat oraz kategorii Then operacja zapisuje się w tabeli operations, lista pokazuje przefiltrowane wyniki i sumy (przychody, wydatki, saldo) ``` ## AC-5: Dashboard z wykresami ```gherkin Given istnieją operacje w bazie When otworzę dashboard Then widzę wykresy ApexCharts: (a) bilans miesięczny przychody vs wydatki, (b) wydatki wg kategorii (donut), (c) saldo skumulowane w czasie — z danymi zgodnymi z operacjami ``` Task 1: Bootstrap CI4 + konfiguracja DB z .env + logowanie jednego użytkownika composer.json, app/Config/Database.php, app/Config/Routes.php, app/Config/Filters.php, app/Filters/AuthFilter.php, app/Controllers/Auth.php, app/Views/auth/login.php, app/Views/layout/main.php - Zainstalować szkielet CodeIgniter 4 (`composer create-project codeigniter4/appstarter` lub równoważnie) w katalogu projektu, zachowując istniejący `.env`, `.paul/`, `.claude/`, `.vscode/`. - W `app/Config/Database.php` ustawić `default` z istniejących kluczy .env: `hostname = env('db_host')`, `username = env('db_user')`, `database = env('db_name')`, `password = env('db_password')`, `DBDriver = 'MySQLi'`, `charset = 'utf8mb4'`. NIE dodawać nowych kluczy do `.env` (żeby nie tworzyć drugiego źródła prawdy). Zdalny host `db_host_remote` zostawić jako komentarz/opcję na wdrożenie. - Utworzyć `AuthFilter` sprawdzający `session()->get('logged_in')`; niezalogowanych przekierowuje na `/login`. Zarejestrować w `Filters.php` jako alias `auth` i nałożyć na grupę tras chronionych w `Routes.php`. - `Auth` controller: `login` (GET formularz, POST weryfikacja wobec `env('user_email')`/`env('user_password')` — porównanie wprost; // ponytail: jawne haslo z .env, podniesc do password_hash jesli pojawi sie wiecej userow), `logout` (czyści sesję). - `app/Views/layout/main.php`: wspólny layout Bootstrap + miejsce na treść + nawigacja (Dashboard, Operacje, Kategorie, Wyloguj). ApexCharts i Bootstrap wpiąć (CDN lub `public/`). - Trasa domyślna `/` → redirect na dashboard (gdy zalogowany) lub `/login`. `php spark serve`, wejście na chronioną trasę przekierowuje na /login; poprawne dane z .env logują i przekierowują na dashboard; złe dane = komunikat; /logout wylogowuje. Brak błędu połączenia z DB. AC-1, AC-2 Task 2: Schemat DB (migracje) + modele + seeder kategorii app/Database/Migrations/*_create_categories.php, app/Database/Migrations/*_create_operations.php, app/Models/CategoryModel.php, app/Models/OperationModel.php, app/Database/Seeds/DefaultCategoriesSeeder.php - Migracja `categories`: `id` PK, `name` VARCHAR, `type` ENUM('income','expense'), `parent_id` INT NULL (FK self, ON DELETE SET NULL), `created_at`/`updated_at`. Indeks na `parent_id`, `type`. - Migracja `operations`: `id` PK, `date` DATE, `amount` DECIMAL(12,2) (dodatnia), `type` ENUM('income','expense'), `category_id` INT NULL (FK categories, ON DELETE SET NULL), `description` VARCHAR NULL, `created_at`/`updated_at`. Indeksy na `date`, `category_id`, `type`. - `CategoryModel`: allowedFields, walidacja (name wymagane, type in income/expense, parent_id istnieje lub null), metoda `flatList()`/`treeList()` i `usedByOperations($id)`. - `OperationModel`: allowedFields, walidacja (date, amount > 0, type in income/expense, category_id istnieje lub null); reguła spójności: `type` operacji musi zgadzać się z `type` wybranej kategorii (jedno źródło prawdy — kategoria narzuca typ). Metody agregujące dla dashboardu: `monthlyBalance($from,$to)`, `byCategory($from,$to,$type)`, `runningBalance($from,$to)`. - `DefaultCategoriesSeeder`: kilka startowych kategorii przychodów (np. Wynagrodzenie, Inne przychody) i wydatków (np. Jedzenie, Mieszkanie, Transport, Rozrywka). `php spark migrate` tworzy tabele bez błędów; `php spark db:seed DefaultCategoriesSeeder` wstawia kategorie; szybki tinker/SQL potwierdza strukturę i FK. AC-3 (schemat), AC-4 (schemat), AC-5 (agregacje) Task 3: Moduł kategorii i operacji (CRUD + filtry + sumy) app/Controllers/Categories.php, app/Controllers/Operations.php, app/Controllers/BaseController.php, app/Views/categories/*, app/Views/operations/*, app/Config/Routes.php - `Categories` controller + widoki: lista (drzewko/płaska z wcięciem wg parent_id), formularz dodaj/edytuj (name, type, parent_id), usuwanie. Usunięcie kategorii używanej przez operacje: zablokować z komunikatem LUB pozwolić (operacje przechodzą na category_id=NULL dzięki FK) — wybrać blokadę z jasnym komunikatem dla bezpieczeństwa danych. - `Operations` controller + widoki: lista z filtrami (zakres dat — datepicker/``, kategoria, typ), formularz dodaj/edytuj (date, amount, type auto z kategorii, category_id, description), usuwanie. Wybór kategorii ustawia typ operacji (spójność jak w Task 2). Lista pokazuje sumy: przychody, wydatki, saldo dla aktualnego filtra. - Trasy CRUD w `Routes.php` w grupie chronionej filtrem `auth`. - Walidacja po stronie serwera przez modele; komunikaty błędów w widokach. Ręcznie: dodać/edytować/usunąć kategorię i operację; filtr po dacie i kategorii zawęża listę; sumy się zgadzają; próba usunięcia używanej kategorii jest zablokowana z komunikatem. AC-3, AC-4 Task 4: Dashboard z wykresami ApexCharts app/Controllers/Dashboard.php, app/Views/dashboard/index.php, app/Config/Routes.php - `Dashboard` controller: pobiera z `OperationModel` dane dla domyślnego zakresu (np. bieżący rok) i oddaje do widoku jako JSON dla ApexCharts. Opcjonalny filtr zakresu dat u góry dashboardu. - Wykresy ApexCharts w `dashboard/index.php`: (a) bilans miesięczny — słupki przychody vs wydatki per miesiąc, (b) wydatki wg kategorii — donut (tylko type=expense), (c) saldo skumulowane w czasie — linia (cumsum operacji: +przychód, −wydatek). - Kafelki podsumowania: suma przychodów, suma wydatków, saldo dla wybranego zakresu. - Trasa `/dashboard` (i `/`) w grupie chronionej. Ręcznie: po dodaniu operacji dashboard pokazuje trzy wykresy z poprawnymi danymi; zmiana zakresu dat aktualizuje wykresy i kafelki. AC-5 ## Nie zmieniać - `.env` — czytamy istniejące klucze, nie dodajemy nowych ani nie zmieniamy wartości. - `.paul/`, `.claude/`, `.vscode/` — infrastruktura projektu. - Repozytorium crmPRO (`C:/visual-studio-code/crmPRO/`) — wyłącznie referencja wzorca, zero modyfikacji. ## Poza zakresem - Moduł inwestycji (operacje inwestycyjne, wyceny, wykres wpłaty vs zarobek) — Plan 2. - Tabela users, rejestracja, reset hasła, wielu użytkowników. - Import z Fakturownia / integracje zewnętrzne (były w crmPRO, tu niepotrzebne). - Hashowanie hasła, 2FA, remember-me. - Wdrożenie produkcyjne na hostido (osobny krok po akceptacji lokalnej). - [ ] `php spark serve` startuje, `/` przekierowuje wg stanu logowania. - [ ] Logowanie wobec `.env` działa (poprawne/błędne dane, logout). - [ ] `php spark migrate` i seeder wykonują się bez błędów. - [ ] CRUD kategorii i operacji działa, filtry i sumy poprawne. - [ ] Dashboard renderuje 3 wykresy ApexCharts z danymi zgodnymi z operacjami. - [ ] Config DB czyta wyłącznie z `.env` (brak drugiego źródła prawdy). - [ ] Typ operacji spójny z typem kategorii (jedno źródło prawdy). - [ ] Quality Radar: ryzyka z `` obsłużone lub odroczone świadomie. - [ ] Wszystkie AC (AC-1..AC-5) przechodzą. - [ ] Weryfikacja kompletna. - [ ] Radar/impact_map zaktualizowane po zbudowaniu kodu (w `$paul-apply`). - [ ] Fundament gotowy pod Plan 2 (inwestycje). SUMMARY.md path: `.paul/plans/20260706-1248-fundament-wydatki-przychody/SUMMARY.md`