diff --git a/app/Services/InvestmentCatalogue.php b/app/Services/InvestmentCatalogue.php index 31ae768f..d6a6e860 100644 --- a/app/Services/InvestmentCatalogue.php +++ b/app/Services/InvestmentCatalogue.php @@ -522,11 +522,11 @@ class InvestmentCatalogue ->whereIn('t.id', InvestmentPortfolioController::visible()->whereNotNull($foreign)->select($foreign)) ->get(['l.opportunity_id', 't.name'])->groupBy('opportunity_id'); } - $features = $missing = []; + $features = $missing = $thematic = []; $areas = (clone $spatial)->whereIn('shape.geometry_type', ['polygon', 'multipolygon'])->orderBy('shape.id') ->get(['o.id', 'o.title', 'o.slug', 'g.name', 'shape.source_system', 'shape.properties', DB::raw('ST_AsGeoJSON(shape.geom) as geometry'), DB::raw("CASE WHEN o.primary_territory_id=g.id OR EXISTS (SELECT 1 FROM opportunity_locations direct WHERE direct.opportunity_id=o.id AND direct.geo_location_id=g.id) THEN 'território declarado da oportunidade' ELSE 'contexto do projeto associado; implantação da oportunidade por confirmar' END AS basis")]) - ->map(fn ($area) => ['geometry' => json_decode($area->geometry, true), 'title' => $area->title.' — '.$area->name.' ('.$area->basis.')', + ->map(fn ($area) => ['opportunity_id' => (int) $area->id, 'geometry' => json_decode($area->geometry, true), 'title' => $area->title.' — '.$area->name.' ('.$area->basis.')', 'source_reference' => $area->source_system, 'source_date' => json_decode($area->properties ?? '{}', true)['source_date'] ?? null, 'url' => '/oportunidades/'.$area->slug.($filters === [] ? '' : '?'.http_build_query($filters))])->all(); $located = 0; @@ -536,6 +536,14 @@ class InvestmentCatalogue foreach ($relations as $relation => $groups) { $properties[$relation] = ($groups->get($record->id) ?? collect())->pluck('name')->unique()->values()->all(); } + $public = app(ProactiveInvestment::class)->publicData($record); + $evidence = array_values(array_filter(StructuredData::collectionItems($public['evidence'] ?? []), + fn ($proof) => in_array($proof['category'] ?? null, ['resource', 'infrastructure'], true) && ($proof['purpose'] ?? null) === 'local')); + if ($evidence !== []) { + $thematic[] = ['id' => $record->id, 'title' => $record->title, 'url' => $properties['url'], 'location' => $properties['location'], + 'state' => $public['state'] ?? 'hypothesis', 'limitations' => $public['limitations'] ?? null, + 'evidence' => array_map(fn ($proof) => array_intersect_key($proof, array_flip(['id', 'category', 'statement', 'source', 'locator', 'period', 'scope', 'coverage', 'verified_on'])), $evidence)]; + } $sites = collect($points->get($record->id) ?? []); if ($sites->isNotEmpty()) { $located++; @@ -552,6 +560,6 @@ class InvestmentCatalogue return ['type' => 'FeatureCollection', 'limit' => 1000, 'matched_count' => $total, 'truncated' => $total > $records->count(), 'georeferenced_count' => $located, 'marker_count' => count($features), 'unlocated' => $missing, 'features' => $features, - 'areas' => $areas, 'complete' => $total === $located]; + 'thematic_records' => $thematic, 'areas' => $areas, 'complete' => $total === $located]; } } diff --git a/docs/investmoz/consolidated-review-matrix-2026-10-03.md b/docs/investmoz/consolidated-review-matrix-2026-10-03.md index 7c406d51..04884677 100644 --- a/docs/investmoz/consolidated-review-matrix-2026-10-03.md +++ b/docs/investmoz/consolidated-review-matrix-2026-10-03.md @@ -2228,3 +2228,18 @@ Delta aprovado: 11 testes de base de dados/125 asserções (cinco novos e seis d Conferência visual no Edge, exclusivamente QA `127.0.0.2:18644`/`main_visual_20261104_test`: Maputo Província mostra zero limites de oito referências distritais acessíveis, lacuna explicitada, nove oportunidades mantidas sem ponto inventado. O snapshot não contém limites públicos para demonstrar visualmente os polígonos inferiores; estes foram exercitados por testes sintéticos. Recibo/hashes: `docs/investmoz/unification/map-subdivision-local-20261104.json`; captura em `outputs/map-subdivision-20261104/`. **ACT-02 permanece parcial.** Camadas factuais de recursos, infra-estruturas, mão-de-obra e potencial económico, cobertura de dados/geometrias e conferência no portal de destino continuam pendentes. Este recorte não encerra V2-07/V2-10 nem substitui aceitação da equipa. Sem push, migração, escrita activa, importação, alteração de permissões ou reinício de serviços. + + +### 04/11/2026 — ACT-20261029-02: camadas de evidência pública de recursos e infra-estruturas + +Incremento sequencial na main local sobre `bbc05f1d`, reutilizando V2-07/V2-10, mapa único, filtros, pontos/áreas públicos e contexto administrativo já demonstrados. Inventário de código e cópia QA antes de fixtures: 48 oportunidades publicadas e duas sínteses proactivas públicas, mas nenhuma evidência pública local das categorias resource/infrastructure. Os campos existentes de zonas e fontes editoriais não foram convertidos automaticamente em disponibilidade ou geometrias temáticas; evidências privadas não foram publicadas. Não é perda confirmada de dados nem diagnóstico do remoto. Conferidos por SHA256 os 23 artefactos dos dois recibos visuais/administrativos anteriores, todos inalterados. + +A API existente de mapa acrescenta `thematic_records` a partir de `ProactiveInvestment::publicData`: somente evidência seleccionada na síntese publicada, categorias recursos/infra-estruturas e propósito local. Conserva facto, fonte, localizador, período, âmbito, cobertura, verificação registada, situação e limitações. Exclui metodologia e outras categorias; não copia o rascunho privado. Mantém a consulta territorial, limite/truncagem e autorização pública anteriores. As áreas acrescentam o identificador da oportunidade para filtragem, sem atribuir a geometria à evidência. + +No mesmo mapa, o selector permite todas as oportunidades, recursos documentados ou infra-estruturas documentadas. A camada filtra apenas pontos/áreas existentes das fichas correspondentes; não alarga a pesquisa geral, não altera CSV nem cria posições. Fichas sem ponto continuam consultáveis no painel de evidências/fontes. Contagens referem fichas, não quantidade/capacidade de recursos. Âmbito da evidência distingue-se da localização da oportunidade; marcadores não representam posição exacta ou disponibilidade de recurso/infra-estrutura. Escolha recuperada na sessão do navegador, com tolerância a armazenamento indisponível/inválido. Falta de evidência, período ou fonte é explícita, sem zero presumido. + +Delta aprovado: oito testes de BD/438 asserções (quatro novos e quatro de filtros provinciais), 14 testes frontend (cinco novos e nove existentes), PHPStan sem erros, tipos, Pint, lint e build QA aprovados. Inclui exclusão de rascunhos/publicação futura/acesso restrito, leitura apenas da síntese pública, fonte/período/limites, província/distrito, reutilização das coordenadas existentes, alternância/reposição de camadas, fichas sem ponto, carregamento/ausência/truncagem, escape de texto e recuperação da escolha. Provas gerais anteriores preservadas, sem repetir a bateria completa. + +Conferência visual no Edge exclusivamente em `127.0.0.2:18644`, base `main_visual_20261104_test`: duas fixtures claramente sintéticas criadas apenas em QA, uma por categoria; nenhuma coordenada/geometria criada. Hash de todas as oportunidades anteriores idêntico antes/depois. Alternância entre ambas conserva pesquisa provincial e duas fichas gerais; cada camada mostra a sua ficha, fonte/período/âmbito/limites e ausência de ponto. Infra-estruturas recuperada após recarregar. Recibo: `docs/investmoz/unification/thematic-map-local-20261104.json`; inventário, hashes, DOM e capturas em `outputs/thematic-map-20261104/`. Demonstração sintética não constitui cobertura económica factual ou publicação de dados reais. + +**ACT-02 permanece parcial.** Cobertura factual de recursos/infra-estruturas no destino, georreferenciação própria quando documentada, mão-de-obra, potencial económico quantitativo, restantes fontes temáticas e lacunas cartográficas continuam pendentes. Não se inferem estas camadas de descrições nem do número de oportunidades. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, alteração activa, migração, publicação automática ou alteração de permissões/serviços. diff --git a/docs/investmoz/unification/thematic-map-local-20261104.json b/docs/investmoz/unification/thematic-map-local-20261104.json new file mode 100644 index 00000000..2bfcfc3f --- /dev/null +++ b/docs/investmoz/unification/thematic-map-local-20261104.json @@ -0,0 +1,151 @@ +{ + "date": "2026-11-04", + "base_commit": "bbc05f1d", + "requirement": "ACT-20261029-02; V2-07/V2-10", + "scope": "Camadas de evidência temática pública de recursos e infra-estruturas no catálogo existente; main local", + "inventory_before_fixtures": { + "database": "main_visual_20261104_test", + "published_opportunities": 48, + "public_proactive_summaries": 2, + "public_local_evidence": { + "resource": 0, + "infrastructure": 0 + }, + "methodology_evidence_not_mapped": 0, + "sources": [], + "other_existing_sources": { + "investment_zones.resources/source_evidence": "Textual scope; not converted to georeferenced resource availability", + "portal_resources/legacy_content": "Editorial and document sources; no automatic thematic geometry", + "private proactive evidence": "Not consulted or published by this increment", + "administrative boundaries": "Existing separate layer retained" + } + }, + "reuse": [ + "ProactiveInvestment::publicData: síntese já publicada/seleccionada, sem ler rascunho privado para divulgação.", + "Categorias resource/infrastructure com propósito local; metodologia e outras categorias excluídas.", + "InvestmentCatalogue::query e map: mesmos filtros, geometrias públicas e limite de 1000 oportunidades.", + "Mapa único e contexto administrativo do incremento bbc05f1d preservados." + ], + "contract": { + "route": "GET /api/v1/investment/map", + "new_field": "thematic_records; id/title/url/location/state/limitations/evidence", + "evidence_fields": [ + "id", + "category", + "statement", + "source", + "locator", + "period", + "scope", + "coverage", + "verified_on" + ], + "area_field": "opportunity_id para filtrar áreas da mesma oportunidade sem atribuir geometria à evidência" + }, + "behaviour": [ + "Todas as oportunidades conserva os pontos/áreas anteriores.", + "Seleccionar uma categoria apresenta apenas locais/áreas das oportunidades com evidência temática pública local; sem criar posições.", + "Fichas sem ponto continuam consultáveis com as evidências e fontes; ausência não equivale a inexistência ou zero.", + "Escolha da camada recuperada na sessão do navegador; falha/valor inválido de armazenamento não bloqueia mapa.", + "Contagens gerais da pesquisa distinguem-se do subconjunto da camada; CSV e resultados gerais mantêm filtros anteriores.", + "Sem inferir mão-de-obra ou potencial económico de descrições ou contagens." + ], + "checks": { + "database_tests": 8, + "database_assertions": 438, + "new_database_tests": 4, + "existing_province_regression_tests": 4, + "frontend_tests": 14, + "new_frontend_tests": 5, + "phpstan_errors": 0, + "types": "passed", + "pint": "passed", + "lint": "passed", + "qa_build": "passed; avisos de fonte opcional e dimensão de chunks" + }, + "visual": { + "target": "http://127.0.0.2:18644", + "database": "main_visual_20261104_test", + "data": "Duas fixtures exclusivamente sintéticas; base QA sem evidência temática local publicada antes das fixtures.", + "resource_selected": true, + "infrastructure_selected": true, + "infrastructure_selection_recovered_after_reload": true, + "source_period_scope_limits_visible": true, + "points_created": false, + "geometry_created": false, + "existing_opportunities_unchanged_sha256": "c9d156f8a71d9196b4f36c3558b830267232b2d407c7abcf9b92bc027bce99d3" + }, + "preservation": { + "prior_artifacts_verified_unchanged": 23, + "accepted_database_suite_tests_preserved_not_reexecuted": 1325, + "prior_records_and_pending_items_retained": true + }, + "pending": [ + "Cobertura factual real de recursos e infra-estruturas depende de evidências públicas locais existentes no destino; nada foi publicado automaticamente.", + "Posição exacta, capacidade e disponibilidade dos recursos/infra-estruturas não foram deduzidas da posição da oportunidade.", + "Mão-de-obra, potencial económico quantitativo, restantes fontes temáticas e cobertura cartográfica continuam pendentes.", + "Sem conferência remota ou encerramento de ACT-02/V2-07/V2-10." + ], + "safety": { + "branch": "main", + "push": false, + "active_database_changed": false, + "schema_or_permissions_changed": false, + "automatic_publication": false, + "other_services_restarted": false + }, + "proofs": { + "outputs/thematic-map-20261104/source-inventory-before-fixtures.json": { + "sha256": "7366d737a5cd516c9667a43d62909d1529928285f4da7197c8f0bddab7f85503", + "bytes": 700 + }, + "outputs/thematic-map-20261104/fixture-receipt.json": { + "sha256": "dcf66ccf5773a694638e86cde14bc40e7d2fec56867d6146ac8c9077fc03659d", + "bytes": 417 + }, + "outputs/thematic-map-20261104/resources.jpg": { + "sha256": "f7c3d03e09728d320662a648b083b96ad12bc5bc40825f22529c2d9c882c164f", + "bytes": 162214 + }, + "outputs/thematic-map-20261104/resources.dom.txt": { + "sha256": "6816332137f2fc2a0c840e213997e9f64589166e3ce0e6ebd1619b27bbde5de9", + "bytes": 14232 + }, + "outputs/thematic-map-20261104/infrastructure-reopened.jpg": { + "sha256": "f97455f86832e72eaffd04ce01f53d0a339b966d658c68ba62cfc1d5eb4bc5ba", + "bytes": 153964 + }, + "outputs/thematic-map-20261104/infrastructure-reopened.dom.txt": { + "sha256": "c5fc7b92df9a69c1026a0f7e61217ce96ac5f27b6e3b15d56a2a53a3c3ffb15f", + "bytes": 14254 + }, + "outputs/main-db-qa-20261104/thematic-map-delta.log": { + "sha256": "ae49afa4a4f8af69ad3ae88470da9d556322b8b6b57b035e2e6476a24d287b1a", + "bytes": 96 + }, + "outputs/main-db-qa-20261104/thematic-map-delta.junit.xml": { + "sha256": "cc3e177001c7c254832c4eebfa8e13cf5b9a3067121f1fb1efe517fe4d4b8d6e", + "bytes": 3756 + }, + "outputs/main-db-qa-20261104/thematic-map-frontend.log": { + "sha256": "5523fa5f62f0d40b0ada1ea0faf9d90e649c797dd1b6df89b4fa7086b7e4a6bd", + "bytes": 1970 + }, + "outputs/main-db-qa-20261104/thematic-map-phpstan.log": { + "sha256": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2", + "bytes": 49 + }, + "outputs/main-db-qa-20261104/thematic-map-types.log": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "outputs/main-db-qa-20261104/thematic-map-lint.log": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "outputs/main-db-qa-20261104/thematic-map-build.log": { + "sha256": "2f452020e952def0eb1fd9c4469880f35016b23d3757054d84520a5d5d4ef1a1", + "bytes": 31606 + } + } +} diff --git a/docs/investmoz/unification/traceability-and-manual.md b/docs/investmoz/unification/traceability-and-manual.md index b3953795..2fdf80ab 100644 --- a/docs/investmoz/unification/traceability-and-manual.md +++ b/docs/investmoz/unification/traceability-and-manual.md @@ -9124,3 +9124,18 @@ Delta aprovado: 11 testes de base de dados/125 asserções (cinco novos e seis d Conferência visual no Edge, exclusivamente QA `127.0.0.2:18644`/`main_visual_20261104_test`: Maputo Província mostra zero limites de oito referências distritais acessíveis, lacuna explicitada, nove oportunidades mantidas sem ponto inventado. O snapshot não contém limites públicos para demonstrar visualmente os polígonos inferiores; estes foram exercitados por testes sintéticos. Recibo/hashes: `docs/investmoz/unification/map-subdivision-local-20261104.json`; captura em `outputs/map-subdivision-20261104/`. **ACT-02 permanece parcial.** Camadas factuais de recursos, infra-estruturas, mão-de-obra e potencial económico, cobertura de dados/geometrias e conferência no portal de destino continuam pendentes. Este recorte não encerra V2-07/V2-10 nem substitui aceitação da equipa. Sem push, migração, escrita activa, importação, alteração de permissões ou reinício de serviços. + + +### 04/11/2026 — ACT-20261029-02: camadas de evidência pública de recursos e infra-estruturas + +Incremento sequencial na main local sobre `bbc05f1d`, reutilizando V2-07/V2-10, mapa único, filtros, pontos/áreas públicos e contexto administrativo já demonstrados. Inventário de código e cópia QA antes de fixtures: 48 oportunidades publicadas e duas sínteses proactivas públicas, mas nenhuma evidência pública local das categorias resource/infrastructure. Os campos existentes de zonas e fontes editoriais não foram convertidos automaticamente em disponibilidade ou geometrias temáticas; evidências privadas não foram publicadas. Não é perda confirmada de dados nem diagnóstico do remoto. Conferidos por SHA256 os 23 artefactos dos dois recibos visuais/administrativos anteriores, todos inalterados. + +A API existente de mapa acrescenta `thematic_records` a partir de `ProactiveInvestment::publicData`: somente evidência seleccionada na síntese publicada, categorias recursos/infra-estruturas e propósito local. Conserva facto, fonte, localizador, período, âmbito, cobertura, verificação registada, situação e limitações. Exclui metodologia e outras categorias; não copia o rascunho privado. Mantém a consulta territorial, limite/truncagem e autorização pública anteriores. As áreas acrescentam o identificador da oportunidade para filtragem, sem atribuir a geometria à evidência. + +No mesmo mapa, o selector permite todas as oportunidades, recursos documentados ou infra-estruturas documentadas. A camada filtra apenas pontos/áreas existentes das fichas correspondentes; não alarga a pesquisa geral, não altera CSV nem cria posições. Fichas sem ponto continuam consultáveis no painel de evidências/fontes. Contagens referem fichas, não quantidade/capacidade de recursos. Âmbito da evidência distingue-se da localização da oportunidade; marcadores não representam posição exacta ou disponibilidade de recurso/infra-estrutura. Escolha recuperada na sessão do navegador, com tolerância a armazenamento indisponível/inválido. Falta de evidência, período ou fonte é explícita, sem zero presumido. + +Delta aprovado: oito testes de BD/438 asserções (quatro novos e quatro de filtros provinciais), 14 testes frontend (cinco novos e nove existentes), PHPStan sem erros, tipos, Pint, lint e build QA aprovados. Inclui exclusão de rascunhos/publicação futura/acesso restrito, leitura apenas da síntese pública, fonte/período/limites, província/distrito, reutilização das coordenadas existentes, alternância/reposição de camadas, fichas sem ponto, carregamento/ausência/truncagem, escape de texto e recuperação da escolha. Provas gerais anteriores preservadas, sem repetir a bateria completa. + +Conferência visual no Edge exclusivamente em `127.0.0.2:18644`, base `main_visual_20261104_test`: duas fixtures claramente sintéticas criadas apenas em QA, uma por categoria; nenhuma coordenada/geometria criada. Hash de todas as oportunidades anteriores idêntico antes/depois. Alternância entre ambas conserva pesquisa provincial e duas fichas gerais; cada camada mostra a sua ficha, fonte/período/âmbito/limites e ausência de ponto. Infra-estruturas recuperada após recarregar. Recibo: `docs/investmoz/unification/thematic-map-local-20261104.json`; inventário, hashes, DOM e capturas em `outputs/thematic-map-20261104/`. Demonstração sintética não constitui cobertura económica factual ou publicação de dados reais. + +**ACT-02 permanece parcial.** Cobertura factual de recursos/infra-estruturas no destino, georreferenciação própria quando documentada, mão-de-obra, potencial económico quantitativo, restantes fontes temáticas e lacunas cartográficas continuam pendentes. Não se inferem estas camadas de descrições nem do número de oportunidades. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, alteração activa, migração, publicação automática ou alteração de permissões/serviços. diff --git a/docs/investmoz/v2/auditoria-portal/backlog.md b/docs/investmoz/v2/auditoria-portal/backlog.md index ebd8a6ed..05d8b0c9 100644 --- a/docs/investmoz/v2/auditoria-portal/backlog.md +++ b/docs/investmoz/v2/auditoria-portal/backlog.md @@ -3432,3 +3432,18 @@ Delta aprovado: 11 testes de base de dados/125 asserções (cinco novos e seis d Conferência visual no Edge, exclusivamente QA `127.0.0.2:18644`/`main_visual_20261104_test`: Maputo Província mostra zero limites de oito referências distritais acessíveis, lacuna explicitada, nove oportunidades mantidas sem ponto inventado. O snapshot não contém limites públicos para demonstrar visualmente os polígonos inferiores; estes foram exercitados por testes sintéticos. Recibo/hashes: `docs/investmoz/unification/map-subdivision-local-20261104.json`; captura em `outputs/map-subdivision-20261104/`. **ACT-02 permanece parcial.** Camadas factuais de recursos, infra-estruturas, mão-de-obra e potencial económico, cobertura de dados/geometrias e conferência no portal de destino continuam pendentes. Este recorte não encerra V2-07/V2-10 nem substitui aceitação da equipa. Sem push, migração, escrita activa, importação, alteração de permissões ou reinício de serviços. + + +### 04/11/2026 — ACT-20261029-02: camadas de evidência pública de recursos e infra-estruturas + +Incremento sequencial na main local sobre `bbc05f1d`, reutilizando V2-07/V2-10, mapa único, filtros, pontos/áreas públicos e contexto administrativo já demonstrados. Inventário de código e cópia QA antes de fixtures: 48 oportunidades publicadas e duas sínteses proactivas públicas, mas nenhuma evidência pública local das categorias resource/infrastructure. Os campos existentes de zonas e fontes editoriais não foram convertidos automaticamente em disponibilidade ou geometrias temáticas; evidências privadas não foram publicadas. Não é perda confirmada de dados nem diagnóstico do remoto. Conferidos por SHA256 os 23 artefactos dos dois recibos visuais/administrativos anteriores, todos inalterados. + +A API existente de mapa acrescenta `thematic_records` a partir de `ProactiveInvestment::publicData`: somente evidência seleccionada na síntese publicada, categorias recursos/infra-estruturas e propósito local. Conserva facto, fonte, localizador, período, âmbito, cobertura, verificação registada, situação e limitações. Exclui metodologia e outras categorias; não copia o rascunho privado. Mantém a consulta territorial, limite/truncagem e autorização pública anteriores. As áreas acrescentam o identificador da oportunidade para filtragem, sem atribuir a geometria à evidência. + +No mesmo mapa, o selector permite todas as oportunidades, recursos documentados ou infra-estruturas documentadas. A camada filtra apenas pontos/áreas existentes das fichas correspondentes; não alarga a pesquisa geral, não altera CSV nem cria posições. Fichas sem ponto continuam consultáveis no painel de evidências/fontes. Contagens referem fichas, não quantidade/capacidade de recursos. Âmbito da evidência distingue-se da localização da oportunidade; marcadores não representam posição exacta ou disponibilidade de recurso/infra-estrutura. Escolha recuperada na sessão do navegador, com tolerância a armazenamento indisponível/inválido. Falta de evidência, período ou fonte é explícita, sem zero presumido. + +Delta aprovado: oito testes de BD/438 asserções (quatro novos e quatro de filtros provinciais), 14 testes frontend (cinco novos e nove existentes), PHPStan sem erros, tipos, Pint, lint e build QA aprovados. Inclui exclusão de rascunhos/publicação futura/acesso restrito, leitura apenas da síntese pública, fonte/período/limites, província/distrito, reutilização das coordenadas existentes, alternância/reposição de camadas, fichas sem ponto, carregamento/ausência/truncagem, escape de texto e recuperação da escolha. Provas gerais anteriores preservadas, sem repetir a bateria completa. + +Conferência visual no Edge exclusivamente em `127.0.0.2:18644`, base `main_visual_20261104_test`: duas fixtures claramente sintéticas criadas apenas em QA, uma por categoria; nenhuma coordenada/geometria criada. Hash de todas as oportunidades anteriores idêntico antes/depois. Alternância entre ambas conserva pesquisa provincial e duas fichas gerais; cada camada mostra a sua ficha, fonte/período/âmbito/limites e ausência de ponto. Infra-estruturas recuperada após recarregar. Recibo: `docs/investmoz/unification/thematic-map-local-20261104.json`; inventário, hashes, DOM e capturas em `outputs/thematic-map-20261104/`. Demonstração sintética não constitui cobertura económica factual ou publicação de dados reais. + +**ACT-02 permanece parcial.** Cobertura factual de recursos/infra-estruturas no destino, georreferenciação própria quando documentada, mão-de-obra, potencial económico quantitativo, restantes fontes temáticas e lacunas cartográficas continuam pendentes. Não se inferem estas camadas de descrições nem do número de oportunidades. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, alteração activa, migração, publicação automática ou alteração de permissões/serviços. diff --git a/resources/js/components/interactive-investment-map.tsx b/resources/js/components/interactive-investment-map.tsx index bbba0cec..cbdbce4f 100644 --- a/resources/js/components/interactive-investment-map.tsx +++ b/resources/js/components/interactive-investment-map.tsx @@ -24,6 +24,7 @@ export type InvestmentMapFeature = { }; }; export type InvestmentMapArea = { + opportunity_id?: number; selected_territory?: boolean; child_territory?: boolean; location_type?: string; diff --git a/resources/js/components/thematic-investment-map.tsx b/resources/js/components/thematic-investment-map.tsx new file mode 100644 index 00000000..568b85bd --- /dev/null +++ b/resources/js/components/thematic-investment-map.tsx @@ -0,0 +1,250 @@ +import { useEffect, useState } from 'react'; +import CatalogueInvestmentMap from './catalogue-investment-map'; +import type { + InvestmentMapArea, + InvestmentMapFeature, +} from './interactive-investment-map'; + +export type ThematicMapRecord = { + id: number; + title: string; + url: string; + location: string; + state: string; + limitations: string | null; + evidence: { + id: string; + category: 'resource' | 'infrastructure'; + statement?: string | null; + source?: string | null; + locator?: string | null; + period?: string | null; + scope?: string | null; + coverage?: string | null; + verified_on?: string | null; + }[]; +}; +const labels = { + resource: 'Recursos documentados', + infrastructure: 'Infra-estruturas documentadas', +}; +const value = (text?: string | null) => text?.trim() || 'Não indicado'; + +export default function ThematicInvestmentMap({ + points, + areas, + records, + territoryId, + truncated, +}: { + points: InvestmentMapFeature[] | null; + areas: InvestmentMapArea[]; + records: ThematicMapRecord[]; + territoryId?: string; + truncated: boolean; +}) { + const [theme, setTheme] = useState('all'); + useEffect(() => { + try { + const saved = window.sessionStorage.getItem( + 'investmoz-map-theme-v1', + ); + if (saved === 'resource' || saved === 'infrastructure') + setTheme(saved); + } catch { + // The server and first client render use the same default layer. + } + }, []); + const selectTheme = (next: string) => { + setTheme(next); + try { + window.sessionStorage.setItem('investmoz-map-theme-v1', next); + } catch { + // Keep the map usable when session storage is unavailable. + } + }; + const selected = records + .map((record) => ({ + ...record, + evidence: record.evidence.filter( + (proof) => theme === 'all' || proof.category === theme, + ), + })) + .filter((record) => record.evidence.length > 0); + const ids = new Set(selected.map((record) => record.id)); + const visiblePoints = + theme === 'all' + ? points + : (points?.filter((point) => ids.has(point.properties.id)) ?? null); + const visibleAreas = + theme === 'all' + ? areas + : areas.filter( + (area) => + area.opportunity_id !== undefined && + ids.has(area.opportunity_id), + ); + const countLabel = (count: number) => + `${count} ${count === 1 ? 'ficha' : 'fichas'}`; + const located = new Set((points ?? []).map((point) => point.properties.id)); + return ( +
+ A camada filtra os locais e áreas das oportunidades com + evidência pública seleccionada. Os marcadores localizam a + oportunidade; não representam a posição exacta, capacidade + ou disponibilidade do recurso ou da infra-estrutura. A + pesquisa geral mantém os seus filtros e resultados. +
++ Mão-de-obra e potencial económico: sem camada quantitativa + nesta consulta; não são inferidos de descrições ou do número + de oportunidades. +
+ {truncated && ( ++ A resposta está limitada; a cobertura temática refere-se + apenas às fichas recebidas. +
+ )} + {points === null ? ( +A carregar evidências temáticas…
+ ) : ( + <> ++ {countLabel(selected.length)} com evidência temática + pública nesta resposta;{' '} + { + selected.filter( + (record) => !located.has(record.id), + ).length + }{' '} + sem ponto público utilizável. Ausência de evidência + não significa ausência do recurso. +
+ {selected.length === 0 && ( ++ Sem evidência pública local de recursos ou + infra-estruturas para esta camada e estes + filtros. Não foram criadas posições no mapa. +
+ )} + {selected.length > 0 && ( ++ Localização da ficha:{' '} + {value(record.location)}. O âmbito + de cada evidência está indicado + abaixo. +
++ Situação publicada:{' '} + {record.state === 'confirmed' + ? 'Confirmada no âmbito da síntese publicada' + : 'Hipótese'} + . Limitações:{' '} + {value(record.limitations)} +
++ {labels[proof.category]} +
++ {value(proof.statement)} +
++ Fonte:{' '} + {value(proof.source)} · + Localizador:{' '} + {value(proof.locator)} +
++ Período:{' '} + {value(proof.period)} · + Verificação registada:{' '} + {value( + proof.verified_on, + )} +
++ Âmbito:{' '} + {value(proof.scope)} · + Cobertura e limites:{' '} + {value(proof.coverage)} +
+