# Florial vendor-install — likusios paketų spragos (užduotys)

## ✅ STATUS — visi sutvarkyti paketuose (GitLab + GitHub main)

| P | Fix (kur) | Host workaround pašalinti |
|---|---|---|
| **P1** | `va-core/core` require `mews/purifier` | ✅ `composer require mews/purifier` |
| **P2** | `va-core/auth` `Authenticate::redirectUsing` → `{env}.auth.login` | ✅ `bootstrap/app.php redirectGuestsTo` |
| **P3** | `florial:install` sėja `FlorialThemeSeeder` (guarded) | ✅ rankinis `db:seed FlorialThemeSeeder` |
| **P4** | nauja `themes:sync-defaults` komanda (`va-core/themes`) — invariantas „1 default per aplinką, tik įdiegta tema", per Composer `InstalledVersions`; kviečiama iš florial/seglo/cleverphant install; `--prefer=env:slug` | ✅ rankinis `UPDATE themes` |
| **P5** | 37 kabinetų blade → `cms_default_locale_tag()` (memoized) vietoj `config('cms.default_locale')` | ✅ `.env APP_LOCALE=lt` tampa tik default |
| **P6** | dokumentuota (variantas a) — install'e ištrinti skeleton welcome route | ✅ (dokumentuota, ne host bug) |
| **P7** | `OFISAI/SEGLO/CLEVERPHANT-INSTALL.md` atnaujinti (require +module-manager +va-cross, .env, srautas, password, aplinkos) | — |
| **P8** | `va-modules/pages` require `va-modules/grid-builder` (kanoniška — ateina per pages) | ✅ rankinis `grid-builder` require |
| **P9** | `va-modules/faq` migracija — `product_categories` FK sąlyginis (`Schema::hasTable`) → shop-less migrate nekrenta | ✅ `faq` išmetimas iš require |
| **P10** | `va-modules/menus` `MenusSeeder` — guard'inti **ABU** shop keliai (`class_exists(ProductCategory)` + `class_exists(ProductBrandGroup)`) + lookup metodų return-type'ai → `?Model` (kad type-resolve neforce'intų shop klasės). MenusSeeder sėja footer+admin.sidebar be shop; tik web.main/web.brands storefront meniu praleidžiami | ✅ `menus`/`custom-links` išmetimas |
| **P4-edge** | `themes:sync-defaults` — nuima phantom default kai aplinkai nėra įdiegtos temos (accounting→seglo) | — |

**Pastaba dėl require:** kadangi P8–P10 sutvarkyti paketuose (shop-optional), `menus`/`custom-links`/`faq` **LIEKA** require sąraše (dabar veikia shop-less), o `grid-builder` **NEvardijamas** (ateina per `va-modules/pages`). `va-cross/*` + `module-manager` — per `va-core/core`. **Švarus require = doc sąrašas, be jokių papildomų/išmetimų.**

**Papildomai (user):** `module-manager` + `va-cross/{media,seo,geo,microdata,cms-badges,logs}` — **hard-dep** (modeliai naudoja trait'us besąlygiškai; middleware) → įtraukti į visų 3 install require sąrašus. Default password `admin@viartas.lt / password` + aplinkų lentelės — visuose install docs. Temų default'ai visoms aplinkoms (florial: web+kabinetai→florial, admin→viartas-default; seglo: accounting→seglo; cleverphant: web→cleverphant).

> Nauja aplinka Florial'ui → tik pridėk `--prefer={env}:florial` prie `themes:sync-defaults` iškvietimo `FlorialInstallCommand`'e.

---


**Kontekstas.** Florial consumer-install (`va-*` paketai iš `satis.viartas.com`, Laravel 12, vendor-install, ne monorepo). Po ankstesnių fiksų app'as **veikia**: login → `/admin` + savitarna/pardavimai/operacijos + `/` (Florial landing) atsidaro. BET dalis dalykų laikinai pataisyta **host-side** (žr. „Host workaround'ai" apačioj) — jie turi persikelti į paketus. Žemiau — ką sutvarkyti paketuose, kad vendor-install veiktų be jokių host hack'ų (išskyrus `.env`).

Verifikacija po fiksų: nuo švaraus `composer create-project` + `composer require ...` + install žingsnių (be rankinių `composer require`, be `bootstrap/app.php` redagavimo, be rankinių DB `UPDATE`), `admin@viartas.lt / password`:
- `ofisai.test/` → Florial landing (200)
- `ofisai.test/admin` (guest) → redirect į login (ne 500)
- login → `/admin`, `/admin/puslapiai`, `/admin/naujienos`, `/admin/vartotojai`, `/admin/vartotojai/roles` (200)
- `/savitarna`, `/pardavimai`, `/operacijos` (200)

---

## P1 — `va-core/core`: nedeklaruotas `mews/purifier` (KRITINIS)
**Problema.** `va-core/core` naudoja `Purifier::clean()` (`src/Models/BaseModel.php:145` `setTranslation()`; taip pat `CmsBootSeeder`), bet `composer.json` nereikalauja `mews/purifier`. Švariame install'e `CmsBootSeeder` krenta: `Class "Mews\Purifier\Facades\Purifier" not found`.
**Fix.** `va-core/core/composer.json` → `require`: `"mews/purifier": "^3.4"`. Rebuild Satis.
**Patikra.** `composer update -W` be host `require mews/purifier`; `php artisan db:seed --class=…\CmsBootSeeder` praeina.

## P2 — Guest redirect: `Route [login] not defined` ties `/admin`
**Problema.** Laravel `Authenticate` middleware neautentikuotą svečią redirect'ina į `route('login')`, bet va-core/auth login route'ai pavadinti `{env}.auth.login` (`admin.auth.login`, `web.auth.login`) — bevardžio `login` nėra. Svečias ties `/admin` gauna 500 (`Route [login] not defined`). (Kabinetai nenukenčia — jų `*.access` middleware redirect'ina pirmiau.)
**Fix (paketuose).** `va-core/auth` (ar core) provider'yje registruoti neautentikuoto redirect'o strategiją, pvz. `Illuminate\Auth\Middleware\Authenticate::redirectUsing(fn ($request) => route(cms_current_environment().'.auth.login'))`, arba užregistruoti alias'ą/route'ą `login`, kuris veda į aktyvios aplinkos login'ą. Idealiai — mapinti pagal aplinką (admin→admin.auth.login, web→web.auth.login).
**Dabar (temp).** host `bootstrap/app.php` `redirectGuestsTo(...)` — turi būti pašalintas, kai paketas tvarko pats.

## P3 — `florial:install` neužsėja florial kabinetų temų
**Problema.** Nei `CmsBootSeeder` (sėja tik viartas-default/admin, protera/web, seglo/accounting), nei `florial:install` neįrašo florial temų eilučių `savitarna`/`pardavimai`/`operacijos`. Be jų kabinetai 500: `No hint path defined for [theme]`. Teko rankiniu būdu `db:seed --class=…\FlorialThemeSeeder`.
**Fix.** `florial:install` turi paleisti `ViartasThemes\Florial\Database\Seeders\FlorialThemeSeeder` (idempotentiškai).
**Patikra.** Po `florial:install` `themes` lentelėj yra florial eilutės savitarna/pardavimai/operacijos/web.

## P4 — Temų default'ai turi būti sudėti seederių VISOMS aplinkoms (ne rankiniu būdu, ne neįdiegta tema)
**Problema.** Po `CmsBootSeeder` + `FlorialThemeSeeder` `themes` lentelės default'ai buvo NETEISINGI vendor-install'e:
- `web` default = `protera` (`is_default=1`), o `florial/web` liko `is_default=0` — **protera šiam install'e neįdiegta**, tad `/` neturėjo galiojančios web temos.
- `accounting` default = `seglo` — **seglo neįdiegta** (Florial subsete accounting nenaudojamas, bet default vis tiek įrašomas).
Teko **rankiniu būdu `UPDATE themes`**, kad florial taptų `web` default. Tai turi tvarkyti seederiai/artisan, ne ranka.
**Fix (esmė).** Temų seederiai (`va-core/themes ThemeSeeder` + `va-themes/florial FlorialThemeSeeder`) turi:
1. Kiekvienai aplinkai (`admin`, `web`, `savitarna`, `pardavimai`, `operacijos`, ir kt.) nustatyti **default'ą į ĮDIEGTĄ temą** — niekada nepalikti default'o rodančio į neįdiegtą temą (protera/seglo). Tikrinti buvimą per Composer `InstalledVersions::isInstalled('va-themes/{slug}')` prieš sėjant/nustatant default.
2. Florial install'e: `web` default = `florial`, `admin` default = `viartas-default`, kabinetai (savitarna/pardavimai/operacijos) default = `florial`.
3. Užtikrinti „lygiai vienas default per aplinką" invariantą (nuimant seną default'ą, kai nustatomas naujas).
4. Būti idempotentiškiems ir paleidžiamiems iš `florial:install` (žr. P3), kad **švarus install'as be jokio rankinio DB `UPDATE`** duotų teisingus default'us visoms aplinkoms.
**Patikra.** Po `florial:install` (be rankinių DB pakeitimų): `SELECT environment,slug,is_default FROM themes WHERE is_default=1` → kiekvienoj aplinkoj default rodo į įdiegtą temą (web→florial, admin→viartas-default, kabinetai→florial); jokios protera/seglo kaip default.

## P5 — Kabinetų blade'ai: locale infix priklauso nuo `APP_LOCALE`
**Problema.** Kabinetų blade'ai skaičiuoja route infix'ą iš `config('cms.default_locale')` (= `env('APP_LOCALE','lt')`), o route **registracija** naudoja `cms_default_locale_tag()` (locales lentelė = `lt`). Jei `APP_LOCALE≠lt`, blade'as lt request'ui daro `route('savitarna.lt.employees')` → neegzistuoja → 500. Pvz.:
- `va-themes/florial/Resources/views/savitarna/company/dashboard.blade.php:26` (`$defaultTag = config('cms.default_locale','lt');` → `route("savitarna.{$infix}employees")`)
- ta pati schema: `va-themes/florial/Resources/views/{savitarna,pardavimai}/**/*.blade.php`, `va-florial/orders/Resources/views/operacijos/production.blade.php`
**Fix.** Blade'ai turi naudoti `cms_route('savitarna.employees')` (helperis jau tvarko locale) arba `$defaultTag = cms_default_locale_tag()` — ne `config('cms.default_locale')`. Tada nepriklausys nuo `APP_LOCALE`.
**Dabar (temp).** host `.env` `APP_LOCALE=lt` maskuoja problemą.

---

## P6 — `routes/web.php` skeleton welcome route užstoja CMS `/`
**Problema.** Laravel skeleton `routes/web.php` turi `Route::get('/', fn()=>view('welcome'))`, kuris **užstoja** CMS web home (`web.pages.home`) → `/` rodo Laravel welcome, ne Florial landing'ą. Teko **rankiniu būdu ištrinti** tą route.
**Fix (pasirinkti).**
- (a) Palikti tai host'o atsakomybe, BET aiškiai dokumentuoti `OFISAI-INSTALL.md`: „ištrink/ištuštink `routes/web.php` welcome route po `composer create-project`". **arba**
- (b) Jei norima „just works" be host redagavimo — apsvarstyti, kad CMS `/` route (per `config('cms.environments')`) registruotųsi taip, kad host welcome nekonfliktuotų (pvz. install komanda ištuština skeleton route, arba paketas dokumentuoja būtiną žingsnį).
**Patikra.** Švarus install → `/` rodo Florial landing (`web.pages.home`), ne `view('welcome')`.

## P7 — Atnaujinti install/docs failus po fiksų
Kai P1–P6 sutvarkyti paketuose, atnaujinti:
- **`OFISAI-INSTALL.md`** (guli ofisai aplanke) — kad atspindėtų realų veikiantį srautą: tikslus `composer require` sąrašas (ar `va-core/core` transityviai traukia va-cross/*, module-manager, grid-builder, mews/purifier), `.env` reikalavimai (žr. „Host konfigas"), seed žingsniai (`CmsBootSeeder` + `florial:install`, kuris jau turi paleisti FlorialThemeSeeder + temų default'us), asset publish, ir lt admin slug'ai.
- **Šitas `PACKAGE-FIXES.md`** — pažymėti kiekvieną P kaip „DONE" kai sutvarkyta, ir išbraukti atitinkamą host workaround'ą.
- Jei kuris paketas keitė `composer.json`/seederius — atsispindėti CHANGELOG'uose.

---

## Host konfigas (NE bug'ai — įtraukti į OFISAI-INSTALL.md, ne į paketus)
- `.env`: `APP_URL=http://ofisai.test`, `DB_DATABASE=ofisai` (root/tuščias), `AUTH_MODEL="ViartasCore\\Users\\Models\\User"`, `APP_LOCALE=lt`, `APP_FALLBACK_LOCALE=lt`.

## Host workaround'ai, kuriuos DABAR pridėjau (pašalinti po paketų fiksų)
Šie pakeitimai padaryti **rankiniu būdu ofisai app'e**, kad būtų galima pamatyti veikiantį puslapį — po atitinkamo P fikso paketuose juos reikia **pašalinti/atstatyti**:
1. `bootstrap/app.php` → `redirectGuestsTo(...)` blokas — pašalinti po **P2**.
2. `routes/web.php` → ištrintas skeleton welcome route (dabar failas ~tuščias) — po **P6** (jei renkatės (a), tai lieka kaip dokumentuotas žingsnis; jei (b) — atstatyti pagal sprendimą).
3. host `composer require mews/purifier` — pašalinti po **P1** (ateis per core transityviai).
4. rankinis `db:seed …\FlorialThemeSeeder` — nebereikės po **P3**.
5. rankinis DB `UPDATE themes SET is_default…` (florial→web default) — nebereikės po **P4**.
6. `.env APP_LOCALE=lt` — po **P5** taps tik patogumo default'u, ne būtinybe.

## Info kitam chatui: admin URL slug'ai
Default (lt) locale admin naudoja verstus slug'us: `/admin/puslapiai` (pages), `/admin/naujienos` (news), `/admin/vartotojai` (users), `/admin/vartotojai/roles`, `/admin/temos` (themes). EN variantai — `/admin/en/pages` ir t.t. `/admin/pages` duoda 404 (tai teisinga elgsena, ne bug'as).

---

## ⚠️ NAUJI radiniai (švaraus install verifikacija, 2-as raundas)

Po P1–P7 švarus install VEIKIA (visos aplinkos 200, jokio host/DB hack'o). BET teko koreguoti `composer require` sąrašą — 3 spragos:

### P8 — `va-modules/pages` nedeklaruoja `va-modules/grid-builder` (hard-dep)
`vendor/va-modules/pages/src/Models/Page.php:28,30` → `use ViartasModules\GridBuilder\Traits\HasGridContent;` (naudojamas besąlygiškai). Nei `va-modules/pages/composer.json`, nei core (va-cross aggregation) jo netraukia → `composer update` `package:discover` fatal: *Trait "ViartasModules\GridBuilder\Traits\HasGridContent" not found*.
**Fix:** `va-modules/pages/composer.json` require `va-modules/grid-builder` (kanoniška), ARBA įtraukti į OFISAI-INSTALL.md require sąrašą. (Dabar rankiniu būdu pridėtas į require.)

### P9 — `va-modules/faq` hard-couple'inasi su shop (`product_categories`)
`create_faq_categories_table` migracija daro FK `faq_categories.product_category_id` → `product_categories` (va-shop lentelė, Florial subsete NĖRA) → `migrate` fatal: `errno 150 "Foreign key constraint is incorrectly formed"`.
**Fix:** faq neturi FK'inti į shop, kai shop neįdiegtas (nullable be FK, arba guard per lentelės buvimą / atskiras optional migracijos žingsnis). ARBA — **išimti `va-modules/faq` iš Florial install require** (dabar išimtas).

### P10 — `va-modules/menus` `MenusSeeder` hard-couple'inasi su shop (`ProductCategory`)
`va-modules/menus/Database/Seeders/MenusSeeder.php:14` `use ViartasShop\ProductCategories\Models\ProductCategory;`, naudojamas `productCategoryBySlug()` (~1235 eil.). `CmsBootSeeder` kviečia `MenusSeeder` (per `callIfExists`, bet guard'as tik ant MENUS paketo buvimo, ne ant shop) → *Class "ViartasShop\ProductCategories\Models\ProductCategory" not found*.
**Fix:** `MenusSeeder` shop-nuorodas guard'inti `class_exists(ProductCategory::class)` (menu vis tiek renderisi be shop items — doc-block tai mini). ARBA — **išimti `va-modules/menus` (+ `custom-links`) iš Florial install require** (dabar išimti).

### Pastaba dėl install require sąrašo
Atnaujintame OFISAI-INSTALL.md require sąraše **`va-modules/menus`, `va-modules/custom-links`, `va-modules/faq` laužia shop-less Florial install** (P9/P10). Kol paketai neguard'inti — juos **išimti iš Florial require** (arba padaryti shop-optional). `va-modules/grid-builder` — **pridėti** (P8), kol pages jo nedeklaruoja.

### P4 edge — `accounting` aplinkos default = `seglo` (neįdiegta)
Po `themes:sync-defaults` `SELECT … WHERE is_default=1`: `accounting → seglo` (seglo neįdiegta). Florial aplinkoms (web/admin/kabinetai) — teisinga (florial/viartas-default). `accounting` Florial'e nenaudojamas, tad neblokuoja, bet `themes:sync-defaults` idealiai turėtų netraukti/neįdėti neįdiegtos temos kaip default ir accounting'ui.

**Švaraus install faktinis require (kas veikia):** doc sąrašas **MINUS** `va-cross/*` + `va-core/module-manager` (ateina per core) **MINUS** `va-modules/{menus,custom-links,faq}` (P9/P10) **PLIUS** `va-modules/grid-builder` (P8).

---

## 🔴 P10 — DAR NE IKI GALO (3-as raundas)

P9 (faq FK) — **ISTAISYTA** ✓ (`create_faq_categories_table` praeina). BET **P10 (menus) VIS DAR LŪŽTA**:

`CmsBootSeeder` → `MenusSeeder` fatal:
```
Class "ViartasShop\ProductBrandGroups\Models\ProductBrandGroup" not found
vendor/va-modules/menus/Database/Seeders/MenusSeeder.php:1251
```
Praeitas fix'as guard'ino `ProductCategory`, bet **`ProductBrandGroup` liko neguard'intas**. Ir esminis dalykas:

**`MenusSeeder` yra padangų-shop storefront meniu seederis** — `run()` sėja `web.main` (padangos: „lengvuju-automobiliu-padangos", „ratlankiai"…), `web.brands` (gamintojai: Michelin/Bridgestone/Continental). Naudoja DVI shop klases (abu `use` viršuje → PHP jas resolve'ina):
- `MenusSeeder.php:13` `use ViartasShop\ProductBrandGroups\Models\ProductBrandGroup;`
- `MenusSeeder.php:14` `use ViartasShop\ProductCategories\Models\ProductCategory;`

**Svarbu:** metodų return-type hint'ai **priverčia** klasės krovimą net su vidiniu `class_exists` guard'u:
- `protected function productBrandGroupBySlug(string $slugLt): ?ProductBrandGroup` (~1249)
- `protected function productCategoryBySlug(string $slugLt): ?ProductCategory` (~1233)
PHP resolve'ina `?ProductBrandGroup`/`?ProductCategory` tipą kvietimo metu → fatal, jei shop neįdiegtas. Guard'inti tik `if (class_exists(...))` viduje NEUŽTENKA.

**Tikras fix (pasirinkti):**
- (a) `CmsBootSeeder` NEkviesti `MenusSeeder` (ar jo shop-meniu dalies) kai shop neįdiegtas — guard `class_exists(ProductCategory::class) && class_exists(ProductBrandGroup::class)` PRIEŠ `callIfExists(MenusSeeder)`. **arba**
- (b) Iškelti shop-meniu (`web.main` padangų sekcijas + `web.brands`) į atskirą shop-only seederį/klasę (be shop `use`/type-hint'ų `MenusSeeder`'yje), kad `MenusSeeder` be shop krautųsi ir sėtų tik ne-shop meniu (footer, admin.sidebar). **arba**
- (c) Florial'e — `va-modules/menus` (+ `custom-links`) neįtraukti į require (kaip P9/P10 pradinė rekomendacija). Padangų storefront meniu Florial'ui vis tiek nereikalingas.

**Statusas:** kai menus išimtas (praeitas raundas), VISKAS kita žalia (visos aplinkos 200, guest redirect, temų default'ai). Vienintelis likęs blokeris švariam install'ui su doc require sąrašu = šitas `MenusSeeder` shop-coupling.
