Mój Budżet — aplikacja finansowa na własnym mikro-frameworku PHP
Projekt PHP · Własny Framework · MySQL · Gemini AI · Bootstrap

Mój Budżet — zarządzanie finansami na własnym mikro-frameworku PHP

Aplikacja internetowa do kompleksowego zarządzania finansami osobistymi — rejestrowanie przychodów i wydatków, kategoryzowanie ich, limity miesięczne i analiza przepływów pieniężnych przez wykresy i zestawienia. Cały backend zbudowany na własnoręcznie napisanym mikro-frameworku PHP: router z regex, kontener DI przez Reflection API, silnik szablonów, walidator z 13 regułami i łańcuch 9 middleware.

PHP + własny framework MySQL + PDO Bootstrap 5 jQuery + DateRangePicker Gemini AI CSRF + Sesje Composer

01Funkcjonalności

Menu i nawigacja aplikacji Mój Budżet
nawigacja główna — Bootstrap navbar z sekcjami: Panel, Przychody, Wydatki, Bilans, Ustawienia
💰

Przychody i wydatki

Dodawanie transakcji z kategorią, metodą płatności, datą i komentarzem. Automatyczna normalizacja kwoty (przecinek → kropka).

🎯

Limity kategorii

Kategoria wydatków może mieć miesięczny limit. AJAX pobiera limit i aktualną sumę — na bieżąco pokazuje balans przed dodaniem kwoty.

📊

Bilans z wykresami

DateRangePicker z predefiniowanymi okresami (dziś, 7 dni, miesiąc, własny). Wykresy kołowe przychodów i wydatków per kategoria. Wybór daty w localStorage.

🤖

AI doradca finansowy

Przy każdym otwarciu bilansu Gemini generuje zwięzłą analizę: Diagnoza Finansowa → Kluczowa Obserwacja → 3 Rekomendacje.

⚙️

Zarządzanie kategoriami

Zakładkowy panel ustawień: dodawanie, usuwanie i edycja kategorii przychodów i wydatków (z limitem) oraz metod płatności.

🔐

Bezpieczeństwo

Sesje PHP, CSRF (token weryfikowany przy każdym POST), ochrona routów przez middleware, bcrypt, prepared statements.

02Zarządzanie transakcjami

Aplikacja umożliwia dodawanie przychodów i wydatków z pełną walidacją — kwoty, daty, kategorii i opcjonalnego komentarza. Kwoty obsługują zarówno format z kropką jak i przecinkiem jako separatorem dziesiętnym. Daty akceptowane są w formatach ze słupkami i z kropkami.

Zestawienie przychodów w aplikacji Mój Budżet
strona bilansu — zestawienie przychodów z podziałem na kategorie, sumy i wykres kołowy
Dodawanie kategorii wydatków
formularz dodawania nowej kategorii wydatków z opcjonalnym limitem miesięcznym
Edycja kategorii
modal edycji kategorii — zmiana nazwy i limitu
// src/App/Services/TransactionService.php — createIncome()
public function createIncome(array $formData)
{
    $date = $formData['date'];
    if (strpos($date, '.') !== false) {
        list($day, $month, $year) = explode('.', $date);
        $date = sprintf('%04d-%02d-%02d', $year, $month, $day);
    }
    $amount = str_replace(',', '.', trim($formData['amount']));

    $this->db->query(
        'INSERT INTO incomes VALUES (NULL, :user_id, :income_category_assigned_to_user_id,
         :amount, :date_of_income, :income_comment)',
        [
            'user_id'   => $_SESSION['logged_id'],
            'category'  => $formData['category'],
            'amount'    => $amount,
            'date'      => $date,
            'comment'   => $formData['comment']
        ]
    );
    $_SESSION['income_added'] = true;
}

03REST API — real-time informacja o limicie

Najbardziej interaktywny element aplikacji: przy dodawaniu wydatku każda zmiana kategorii lub wpisywanej kwoty wyzwala AJAX do endpointu, który sprawdza ustawiony limit i aktualną sumę wydatków w bieżącym miesiącu. Użytkownik widzi natychmiast, ile mu zostało i jaki będzie balans po dodaniu tej kwoty.

