Полный PDF/DOCX-экспорт ПТИЦА-отчёта (/analyze): §1-§7 + альтернативы #2259

Closed
opened 2026-07-03 06:19:17 +00:00 by bot-backend · 2 comments
Collaborator

Обнаружено при «догоне» экспортеров (2026-07-03): backend-экспортёра полного ПТИЦА-отчёта /analyze не существует. Текущие экспортёры рендерят другое:

  • layout_tz_pdf — только ТЗ unit-mix §4.2 (supply-only блок догнан);
  • report_pdf/md/docx/pptx — отдельный форсайт-отчёт §13/§22 (run.result), не /analyze;
  • snapshot_pdf — одностраничный снимок POI+конкуренты.

Секции §1-§7 (сети/резервы §3, планировки §4.2, тренд §4.3, атмосфера, прогноз §6, концепция §7, «Как участок сходится») живут только во фронте.

Задача: экспортёр полного отчёта (WeasyPrint HTML по паттерну report_pdf, данные — тот же analyze-ответ + best-layouts + connection-capacity), кнопка «Скачать отчёт (PDF)» на странице анализа. Размер M-L → дробить (Foundation: HTML-шаблон §1-§3 → §4-§6 → §7+альтернативы+карты-статика).

Приоритет — по слову Anton (для встреч/презентаций девелоперам может быть ценно).

Обнаружено при «догоне» экспортеров (2026-07-03): backend-экспортёра **полного** ПТИЦА-отчёта `/analyze` не существует. Текущие экспортёры рендерят другое: - `layout_tz_pdf` — только ТЗ unit-mix §4.2 (supply-only блок догнан); - `report_pdf/md/docx/pptx` — отдельный форсайт-отчёт §13/§22 (`run.result`), не /analyze; - `snapshot_pdf` — одностраничный снимок POI+конкуренты. Секции §1-§7 (сети/резервы §3, планировки §4.2, тренд §4.3, атмосфера, прогноз §6, концепция §7, «Как участок сходится») живут только во фронте. **Задача:** экспортёр полного отчёта (WeasyPrint HTML по паттерну report_pdf, данные — тот же analyze-ответ + best-layouts + connection-capacity), кнопка «Скачать отчёт (PDF)» на странице анализа. Размер M-L → дробить (Foundation: HTML-шаблон §1-§3 → §4-§6 → §7+альтернативы+карты-статика). Приоритет — по слову Anton (для встреч/презентаций девелоперам может быть ценно).
Author
Collaborator

План реализации (tech-analyst, 2026-07-03) — R1 = PDF end-to-end, 5 sub-PR

Ключевые решения:

  • Карты/3D → server-side статика без браузера: geopandas+matplotlib+contextily (OSM basemap) — все слои уже в analyze-payload как GeoJSON; §7 = 2D-footprint корпусов из ConceptVariantsResult (настоящий 3D в PDF не нужен). Скриншот-подход отвергнут (Chromium только в worker-образе, хрупко, зависимость от фронт-рантайма). Fallback: при недоступности OSM-тайлов — карта без подложки, PDF не падает.
  • Celery-джоба + поллинг (зеркало forecast_site_finder_report): POST /{cad}/report → 202, GET status, GET download (FileResponse). Sync-endpoint отвергнут — 30+ страниц WeasyPrint.
  • Кэш: PDF-файл на общий volume + метадата-ран report-pdf-1.0 в analysis_runs; ключ включает run_id обоих источников (analyze + forecast).
  • §7: дефолтная программа concepts (count=3 comfort) — отчёт самодостаточен.
  • DOCX — R2 (python-docx по тем же нормализованным словарям + PNG-карты; не блокер сценария «один файл инвесткомитету»).
  • DRY: §4–§7 переиспользуют PURE-хелперы report_pdf (_normalize/_fmt/…); образец архитектуры — layout_tz_pdf (PURE build_html + тонкая WeasyPrint-обёртка). Кириллица/шрифты уже решены в runner-образе (fonts-dejavu-core).

Sub-PR (порядок мёржа):

PR Содержимое Оценка
A Foundation PURE HTML §1–§3 + альтернативы (full_report_html.py) M
B Sections PURE HTML §4–§7 (реюз report_pdf-хелперов) M
C Maps report_maps.py (matplotlib/contextily + footprint) + deps/uv.lock M
D Integration BE Celery task + кэш + 3 endpoint'а M
E Integration FE Кнопка «Полный отчёт» в PticaReports/ExportButtons + поллинг S

Риски: WeasyPrint память (только worker, PNG ≤1600px), contextily-сеть (timeout+fallback), uv.lock sync для новых deps, свежесть ранов (дата в статусе).

Стартую PR-A.

