Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d45541a11 | ||
|
|
066707ece6 |
@@ -19,12 +19,21 @@ class InvestmentTerritoryController extends Controller
|
||||
$data = $request->validate(['territory_id' => ['required', 'uuid']]);
|
||||
$profile = $request->is('minhas-oportunidades/*');
|
||||
$management = $request->is('management/*') || $profile;
|
||||
$actor = $request->user();
|
||||
$access = app(PortalProfileAccess::class);
|
||||
// The general consumers use this same endpoint while authenticated.
|
||||
// Reuse the read access already granted by the private cadastral routes.
|
||||
$profileAccess = $actor && $actor->hasVerifiedEmail()
|
||||
&& ($access->grants($actor) !== [] || $access->superuser($actor));
|
||||
$internal = $profileAccess || ($actor?->hasVerifiedEmail() && $actor->can('manage-portal'));
|
||||
if ($management) {
|
||||
$access = app(PortalProfileAccess::class);
|
||||
abort_unless($profile ? ($access->grants($request->user()) !== [] || $access->superuser($request->user())) : $request->user()?->can('manage-portal'), 403);
|
||||
abort_unless($profile ? $profileAccess : $internal, 403);
|
||||
}
|
||||
|
||||
return response()->json(app(TerritoryGeometry::class)->context($data['territory_id'], $management));
|
||||
return response()->json([
|
||||
...app(TerritoryGeometry::class)->context($data['territory_id'], $internal),
|
||||
'geometry_scope' => $internal ? 'authorized_internal' : 'public',
|
||||
])->header('Cache-Control', 'private, no-store');
|
||||
}
|
||||
|
||||
private const TABLES = ['opportunities' => 'opportunities', 'projects' => 'projects', 'clusters' => 'economic_clusters', 'corridors' => 'development_corridors', 'zones' => 'investment_zones'];
|
||||
|
||||
@@ -14,12 +14,13 @@ final class EnsureScopedPortalAdministration
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$actor = $request->user();
|
||||
abort_unless($actor, 403);
|
||||
abort_unless($actor !== null, 403);
|
||||
$scope = app(ScopedPortalAdministration::class);
|
||||
$path = $request->path();
|
||||
$interests = $request->is('management/interests', 'management/interests/*', 'api/v1/investment/admin/interests/*');
|
||||
// Fiscal maintenance reuses authorised administration; unrelated gates remain unchanged.
|
||||
$catalogue = $request->is('management/territory-geometry-import', 'management/territory-geometry-import/*',
|
||||
$geometryRead = $request->isMethod('GET') && $path === 'management/territory-geometries';
|
||||
$catalogue = $geometryRead || $request->is('management/territory-geometry-import', 'management/territory-geometry-import/*',
|
||||
'management/economic-references/lot-01', 'management/economic-references/lot-01/*',
|
||||
'management/education', 'management/education/*', 'management/investment/references', 'management/investment/references/*', 'api/v1/investment/admin/references', 'api/v1/investment/admin/references/*',
|
||||
'management/investment/zones', 'management/investment/zones/*', 'api/v2/investment/admin/zones', 'api/v2/investment/admin/zones/*',
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/** Public read projection authorized by Tempo; source rows and originals stay private. */
|
||||
class ApprovedAdministrativeBoundaries
|
||||
{
|
||||
public const HASH = '06ab905fcf9b19115c3521bf81de03f37873880f7765f229b9e1f79d99df7adc';
|
||||
|
||||
/** @var array<string,array<string,string>>|null */
|
||||
private ?array $items = null;
|
||||
|
||||
/** @return array<string,array<string,string>> */
|
||||
public function snapshots(): array
|
||||
{
|
||||
if ($this->items !== null) {
|
||||
return $this->items;
|
||||
}
|
||||
$contents = file_get_contents(base_path('docs/investmoz/unification/approved-administrative-boundaries-20261024.json'));
|
||||
if ($contents === false || ! hash_equals(self::HASH, hash('sha256', str_replace("\r\n", "\n", $contents)))) {
|
||||
throw new RuntimeException('Approved administrative boundary manifest changed.');
|
||||
}
|
||||
$manifest = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);
|
||||
if (count($manifest['items']) !== 408) {
|
||||
throw new RuntimeException('Exact 408-boundary scope required.');
|
||||
}
|
||||
$this->items = array_column($manifest['items'], null, 'id');
|
||||
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
public function allows(string $id, string $territoryId, string $geometryHash, string $propertiesHash): bool
|
||||
{
|
||||
$item = $this->snapshots()[$id] ?? null;
|
||||
|
||||
return $item !== null && $item['territory_id'] === $territoryId
|
||||
&& hash_equals($item['geometry_sha256'], $geometryHash)
|
||||
&& hash_equals($item['properties_sha256'], $propertiesHash);
|
||||
}
|
||||
}
|
||||
@@ -14,16 +14,31 @@ final class TerritoryGeometry
|
||||
abort_unless($geography->references($management)->where('id', $id)->exists(), 404);
|
||||
$path = $geography->path($id, $management);
|
||||
$ids = array_map(fn ($node) => $node->id, $path);
|
||||
$approved = app(ApprovedAdministrativeBoundaries::class);
|
||||
$rows = DB::table('geo_geometries as g')->join('geo_locations as l', 'l.id', '=', 'g.geo_location_id')
|
||||
->whereIn('g.geo_location_id', $ids)->whereNull('g.deleted_at')->whereNull('l.deleted_at')
|
||||
->whereIn('g.data_classification', $management ? ['internal', 'public'] : ['public'])
|
||||
->where(function ($query) use ($management, $approved) {
|
||||
$query->where('g.data_classification', 'public');
|
||||
$query->orWhere(function ($internal) use ($management, $approved) {
|
||||
$internal->where('g.data_classification', 'internal');
|
||||
if (! $management) {
|
||||
$internal->whereIn('g.id', array_keys($approved->snapshots()));
|
||||
}
|
||||
});
|
||||
})
|
||||
->whereRaw("g.properties->>'purpose' = 'administrative_boundary'")
|
||||
->whereIn('g.geometry_type', ['polygon', 'multipolygon'])
|
||||
->whereRaw('ST_IsValid(g.geom) AND NOT ST_IsEmpty(g.geom) AND ST_SRID(g.geom)=4326')
|
||||
->orderBy('g.geo_location_id')->orderBy('g.id')->limit(101)
|
||||
->get(['g.id', 'g.geo_location_id', 'l.name', 'l.location_type', 'g.properties', 'g.data_classification',
|
||||
DB::raw('ST_AsGeoJSON(ST_SimplifyPreserveTopology(g.geom,0.0001),6) as geometry')]);
|
||||
$areas = $rows->take(100)->map(function ($row) use ($id) {
|
||||
DB::raw('ST_AsGeoJSON(ST_SimplifyPreserveTopology(g.geom,0.0001),6) as geometry'),
|
||||
DB::raw("encode(sha256(ST_AsEWKB(g.geom)),'hex') as geometry_sha256"),
|
||||
DB::raw("encode(sha256(convert_to(g.properties::text,'UTF8')),'hex') as properties_sha256")]);
|
||||
if (! $management) {
|
||||
$rows = $rows->filter(fn ($row) => $row->data_classification === 'public'
|
||||
|| $approved->allows($row->id, $row->geo_location_id, $row->geometry_sha256, $row->properties_sha256))->values();
|
||||
}
|
||||
$areas = $rows->take(100)->map(function ($row) use ($id, $management) {
|
||||
$source = json_decode($row->properties, true, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
return ['id' => $row->id, 'territory_id' => $row->geo_location_id, 'location_type' => $row->location_type,
|
||||
@@ -31,7 +46,7 @@ final class TerritoryGeometry
|
||||
'title' => 'Limite administrativo: '.$row->name, 'purpose' => 'administrative_boundary',
|
||||
'source_reference' => $source['authority'] ?? null, 'source_date' => $source['source_version'] ?? null,
|
||||
'source_url' => $source['source_url'] ?? null, 'source_sha256' => $source['source_sha256'] ?? null,
|
||||
'data_classification' => $row->data_classification, 'legal_currentness' => $source['legal_currentness'] ?? 'not_determined', 'url' => ''];
|
||||
'data_classification' => $management ? $row->data_classification : 'public', 'legal_currentness' => $source['legal_currentness'] ?? 'not_determined', 'url' => ''];
|
||||
})->all();
|
||||
|
||||
return ['territory_id' => $id, 'territory_registered' => true,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,123 @@
|
||||
{
|
||||
"scope": "Shared administrative maps stabilization",
|
||||
"source_revision": "cf2ddf21",
|
||||
"candidate": "066707ec",
|
||||
"owner_decision": "Tempo 2026-10-24: public consultation of the exact accepted administrative contours; originals private, no parcels or other internal layers",
|
||||
"diagnosis": {
|
||||
"data_loss": false,
|
||||
"common_consumers": "Public-only filter excluded all 408 internal administrative boundaries",
|
||||
"administration": "Legacy manage-portal gate excluded both approved superusers",
|
||||
"comparison": "No change in common geometry service/controller/components between 30aed7cd and cf2ddf21",
|
||||
"base_map": "Provider tiles and served assets respond; browser framing is checked after installation"
|
||||
},
|
||||
"qa": {
|
||||
"database": "simulator_fiscal_delta_20261021_test",
|
||||
"port": 55441,
|
||||
"tests": 6,
|
||||
"assertions": 64,
|
||||
"result": "passed",
|
||||
"phpstan": "passed",
|
||||
"writes": "Only isolated QA transactions, rolled back"
|
||||
},
|
||||
"baseline": {
|
||||
"published_fiches": 29,
|
||||
"territorial_relations": 28,
|
||||
"geometries": 408,
|
||||
"geometry_rows_checksum": "7d8b71d3e65d89ffdc43c748b0572dbc"
|
||||
},
|
||||
"backup": {
|
||||
"tables": 174,
|
||||
"files_verified": 369,
|
||||
"restore_tables_verified": 174,
|
||||
"restore_network": "none",
|
||||
"dump_sha256": "2fb5b4488799bb6072c38ee41ccf91fc2a55561363c19e280ab066363d9e0647"
|
||||
},
|
||||
"public_manifest_sha256": "06ab905fcf9b19115c3521bf81de03f37873880f7765f229b9e1f79d99df7adc",
|
||||
"installed": {
|
||||
"status": "installed",
|
||||
"commit": "066707ece631f0a7c963031c211844fbdd68916b",
|
||||
"release": "/var/www/investmoz-homologacao/releases/066707ece631f0a7c963031c211844fbdd68916b-6b7bb5bd",
|
||||
"previous_release": "/var/www/investmoz-homologacao/releases/cf2ddf21a1457f4852fe6aa10069ec3b854f1567-7749f82e",
|
||||
"database_migrations": 0,
|
||||
"content_imports": 0
|
||||
},
|
||||
"deferred": [
|
||||
"Statistics",
|
||||
"AI"
|
||||
],
|
||||
"accepted_tests_repeated": false,
|
||||
"public_projection": {
|
||||
"available": 408,
|
||||
"levels": {
|
||||
"admin_post": 264,
|
||||
"district": 133,
|
||||
"province": 11
|
||||
},
|
||||
"failures": [],
|
||||
"manifest_sha256": "06ab905fcf9b19115c3521bf81de03f37873880f7765f229b9e1f79d99df7adc"
|
||||
},
|
||||
"preservation": {
|
||||
"tables": 174,
|
||||
"changed_tables": {
|
||||
"cache": {
|
||||
"before": {
|
||||
"rows": 104,
|
||||
"checksum": "5d172b4d252c7b025f23ac70cf570cb6"
|
||||
},
|
||||
"after": {
|
||||
"rows": 104,
|
||||
"checksum": "a60f3e47e1ae28937404f05f45e33135"
|
||||
}
|
||||
},
|
||||
"sessions": {
|
||||
"before": {
|
||||
"rows": 6,
|
||||
"checksum": "dcdb7eba3f3e8f29f40ec3f7542be6ce"
|
||||
},
|
||||
"after": {
|
||||
"rows": 7,
|
||||
"checksum": "0059c0b0e16d532c6658fd420582f2e9"
|
||||
}
|
||||
}
|
||||
},
|
||||
"unchanged_tables": 172
|
||||
},
|
||||
"installed_file_sha256": {
|
||||
"app/Services/ApprovedAdministrativeBoundaries.php": "401fd62795ca8f33106be6e07130d9207d6661695440bfc40f62f6f6b42bec64",
|
||||
"app/Services/TerritoryGeometry.php": "00ce3e6dde92868b0d34b963b8e59a26e6663149cdc0398c645ef636ca382966",
|
||||
"app/Http/Controllers/InvestmentTerritoryController.php": "3b184c6ea1b97f0abe86d01567d3d73444c49192c638478a6d53619e63d5d18d",
|
||||
"app/Http/Middleware/EnsureScopedPortalAdministration.php": "1474db760f6bd6003a5325ae721698e90e2709a2354b51abde77f920a9dad81a",
|
||||
"docs/investmoz/unification/approved-administrative-boundaries-20261024.json": "06ab905fcf9b19115c3521bf81de03f37873880f7765f229b9e1f79d99df7adc"
|
||||
},
|
||||
"pipeline_summaries": [
|
||||
"OK (1 test, 3106 assertions)",
|
||||
"built in 24.58s",
|
||||
"OK (57 tests, 309 assertions)",
|
||||
"# tests 216",
|
||||
"# pass 216",
|
||||
"# fail 0"
|
||||
],
|
||||
"proofs": {
|
||||
"anonymous_http": {
|
||||
"status": 200,
|
||||
"territory_id": "dd219b89-cc17-5944-8c7d-d2766c82b526",
|
||||
"selected": "DONDO",
|
||||
"ancestor": "Sofala",
|
||||
"areas": 2
|
||||
},
|
||||
"browser": {
|
||||
"province_to_district": "passed",
|
||||
"framing": "selected district with ancestor context",
|
||||
"reload_preserves_selection": true,
|
||||
"zoom": "passed",
|
||||
"visible_tiles_loaded": 36,
|
||||
"visible_tiles_failed": 0,
|
||||
"screenshot": "outputs/map-stabilization-20261024/dondo-installed.png",
|
||||
"screenshot_sha256": "7569f3b66aceb7ef9816c31bfaa172ebcdfa10e4911961b67a129a654b5cd349"
|
||||
},
|
||||
"business_rows_unchanged": true,
|
||||
"active_synthetic_requests_created": 0
|
||||
},
|
||||
"status": "installed_delta_verified",
|
||||
"remaining_in_scope": []
|
||||
}
|
||||
@@ -1,5 +1,19 @@
|
||||
# Rastreabilidade, utilização e formação
|
||||
|
||||
## Mapas — estabilização comum e divulgação delimitada, 24/10/2026
|
||||
|
||||
Diagnóstico por leitura autenticada na homologação `cf2ddf21`: **29 fichas, 28 relações territoriais e 408 geometrias válidas**, sem eliminação. Os 408 limites INE/2019 conservam classificação interna, propósito administrativo e SRID 4326. O fingerprint integral das linhas é `7d8b71d3e65d89ffdc43c748b0572dbc`. Não há RLS nas tabelas comparadas. O serviço comum não mudou desde `30aed7cd`: os consumidores gerais pediam exclusivamente geometrias públicas; o cadastro usava ainda `manage-portal`, ausente nos dois superutilizadores aprovados. A prova anterior demonstrava o cadastro privado, não a divulgação pública. O mapa base, tiles e assets carregam; a resposta territorial vazia explica a ausência de contornos e de enquadramento do território escolhido.
|
||||
|
||||
**Decisão expressa da Tempo nesta passagem:** «Sim, disponibilizar os contornos administrativos aceites». Implementada uma projecção pública de leitura dos [408 snapshots exactos](approved-administrative-boundaries-20261024.json), conferindo identidade e hashes da geometria original e metadados. Não há reimportação, reclassificação de linhas, publicação de parcelas, acesso aos ficheiros originais ou abertura de outras camadas internas. Alterações posteriores não recebem divulgação automática. Os perfis autorizados reutilizam o acesso privado já aprovado; a leitura administrativa conserva MFA. Respostas privadas não são guardadas em cache partilhada.
|
||||
|
||||
QA isolado `simulator_fiscal_delta_20261021_test:55441`: seis testes dirigidos, 64 asserções; selecção, gravação/recuperação no dossier e prefill do simulador com a mesma identidade, leitura pública autorizada, bloqueio de camadas não autorizadas e de snapshots alterados, permissões/MFA e fingerprint original preservado. PHPStan dos quatro ficheiros funcionais passou. Backup fresco: 174 tabelas, 369 ficheiros conferidos; restauro isolado sem rede reproduziu as 174 tabelas.
|
||||
|
||||
**Entregue na homologação em `066707ece631f0a7c963031c211844fbdd68916b`**, por avanço normal do Git, preservando `cf2ddf21` e as alterações concorrentes. Instalador: contrato 1/3106, PHP 57/309, frontend 216/216 e build aprovados; zero migrações e zero importações. Os cinco ficheiros funcionais instalados coincidem com o Git. Consulta pública pelo serviço instalado: **408/408 disponíveis**, 11 províncias, 133 distritos e 264 postos, zero falhas. HTTP anónimo recupera Dondo e Sofala pela identidade canónica, com Dondo seleccionado e Sofala como contexto ancestral. Conferência visual: mudança de província para distrito actualiza o contorno e enquadramento; escolha preservada após recarregar, zoom operacional e 36 tiles carregados sem falha na observação final. Houve falhas transitórias de tiles na janela anterior; os mesmos URLs responderam 200 e o recarregamento recuperou a base, sem alteração de configuração ou fornecedor.
|
||||
|
||||
Comparação das 174 tabelas: **172 iguais por contagem/hash**, diferenças apenas em `cache` e `sessions`; tabelas de negócio, geometrias, permissões e fontes intactas. Conservados 29 fichas, 28 relações e o fingerprint integral das 408 geometrias. Nenhum dossier/pedido sintético criado na homologação. [Recibo da estabilização](map-stabilization-receipt-20261024.json); prova visual em `outputs/map-stabilization-20261024/dondo-installed.png`. O saldo técnico desta reposição está encerrado; a avaliação de navegação e apresentação pela Tempo permanece o próximo trabalho.
|
||||
|
||||
Preservados os fechos `d8224ba8`, `55136b44`, `8036b9b0` e `cf2ddf21`/`c1f4a719`, sem repetição das provas aceites. Localidades sem polígono próprio conservam apenas o contexto ancestral explicitamente identificado; não são inventadas coordenadas ou parcelas. Estatísticas e IA permanecem adiadas. Esta estabilização não declara concluída a aplicação transversal nem substitui a avaliação de navegação e apresentação pela Tempo.
|
||||
|
||||
## Projectos âncora — entregues na homologação em cf2ddf21, 23/10/2026
|
||||
|
||||
Reconciliado o saldo de `6985f82e` com as provas territoriais de 7 de Outubro e os recibos de reposição. A leitura autenticada da homologação, com o papel da aplicação e transacção apenas de leitura, confirmou **29 fichas publicadas, 13 relações de clusters e zero ligações em `project_locations`**. As cinco tabelas comparadas não usam RLS. Os projectos transportados têm identificadores diferentes dos originais e perderam as 28 ligações territoriais e os respectivos metadados de citação; não desapareceram as 29 fichas. A reposição de visibilidade anterior não abrangia estas relações. A comparação delimita a omissão no transporte; não identifica por si só o instante em que ocorreu.
|
||||
|
||||
@@ -4570,13 +4570,7 @@ AUD-GEO-03,Cartografia de todas as entidades e campos,"Pedido direto 09/10/2026,
|
||||
|
||||
[Manual 13/10/2026 — base 396c691930bc] Responsável confirmou «3: seletores, mapa e recuperação»: caso32, consumidor /minhas-oportunidades/32/resources. Sem extrapolar para documentos, área, workflow, outros mapas/perfis, teclado ou dispositivo. Conta específica e modo de recuperação não indicados; não se inventam detalhes.
|
||||
|
||||
[Reconciliação visual14/10/2026 — sem novo ensaio] Limites/mapa/recovery15 e32 cobertos. Faltam apresentação/ausência por consumidor nas rotas públicas/carteira/fundiário/Balcão/56 listadas; nenhuma geometria publicada por inferência. Referência: outputs/investmoz-audit-current-20261012/acceptance-396c-visual-reconciliation-20261014.json",Implementado parcialmente,"Restam mapas públicos/zonas/carteira/parcerias/terra/Balcão e apresentação QA56. 173 correspondências e Mandie/Guro mantidos; localidades/parcelas sem geometria oficial no exemplar. Disponibilidade interna não é divulgação nem implantação ativa.
|
||||
|
||||
[B5 QA 13/10/2026] Mesmos cinco consumidoresL3.1–5; geometria/fonte/visibilidade e falta explícita, sem transformar limiteINE emparcela. Renderização/legenda/teclado somenteL4; sem importação/publicaçãoativa. Plano/reorganização não é demonstração funcional ou visual. L1.1/L2.3 técnicos satisfeitos pelos grupos próprios; restante nominal na checklist. C135 bloqueia L4. A/B/C37 preservados; C132 separado, proposta com ações corretivas pendentes vazias. Ativação/foraB excluídos.
|
||||
|
||||
[B6 QA 13/10/2026] Mesmo saldoL3.1/4/5, renderização/legenda emL4; zero geometria pública na amostra explicitado, não é cartografia integral ou importação/publicação. Desenho/legenda/controles/apresentação sóL4; zero markers/áreas na amostra não prova povoamento integral nem seletores/parcela32, fundiário ouBalcão. Ativo não testado/alterado neste fix; recompilação desnecessária. Planeamento/inspeção de permissões não é fluxo demonstrado. L1.2/3/5 eL3.1/4/5/6/7/8 ainda executáveis; candidata final/backup-restauroQA correspondente pendentes; A/B/C37/COUNTRY02 preservados.
|
||||
|
||||
[B8 QA 13/10/2026] Somente oito percursos visuaisL4/C135 e consolidação/backup-restauroQA da revisãofixa restam na checklistB; não há exigência técnica genérica nova. Requisito agregado continua parcial; critérios foraB e ativação separados.","QA408/581INE; ativo0geometrias;173correspondências por nome/edição/pai, Mandie ambíguo. Publicação é ação separada. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","AUD-GEO-03: Mostrar geometrias cadastradas e lista dos não localizados, sem pontos inventados | Para consolidação: critérios individuais S01–S19 e cenários A/B na proposta, com UI→API→gravação→nova sessão→resultado e ação independente.",P1,"AUD-GEO-03: Relatórios históricos mantidos; estado ativo apurado por leitura nesta auditoria
|
||||
[Reconciliação visual14/10/2026 — sem novo ensaio] Limites/mapa/recovery15 e32 cobertos. Faltam apresentação/ausência por consumidor nas rotas públicas/carteira/fundiário/Balcão/56 listadas; nenhuma geometria publicada por inferência. Referência: outputs/investmoz-audit-current-20261012/acceptance-396c-visual-reconciliation-20261014.json",Implementado parcialmente,Reposicao comum dos mapas encerrada em 066707ec. Proximo trabalho: avaliacao de navegacao e apresentacao pela Tempo. Localidades/parcelas sem geometria propria nao sao inventadas; desenvolvimento futuro distinto de regressao. Historico anterior preservado na coluna Lacuna anterior.,"408 geometrias existentes e validas, originais internos preservados. Divulgacao dos contornos administrativos autorizada pela Tempo em 24/10/2026; sem dependencia restante para este recorte.","AUD-GEO-03: Mostrar geometrias cadastradas e lista dos não localizados, sem pontos inventados | Para consolidação: critérios individuais S01–S19 e cenários A/B na proposta, com UI→API→gravação→nova sessão→resultado e ação independente.",P1,"AUD-GEO-03: Relatórios históricos mantidos; estado ativo apurado por leitura nesta auditoria
|
||||
|
||||
[Workflow QA 11/10/2026 — critérios de saída] Pendências históricas substituídas apenas nos subcritérios demonstrados, conservadas: {""Lacuna"": ""[QA Response/materialidade/consumidores/candidata 11/10/2026] Ficha pública Parque Industrial Balama: ação de mapa por teclado, resposta200 e estado explícito sem geometria própria autorizada,390px sem extravasamento após C107. GestãoQA17: seletor e limite administrativo por consumidor; editor não contém o mapa de geometrias próprias da ficha pública. GestorQA14 sem MFA recebe403 fundamentado; não reduzir segurança. Território cadastrado/limite administrativo não prova geometria da zona. Restam geometria própria oficialmente correspondente, mapas/seletores dos restantes consumidores, pública e privada por perfil; não inferir parcela/associação territorial. | ObservaçãoC108 esclarecida: o harness bloqueava todos os pedidos fora doQA por route.abort; não foi falha do portal/rede/TLS. Ensaio separado permite somenteGETde tile.openstreetmap.org:200/3tilescarregados/fundo apresentado. Recibo revision-map-basemap-allowed-20261011.json. Geometria própria da zona continua ausente; fundo e limite administrativo não a substituem."", ""Dependência"": ""Histórico até09/10 (preservado): Reconciliar nomes/pais por identidade administrativa, sem fuzzy match; revisão/autorização autenticada para eventual uso ativo; nunca publicar lote automaticamente. Adm3 excede limite de upload 20MB: scan GIS CLI específico, sem aumentar limites do portal. | I1–I3 autorizados exclusivamente em QA: concluir demonstração A/B na interface, cobertura de contexto/prefill e provas da versão. Ativação ativa não autorizada. I0 continua independente. | [QA independente 10/10/2026] Correspondência inequívoca por exemplar/pai; revisão visual por consumidor/perfil e publicação separada. C37 não bloqueia desenvolvimento/consulta QA independente.""}
|
||||
|
||||
@@ -4606,19 +4600,19 @@ AUD-GEO-03,Cartografia de todas as entidades e campos,"Pedido direto 09/10/2026,
|
||||
|
||||
[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Pedidos relacionados sem novo inventário/backlog paralelo; referência documental acrescentada, critérios anteriores preservados. Confirmar os bytes do v1(3) antes do fecho documental.",parcial,"COUNTRY02 ativo485ee04c40b2 preservado, somente050000; ativo288tabelas/13contas/0org/representações,030/040/190 ausentes e flags restantesOFF conforme prova ativa anterior. Incremento somente cópiaQA, nenhuma escrita/configuração/aplicação ativa. Hashes críticos ativos e todos os assets conservados.
|
||||
|
||||
[Candidata workflow QA 11/10/2026 — fecho do lote] Nenhuma escrita ativa;288tabelas13contas0org/representações,020/050presentes,COUNTRY02ON,demaisflagsOFF. QA295tem7tabelas de030/040 adicionais; não importar/povoar por inferência. Reversão/limites/decisões no pacote.","Capacidades/provas específicas anteriores existem, mas o requisito agregado ainda tem os critérios restantes explicitados; fechos parciais preservados.
|
||||
[Candidata workflow QA 11/10/2026 — fecho do lote] Nenhuma escrita ativa;288tabelas13contas0org/representações,020/050presentes,COUNTRY02ON,demaisflagsOFF. QA295tem7tabelas de030/040 adicionais; não importar/povoar por inferência. Reversão/limites/decisões no pacote.","24/10/2026 MAPAS: entregue em 066707ec; recibo docs/investmoz/unification/map-stabilization-receipt-20261024.json. Causa: filtro publico excluia os 408 limites internos e gate legado de leitura excluia os superutilizadores aprovados. Decisao expressa Tempo: disponibilizar os contornos administrativos aceites. Projeccao publica de 408 snapshots exactos, originais privados e outras camadas internas preservadas. QA 6/64; backup/restauro 174 tabelas e 369 ficheiros; delta instalado 408/408 disponiveis (11/133/264), 29 fichas e 28 relacoes preservadas. 172 tabelas iguais; apenas cache/sessions diferentes. Dondo/Sofala: seleccao, enquadramento, recuperacao e fonte INE/2019 conferidos. Sem reimportacao ou alteracao de dados/permissoes. Substitui referencias historicas a zero geometrias ou mapas publicos pendentes neste recorte; nao reabre fechos aceites. Estatisticas/IA adiadas. | Historico preservado: Capacidades/provas específicas anteriores existem, mas o requisito agregado ainda tem os critérios restantes explicitados; fechos parciais preservados.
|
||||
|
||||
[Manual 13/10/2026 — base 396c691930bc] Responsável confirmou «3: seletores, mapa e recuperação»: caso32, consumidor /minhas-oportunidades/32/resources. Sem extrapolar para documentos, área, workflow, outros mapas/perfis, teclado ou dispositivo. Conta específica e modo de recuperação não indicados; não se inventam detalhes.
|
||||
|
||||
[Reconciliação visual14/10/2026 — sem novo ensaio] Limites/mapa/recovery15 e32 cobertos. Faltam apresentação/ausência por consumidor nas rotas públicas/carteira/fundiário/Balcão/56 listadas; nenhuma geometria publicada por inferência. Referência: outputs/investmoz-audit-current-20261012/acceptance-396c-visual-reconciliation-20261014.json
|
||||
|
||||
[RECONCILIACAO-43-20261019] 23: 1921 referências e zero geometrias no destino. Reconciliar geometrias/fontes/classificação existentes em QA e consumidores abertos; corrigir bug de2. Não transformar divergência de contagens em importação.","[B8 QA 13/10/2026] Somente oito percursos visuaisL4/C135 e consolidação/backup-restauroQA da revisãofixa restam na checklistB; não há exigência técnica genérica nova. Requisito agregado continua parcial; critérios foraB e ativação separados.
|
||||
[RECONCILIACAO-43-20261019] 23: 1921 referências e zero geometrias no destino. Reconciliar geometrias/fontes/classificação existentes em QA e consumidores abertos; corrigir bug de2. Não transformar divergência de contagens em importação.","Saldo da reposicao dos mapas: zero. A avaliacao de navegacao/apresentacao pela Tempo sucede a entrega. Criterios agregados fora deste recorte nao sao declarados concluidos. | Historico preservado: [B8 QA 13/10/2026] Somente oito percursos visuaisL4/C135 e consolidação/backup-restauroQA da revisãofixa restam na checklistB; não há exigência técnica genérica nova. Requisito agregado continua parcial; critérios foraB e ativação separados.
|
||||
|
||||
[Manual 13/10/2026] Não repetir login/MFA/dashboard das seis contas confirmadas nem seletores/mapa/recuperação do cenário3. Nesse cenário restam apresentação da área/documentos, transições/revisões/publicação e teclado/foco/rótulos/erros sem confirmação. Outros sete percursos permanecem pendentes nos seus critérios específicos; requisitos agregados e variantes foraB não encerrados.
|
||||
|
||||
[Reconciliação visual14/10/2026 — sem novo ensaio] A classificação anterior «outrossetepercursos pendentes» é histórica e não invalida critérios visuais válidos. Roteiro atual:12trechos específicos em1/4/5/6/7/8;2/3 sem passos restantes. Sem novo critério, nem fecho global/opçãoB/candidata/ativação. Limites/mapa/recovery15 e32 cobertos. Faltam apresentação/ausência por consumidor nas rotas públicas/carteira/fundiário/Balcão/56 listadas; nenhuma geometria publicada por inferência.
|
||||
|
||||
[UTILIZACAO-HOMOLOGACAO-20261019] 23: Implementação parcial + dados — Consumidores cartográficos restantes e correspondências geográficas por item; diferença de contagens não identifica registos em falta.","InvestmentGeography, campos TerritoryFields/ProvinceSelect, geo_locations/geo_geometries e importador autenticado","QA408/581INE; ativo0geometrias;173correspondências por nome/edição/pai, Mandie ambíguo. Publicação é ação separada.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Completar critérios restantes sem repetir provas válidas,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: território. Esforço de código adicional só após lacuna reproduzida.,"outputs/investmoz-audit-current-20261012/reused-evidence-integrity.json: 35 recibos anteriores com hashes correspondentes; o âmbito de cada recibo permanece limitado ao critério ensaiado. outputs/investmoz-audit-current-20261012/http-promoter.json; http-validator.json; http-publisher.json; http-manager.json. outputs/investmoz-audit-current-20261012/consumer-context-qa.json; correspondencias-cartograficas.md (nomes/edição/código/pai).; visao-consolidada-modulos.md e proof-groups.json: COEDIT-GEO | QA56 distingue território cadastrado de geometria: província/distrito/posto têm limite INE, localidade Ancuabe-Sede não tem. Localidade recebe apenas três limites ancestrais; investment_site=false. Consulta pública destes limites internos devolve0. Sem importação/publicação adicional; apresentação não observada. Provas: consumer-lot-prepare-HTTP.json; consumer-lot-quarantine-HTTP.json; consumer-lot-derive-HTTP.json; consumer-lot-recover-HTTP.json; consumer-lot-document-state-original.json; consumer-lot-document-state-derivatives.json; consumer-lot-final-SQL.json; franchise-materiality-before.json; franchise-materiality-after.json; workflow-franchise-materiality-HTTP.json; workflow-franchise-finish-HTTP.json; connector-diagnosis-C135.json
|
||||
[UTILIZACAO-HOMOLOGACAO-20261019] 23: Implementação parcial + dados — Consumidores cartográficos restantes e correspondências geográficas por item; diferença de contagens não identifica registos em falta.","InvestmentGeography, campos TerritoryFields/ProvinceSelect, geo_locations/geo_geometries e importador autenticado","QA408/581INE; ativo0geometrias;173correspondências por nome/edição/pai, Mandie ambíguo. Publicação é ação separada.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Completar critérios restantes sem repetir provas válidas,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: território. Esforço de código adicional só após lacuna reproduzida.,"24/10/2026 MAPAS: entregue em 066707ec; recibo docs/investmoz/unification/map-stabilization-receipt-20261024.json. Causa: filtro publico excluia os 408 limites internos e gate legado de leitura excluia os superutilizadores aprovados. Decisao expressa Tempo: disponibilizar os contornos administrativos aceites. Projeccao publica de 408 snapshots exactos, originais privados e outras camadas internas preservadas. QA 6/64; backup/restauro 174 tabelas e 369 ficheiros; delta instalado 408/408 disponiveis (11/133/264), 29 fichas e 28 relacoes preservadas. 172 tabelas iguais; apenas cache/sessions diferentes. Dondo/Sofala: seleccao, enquadramento, recuperacao e fonte INE/2019 conferidos. Sem reimportacao ou alteracao de dados/permissoes. Substitui referencias historicas a zero geometrias ou mapas publicos pendentes neste recorte; nao reabre fechos aceites. Estatisticas/IA adiadas. | Historico preservado: outputs/investmoz-audit-current-20261012/reused-evidence-integrity.json: 35 recibos anteriores com hashes correspondentes; o âmbito de cada recibo permanece limitado ao critério ensaiado. outputs/investmoz-audit-current-20261012/http-promoter.json; http-validator.json; http-publisher.json; http-manager.json. outputs/investmoz-audit-current-20261012/consumer-context-qa.json; correspondencias-cartograficas.md (nomes/edição/código/pai).; visao-consolidada-modulos.md e proof-groups.json: COEDIT-GEO | QA56 distingue território cadastrado de geometria: província/distrito/posto têm limite INE, localidade Ancuabe-Sede não tem. Localidade recebe apenas três limites ancestrais; investment_site=false. Consulta pública destes limites internos devolve0. Sem importação/publicação adicional; apresentação não observada. Provas: consumer-lot-prepare-HTTP.json; consumer-lot-quarantine-HTTP.json; consumer-lot-derive-HTTP.json; consumer-lot-recover-HTTP.json; consumer-lot-document-state-original.json; consumer-lot-document-state-derivatives.json; consumer-lot-final-SQL.json; franchise-materiality-before.json; franchise-materiality-after.json; workflow-franchise-materiality-HTTP.json; workflow-franchise-finish-HTTP.json; connector-diagnosis-C135.json
|
||||
|
||||
[B5 QA 13/10/2026] Mesma matriz/22grupos/âmbitoB:18posições técnicas e8cenários visuais finitos no backlog. Estimativa25–43h mantida, lotes7–12/4–7/8–14/6–10, sem somar provas compartilhadas duas vezes. Inventário permitido vazio/No browser is available antes de selecionar tab; sem reset/contorno. Código/configuração/bundle ativos intactos.
|
||||
|
||||
@@ -4634,7 +4628,13 @@ outputs/investmoz-audit-current-20261012/acceptance-396c-visual-reconciliation-2
|
||||
|
||||
[RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário.
|
||||
|
||||
[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação.",território,"12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada | Lote consumidores C135/C136,12/10/2026; QA exclusiva.",,,"Restauro de oportunidade proposta R-ARCHIVE/R-DRAFT, sem implementação antecipada. Variantes por modalidade e contratos §25 ainda por critério, conforme tabela por categoria; Response§27 de compatibilidade com normative_response_complete=false (IDs/história/estados preservados). Interesse no anúncio público de negócio existente e outras variantes de país/estatística/mapa/documento têm consumidores separados.173correspondências eMandie/Guro; partilha individual de documentos de oportunidade não criada. Leitor de ecrã, PDF etiquetado e dispositivos reais pendentes. Sem fecho global por contagem de testes.","030000+040000 já instaladosQA, prévias autenticadas e dependências consistentes, sem reinstalar. ClamDQA13310 real/fresco+fila+GDWebP usados conjuntamente. Destino3310 assinaturas09/10 com>51h, signatures_stale pelo limite48h: novos scans bloqueados; verificar worker supervisionado. Prévias antigas ready=false não habilitam aplicação. Para futura instalação, renovar backup/restauro do alvo ativo/fingerprint, prévia030→040 e habilitações legítimas separadas.190000 somente percurso integrado, OFF nestaQA; não bloqueia workflow isolado. Legado/modulares/ofertas/SLA separados.
|
||||
[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação.",território,"12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada | Lote consumidores C135/C136,12/10/2026; QA exclusiva.",,,"Restauro de oportunidade proposta R-ARCHIVE/R-DRAFT, sem implementação antecipada. Variantes por modalidade e contratos §25 ainda por critério, conforme tabela por categoria; Response§27 de compatibilidade com normative_response_complete=false (IDs/história/estados preservados). Interesse no anúncio público de negócio existente e outras variantes de país/estatística/mapa/documento têm consumidores separados.173correspondências eMandie/Guro; partilha individual de documentos de oportunidade não criada. Leitor de ecrã, PDF etiquetado e dispositivos reais pendentes. Sem fecho global por contagem de testes. | Historico antes da estabilizacao de 24/10/2026: Restam mapas públicos/zonas/carteira/parcerias/terra/Balcão e apresentação QA56. 173 correspondências e Mandie/Guro mantidos; localidades/parcelas sem geometria oficial no exemplar. Disponibilidade interna não é divulgação nem implantação ativa.
|
||||
|
||||
[B5 QA 13/10/2026] Mesmos cinco consumidoresL3.1–5; geometria/fonte/visibilidade e falta explícita, sem transformar limiteINE emparcela. Renderização/legenda/teclado somenteL4; sem importação/publicaçãoativa. Plano/reorganização não é demonstração funcional ou visual. L1.1/L2.3 técnicos satisfeitos pelos grupos próprios; restante nominal na checklist. C135 bloqueia L4. A/B/C37 preservados; C132 separado, proposta com ações corretivas pendentes vazias. Ativação/foraB excluídos.
|
||||
|
||||
[B6 QA 13/10/2026] Mesmo saldoL3.1/4/5, renderização/legenda emL4; zero geometria pública na amostra explicitado, não é cartografia integral ou importação/publicação. Desenho/legenda/controles/apresentação sóL4; zero markers/áreas na amostra não prova povoamento integral nem seletores/parcela32, fundiário ouBalcão. Ativo não testado/alterado neste fix; recompilação desnecessária. Planeamento/inspeção de permissões não é fluxo demonstrado. L1.2/3/5 eL3.1/4/5/6/7/8 ainda executáveis; candidata final/backup-restauroQA correspondente pendentes; A/B/C37/COUNTRY02 preservados.
|
||||
|
||||
[B8 QA 13/10/2026] Somente oito percursos visuaisL4/C135 e consolidação/backup-restauroQA da revisãofixa restam na checklistB; não há exigência técnica genérica nova. Requisito agregado continua parcial; critérios foraB e ativação separados.","030000+040000 já instaladosQA, prévias autenticadas e dependências consistentes, sem reinstalar. ClamDQA13310 real/fresco+fila+GDWebP usados conjuntamente. Destino3310 assinaturas09/10 com>51h, signatures_stale pelo limite48h: novos scans bloqueados; verificar worker supervisionado. Prévias antigas ready=false não habilitam aplicação. Para futura instalação, renovar backup/restauro do alvo ativo/fingerprint, prévia030→040 e habilitações legítimas separadas.190000 somente percurso integrado, OFF nestaQA; não bloqueia workflow isolado. Legado/modulares/ofertas/SLA separados.
|
||||
|
||||
[Candidata workflow QA 11/10/2026 — fecho do lote] Destino READONLY12:14:31UTC:1990territórios/0geometrias,030/040/190 ausentes;COUNTRY02ON. Limites de mapas no destino requerem importação separadamente autorizada. ClamD3310 signatures_stale51,59h; worker supervisionado por verificar. Candidata não pronta para ativar; renovar backup/restauro/prévias correspondentes ao alvo e designações legítimas.190000 não é dependência do workflow isolado.
|
||||
|
||||
@@ -4658,7 +4658,7 @@ B8-TERRITORY-CONTEXT, B8-FINITE-PROGRESS
|
||||
|
||||
MANUAL-B396C-P3-GEO3
|
||||
|
||||
VISUAL-B396C-REUSE-20261014","COEDIT-GEO: Editor de recursos ensaiado: coeditor organizacional autorizado, organização estranha negada; mudança do pai limpa descendentes, país estrangeiro não aceita hierarquia moçambicana, rascunho incompleto recupera país/localização/mapa noutra sessão. | QA56 distingue território cadastrado de geometria: província/distrito/posto têm limite INE, localidade Ancuabe-Sede não tem. Localidade recebe apenas três limites ancestrais; investment_site=false. Consulta pública destes limites internos devolve0. Sem importação/publicação adicional; apresentação não observada.
|
||||
VISUAL-B396C-REUSE-20261014","24/10/2026 MAPAS: entregue em 066707ec; recibo docs/investmoz/unification/map-stabilization-receipt-20261024.json. Causa: filtro publico excluia os 408 limites internos e gate legado de leitura excluia os superutilizadores aprovados. Decisao expressa Tempo: disponibilizar os contornos administrativos aceites. Projeccao publica de 408 snapshots exactos, originais privados e outras camadas internas preservadas. QA 6/64; backup/restauro 174 tabelas e 369 ficheiros; delta instalado 408/408 disponiveis (11/133/264), 29 fichas e 28 relacoes preservadas. 172 tabelas iguais; apenas cache/sessions diferentes. Dondo/Sofala: seleccao, enquadramento, recuperacao e fonte INE/2019 conferidos. Sem reimportacao ou alteracao de dados/permissoes. Substitui referencias historicas a zero geometrias ou mapas publicos pendentes neste recorte; nao reabre fechos aceites. Estatisticas/IA adiadas. | Historico preservado: COEDIT-GEO: Editor de recursos ensaiado: coeditor organizacional autorizado, organização estranha negada; mudança do pai limpa descendentes, país estrangeiro não aceita hierarquia moçambicana, rascunho incompleto recupera país/localização/mapa noutra sessão. | QA56 distingue território cadastrado de geometria: província/distrito/posto têm limite INE, localidade Ancuabe-Sede não tem. Localidade recebe apenas três limites ancestrais; investment_site=false. Consulta pública destes limites internos devolve0. Sem importação/publicação adicional; apresentação não observada.
|
||||
|
||||
[B5 QA 13/10/2026] Mesma matriz/22grupos/âmbitoB:18posições técnicas e8cenários visuais finitos no backlog. Estimativa25–43h mantida, lotes7–12/4–7/8–14/6–10, sem somar provas compartilhadas duas vezes. Inventário permitido vazio/No browser is available antes de selecionar tab; sem reset/contorno. Código/configuração/bundle ativos intactos.
|
||||
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\ApprovedAdministrativeBoundaries;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class TerritoryGeometryConsumerAccessTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
private User $actor;
|
||||
|
||||
private string $territory;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$identity = DB::selectOne('select current_database() as name,inet_server_port() as port');
|
||||
$this->assertSame('simulator_fiscal_delta_20261021_test', $identity->name);
|
||||
$this->assertSame(55441, (int) $identity->port);
|
||||
$this->withoutVite();
|
||||
$this->withoutMiddleware(ThrottleRequests::class);
|
||||
config(['portal.profile_access_enabled' => true, 'portal.managers' => [], 'investor-path.enabled' => true, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
|
||||
$this->actor = User::factory()->create(['two_factor_secret' => Crypt::encryptString('JBSWY3DPEHPK3PXP'), 'two_factor_confirmed_at' => now()]);
|
||||
$other = User::factory()->create();
|
||||
DB::table('portal_superuser_pair')->updateOrInsert(['id' => 1], ['first_user_id' => $this->actor->id, 'second_user_id' => $other->id, 'approved_by' => $other->id]);
|
||||
$this->territory = DB::table('geo_geometries as g')->join('geo_locations as l', 'l.id', '=', 'g.geo_location_id')
|
||||
->where('g.source_system', 'ine-cod-ab')->where('g.data_classification', 'internal')->where('l.location_type', 'province')->value('l.id');
|
||||
$this->assertNotEmpty($this->territory);
|
||||
}
|
||||
|
||||
public function test_general_consumer_uses_existing_authenticated_read_access_without_the_legacy_gate(): void
|
||||
{
|
||||
$this->assertFalse($this->actor->can('manage-portal'));
|
||||
$before = $this->fingerprint();
|
||||
$this->actingAs($this->actor)->getJson('/api/v1/investment/territory-geometries?territory_id='.$this->territory)
|
||||
->assertOk()->assertJsonPath('selected_geometry_available', true)->assertJsonPath('geometry_scope', 'authorized_internal')
|
||||
->assertJsonPath('areas.0.territory_id', $this->territory)->assertHeader('Cache-Control', 'no-store, private');
|
||||
$this->assertSame($before, $this->fingerprint());
|
||||
}
|
||||
|
||||
public function test_existing_administration_reaches_the_same_geometry_with_its_completed_mfa_session(): void
|
||||
{
|
||||
$this->actingAs($this->actor)->withSession(['portal.mfa_actor' => $this->actor->id, 'portal.mfa_at' => time(), 'portal.access_revision' => (int) $this->actor->portal_access_revision]);
|
||||
$this->getJson('/management/territory-geometries?territory_id='.$this->territory)->assertOk()->assertJsonPath('selected_geometry_available', true);
|
||||
session()->forget(['portal.mfa_actor', 'portal.mfa_at']);
|
||||
$this->getJson('/management/territory-geometries?territory_id='.$this->territory)->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_anonymous_and_ordinary_accounts_do_not_receive_or_publish_internal_layers(): void
|
||||
{
|
||||
$before = $this->fingerprint();
|
||||
$url = '/api/v1/investment/territory-geometries?territory_id='.$this->territory;
|
||||
$this->getJson($url)->assertOk()->assertJsonPath('geometry_scope', 'public')->assertJsonPath('selected_geometry_available', false)->assertJsonCount(0, 'areas');
|
||||
$this->actingAs(User::factory()->create())->getJson($url)->assertOk()->assertJsonPath('geometry_scope', 'public')->assertJsonCount(0, 'areas');
|
||||
$this->getJson('/management/territory-geometries?territory_id='.$this->territory)->assertForbidden();
|
||||
$this->assertSame($before, $this->fingerprint());
|
||||
}
|
||||
|
||||
public function test_saved_territory_is_recovered_in_dossier_and_simulator_and_the_map_uses_that_identity(): void
|
||||
{
|
||||
$this->actingAs($this->actor);
|
||||
$id = $this->postJson('/investimentos', ['title' => 'SYNTHETIC QA - mapa recuperado', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
|
||||
$body = ['version' => $this->getJson('/investimentos/'.$id.'/contexto')->json('case.version'), 'selection' => ['territory' => 'territory:'.$this->territory]];
|
||||
$preview = $this->postJson('/investimentos/'.$id.'/contexto/previa', $body)->assertOk()->json();
|
||||
$this->postJson('/investimentos/'.$id.'/contexto/confirmar', [...$body, 'preview_hash' => $preview['preview_hash'], 'operation_key' => (string) Str::uuid(), 'confirm' => true])->assertOk();
|
||||
$view = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json();
|
||||
$this->assertSame($this->territory, $view['context']['selection']['territory']['id']);
|
||||
$this->assertSame($this->territory, $view['prefill']['simulator']['province_id']);
|
||||
$this->getJson('/api/v1/investment/territory-geometries?territory_id='.$view['prefill']['simulator']['province_id'])
|
||||
->assertOk()->assertJsonPath('selected_geometry_available', true)->assertJsonPath('areas.0.selected_territory', true);
|
||||
$this->assertSame($this->territory, $this->getJson('/investimentos/'.$id.'/contexto')->json('context.selection.territory.id'));
|
||||
}
|
||||
|
||||
public function test_only_the_approved_unchanged_snapshot_is_public_without_reclassifying_the_original(): void
|
||||
{
|
||||
$before = $this->fingerprint();
|
||||
$row = DB::table('geo_geometries as g')->where('geo_location_id', $this->territory)->first([
|
||||
'g.id', 'g.geo_location_id', DB::raw("encode(sha256(ST_AsEWKB(g.geom)),'hex') as geometry_sha256"),
|
||||
DB::raw("encode(sha256(convert_to(g.properties::text,'UTF8')),'hex') as properties_sha256"),
|
||||
]);
|
||||
// The QA import has its own identities; never copy or replace production rows.
|
||||
$approved = $this->partialMock(ApprovedAdministrativeBoundaries::class);
|
||||
$approved->shouldReceive('snapshots')->andReturn([$row->id => [
|
||||
'territory_id' => $row->geo_location_id, 'geometry_sha256' => $row->geometry_sha256,
|
||||
'properties_sha256' => $row->properties_sha256,
|
||||
]]);
|
||||
$url = '/api/v1/investment/territory-geometries?territory_id='.$this->territory;
|
||||
$this->getJson($url)->assertOk()->assertJsonPath('selected_geometry_available', true)
|
||||
->assertJsonPath('areas.0.data_classification', 'public')->assertJsonPath('investment_site', false);
|
||||
$this->actingAs(User::factory()->create())->getJson($url)->assertOk()->assertJsonPath('selected_geometry_available', true);
|
||||
$this->assertSame($before, $this->fingerprint());
|
||||
$this->assertSame('internal', DB::table('geo_geometries')->where('id', $row->id)->value('data_classification'));
|
||||
DB::table('geo_geometries')->where('id', $row->id)->update(['properties' => DB::raw("properties || '{\"qa_changed\":true}'::jsonb")]);
|
||||
$this->getJson($url)->assertOk()->assertJsonPath('selected_geometry_available', false)->assertJsonCount(0, 'areas');
|
||||
$this->actingAs($this->actor)->getJson($url)->assertOk()->assertJsonPath('selected_geometry_available', true);
|
||||
}
|
||||
|
||||
public function test_public_manifest_has_the_exact_approved_scope_and_immutable_hash(): void
|
||||
{
|
||||
$items = app(ApprovedAdministrativeBoundaries::class)->snapshots();
|
||||
$this->assertCount(408, $items);
|
||||
$this->assertCount(408, array_unique(array_column($items, 'territory_id')));
|
||||
$this->assertSame(['2019-06-07'], array_values(array_unique(array_column($items, 'source_version'))));
|
||||
}
|
||||
|
||||
private function fingerprint(): string
|
||||
{
|
||||
return DB::selectOne("select md5(string_agg(row_to_json(g)::text,E'\\n' order by id)) as hash from geo_geometries g")->hash;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user