Files
admin/.tasks-imported/cms-admin-assets-root-folders-seed.md
vitya 85b3ee847f import-stage: .tasks/ via split (temp prefix, await STATUS.md merge)
git-subtree-dir: .tasks-imported
git-subtree-mainline: c40418239e
git-subtree-split: cbdc2b39aa
2026-05-21 13:48:02 +03:00

75 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# cms-admin-assets-root-folders-seed
## Goal
Для каждого `Sites.SiteId` в DB `MoreThenCms` где нет соответствующего root `Folders` row с `Discriminator='AssetsFolder'`, `LoweredPath='/'`, `OwnerId=<SiteId>` — добавить недостающий root row. Это unblock'нёт admin `/admin/assets/<siteId>/getList?path=` который сейчас crash'ит 500 NullReferenceException на пустых assets для 15+ sites (включая `emspb.ru`, `pilorama98.ru`, `labtools.pro`, `kupimknigi.spb.ru`, `sestech.ru`, etc.).
## Root cause
`MoreThenCms.Admin.ViewModels.Builders.AssetsJsonViewModelBuilder.Build` (`AssetsJsonViewModelBuilder.cs:22`) делает `new JValue(model.ParentPath)` БЕЗ null-check на model. `_assetsFoldersService.GetFolderByPath(ctx, ownerId, '')` возвращает null когда root folder не существует. Это происходит для sites которые **никогда не открывали admin assets UI** (root создаётся lazy при first upload, видимо).
Frontend код (`AssetsAppFunc.cs:66-86`) делает proper null-check → HTTP 404. Только admin view-model builder упустил.
Двух-уровневое решение:
- **Краткосрочно (этой task'и):** seed missing root rows в DB. Один INSERT per site. Risk: minimal (lookup existing row pattern; используем same shape).
- **Долгосрочно (отдельный task):** patch `AssetsJsonViewModelBuilder.Build` → null-guard → empty response. Требует recompile DLL `MoreThenCms.Admin.dll` (нет полного build env, рискованно).
## Key files
- `MoreThenCms\Assets\Services\AssetsFoldersService.cs:47-54``GetFolderByPath` query (returns null if not found).
- `MoreThenCms.Web\ViewModels\Builders\AssetsJsonViewModelBuilder.cs:22` — точка падения.
- `MoreThenCms.Web\Admin\Controllers\AssetsController.cs:44-54` — вызов GetList.
- DB: `[MoreThenCms].[dbo].[Folders]` (polymorphic, Discriminator='AssetsFolder' для assets).
## Discovery (2026-05-19)
- 15 sites без root AssetsFolder подтверждены через `SELECT s.SiteId, s.PrimaryDomain, ... FROM Sites s LEFT JOIN ...`. См. полный список в Decisions.
- Sample existing root row: `FolderId=1591A38C-..., OwnerId=7EB313DD-F289-..., Path='/', LoweredPath='/', DateCreated=2017-03-13 07:10:15, CreatedById=E4CC416B-...`. Тот же shape надо воспроизвести для missing.
- Затрагивает: emspb.ru (`96EBC481-...`), pilorama98.ru (`37E67FC4-...`), labtools.pro, kupimknigi.spb.ru, sestech.ru, aquamax.spb.ru, artmone.pro, priemka-kvartiry.ru, profund.spb.ru, ics-artmaterials.com, _voda-indigo.ru, plus 4 sites с NULL `PrimaryDomain`.
## План
1. **Dry-run**: `SELECT COUNT(*) FROM Sites s WHERE NOT EXISTS (root for s.SiteId)` — должно быть = 15 (sanity check).
2. **Seed**: INSERT root row per missing site. Один transaction, no rollback unless count mismatch.
3. **Verify**: повторить original probe — root count should be 0 missing.
4. **Test**: hit `https://emspb.snolla.com/admin/assets/96EBC481-.../getList?path=` (через docker exec без auth → 302→login без crash). Затем user-side browser test.
## SQL
```sql
DECLARE @CreatedById uniqueidentifier = (
SELECT TOP 1 CreatedById FROM Folders
WHERE LoweredPath='/' AND Discriminator='AssetsFolder'
);
INSERT INTO Folders (FolderId, OwnerId, Path, LoweredPath, DateCreated, UtcDateCreated, CreatedById, Discriminator)
SELECT NEWID(), s.SiteId, '/', '/', SYSDATETIME(), SYSUTCDATETIME(), @CreatedById, 'AssetsFolder'
FROM Sites s
WHERE NOT EXISTS (
SELECT 1 FROM Folders f
WHERE f.OwnerId = s.SiteId
AND f.LoweredPath = '/'
AND f.Discriminator = 'AssetsFolder'
);
```
## Atomic revert
Сохранить список inserted FolderId через `OUTPUT INSERTED.FolderId` в temp file. Если что:
```sql
DELETE FROM Folders WHERE FolderId IN (<list>);
```
## Open questions
- [ ] Аналогичная проблема для ImagesFolder/StylesheetsFolder/ScriptsFolder в admin Themes UI? Проверить.
- [ ] DLL patch `AssetsJsonViewModelBuilder.Build` нужен в долгую — отдельная task. Сейчас обходим seed'ом.
## Decisions log
- 2026-05-19: вынес из `cms-port-leak-fix` (там был open issue #8 на emspb). User подтвердил воспроизводимость на pilorama98 → не site-specific, общая data issue.
- 2026-05-19: **DB seed применён** — 15 rows inserted (single transaction, idempotent NOT EXISTS). Inserted FolderId/OwnerId captured в `cms-admin-assets-root-folders-seed.inserted-rows.txt`. Server-side verified (probe вернул 302→login вместо 500). User browser-verified на pilorama98/emspb — admin assets открывается, empty list без ошибок.
- 2026-05-19: **DLL recompile отложен**`AssetsJsonViewModelBuilder.Build` нужен null-guard как defensive code, но требует build env (нет gitea/build/registry на recovery host'е). Ждёт [[vds-kzntsv-bootstrap]] для восстановления pipeline'а. На текущем seed-only fix'е admin assets работает для всех 15 sites.
## Completed steps
- [x] Diagnostic: stack trace из Application event log → `AssetsJsonViewModelBuilder.cs:22` NullRef on `model.ParentPath`. Source code analysis показал отсутствие null-check (vs proper null-check во frontend `AssetsAppFunc.cs:66-86`).
- [x] DB probe schema: `Folders` table polymorphic с Discriminator, columns FolderId/OwnerId/Path/LoweredPath/DateCreated/CreatedById обязательные.
- [x] Dry-run: 15 sites без root AssetsFolder (включая emspb/pilorama98/labtools.pro/kupimknigi/sestech/etc), 4 sites с NULL PrimaryDomain тоже в списке.
- [x] **SQL seed** через `docker exec mssql sqlcmd` — INSERT 15 rows с `OUTPUT INSERTED.FolderId, INSERTED.OwnerId INTO @Inserted`, output saved в `.tasks/cms-admin-assets-root-folders-seed.inserted-rows.txt`.
- [x] Verify: missing-root count = 0. Probe `wget --header='Host: emspb.snolla.com'` на getList URL → 302 Found (auth redirect — normal), нет больше 500.
- [x] User browser-verified pilorama98 admin assets открывается.
- [x] Wiki ingest: новый concept `cms-admin-assets-root-folder-seed.md`, snapshot issue #8 → resolved, `cms-server-port-leak-fix` sibling-link, log.md + index.md обновлены.
## Notes
- Связано: [[cms-server-port-leak-fix]] (предыдущая task'а закрыта; admin URLs теперь без `:8089`); [[recovery-architecture-snapshot]] (issue #8 — resolved); [[vds-kzntsv-bootstrap]] (build env для долгосрочного DLL fix'а).