234 lines
11 KiB
Markdown
234 lines
11 KiB
Markdown
# 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 `<DZIAL>`, `<STATUS>`):
|
||
|
||
```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='<DZIAL>' AND DRS_STATUS_DIC_ID=<STATUS>;
|
||
```
|
||
|
||
Porównać z `->total()` na `/wells?status=<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).
|