Endpoint API limitu kategorii
odpowiedź endpointu GET /api/limit/{category}/{date} — limit kategorii i suma wydatków w miesiącu
GET
/api/limit/{category}/{date}
Zwraca limit kategorii wydatków i sumę wydaną w danym miesiącu (YEAR/MONTH z daty). Wymaga sesji — chroniony przez AuthRequiredMiddleware.
// src/App/Services/ApiService.php
public function fetchLimit($categoryId): array|false
{
    return $this->db->query(
        'SELECT `limit` FROM expenses_category_assigned_to_users WHERE id = :id',
        ['id' => (int) $categoryId]
    )->fetch();
}

public function fetchMoneyspentSoFar($categoryId, $pickedDate): array
{
    return $this->db->query(
        'SELECT SUM(amount) AS total_spent FROM expenses
         WHERE expense_category_assigned_to_user_id = :id
           AND YEAR(date_of_expense) = :year
           AND MONTH(date_of_expense) = :month',
        [
            'id'    => (int) $categoryId,
            'year'  => (int) substr($pickedDate, 0, 4),
            'month' => (int) substr($pickedDate, 5, 2)
        ]
    )->fetch();
}

04Własny mikro-framework PHP

Serce projektu — katalog src/Framework/ z samodzielną implementacją każdej warstwy tradycyjnie dostarczanej przez Laravel czy Symfony. Rozumienie frameworka przez jego zbudowanie od zera.

Router — dispatch z middleware chain

// src/Framework/Router.php — middleware jako zagnieżdżone domknięcia
foreach ($allMiddleware as $middleware) {
    $middlewareInstance = $container->resolve($middleware);
    $action = fn() => $middlewareInstance->process($action);
}
$action(); // uruchamia cały łańcuch od zewnątrz do wewnątrz

Container — autowiring przez Reflection API

// src/Framework/Container.php
public function resolve(string $className)
{
    $reflectionClass = new ReflectionClass($className);
    $params = $reflectionClass->getConstructor()->getParameters();

    $dependencies = [];
    foreach ($params as $param) {
        $type = $param->getType()->getName(); // odczytaj type hint
        $dependencies[] = $this->get($type);  // rekursywnie wstrzyknij
    }

    return $reflectionClass->newInstanceArgs($dependencies);
    // → np. BalanceController(TemplateEngine, TransactionService, ApiService)
    // → automatycznie, bez jednej linii konfiguracji
}

05Łańcuch middleware — 9 klas

SessionMiddleware
Inicjalizacja sesjisession_start(), konfiguracja cookie (httpOnly, SameSite, secure w produkcji)
FlashMiddleware
Flash messages — jednorazowe dane z sesji (błędy walidacji, stare dane formularza, flagi sukcesu)
CsrfTokenMiddleware
Generowanie tokenabin2hex(random_bytes(32)) w sesji, udostępniany w szablonach przez addGlobal()
CsrfGuardMiddleware
Weryfikacja tokena — dla każdego POST sprawdza zgodność tokena z sesją. Brak → 403
ValidationException
Middleware
Obsługa błędów walidacji — przechwytuje ValidationException, zapisuje błędy i stare dane do flash, przekierowuje z powrotem
TemplateDataMiddleware
Dane globalne widoku — tytuł strony i inne dane dostępne w każdym szablonie
AuthRequiredMiddleware
Ochrona routów — brak sesji → redirect do logowania. Dołączany per-rout
IncomesCategoriesMiddleware
OutcomesCategoriesMiddleware
Ładowanie kategorii — pobiera z bazy kategorie zalogowanego użytkownika i zapisuje do sesji
BalanceDateMiddleware
Zakres dat bilansu — zarządza wybranym przedziałem dat, przechowuje w sesji

06Stack technologiczny