## План реализации (tech-analyst, 2026-07-03) — R1 = PDF end-to-end, 5 sub-PR **Ключевые решения:** - **Карты/3D → server-side статика без браузера**: geopandas+matplotlib+contextily (OSM basemap) — все слои уже в analyze-payload как GeoJSON; §7 = 2D-footprint корпусов из ConceptVariantsResult (настоящий 3D в PDF не нужен). Скриншот-подход отвергнут (Chromium только в worker-образе, хрупко, зависимость от фронт-рантайма). Fallback: при недоступности OSM-тайлов — карта без подложки, PDF не падает. - **Celery-джоба + поллинг** (зеркало forecast_site_finder_report): POST /{cad}/report → 202, GET status, GET download (FileResponse). Sync-endpoint отвергнут — 30+ страниц WeasyPrint. - **Кэш**: PDF-файл на общий volume + метадата-ран `report-pdf-1.0` в analysis_runs; ключ включает run_id обоих источников (analyze + forecast). - **§7**: дефолтная программа concepts (count=3 comfort) — отчёт самодостаточен. - **DOCX — R2** (python-docx по тем же нормализованным словарям + PNG-карты; не блокер сценария «один файл инвесткомитету»). - **DRY**: §4–§7 переиспользуют PURE-хелперы report_pdf (_normalize/_fmt/…); образец архитектуры — layout_tz_pdf (PURE build_html + тонкая WeasyPrint-обёртка). Кириллица/шрифты уже решены в runner-образе (fonts-dejavu-core). **Sub-PR (порядок мёржа):** | PR | Содержимое | Оценка | |---|---|---| | A Foundation | PURE HTML §1–§3 + альтернативы (full_report_html.py) | M | | B Sections | PURE HTML §4–§7 (реюз report_pdf-хелперов) | M | | C Maps | report_maps.py (matplotlib/contextily + footprint) + deps/uv.lock | M | | D Integration BE | Celery task + кэш + 3 endpoint'а | M | | E Integration FE | Кнопка «Полный отчёт» в PticaReports/ExportButtons + поллинг | S | Риски: WeasyPrint память (только worker, PNG ≤1600px), contextily-сеть (timeout+fallback), uv.lock sync для новых deps, свежесть ранов (дата в статусе). Стартую PR-A.
Author
Collaborator

R1 закрыт (2026-07-03) — PDF end-to-end на проде, прод-верифицирован

6 PR за один заход (все с pre-push ревью и правками):

  • #2284 PR-A — PURE HTML §1–§3 + блок альтернатив (13 тестов)
  • #2285 PR-B — §4–§7 (ревью поймало: building_program не существует на выходном ConceptVariant — переисточено из buildings_geojson.features)
  • #2286 PR-C — карты geopandas/matplotlib/contextily без браузера (ревью поймало утечку фигур в Celery — закрыта CM'ом, мутационно проверено)
  • #2287 PR-D — Celery-джоба + кэш (analyze_run_id, forecast_run_id) + 3 endpoint'а + volume с chown в deploy (ревью: атомарная запись, whitelist cad, дата из generated_at)
  • #2288 PR-E — кнопка «Полный отчёт (PDF)» в PticaReports + ExportButtons (общий хук, поллинг 5с/cap 3 мин; попутно заякорен reports//reports/ в .gitignore)
  • #2289 — косметика «Скачать отчёт ()» на fast-path из кэша (найдено qa)

Прод-верификация: /opt/gendesign/reports создан с правильным владельцем (chown из deploy отработал); полный цикл на 66:41:0404019:4728 — POST 202 → ready за ~10 сек → PDF 700 КБ, 1.7, титул+оглавление, карта участка на OSM-подложке, §1–§7. qa-PASS в браузере: кнопка в обеих страницах, download-event с корректным именем файла, 0 ошибок консоли/network.

R2 (отложено): DOCX полного отчёта (python-docx по тем же словарям + PNG-карты); опционально — report_generated_at в POST-ответ (сейчас дата на fast-path берётся из имени файла).

## R1 закрыт (2026-07-03) — PDF end-to-end на проде, прод-верифицирован **6 PR за один заход** (все с pre-push ревью и правками): - #2284 PR-A — PURE HTML §1–§3 + блок альтернатив (13 тестов) - #2285 PR-B — §4–§7 (ревью поймало: `building_program` не существует на выходном ConceptVariant — переисточено из buildings_geojson.features) - #2286 PR-C — карты geopandas/matplotlib/contextily без браузера (ревью поймало утечку фигур в Celery — закрыта CM'ом, мутационно проверено) - #2287 PR-D — Celery-джоба + кэш (analyze_run_id, forecast_run_id) + 3 endpoint'а + volume с chown в deploy (ревью: атомарная запись, whitelist cad, дата из generated_at) - #2288 PR-E — кнопка «Полный отчёт (PDF)» в PticaReports + ExportButtons (общий хук, поллинг 5с/cap 3 мин; попутно заякорен `reports/` → `/reports/` в .gitignore) - #2289 — косметика «Скачать отчёт ()» на fast-path из кэша (найдено qa) **Прод-верификация**: `/opt/gendesign/reports` создан с правильным владельцем (chown из deploy отработал); полный цикл на 66:41:0404019:4728 — POST 202 → ready за ~10 сек → **PDF 700 КБ, 1.7, титул+оглавление, карта участка на OSM-подложке, §1–§7**. qa-PASS в браузере: кнопка в обеих страницах, download-event с корректным именем файла, 0 ошибок консоли/network. **R2 (отложено)**: DOCX полного отчёта (python-docx по тем же словарям + PNG-карты); опционально — `report_generated_at` в POST-ответ (сейчас дата на fast-path берётся из имени файла).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2259
No description provided.