# SoftSPM_2 - aplikacja Laravel (nakładka + szkielet) Historycznie ten katalog trzymał **tylko pliki specyficzne dla SoftSPM** (modele, kontrolery, widoki, konfiguracja, trasy), a czysty szkielet Laravela stał osobno na UAT jako `softspm_pge`. Od 2026-09-03 katalog jest **pełnym, uruchamialnym projektem Laravel** - szkielet został domieszany lokalnie, żeby dało się pracować i testować na stacji roboczej. Lista plików nakładki (to, co nakładamy na szkielet na UAT/produkcji) jest zapisana w [`docker/overlay-files.txt`](docker/overlay-files.txt). > Migracja legacy PHP 5.4/5.6 → Laravel. > **Źródło migracji: `C:\Programy\xampp_old\htdocs\trzeciCloude_v1\`** - NIE `newPGE` > ani inne kopie w `htdocs/`. Audyt legacy i mapa `siteNNN` → trasy: [docs/LEGACY.md](docs/LEGACY.md). > Kontekst i decyzje: patrz pamięć > projektu Claude. Charakterystyka: 3 bazy MariaDB, **produkcja bez internetu > (air-gap, LAN)**. > **Wersja frameworka: Laravel 12** (nie 11). Laravel 11 jest EOL - Composer > odmawia instalacji każdego wydania 11.31+ z powodu niezałatanych advisory > bezpieczeństwa, a nowszych 11.x już nie ma. **UAT/produkcję trzeba podnieść > do 12.** Kod nakładki nie wymagał żadnych zmian przy tym przejściu. > **Tailwind v4**, konfigurowany w CSS (`@theme` w `resources/css/app.css`). > Pliku `tailwind.config.js` **nie ma i nie powinno być** - starsze fragmenty > tego README, które go wymieniają, są nieaktualne. ### Środowiska | Środowisko | OS | Ścieżka | Internet | |---|---|---|---| | **UAT / testowe** | Debian | `/var/www/html/softspm_pge` | jest (build assetów tutaj) | | **Produkcja** | Windows Server | (web root → `public/`) | **BRAK (air-gap, LAN)** | > **Debian = case-sensitive!** Nazwy plików/ścieżek (komponenty Blade, fonty, > obrazki) muszą zgadzać się co do wielkości liter. Trzymamy wszystko lowercase. ## Środowisko lokalne (Docker) Stacja robocza ma tylko PHP 5.6 i 7.4 (XAMPP), a Laravel 12 wymaga PHP ≥ 8.2 - dlatego dev stoi w kontenerze. **Baza NIE jest kontenerem**: łączymy się do istniejącej MariaDB `10.42.1.210` (podejście database-first). Kontener: `docker/Dockerfile` (PHP 8.3 + Apache + Node 20, rozszerzenia `pdo_mysql mysqli soap zip gd intl opcache`; `soap` jest wymagany przez `SyndisService`). DocumentRoot → `public/`. ```bash docker compose up -d app # aplikacja na http://localhost:8000 docker compose exec app php artisan ... # artisan docker compose exec app composer ... # composer docker compose exec app npm run build # produkcyjny build assetów docker compose --profile dev up vite # opcjonalny hot-reload (port 5173) ``` Pierwsze uruchomienie na czystej maszynie: ```bash cp .env.example .env # uzupełnić DB_PASSWORD docker compose build app docker compose up -d app docker compose exec app composer install docker compose exec app npm install docker compose exec app npm run build docker compose exec app php artisan key:generate docker compose exec app chmod -R 777 storage bootstrap/cache docker compose exec app php docker/check/db-check.php # smoke-test 3 połączeń ``` `php artisan migrate` **nie jest uruchamiane** - sesje i cache lecą na pliki, schematu legacy nie dotykamy. ### Zasoby binarne (air-gap) Nie da się ich pobrać na produkcji, więc leżą w repo (`.gitignore` ma na nie wyjątki): | Plik | Skąd | |---|---| | `public/images/logo.png`, `dashboard_01.png`, `dashboard_02.png` | makiety `newPGE/uj_dashboard/` (jedyna rzecz, po jaką sięgamy do `newPGE` - kodu legacy szukamy w `trzeciCloude_v1`) | | `public/fonts/inter/Inter-Variable.woff2` | fontsource (Inter VF, latin) | | `public/fonts/jetbrains-mono/JetBrainsMono-Variable.woff2` | fontsource (JetBrains Mono VF, latin) | | `public/fonts/material-symbols/MaterialSymbolsOutlined.woff2` | fontsource (Material Symbols Outlined VF) | Vite przy buildzie ostrzega, że `/fonts/...` nie rozwiązuje się w czasie budowania - to jest **oczekiwane**: ścieżki są absolutne i obsługuje je serwer z `public/`. ## Jak nałożyć na `softspm_pge` (UAT, Debian) 1. Skopiować pliki nakładki (lista: `docker/overlay-files.txt`) do `/var/www/html/softspm_pge/`, nadpisując m.in. `config/database.php`, `config/navigation.php`, `config/softspm.php`, `routes/web.php`, `resources/`, `package.json`, `vite.config.js`. `vendor/` i `node_modules/` zostają; z `public/` kopiujemy tylko `images/` i `fonts/`. 2. Uprawnienia (Debian): `chown -R www-data:www-data storage bootstrap/cache`. 3. Front-end (Tailwind v4 przez `@tailwindcss/vite`, konfiguracja w `resources/css/app.css`; NIE ma `tailwind.config.js` ani `postcss.config.js`): ``` npm install npm run build # produkcyjny build do public/build ``` 4. `.env` (sekcja niżej) + `php artisan config:cache`. **NIE** uruchamiać `php artisan migrate` - sesje/cache trzymamy na plikach (patrz `.env`), więc nie tworzymy żadnych tabel; legacy schematu nie dotykamy. ## Zmienne `.env` ```dotenv APP_NAME=SoftSPM APP_LOCALE=pl # Database-first + brak potrzeby tabel pomocniczych → sesje/cache na plikach. # Dzięki temu NIE uruchamiamy migracji i nie dorzucamy tabel do baz legacy. SESSION_DRIVER=file CACHE_STORE=file QUEUE_CONNECTION=sync DB_CONNECTION=softspm # Baza operacyjna (domyślna) DB_HOST=10.42.1.210 DB_PORT=3306 DB_DATABASE=softspm DB_USERNAME=przemek DB_PASSWORD=visia2209 # Bazy raportowa i historyczna (ten sam host/user, inna nazwa bazy) DB_REP_DATABASE=softspm_rep DB_HIS_DATABASE=softspm_his # Migracja haseł MD5->bcrypt - włączyć DOPIERO po rozszerzeniu # kolumny sys_users.USR_PASSWORD do VARCHAR(255). SOFTSPM_REHASH=false ``` ## Air-gap (produkcja bez internetu) - zasady - **Zero CDN w runtime.** Tailwind kompilujemy lokalnie (Vite). W makietach (`uj_dashboard/`) Tailwind/fonty szły z CDN - to tylko podgląd. - **Fonty self-hosted.** Pobrać i umieścić w `public/fonts/` (na maszynie z netem), zgodnie z `@font-face` w `resources/css/app.css`: - `public/fonts/inter/Inter-Variable.woff2` - `public/fonts/jetbrains-mono/JetBrainsMono-Variable.woff2` - `public/fonts/material-symbols/MaterialSymbolsOutlined.woff2` - **Tło logowania:** `public/images/login-bg.jpg` (zamiast obrazka z Google w makiecie - można użyć `trzeciCloude_v1/images/tlo.jpg`). - **Build na UAT (Debian, ma internet), wdrożenie na Windows (air-gap):** assety i zależności budujemy na UAT (`npm run build`, `composer install`), a na produkcję Windows kopiujemy **gotowy artefakt** - pełny `vendor/` + skompilowane `public/build/` + self-hostowane fonty/obrazki. Na produkcji **bez** `composer install` / `npm install` (brak internetu i często Node). - **Web root produkcji (Windows):** serwer (IIS/Apache) musi wskazywać podkatalog `public/`, nie korzeń projektu. ## Co już jest (pierwszy pionowy slice) | Plik | Rola | |---|---| | `config/database.php` | 3 połączenia MariaDB (database-first, bez zmiany schematu) | | `config/softspm.php` | flaga migracji haseł MD5→bcrypt | | `resources/css/app.css` | tokeny „Industrial Precision" (Tailwind v4, `@theme`) + fonty self-hosted | | `resources/views/components/guest-layout.blade.php` | layout logowania | | `resources/views/components/app-layout.blade.php` | layout aplikacji (topbar + sidebar) | | `resources/views/auth/login.blade.php` | ekran logowania (wg makiety) | | `resources/views/dashboard.blade.php` | pulpit (placeholder mapy) | | `app/Models/User.php` | model na `sys_users` | | `app/Http/Controllers/Auth/LoginController.php` | logowanie MD5/bcrypt + wybór oddziału | | `app/Http/Controllers/WellController.php` | Studnie: lista (site401) + dodawanie/edycja (site301A/E/inf) | | `app/Services/WellService.php` | transakcyjny zapis studni (lookupy + create + update) | | `resources/views/wells/index.blade.php` | lista studni (wg makiety "Well Inventory") | | `resources/views/wells/create.blade.php`, `edit.blade.php` | formularze dodania/edycji | | `resources/views/components/well-field.blade.php`, `well-select.blade.php` | pola formularza | | `routes/web.php` | trasy: login / logout / dashboard / wells (CRUD) | ## Weryfikacja parytetu: Studnie (site401 → /wells) Nowa lista zastępuje **N+1** z legacy (podzapytania pompa/silnik/ON-OFF na każdy wiersz) **jednym** zapytaniem z JOIN-ami. Przed zatwierdzeniem sprawdzić na serwerze testowym, że zwraca ten sam zestaw studni co legacy, dla tego samego oddziału i statusu. Szybki test liczności (MariaDB, podstaw ``, ``): ```sql -- Legacy: bazowa lista (przed N+1) - site401.php, zapytanie $query SELECT COUNT(*) FROM seg_wells LEFT JOIN seg_dev_resources ON DRS_DEV_ID=WLL_ID AND DRS_DEV_TYPE=12 LEFT JOIN seg_well_pump_eng_rel ON RWL_WLL_ID=WLL_ID WHERE DRS_DEPARTMENT='' AND DRS_STATUS_DIC_ID=; ``` Porównać z `->total()` na `/wells?status=` (ten sam oddział z sesji). Dodatkowo wyrywkowo sprawdzić kilka studni: nazwa pompy/silnika, nr seryjny i ostatni stan ON/OFF (DRD_RESOURCES_DETAIL=507, najnowszy DRD_ID) muszą się zgadzać. ### Świadome odstępstwa od legacy (do akceptacji) - **Paginacja serwerowa** (`paginate(20)`) zamiast cache w sesji + limit 100. Usuwa to limit 100 i checkbox „Pokaż wszystkie" (zbędny przy realnej paginacji). - **Filtry przez GET** (zamiast POST+sesja) - czyste linki, komponują się z paginacją. - **Stan ON/OFF jako chip** (ON/OFF) zamiast ikon power_on/off.png. ## Dodawanie / edycja studni (site301A/E/inf → /wells/create, /wells/{drs}/edit) Zapis jest **wielotabelowy**. Dodanie studni wstawia do: `seg_wells`, `seg_dev_resources` (typ 12), `seg_dev_resources_det` ×3 (średnica `DST`, głębokość `LS`, zasilanie `LZ`), `seg_object_hole_cards`, `seg_object_hole_cards_his`, `seg_dev_resources_his`. Edycja aktualizuje `seg_wells`, `seg_dev_resources`, `seg_object_hole_cards` oraz (gdy istnieje) datę zabudowy w `seg_wells_exchanged`. Cała logika w `WellService`. ### Ulepszenia względem legacy - **Transakcja** (`DB::transaction`) - legacy robił te INSERT-y bez transakcji (ryzyko danych częściowych przy błędzie). Teraz zapis jest atomowy. - **Walidacja** wejścia + kontrola unikalności nazwy. ### Świadome odstępstwa / pominięcia (do akceptacji) - **NIE przebudowujemy `rep_object_departments`** po każdym dodaniu (legacy robił `truncate`+`insert` całej tabeli przez ajax `refresh_departments`). To wąskie gardło wydajności; nowa lista `/wells` go nie używa. Do rewizji przy migracji raportów, jeśli inne ekrany na nim polegają. - **Słowniki w języku PL** (`DIC_POL_LANG`) - pełne i18n PL/EN/DE w osobnym etapie. - **`build_time`** jako jedno pole `time` (HH:MM) zamiast dwóch selectów godz./min. ### Weryfikacja (na serwerze testowym) Dodać testową studnię w wybranym oddziale → sprawdzić, że pojawia się na `/wells` (status 3, ten oddział) oraz że powstały spójne wpisy w 6 tabelach. Edytować → sprawdzić aktualizację `seg_wells`/`seg_dev_resources`/`seg_object_hole_cards`. ## Otwarte do ustalenia - **Hasła MD5 → bcrypt** - `USR_PASSWORD` to `varchar(64)`, więc bcrypt się mieści (rehash bezpieczny bez zmiany schematu). Czeka na zgodę klienta (`SOFTSPM_REHASH=true`). - **Mapa offline** - strategia kafelków bez internetu (lokalny tile-server / kafelki statyczne / własny podkład kopalni). - **`rep_object_departments`** - czy odtworzyć przebudowę po zapisie studni (na razie pominięta - patrz wyżej).