Backend

  • PHP (strict_types)własny framework src/Framework/
  • MySQL + PDOprepared statements, FETCH_ASSOC, method chaining
  • Composer + PSR-4autoloading namespace App\ i Framework\
  • bcrypthashowanie haseł przy rejestracji
  • Gemini APIwywołanie przez file_get_contents + stream_context
  • PHP Reflection APIautowiring w kontenerze DI
  • CSRF (bin2hex/random_bytes)kryptograficznie bezpieczny token

Frontend

  • Bootstrap 5responsywny layout, Tabs, Modal, Navbar
  • jQueryDOM manipulation, AJAX, event handling
  • DateRangePickerpicker z predefiniowanymi przedziałami dat
  • Moment.jsformatowanie i parsowanie dat po stronie klienta
  • Vanilla JS (outcome.js)real-time limit info, dynamiczne klasy CSS
  • LocalStoragepersystencja wybranego okresu i aktywnego taba
  • Castoro (Google Fonts)serif font dla nagłówków

07Struktura projektu

MOJ_BUDZET/ ├── public/ # document root │ ├── index.php # entry point │ └── assets/ │ ├── balance.js # DateRangePicker, wykresy, AJAX dat │ ├── outcome.js # real-time limit info │ └── settings.js # tab persistence, modale kategorii │ ├── src/ │ ├── Framework/ # własny mikro-framework │ │ ├── App.php # fluent API: ->get()->post()->add() │ │ ├── Router.php # regex routing + middleware chain │ │ ├── Container.php # DI przez Reflection API │ │ ├── Database.php # PDO wrapper, method chaining │ │ ├── TemplateEngine.php # output buffering, globale szablonu │ │ ├── Validator.php # walidacja z 13 regułami │ │ ├── Contracts/ # RuleInterface, MiddlewareInterface │ │ └── Rules/ # 13 klas reguł walidacji │ │ │ └── App/ │ ├── Config/Routes.php # rejestracja routów z middleware │ ├── Controllers/ # 8 kontrolerów │ ├── Services/ # Transaction, User, Api, Validator │ ├── Middleware/ # 9 klas middleware │ ├── Resources/prompts/ │ │ └── financialAdvisor.txt # prompt-szablon dla Gemini │ └── views/ # widoki PHP + partials │ ├── database.sql # schemat bazy MySQL └── composer.json # PSR-4 autoloading

08Czego dowodzi ten projekt

Własny framework

Router, DI container, template engine, validator, 9 middleware — zbudowany od zera, dowód rozumienia architektury MVC.

Reflection API

Autowiring przez ReflectionClass — mechanizm używany przez Laravel i Symfony pod maską.

REST API + AJAX

Endpoint limit-info wywoływany dynamicznie przy każdej zmianie kategorii lub kwoty — bez przeładowania strony.

Prompt engineering

Sztywny szablon dla Gemini z twardymi ograniczeniami — strukturyzacja wyjścia LLM na potrzeby UI.

Bezpieczeństwo

CSRF z kryptograficznym tokenem, ochrona routów middleware, bcrypt, prepared statements.

Reguły OCP

13 klas implementujących RuleInterface — nowa reguła = nowa klasa, zero zmian w Validatorze.

MySQL + JOINy

Sumy przez GROUP BY, filtrowanie BETWEEN dat, INNER JOIN między transakcjami a kategoriami użytkownika.

Pełny produkt

Rejestracja → kategorie → transakcje → bilans → AI analiza — kompletny flow finansowy gotowy do użycia.

Zobacz pełny kod na GitHubie

Repozytorium zawiera pełny framework PHP, aplikację, schemat bazy danych i prompt AI doradcy finansowego.

Zobacz kod na GitHub

09Aplikacja w akcji

Poniżej nagranie pokazujące aplikację w działaniu — dodawanie transakcji, real-time informacja o limicie kategorii, bilans z wykresami i DateRangePicker oraz analiza AI doradcy finansowego.

· · ·
Udostępnij jeśli spodobał Ci się mój projekt