Compare commits

..
Author SHA1 Message Date
nala e1f010f941 fix: preserve corridor filters and keep investment previews readable
tests / ci (push) Canceled after 0s
2026-10-23 13:30:10 +02:00
nala 0025309b98 feat: adapt investment territories to Tempo corridor configuration
tests / ci (push) Canceled after 0s
2026-10-23 13:24:58 +02:00
nala a0e80db4ec docs: confirm opportunity preparation continuity in homologation
tests / ci (push) Canceled after 0s
2026-10-23 12:31:36 +02:00
nala 7226287526 fix: keep opportunity preparation focused on the pending selection
tests / ci (push) Canceled after 0s
2026-10-23 12:29:26 +02:00
nala f1ac82ae4d docs: record clean investor entry verified in homologation
tests / ci (push) Canceled after 0s
2026-10-23 12:20:28 +02:00
nala 98474777f6 fix: remove internal metadata from investor dossier presentation
tests / ci (push) Canceled after 0s
2026-10-23 12:18:25 +02:00
nala 3848f29bea docs: record corridor catalogue verification in homologation
tests / ci (push) Canceled after 0s
2026-10-23 12:12:05 +02:00
nala 203492997e feat: explore the public opportunity catalogue by corridor
tests / ci (push) Canceled after 0s
2026-10-23 12:08:33 +02:00
nala 165c2f6171 fix: keep internal agribusiness delivery notes out of portal presentation
tests / ci (push) Canceled after 0s
2026-10-23 11:22:39 +02:00
nala 4ad1bf402b docs: record authenticated publication of 34 agribusiness opportunities
tests / ci (push) Canceled after 0s
2026-10-23 11:12:45 +02:00
nala e12ef6ad42 Record installed agribusiness workflow, preserved destination and pending real-account publication
tests / ci (push) Canceled after 0s
2026-10-23 11:00:30 +02:00
nala c641b267ac Publish agribusiness lot through scoped management and extend existing dossier for multiple opportunities
tests / ci (push) Canceled after 0s
2026-10-23 10:49:50 +02:00
nala 7d08c2c664 Register 34 private agribusiness opportunities with promotional management and investor paths in QA 2026-10-23 10:15:41 +02:00
nala 761035aefb Record homologation agribusiness installation and preserved QA evidence
tests / ci (push) Canceled after 0s
2026-10-23 09:58:13 +02:00
nala 20a4099d10 Present 34 agribusiness opportunities in existing corridor sections
tests / ci (push) Canceled after 0s
2026-10-23 09:56:22 +02:00
nala e03de682ca Preserve completed features and restore approved portfolio visibility
tests / ci (push) Canceled after 0s
2026-10-23 09:19:25 +02:00
nala 37a8eb015a docs: record private legacy registration and authenticated editorial access
tests / ci (push) Canceled after 0s
2026-10-22 23:55:57 +02:00
nala 65eddf6bc7 merge: install reviewed private legacy editorial workflow
tests / ci (push) Canceled after 0s
2026-10-22 23:40:27 +02:00
74 changed files with 5641 additions and 279 deletions
+10
View File
@@ -46,3 +46,13 @@ Referenciar estas orientações nos requisitos correspondentes da matriz existen
A legislação, os formulários e os procedimentos oficiais disponibilizados são fontes válidas para implementar os requisitos. As decisões e procedimentos da Tempo orientam a sua utilização no portal. Traduzir essas fontes em campos, regras, documentos, cálculos e percursos executáveis com rastreabilidade, sem exigir nova validação jurídica genérica ou criar aprovadores, restrições ou condições por interpretação do Codex.
Uma divergência concreta deve identificar os trechos, períodos e comportamento afectados; prosseguir com os restantes requisitos. Uma decisão de implementação em falta deve ser apresentada especificamente à Tempo, sem a substituir por regra inventada. Rever e remover bloqueios anteriores sem fundamento numa fonte aplicável ou decisão expressa da Tempo, preservando dados e histórico. A rastreabilidade explica a execução e não constitui uma autoridade adicional. Mantêm-se os limites autorizados de QA e das alterações no activo.
## Preservação do concluído — pedido expresso da Tempo, 23/10/2026
Antes de avançar com novas rondas de testes/validações, inventariar na matriz e no manual existentes as funcionalidades concluídas e as funcionalidades desaparecidas, e repor as perdas confirmadas. Preservar as aprovações, dados, originais, relações, versões, histórico e acessos já concluídos. Não transformar uma entrega anterior em funcionalidade nova nem exigir novamente a decisão organizacional já registada.
Comparar código, schema, dados, configuração e permissões entre o último estado demonstrado e o destino. Distinguir eliminação, perda de visibilidade, diferença de ambiente, pendência real e estado documental desactualizado; uma página vazia ou a falta de nova prova não apagam a aceitação anterior. Reutilizar as provas aceites e conferir apenas o delta da reposição. Cada entrega seguinte deve explicar qualquer redução do âmbito previamente disponível, em vez de a aceitar como consequência normal da implementação.
Transporte privado não equivale à revogação de uma divulgação anterior aprovada. Reconciliar a decisão anterior de forma delimitada e auditada, sem publicar automaticamente conteúdos novos, reviver exemplares arquivados ou sobrescrever edições posteriores. Mantêm-se backup/restauro, autenticação e os limites concretos de cada tarefa.
Escolha técnica de verificação: comparar dados protegidos por segurança por linha (RLS) com identidades e contexto de acesso equivalentes. Uma leitura da aplicação sem actor pode ocultar registos que o utilizador do backup consegue ler; confirmar essa diferença antes de declarar perda ou propor reposição. Esta orientação não altera permissões do portal nem autoriza contornar RLS numa operação da equipa.
@@ -0,0 +1,73 @@
<?php
namespace App\Http\Controllers;
use App\Models\Opportunity;
use App\Services\CorridorAgribusinessOpportunities;
use App\Services\OpportunityManagement;
use App\Services\OpportunityPromotion;
use App\Services\PortalProfileAccess;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
final class CorridorAgribusinessController extends Controller
{
private function manifest(CorridorAgribusinessOpportunities $service): string
{
return hash('sha256', json_encode($service->entries(), JSON_THROW_ON_ERROR));
}
public function show(Request $request, CorridorAgribusinessOpportunities $service)
{
$access = app(PortalProfileAccess::class);
abort_unless($access->internalAssignment($request->user(), 'investment_project') || $access->has($request->user(), 'publisher'), 403);
$records = Opportunity::withTrashed()->whereIn('management_creation_key', array_column($service->entries(), 'key'))->get()->keyBy('management_creation_key');
foreach ($records as $record) abort_unless($access->canView($request->user(), $record), 403);
return Inertia::render('management/corridor-agribusiness', ['manifestHash' => $this->manifest($service),
'canRegister' => (bool) $access->internalAssignment($request->user(), 'investment_project'),
'entries' => array_map(function ($entry) use ($records) {
$r = $records->get($entry['key']);
return [...$entry, 'id' => $r?->id, 'status' => $r?->status, 'href' => $r ? '/oportunidades/'.$r->slug : null];
}, $service->entries())]);
}
public function register(Request $request, CorridorAgribusinessOpportunities $service)
{
$data = $request->validate(['manifest_hash' => 'required|string|size:64', 'confirm' => 'required|accepted']);
abort_unless(hash_equals($this->manifest($service), $data['manifest_hash']), 409, 'A fonte mudou; recupere a prévia.');
$access = app(PortalProfileAccess::class);
$grant = $access->internalAssignment($request->user(), 'investment_project');
abort_unless($grant && $access->mfa($request->user()), 403, 'Use a designação existente e MFA recente.');
return response()->json(['records' => $service->register($request->user(), $grant->organization_id)]);
}
public function preview(Request $request, CorridorAgribusinessOpportunities $service)
{
$previews = [];
foreach ($service->entries() as $entry) {
$record = Opportunity::where('management_creation_key', $entry['key'])->firstOrFail();
$input = data_get($record->workflow_context, 'promotional_summary.input');
abort_unless(is_array($input), 409, 'Complete a selecção pública na divulgação individual.');
$previews[] = ['id' => $record->id, ...app(OpportunityPromotion::class)->preview($request->user(), $record,
[...$input, 'source_date' => $input['source_date'] ?: null, 'action' => 'disclose', 'etag' => app(OpportunityManagement::class)->etag($record)])];
}
return response()->json(['previews' => $previews]);
}
public function disclose(Request $request, CorridorAgribusinessOpportunities $service)
{
$data = $request->validate(['confirm' => 'required|accepted', 'reason' => 'required|string|min:20|max:1000',
'previews' => 'required|array|size:34', 'previews.*.id' => 'required|integer|distinct',
'previews.*.token' => 'required|string|max:300000', 'previews.*.operation_key' => 'required|uuid|distinct']);
$expected = Opportunity::whereIn('management_creation_key', array_column($service->entries(), 'key'))->pluck('id')->sort()->values()->all();
$supplied = array_column($data['previews'], 'id'); sort($supplied);
abort_unless($expected === $supplied && count($expected) === 34, 409, 'A prévia deve identificar exactamente as 34 fichas deste lote.');
return response()->json(DB::transaction(function () use ($request, $data) {
$result = [];
foreach ($data['previews'] as $preview) $result[] = app(OpportunityPromotion::class)->confirm($request->user(), $preview['id'],
[...$preview, 'confirm' => true, 'reason' => $data['reason']]);
return ['records' => $result];
}));
}
}
@@ -26,6 +26,7 @@ class InvestmentDiscoveryController extends Controller
}
return Inertia::render('investment/catalogue', ['filters' => $filters, 'catalogueUrl' => $request->routeIs('investment.education') ? '/educacao' : '/oportunidades', 'references' => $catalogue->references(false, $filters),
'corridorGroups' => ($filters['view'] ?? '') === 'corridors' ? app(\App\Services\OpportunityCorridorExplorer::class)->groups($filters) : [],
'territorySelection' => app(InvestmentGeography::class)->selection($filters),
'guides' => app(\App\Services\SectorInvestment::class)->guides(\App\Models\Sector::where('slug', $filters['sector'] ?? '')->where('is_active', true)->whereNotNull('published_at')->first()),
'results' => $catalogue->query($filters)->paginate(12)->withQueryString(),
@@ -33,12 +33,40 @@ final class InvestorContextController extends Controller
return response()->json($context->options($d['q'] ?? ''));
}
public function corridorOptions(Request $r)
{
$data = $r->validate(['corridor' => ['nullable', \Illuminate\Validation\Rule::in(array_keys(config('investment_corridors')))], 'territory' => 'nullable|uuid']);
$service = app(\App\Services\InvestmentCorridorContext::class);
return response()->json(['corridors' => collect(config('investment_corridors'))->map(fn($entry,$key)=>['key'=>$key,'name'=>$entry['name'],'provinces'=>$service->provinces($key)])->values(),
'parks' => $service->parks($data['corridor'] ?? null, $data['territory'] ?? null)]);
}
public function saveDraft(Request $r, string $id, InvestorContext $context)
{
return response()->json($context->saveDraft($r->user(), $id, $r->all()));
}
public function edit(Request $r, string $id, InvestorContext $context)
{
$data = $context->view($r->user(), $id);
abort_unless($data['can_write'], 403);
return Inertia::render('investor-path/context', ['initial' => $data, 'options' => $context->options(), 'source' => $r->query('source') ? $context->reference($r->validate(['source' => 'required|string|max:100'])['source']) : null, 'territorySelection' => isset($data['context']['selection']['territory']) ? app(InvestmentGeography::class)->path($data['context']['selection']['territory']['id']) : []]);
$ids = $r->validate(['opportunities' => 'sometimes|array|max:100', 'opportunities.*' => 'integer|distinct|min:1'])['opportunities'] ?? [];
$choices = $ids ? app(\App\Services\InvestmentOpportunityChoices::class)->resolve(array_map(fn ($id) => ['source' => 'opportunity:'.$id], $ids)) : null;
$source = $r->query('source') ? $context->reference($r->validate(['source' => 'required|string|max:100'])['source']) : null;
if ($choices === null && ($source['kind'] ?? '') === 'opportunity') $choices = app(\App\Services\InvestmentOpportunityChoices::class)->resolve([['source' => $source['key']]]);
$explicitChoices=$choices;
$selectionKey=$r->validate(['selection_key'=>'nullable|uuid'])['selection_key']??null;
$entryKey=fn($c)=>$c['opportunity']['key'].($selectionKey?'@'.$selectionKey:'');
$entrySources=array_map($entryKey,$explicitChoices??[]);
if ($choices !== null) $choices = collect([...($data['context']['opportunity_choices'] ?? []), ...$choices])->unique(fn ($choice) => $choice['opportunity']['key'])->values()->all();
$draft = $context->draft($r->user(), $id);
if ($draft && isset($draft['opportunity_choices'])) {
$recovered = app(\App\Services\InvestmentOpportunityChoices::class)->resolve($draft['opportunity_choices'], $data['context']['opportunity_choices'] ?? [], true);
$new=array_filter($explicitChoices??[],fn($c)=>!in_array($entryKey($c),$draft['entry_sources']??[],true));
$choices = collect([...$recovered, ...$new])->unique(fn($c)=>$c['opportunity']['key'])->values()->all();
}
return Inertia::render('investor-path/context', ['entrySources'=>$entrySources,'draft' => $draft, 'requestedChoices' => $choices, 'initial' => $data, 'options' => $context->options(), 'source' => $source, 'territorySelection' => isset($data['context']['selection']['territory']) ? app(InvestmentGeography::class)->path($data['context']['selection']['territory']['id']) : []]);
}
public function preview(Request $r, string $id, InvestorContext $context)
@@ -56,7 +84,9 @@ final class InvestorContextController extends Controller
$d = $r->validate(['source' => 'nullable|string|max:100', 'step' => ['nullable', 'regex:/^S(0[1-9]|1[0-9])$/']]);
$ref = isset($d['source']) ? $context->reference($d['source']) : null;
return Inertia::render('investor-path/context-start', ['contexts' => $path->contexts($r->user()), 'source' => $ref, 'step' => $d['step'] ?? null]);
$ids = $r->validate(['opportunities' => 'sometimes|array|max:100', 'opportunities.*' => 'integer|distinct|min:1'])['opportunities'] ?? [];
$choices = $ids ? app(\App\Services\InvestmentOpportunityChoices::class)->resolve(array_map(fn ($id) => ['source' => 'opportunity:'.$id], $ids)) : [];
return Inertia::render('investor-path/context-start', ['opportunityChoices' => $choices, 'contexts' => $path->contexts($r->user()), 'source' => $ref, 'step' => $d['step'] ?? null]);
}
public function installation(Request $r, InvestorContextInstallation $install)
@@ -103,6 +103,7 @@ class OpportunityManagementController extends Controller
$records = $query->orderByDesc('id')->paginate(20)->withQueryString();
$records->getCollection()->each(function (Opportunity $r) use ($access, $service, $request) {
$r->setAttribute('can_edit', $access->canEdit($request->user(), $r));
$r->setAttribute('can_promote', app(\App\Services\OpportunityPromotion::class)->allowed($request->user(), $r));
$r->setAttribute('working_status', $access->state($r));
$r->setAttribute('publication', $r->publicationPresentation());
$r->setAttribute('draft_title', $service->values($r)['canonical']['official_title'] ?? $r->title);
@@ -130,6 +131,7 @@ class OpportunityManagementController extends Controller
'profileReauthenticationRequired' => $record && $record->owner_user_id !== null
? app(OpportunityProfileWorkflow::class)->reauthenticationRequired($request->user(), $record) : false,
'publicationState' => $record?->publicationPresentation(),
'promotionHref' => $record && app(\App\Services\OpportunityPromotion::class)->allowed($request->user(), $record) ? '/minhas-oportunidades/'.$record->id.'/divulgacao' : null,
'canonicalResponse' => $record?->owner_user_id !== null ? app(OpportunityCanonicalResponse::class)->read($request->user(), $record) : null,
'canEditDraft' => $record ? $access->canEdit($request->user(), $record) : false,
'workflowParticipants' => $record && $record->owner_user_id !== null ? app(OpportunityProfileWorkflow::class)->participants($request->user(), $record) : ['validators' => [], 'publishers' => []],
@@ -0,0 +1,26 @@
<?php
namespace App\Http\Controllers;
use App\Models\Opportunity;
use App\Services\OpportunityPromotion;
use Illuminate\Http\Request;
use Inertia\Inertia;
final class OpportunityPromotionController extends Controller
{
public function show(Request $request, int $id, OpportunityPromotion $service): \Inertia\Response
{
return Inertia::render('management/opportunity-promotion', $service->editor($request->user(), Opportunity::findOrFail($id)));
}
public function preview(Request $request, int $id, OpportunityPromotion $service): \Illuminate\Http\JsonResponse
{
return response()->json($service->preview($request->user(), Opportunity::findOrFail($id), $request->all()));
}
public function confirm(Request $request, int $id, OpportunityPromotion $service): \Illuminate\Http\JsonResponse
{
return response()->json($service->confirm($request->user(), $id, $request->all()));
}
}
@@ -11,8 +11,13 @@ class PublicGeographyController extends Controller
{
public function options(Request $request, InvestmentGeography $geography): JsonResponse
{
$data = $request->validate(['type' => ['required', 'in:province,district,admin_post,locality'], 'id' => ['nullable', 'uuid'], 'parent_id' => ['nullable', 'uuid'], 'q' => ['nullable', 'string', 'max:100'], 'page' => ['nullable', 'integer', 'min:1']]);
$data = $request->validate(['corridor' => ['nullable', \Illuminate\Validation\Rule::in(array_keys(config('investment_corridors')))], 'type' => ['required', 'in:province,district,admin_post,locality'], 'id' => ['nullable', 'uuid'], 'parent_id' => ['nullable', 'uuid'], 'q' => ['nullable', 'string', 'max:100'], 'page' => ['nullable', 'integer', 'min:1']]);
$query = $geography->publicReferences()->where('location_type', $data['type']);
if (!empty($data['corridor'])) {
$corridors = app(\App\Services\InvestmentCorridorContext::class);
if ($data['type'] === 'province') $query->whereIn('id', array_column($corridors->provinces($data['corridor']), 'id'));
elseif (!$corridors->compatible($data['corridor'], $data['parent_id'] ?? null)) abort(422, 'O território não pertence ao corredor escolhido.');
}
if (! empty($data['id'])) {
$query->where('id', $data['id']);
}
@@ -29,6 +34,6 @@ class PublicGeographyController extends Controller
->orWhereRaw('source_code ILIKE ?', [$term]));
}
return response()->json($query->orderBy('name')->orderBy('id')->paginate(100, ['id', 'name', 'parent_id', 'location_type', 'source_code']));
return response()->json($query->orderBy('name')->orderBy('id')->paginate(100, ['id', 'name', 'parent_id', 'location_type', 'source_code'])->withQueryString());
}
}
@@ -29,7 +29,9 @@ class ProtectProfileOpportunity
if ($record && ($record->owner_user_id !== null || str_starts_with($request->path(), 'minhas-oportunidades'))) {
abort_if($record->owner_user_id === null && str_starts_with($request->path(), 'minhas-oportunidades'), 403, 'Registo legado não convertido para a política v1.');
$access = app(PortalProfileAccess::class);
$access->authorize($request->user(), $request->isMethod('GET') || str_ends_with($request->path(), '/workflow') || str_ends_with($request->path(), '/preview') || $request->is('minhas-oportunidades/*/classification/review') ? 'view' : 'edit', $record);
// The promotional controller checks its own scoped disclosure capability,
// like workflow decisions; publication does not grant draft editing.
$access->authorize($request->user(), $request->isMethod('GET') || str_ends_with($request->path(), '/workflow') || str_ends_with($request->path(), '/preview') || $request->is('minhas-oportunidades/*/classification/review', 'minhas-oportunidades/*/divulgacao/previa', 'minhas-oportunidades/*/divulgacao/confirmar') ? 'view' : 'edit', $record);
abort_if($request->is('management/opportunity-origin/apply'), 403, 'O cadastro privado v1 não usa a classificação editorial dos exemplos legados.');
abort_if($request->isMethod('POST') && str_ends_with($request->path(), '/lifecycle') && ! str_contains($request->path(), '/resources/'), 403, 'Use o workflow com decisões segregadas; o perfil não concede exclusão.');
}
@@ -72,7 +72,7 @@ class StoreSimulationFormDraftRequest extends FormRequest
'economic_snapshot.business_plan_snapshot' => ['nullable', 'string', 'max:60000'],
'economic_snapshot.financial_tools_snapshot' => ['nullable', 'string', 'max:30000'],
'economic_snapshot.cashflow_snapshot' => ['nullable', 'string', 'max:20000'],
'economic_snapshot.context_applicability_snapshot' => ['nullable', 'string', 'max:20000'],
'economic_snapshot.context_applicability_snapshot' => ['nullable', 'string', 'max:1000000'],
'economic_snapshot.investment_regime' => ['nullable', 'in:general,industrial_park,zee,zfi'],
'economic_snapshot.context_reuse' => ['nullable', 'string', 'max:10000'],
'economic_snapshot.compatible_fields_snapshot' => ['nullable', 'string', 'max:10000'],
+9 -1
View File
@@ -31,6 +31,13 @@ class Opportunity extends Model
protected $appends = ['maturity_catalogue_version'];
public function toArray(): array
{
$data = parent::toArray();
if (isset($data['description'])) $data['description'] = \App\Services\OpportunityPublicText::description($this, $data['description']);
return $data;
}
public function getMaturityCatalogueVersionAttribute(): ?string
{
// Only published metadata is public; never expose the current private draft.
@@ -68,7 +75,8 @@ class Opportunity extends Model
$scope = $public ? 'public' : ($visible && $this->owner_user_id !== null ? 'restricted' : 'unpublished');
return ['scope' => $scope, 'public_catalog' => $public, 'label' => match ($scope) {
'public' => 'Publicada no catálogo público',
'public' => data_get($this->workflow_context, 'publication.purpose') === 'promotional_preparation'
? 'Resumo divulgado — Em preparação; não autoriza execução' : 'Publicada no catálogo público',
'restricted' => 'Disponibilizada com acesso restrito — perfis e organização autorizados',
default => 'Sem versão disponibilizada; aprovação interna é uma etapa distinta',
}];
+83
View File
@@ -0,0 +1,83 @@
<?php
namespace App\Services;
use DOMDocument;
use DOMElement;
/** Supplement the six named agribusiness sections without changing corridor masters or source documents. */
final class CorridorAgribusiness
{
public function enrich(string $html, array $links = []): string
{
$data = json_decode(file_get_contents(__DIR__.'/../../database/data/corridor-investment-opportunities.json'), true, 512, JSON_THROW_ON_ERROR);
$doc = new DOMDocument;
$previous = libxml_use_internal_errors(true);
try {
$doc->loadHTML('<?xml encoding="UTF-8"><html><body>'.$html.'</body></html>', LIBXML_NONET);
$body = $doc->getElementsByTagName('body')->item(0);
if (! $body) {
return $html;
}
$changed = false;
foreach ($data['groups'] as $index => $group) {
$marker = 'agronegocio-oportunidades-'.($index + 1);
if ($doc->getElementById($marker)) {
continue;
}
foreach (iterator_to_array($body->childNodes) as $heading) {
if (! $heading instanceof DOMElement) {
continue;
}
$name = preg_replace('/^[a-f]\)\s*/u', '', trim($heading->textContent));
if ($name !== $group['name']) {
continue;
}
$chains = $heading->nextSibling;
while ($chains && ! $chains instanceof DOMElement) {
$chains = $chains->nextSibling;
}
// Insert only into the exact named section and its existing priority-chain paragraph.
if (! $chains || ! str_starts_with(trim($chains->textContent), 'Cadeias de valor prioritárias:')) {
continue;
}
$fragment = $doc->createDocumentFragment();
$label = $doc->createElement('p');
$strong = $doc->createElement('strong');
$strong->appendChild($doc->createTextNode('Oportunidades de investimento em agronegócio:'));
$label->appendChild($strong);
$fragment->appendChild($label);
$list = $doc->createElement('ul');
$list->setAttribute('id', $marker);
foreach ($group['opportunities'] as $itemIndex => $opportunity) {
$item = $doc->createElement('li');
$chain = $doc->createElement('strong');
$chain->appendChild($doc->createTextNode($opportunity['chain'].': '));
$item->appendChild($chain);
$item->appendChild($doc->createTextNode($opportunity['description']));
if (isset($links[$index][$itemIndex])) {
$item->appendChild($doc->createTextNode(' '));
$link = $doc->createElement('a');
$link->setAttribute('href', $links[$index][$itemIndex]);
$link->appendChild($doc->createTextNode('Conhecer a oportunidade e iniciar o roteiro'));
$item->appendChild($link);
}
$list->appendChild($item);
}
$fragment->appendChild($list);
$source = $doc->createElement('p');
$source->appendChild($doc->createTextNode('Fonte das oportunidades: '.$data['source']));
$fragment->appendChild($source);
$body->insertBefore($fragment, $chains->nextSibling);
$changed = true;
break;
}
}
return $changed ? implode('', array_map(fn ($node) => $doc->saveHTML($node), iterator_to_array($body->childNodes))) : $html;
} finally {
libxml_clear_errors();
libxml_use_internal_errors($previous);
}
}
}
@@ -0,0 +1,86 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
use App\Models\Sector;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Ramsey\Uuid\Uuid;
/** Source-defined opportunities; never infer a master corridor, site or promoter. */
final class CorridorAgribusinessOpportunities
{
public const SOURCE_HASH = '1473b06c48aa234e771660e3f2a51b9d2e4e1943bd52d878e0ae854ee6657055';
public const LIMITATIONS = 'Promotor, implantação exacta, área, montante, financiamento, viabilidade e licenças não indicados nesta fonte. O corredor é um enquadramento documental; não identifica uma parcela nem confirma disponibilidade.';
public function entries(): array
{
$data = json_decode(file_get_contents(database_path('data/corridor-investment-opportunities.json')), true, 512, JSON_THROW_ON_ERROR);
if ($data['source_sha256'] !== self::SOURCE_HASH) throw new \RuntimeException('Fonte divergente; reconciliar antes de cadastrar.');
$sector = Sector::where('slug', 'agronegocio')->where('is_active', true)->whereNull('deleted_at')->firstOrFail();
$entries = [];
foreach ($data['groups'] as $g => $group) {
foreach ($group['opportunities'] as $i => $item) {
$key = (string) Uuid::uuid5(Uuid::NAMESPACE_URL, 'investmoz:agronegocio:'.self::SOURCE_HASH.':'.$g.':'.$i);
$title = Str::limit($item['chain'].' — '.$group['name'], 150, '…');
$description = $item['description']."\n\nEnquadramento documental: ".$group['name'].".\n\nFonte: ".$data['source'].'; SHA-256 '.self::SOURCE_HASH.".\n\n".self::LIMITATIONS;
$entries[] = ['key' => $key, 'group' => $g, 'index' => $i, 'corridor' => $group['name'], 'chain' => $item['chain'],
'source' => $data['source'], 'source_sha256' => self::SOURCE_HASH, 'title' => $title,
'summary' => $item['description'], 'description' => $description, 'sector_id' => $sector->id];
}
}
if (count($entries) !== 34) throw new \RuntimeException('O lote deve conter as 34 entradas da fonte.');
return $entries;
}
public function register(User $actor, string $organization): array
{
// The caller uses the ordinary profile creation route and its approved scope.
abort_unless(str_starts_with(request()->path(), 'minhas-oportunidades'), 422);
return DB::transaction(function () use ($actor, $organization) {
DB::select('SELECT pg_advisory_xact_lock(231026, 34)');
$result = [];
foreach ($this->entries() as $entry) {
$record = Opportunity::withTrashed()->where('management_creation_key', $entry['key'])->first();
if ($record) {
abort_unless(app(PortalProfileAccess::class)->canView($actor, $record), 403);
abort_unless(data_get($record->workflow_context, 'corridor_agribusiness.source_sha256') === self::SOURCE_HASH, 409);
// Recovery never overwrites editorial changes, withdrawal or archive.
$result[] = ['id' => $record->id, 'created' => false, 'key' => $entry['key']];
continue;
}
$record = app(OpportunityManagement::class)->save($actor, ['creation_key' => $entry['key'], 'organization_id' => $organization,
'opportunity_category' => 'investment_project', 'sector_id' => $entry['sector_id'],
'title' => $entry['title'], 'summary' => $entry['summary'], 'description' => $entry['description'],
'canonical' => ['opportunity_category' => 'investment_project', 'official_title' => $entry['title'],
'executive_summary' => $entry['summary'], 'demand_statement' => $entry['description'], 'sector_id' => $entry['sector_id']],
'reason' => 'Cadastro privado das 34 oportunidades de agronegócio solicitado pela Tempo em 23/10/2026; não constitui publicação nem aprovação de execução.']);
$context = $record->workflow_context ?? [];
$context['corridor_agribusiness'] = $entry;
$context['promotional_summary'] = ['input' => ['title' => $entry['title'], 'summary' => $entry['summary'],
'description' => $entry['description'], 'source_reference' => $entry['source'].'; SHA-256 '.self::SOURCE_HASH,
'limitations' => self::LIMITATIONS, 'edition' => '', 'source_date' => '', 'territory_ids' => [], 'sector_id' => $entry['sector_id']]];
$record->workflow_context = $context;
$record->maturity_label = 'Em preparação';
$record->save();
DB::table('audit_events')->insert(['source_system' => 'corridor-agribusiness-registration', 'entity_type' => 'opportunity',
'action' => 'private_source_registered', 'actor_user_id' => $actor->id, 'data_classification' => 'restricted',
'after_data' => json_encode(['record_id' => $record->id, 'source' => $entry, 'no_publication' => true, 'no_master_relation_inferred' => true], JSON_THROW_ON_ERROR)]);
$result[] = ['id' => $record->id, 'created' => true, 'key' => $entry['key']];
}
return $result;
});
}
public function articleLinks(): array
{
$records = Opportunity::published()->whereIn('management_creation_key', array_column($this->entries(), 'key'))->get()->keyBy('management_creation_key');
$links = [];
foreach ($this->entries() as $entry) {
if ($record = $records->get($entry['key'])) $links[$entry['group']][$entry['index']] = '/oportunidades/'.$record->slug;
}
return $links;
}
}
+13 -1
View File
@@ -26,7 +26,7 @@ class InvestmentCatalogue
'cluster_id' => ['nullable', 'uuid'], 'corridor_id' => ['nullable', 'uuid'], 'project_id' => ['nullable', 'uuid'],
'geo_location_id' => ['nullable', 'uuid'], 'education' => ['nullable', 'boolean'],
'zee_id' => ['nullable', 'uuid'], 'zfi_id' => ['nullable', 'uuid'], 'park_id' => ['nullable', 'uuid'],
'dimension' => ['nullable', 'in:cluster,corridor,zee,zfi'], 'view' => ['nullable', 'in:grid,list,map,combined'],
'dimension' => ['nullable', 'in:cluster,corridor,zee,zfi'], 'view' => ['nullable', 'in:grid,list,map,combined,corridors'],
'maturity_level' => ['nullable', 'integer', 'between:1,8'], 'facets' => ['nullable', 'array', 'max:20'], 'facets.*' => ['integer', 'min:1'],
'min_amount' => ['nullable', 'numeric', 'min:0', 'max:999999999999'],
'max_amount' => ['nullable', 'numeric', 'min:0', 'max:999999999999', ...($request->filled('min_amount') ? ['gte:min_amount'] : [])],
@@ -308,6 +308,18 @@ class InvestmentCatalogue
/** @return array<string,mixed> */
public function context(int $id, bool $management = false): array
{
$opportunity = Opportunity::findOrFail($id);
if (! $management && data_get($opportunity->workflow_context, 'publication.purpose') === OpportunityPromotion::PURPOSE) {
// Promotional disclosure includes only its explicit public coverage.
// Private profiles, source evidence and other dossier relations are not auto-published.
$public = ['profile' => null, 'facets' => collect(), 'zones' => collect(), 'classification' => [], 'source_evidence' => [],
'primary_territory_path' => app(InvestmentGeography::class)->path($opportunity->primary_territory_id, true),
'opportunity_locations' => app(InvestmentRelations::class)->opportunityLocations($id)];
foreach (self::RELATIONS as $relation => $_) $public[$relation] = collect();
$public['locations'] = DB::table('opportunity_locations as l')->join('geo_locations as g', 'g.id', '=', 'l.geo_location_id')
->where('l.opportunity_id', $id)->where('g.data_classification', 'public')->whereNull('g.deleted_at')->get(['g.id', 'g.name']);
return $public;
}
$result = ['profile' => DB::table('opportunity_profiles')->where('opportunity_id', $id)->first(),
'facets' => DB::table('opportunity_facets as f')->join('investment_reference_options as o', 'o.id', '=', 'f.option_id')
->where('f.opportunity_id', $id)->get(['o.id', 'o.group', 'o.label'])];
@@ -0,0 +1,48 @@
<?php
namespace App\Services;
/** Preparation within the existing path; no licence, DUAT or fiscal benefit is granted. */
final class InvestmentContextRequirements
{
public const VERSION = 'context-requirements-20261023';
public function assess(array $context): array
{
$rows = [];
foreach ($context['opportunity_choices'] ?? [] as $choice) {
$activities = $choice['activities'] ?? [];
$key = $choice['opportunity']['key'];
$common = ['opportunity_key' => $key, 'opportunity_title' => $choice['opportunity']['title']];
$add = function ($code, $title, $state, $step, $authority, $documents, $basis, $url) use (&$rows, $common) {
$rows[] = [...$common, 'code' => $code, 'title' => $title, 'state' => $state, 'step' => $step,
'authority' => $authority, 'documents' => $documents, 'basis' => $basis, 'source_url' => $url,
'decision' => 'Preparação; enquadramento e acto concreto conservam confirmação na etapa correspondente.'];
};
$add('geography', 'Localização e geolocalização', $choice['territory'] ? 'selected' : 'missing', 'S09', 'Cadastro territorial e serviços de cadastro competentes',
['Referência administrativa confirmada', 'Planta/esboço e coordenadas quando disponíveis; não inventar polígonos'],
'Referência territorial escolhida no dossier; não comprova disponibilidade nem direito de uso.', '/investimentos');
$add('land', 'Acesso à terra e DUAT', 'conditional', 'S10', 'Serviços de cadastro e órgão competente para o pedido territorial concreto',
['Fundamento do uso: DUAT, arrendamento ou situação declarada', 'Planta/esboço do local; documentação do pedido correspondente'],
'Regulamento de Investimento, artigos 9(1)(c)–(d) e 14(1)(c)–(d). A preparação distingue DUAT e arrendamento; escolher território não atribui terra.', PrivateInvestmentPreparation::SOURCE.'#page=42');
$add('environment', 'Enquadramento ambiental', 'conditional', 'S08', 'Autoridade de Avaliação do Impacto Ambiental; competência central/provincial conforme categorização',
['Descrição da actividade, dimensão e localização', 'Instrumento ambiental definido pela categorização competente; acto e condições quando emitidos'],
'Decreto 54/2015: a natureza, dimensão e localização determinam o enquadramento; a categoria não é deduzida do corredor ou do sector.', 'https://sibmoz.gov.mz/legal-framework/');
$add('sector', 'Licenciamento sectorial', $activities ? 'declared' : 'missing', 'S08', 'BAU, IP e autoridade sectorial competente conforme a actividade',
['Actividades efectivas e modalidade', 'Requerimento e anexos da modalidade aplicável; acto quando emitido'],
'Identificar as actividades efectivas antes de seleccionar o procedimento. O nome Agronegócio não escolhe uma licença única.', 'https://www.bau.gov.mz/nossos-servicos/');
foreach (['processing' => ['Licenciamento industrial', 'Decreto 22/2014'], 'trade' => ['Licenciamento comercial', 'Decreto 34/2013']] as $activity => [$title, $basis]) {
if (in_array($activity, $activities, true)) $add($activity, $title, 'conditional', 'S08', 'BAU, IP / entidade licenciadora da modalidade',
['Caracterização do estabelecimento e actividade', 'Documentos e regime aplicáveis, incluindo simplificado ou mera comunicação quando preenchidas as suas condições'],
$basis.'; regimes 39/2017 e 27/2023 no catálogo oficial BAU. Dimensão e modalidade ainda devem ser especificadas; não se selecciona automaticamente o regime.', 'https://www.bau.gov.mz/legislacao/');
}
foreach (['water' => 'Uso de água', 'forestry' => 'Actividade florestal', 'animal' => 'Actividade pecuária', 'transport' => 'Transporte e logística'] as $activity => $title) {
if (in_array($activity, $activities, true)) $add($activity, $title, 'undetermined', 'S08', 'Autoridade sectorial competente a identificar para a modalidade declarada',
['Modalidade e dimensão da actividade', 'Fonte e documentação sectorial específica a associar ao dossier'],
'Actividade declarada; a referência do lote não contém o procedimento específico. Não se considera dispensada ou autorizada.', 'https://www.apiex.gov.mz/wp-content/uploads/2024/01/Mozambique-Business-Licensing-Guide.pdf');
}
}
return ['version' => self::VERSION, 'requirements' => $rows,
'fiscal_notice' => 'Localização, corredor, cluster ou projecto âncora não activam benefícios fiscais. O simulador mantém as condições, fonte, período e âmbito próprios; condições ausentes permanecem indeterminadas.'];
}
}
@@ -0,0 +1,59 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
use Illuminate\Support\Facades\DB;
final class InvestmentCorridorContext
{
public function key(Opportunity $record): ?string
{
$name = data_get($record->workflow_context, 'corridor_agribusiness.corridor');
foreach (config('investment_corridors') as $key => $entry) if ($entry['name'] === $name) return $key;
return null;
}
public function provinces(string $key): array
{
$entry = config('investment_corridors.'.$key);
abort_unless(is_array($entry), 422, 'Seleccione um corredor disponível.');
$records = app(InvestmentGeography::class)->publicReferences()->where('location_type', 'province')
->whereIn('source_code', $entry['provinces'])->get(['id', 'name', 'parent_id', 'location_type', 'source_code'])->all();
abort_unless(count($records) === count($entry['provinces']), 503, 'Não foi possível recuperar todas as províncias deste corredor. Tente novamente.');
return $records;
}
public function compatible(string $key, ?string $territory): bool
{
if (!$territory) return true;
$path = app(InvestmentGeography::class)->path($territory);
return $path !== [] && in_array($path[0]->id, array_column($this->provinces($key), 'id'), true);
}
/** Both membership in the selected area and documented public zone coverage are required. */
public function parks(?string $key, ?string $territory): array
{
if (!$key || !$territory) return [];
abort_unless($this->compatible($key, $territory), 422, 'A localização não pertence ao corredor escolhido.');
$selectedPath = array_column(app(InvestmentGeography::class)->path($territory), 'id');
$candidates = app(InvestmentZones::class)->visible()->whereIn('category', ['industrial_park', 'zee', 'zfi'])->orderBy('name')->get();
$result = [];
foreach ($candidates as $zone) {
$ids = DB::table('investment_zone_locations')->where('zone_id', $zone->id)->where('validation_status', 'validated')
->whereIn('scope_type', ['legal_scope', 'administrative', 'site'])
->where(fn($q)=>$q->whereNull('valid_from')->orWhereDate('valid_from','<=',today()))
->where(fn($q)=>$q->whereNull('valid_until')->orWhereDate('valid_until','>=',today()))->get(['geo_location_id','scope_type'])->all();
if ($zone->primary_territory_id) $ids[] = (object)['geo_location_id'=>$zone->primary_territory_id,'scope_type'=>'site'];
foreach ($ids as $link) {
$id=$link->geo_location_id;
if (!$this->compatible($key, $id)) continue;
$path = array_column(app(InvestmentGeography::class)->path($id), 'id');
if (in_array($territory, $path, true) || ($link->scope_type==='legal_scope' && in_array($id, $selectedPath, true))) {
$result[] = $zone->only(['id', 'name', 'category', 'version_no']); break;
}
}
}
return $result;
}
}
@@ -0,0 +1,50 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
/** Multiple identified references in the existing encrypted investment context. */
final class InvestmentOpportunityChoices
{
public function resolve(array $choices, array $previous = [], bool $pending = false): array
{
$result = [];
foreach ($choices as $choice) {
$ref = app(InvestorContext::class)->reference($choice['source']);
abort_unless($ref['kind'] === 'opportunity', 422, 'Seleccione uma ficha de oportunidade.');
$record = Opportunity::findOrFail($ref['id']);
$old = collect($previous)->first(fn ($row) => $row['opportunity']['key'] === $ref['key']);
$corridors = app(InvestmentCorridorContext::class);
$corridor = $choice['corridor_key'] ?? $old['corridor_key'] ?? $corridors->key($record);
$provinces = $corridor ? $corridors->provinces($corridor) : [];
$documented = $record->primary_territory_id;
$territory = $choice['territory'] ?? ($documented ? 'territory:'.$documented : null);
if (!$territory && count($provinces) === 1) $territory = 'territory:'.$provinces[0]->id;
if ($corridor && $territory) abort_unless($corridors->compatible($corridor, substr($territory, 10)), 422, 'A localização não pertence ao corredor escolhido.');
$previousTerritory = $old['territory']['key'] ?? null;
$newAlternative = $documented && $territory !== 'territory:'.$documented
&& (! $old || ($old['documented_territory_id'] ?? null) !== $documented || $territory !== $previousTerritory);
$corridorChanged = $old && ($old['corridor_key'] ?? $corridors->key($record)) !== $corridor;
$incompatibleOld = $corridorChanged && $previousTerritory && !$corridors->compatible($corridor, substr($previousTerritory, 10));
if (!$pending && ($newAlternative || ($previousTerritory && $territory !== $previousTerritory && !$incompatibleOld))) {
abort_unless(! empty($choice['confirm_location_change']) && mb_strlen(trim($choice['location_reason'] ?? '')) >= 20,
422, 'Uma localização documentada ou já confirmada só muda por escolha explícita, com confirmação e motivo.');
}
$location = $territory ? app(InvestorContext::class)->reference($territory) : null;
abort_unless($location === null || $location['kind'] === 'territory', 422);
$result[] = ['opportunity' => $ref, 'territory' => $location,
'corridor_key' => $corridor, 'corridor_name' => $corridor ? config('investment_corridors.'.$corridor.'.name') : null,
'allowed_provinces' => array_map(fn($p)=>(array)$p, $provinces),
'territory_path' => $location ? array_map(fn ($node) => \Illuminate\Support\Arr::only((array) $node, ['id', 'name', 'parent_id', 'location_type']), app(InvestmentGeography::class)->path($location['id'], true)) : [],
'activities' => $choice['activities'] ?? ($old['activities'] ?? []),
'documented_territory_id' => $documented, 'location_reason' => $choice['location_reason'] ?? '',
'location_state' => $location ? ($documented && $territory === 'territory:'.$documented ? 'documented' : 'investor_selected') : 'undetermined',
'location_changed_explicitly' => $old && $territory === $previousTerritory ? (bool) ($old['location_changed_explicitly'] ?? false) : (bool) ($choice['confirm_location_change'] ?? false),
'coverage' => data_get($record->workflow_context, 'corridor_agribusiness.corridor'),
'source' => data_get($record->workflow_context, 'corridor_agribusiness.source'),
'source_sha256' => data_get($record->workflow_context, 'corridor_agribusiness.source_sha256')];
}
return $result;
}
}
+115 -7
View File
@@ -27,6 +27,64 @@ final class InvestorContext
public function __construct(private readonly VirtualDesk $desk) {}
public function draft(User $actor, string $id): ?array
{
$case = $this->desk->case($actor, $id, true);
$draft = $this->desk->decode($case->payload)['investor_path']['context_drafts'][(string)$actor->id] ?? null;
return $draft ? [...$draft, 'needs_review' => (int)$draft['version'] !== (int)$case->version] : null;
}
public function saveDraft(User $actor, string $id, array $input): array
{
$case=$this->desk->case($actor,$id,true);
abort_if($case->closed_at,409);
$sequence = (int)($input['draft_sequence'] ?? 0);
$entrySources=Validator::make($input,['entry_sources'=>'sometimes|array|max:100','entry_sources.*'=>'string|max:100'])->validate()['entry_sources']??[];
unset($input['draft_sequence'],$input['entry_sources']);
abort_unless($sequence > 0, 422);
$data = $this->input($input);
foreach ($data['selection'] as $slot=>$key) {
if (!$key) continue;
$ref=$this->reference($key);
abort_unless(in_array($ref['kind'],$slot==='opportunity'?['opportunity','business']:[$slot],true),422,'Referência incompatível com a escolha.');
}
foreach ($data['opportunity_choices'] ?? [] as $choice) {
$ref = $this->reference($choice['source']);
abort_unless($ref['kind'] === 'opportunity', 422);
$record = Opportunity::findOrFail($ref['id']);
$key = $choice['corridor_key'] ?? app(InvestmentCorridorContext::class)->key($record);
if (!empty($choice['territory'])) {
$location = $this->reference($choice['territory']);
abort_unless($location['kind'] === 'territory', 422);
if ($key) abort_unless(app(InvestmentCorridorContext::class)->compatible($key, $location['id']), 422, 'A localização não pertence ao corredor escolhido.');
}
}
if (!empty($data['selection']['park'])) {
$first=$data['opportunity_choices'][0] ?? null;
$source=$first['source'] ?? $data['selection']['opportunity'] ?? null;
if ($source && str_starts_with($source,'opportunity:')) {
$key=$first['corridor_key'] ?? app(InvestmentCorridorContext::class)->key(Opportunity::findOrFail(substr($source,12)));
if ($key) {
$territory=$first['territory'] ?? $data['selection']['territory'] ?? null;
$ids=app(InvestmentCorridorContext::class)->provinces($key);
$territory=$territory ? substr($territory,10) : (count($ids)===1?$ids[0]->id:null);
$park=$this->reference($data['selection']['park']);
abort_unless($park['kind']==='park' && in_array($park['id'],array_column(app(InvestmentCorridorContext::class)->parks($key,$territory),'id'),true),422,'A zona ou parque não tem enquadramento compatível documentado nesta localização.');
}
}
}
return DB::transaction(function () use ($actor, $id, $data, $sequence, $entrySources) {
$case = $this->desk->case($actor, $id, true, true);
abort_if($case->closed_at || (int)$case->version !== (int)$data['version'], 409, 'O dossier mudou. Recupere os dados antes de continuar.');
$payload = $this->desk->decode($case->payload);
$previous = $payload['investor_path']['context_drafts'][(string)$actor->id] ?? [];
abort_if(($previous['draft_sequence'] ?? 0) > $sequence, 409, 'Existe um rascunho mais recente. Recupere o dossier antes de continuar.');
$payload['investor_path']['context_drafts'][(string)$actor->id] = [...$data, 'draft_sequence' => $sequence, 'entry_sources'=>array_values(array_unique([...($previous['entry_sources']??[]),...$entrySources]))];
DB::table('desk_cases')->where('id', $id)->update(['payload' => $this->desk->encode($payload)]);
return ['saved' => true];
});
}
public function installed(): bool
{
return Schema::hasTable('investor_navigation_preferences');
@@ -268,7 +326,7 @@ final class InvestorContext
private function input(array $input): array
{
abort_if(array_diff(array_keys($input), ['version', 'selection', 'declarations', 'replace_fields', 'preview_hash', 'operation_key', 'confirm', 'document_links', '_token']), 422, 'Campo de controlo desconhecido.');
abort_if(array_diff(array_keys($input), ['opportunity_choices', 'version', 'selection', 'declarations', 'replace_fields', 'preview_hash', 'operation_key', 'confirm', 'document_links', '_token']), 422, 'Campo de controlo desconhecido.');
abort_if(! app(PrivateInvestmentPreparation::class)->available() && (! empty($input['document_links']) || array_intersect(array_keys(is_array($input['declarations'] ?? null) ? $input['declarations'] : []), PrivateInvestmentPreparation::FIELDS)), 409, 'Esta preparação ainda não está disponível neste ambiente. As respostas foram preservadas.');
@@ -280,7 +338,13 @@ final class InvestorContext
$inputRules['declarations.'.$question['key']] = isset($question['options']) ? ['nullable', Rule::in(array_keys($question['options']))] : ['nullable', 'regex:/^\d+(?:\.\d+)?$/D', 'numeric', 'min:0', 'max:999999999999999999'];
}
return Validator::make($input, [...$inputRules, 'version' => 'required|integer|min:1', 'selection' => 'present|array:opportunity,sector,territory,park',
return Validator::make($input, [...$inputRules,
'opportunity_choices' => 'sometimes|array|max:100', 'opportunity_choices.*' => 'array:source,territory,location_reason,confirm_location_change,activities,corridor_key',
'opportunity_choices.*.corridor_key' => ['sometimes', 'nullable', Rule::in(array_keys(config('investment_corridors')))],
'opportunity_choices.*.activities' => 'sometimes|array', 'opportunity_choices.*.activities.*' => 'string|distinct|in:production,processing,trade,transport,water,forestry,animal',
'opportunity_choices.*.source' => 'required|string|distinct|max:100', 'opportunity_choices.*.territory' => 'nullable|string|max:100',
'opportunity_choices.*.location_reason' => 'nullable|string|max:2000', 'opportunity_choices.*.confirm_location_change' => 'sometimes|boolean',
'version' => 'required|integer|min:1', 'selection' => 'present|array:opportunity,sector,territory,park',
'selection.*' => 'nullable|string|max:100', 'declarations' => 'nullable|array:project_title,project_summary,currency,expected_start_date,investor_origin,person_type,entity_stage,tax_residency_country,fiscal_residency_country,project_type,maturity_stage,'.implode(',', PrivateInvestmentPreparation::FIELDS), 'declarations.project_title' => 'nullable|string|max:200', 'declarations.project_summary' => 'nullable|string|max:5000',
'declarations.currency' => 'nullable|regex:/^[A-Z]{3}$/', 'declarations.expected_start_date' => 'nullable|date_format:Y-m-d', 'declarations.investor_origin' => 'nullable|in:national,foreign,mixed', 'declarations.person_type' => 'nullable|in:singular,collective,sole_trader,consortium', 'declarations.entity_stage' => 'nullable|in:existing,being_formed', 'declarations.tax_residency_country' => ['nullable', 'string', app(CountryCatalogue::class)->rule()], 'declarations.fiscal_residency_country' => ['nullable', 'string', app(CountryCatalogue::class)->rule()], 'declarations.project_type' => 'nullable|string|max:100', 'declarations.maturity_stage' => 'nullable|string|max:100',
'replace_fields' => 'nullable|array', 'replace_fields.*' => 'string|in:'.implode(',', self::FIELDS)])->validate();
@@ -303,6 +367,23 @@ final class InvestorContext
unset($links[$key]);
}
}
$choices = $old['opportunity_choices'] ?? [];
if (! array_key_exists('opportunity_choices', $data) && array_key_exists('territory', $data['selection'])) {
$source = $data['selection']['opportunity'] ?? ($old['selection']['opportunity']['key'] ?? null);
if ($source && str_starts_with($source, 'opportunity:')) {
$documented = Opportunity::findOrFail(substr($source, 12))->primary_territory_id;
abort_if($documented && $data['selection']['territory'] !== 'territory:'.$documented, 422,
'Confirme a alternativa territorial por ficha e indique o motivo; a localização documentada foi preservada.');
}
}
if (array_key_exists('opportunity_choices', $data)) {
$choices = app(InvestmentOpportunityChoices::class)->resolve($data['opportunity_choices'], $choices);
$data['selection']['opportunity'] = $choices[0]['opportunity']['key'] ?? null;
// Shared fields concern the first identified opportunity; other sites remain separate.
$data['selection']['territory'] = $choices[0]['territory']['key'] ?? null;
} elseif (array_key_exists('opportunity', $data['selection']) && $choices !== []) {
abort(422, 'Actualize a selecção identificada de oportunidades; não substitua silenciosamente o conjunto por uma ficha.');
}
$selection = $old['selection'];
foreach ($data['selection'] as $slot => $key) {
if ($key === null || $key === '') {
@@ -315,6 +396,16 @@ final class InvestorContext
abort_unless(in_array($ref['kind'], $expected, true), 422, 'Referência incompatível com a dimensão.');
$selection[$slot] = $ref;
}
$corridor = $choices[0]['corridor_key'] ?? (isset($selection['opportunity']) && $selection['opportunity']['kind'] === 'opportunity'
? app(InvestmentCorridorContext::class)->key(Opportunity::findOrFail($selection['opportunity']['id'])) : null);
if ($corridor && isset($selection['territory'])) abort_unless(app(InvestmentCorridorContext::class)->compatible($corridor, $selection['territory']['id']), 422, 'A localização não pertence ao corredor escolhido.');
if ($corridor && isset($selection['park'])) {
$eligible = array_column(app(InvestmentCorridorContext::class)->parks($corridor, $selection['territory']['id'] ?? null), 'id');
if (!in_array($selection['park']['id'], $eligible, true)) {
abort_if(!empty($data['selection']['park']), 422, 'A zona ou parque não tem enquadramento compatível documentado nesta localização.');
unset($selection['park']);
}
}
// A new opportunity may propose its explicitly stored sector; it never matches names.
if (isset($data['selection']['opportunity']) && ! array_key_exists('sector', $data['selection']) && isset($selection['opportunity']['fields']['sector_id'])) {
if (Sector::where('is_active', true)->whereKey($selection['opportunity']['fields']['sector_id'])->exists()) {
@@ -359,6 +450,16 @@ final class InvestorContext
unset($fields[$key],$provenance[$key]);
}
}
if ($corridor) {
foreach (['province_id','district_id','admin_post_id','locality_id','province','district','location'] as $key) {
if (isset($selection['territory']['fields'][$key])) {
$fields[$key]=(string)$selection['territory']['fields'][$key];
$provenance[$key]=Arr::except($selection['territory'],['fields']);
} else unset($fields[$key],$provenance[$key]);
}
$fields['special_zone_id']=$selection['park']['id']??'';
$fields['investment_regime']=$selection['park']['fields']['investment_regime']??'general';
}
$replaced = [];
foreach (array_unique([...array_keys($old['fields']), ...array_keys($fields)]) as $key) {
if (($old['fields'][$key] ?? null) !== ($fields[$key] ?? null)) {
@@ -371,10 +472,12 @@ final class InvestorContext
}
}
$changedFields = array_column($replaced, 'field');
$choicesChanged = $choices !== ($old['opportunity_choices'] ?? []);
if ($choicesChanged) $changed = array_values(array_unique([...$changed, 'opportunity', 'territory']));
$conditionsChanged = (bool) array_intersect($changedFields, array_diff(self::FIELDS, ['project_title', 'project_summary']));
$dependencyChanged = $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || $conditionsChanged;
$dependencyChanged = $choicesChanged || $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || $conditionsChanged;
$privateConditionsChanged = (bool) array_intersect($changedFields, PrivateInvestmentPreparation::FIELDS);
$calculationInputsChanged = $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || (bool) array_intersect($changedFields, array_diff(self::FIELDS, ['project_title', 'project_summary', ...array_diff(PrivateInvestmentPreparation::FIELDS, ['total_investment', 'area_required', 'area_unit'])]));
$calculationInputsChanged = $choicesChanged || $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || (bool) array_intersect($changedFields, array_diff(self::FIELDS, ['project_title', 'project_summary', ...array_diff(PrivateInvestmentPreparation::FIELDS, ['total_investment', 'area_required', 'area_unit'])]));
$payload = $this->desk->decode($case->payload);
$results = $payload['investor_path']['results'] ?? [];
$requests = DB::table('desk_requests')->where('case_id', $id)->orderBy('id')->get(['id', 'status', 'protocol', 'version'])->all();
@@ -392,11 +495,12 @@ final class InvestorContext
$afterPreparation = app(PrivateInvestmentPreparation::class)->assess(['fields' => $fields, 'selection' => $selection, 'preparation_documents' => $links], $docs);
$privatePreparation = ['before' => $beforePreparation, 'after' => $afterPreparation];
}
$plan = ['case_id' => $id, 'version' => (int) $case->version, 'revision' => (int) $old['revision'], 'selection' => $selection, 'fields' => $fields, 'provenance' => $provenance,
$plan = ['opportunity_choices' => $choices, 'case_id' => $id, 'version' => (int) $case->version, 'revision' => (int) $old['revision'], 'selection' => $selection, 'fields' => $fields, 'provenance' => $provenance,
'preparation_documents' => $links, 'private_investment' => $privatePreparation,
'updated' => $replaced, 'maintained' => $kept, 'changed_dimensions' => $changed, 'dependent_results' => (int) $case->user_id === $actor->id && $calculationInputsChanged ? array_map(fn ($r) => ['id' => $r['id'], 'engine' => $r['engine']], $results) : [],
'requests' => $requests, 'review_steps' => $steps, 'dependency_changed' => $dependencyChanged, 'calculation_inputs_changed' => $calculationInputsChanged, 'documents_preserved' => DB::table('desk_documents')->where('case_id', $id)->count(),
'notice' => 'Não confirma incentivos, licenças, disponibilidade de terra, reserva ou autorização. Submissões e decisões anteriores mantêm o conteúdo enviado.'];
$plan['requirements_assessment'] = app(InvestmentContextRequirements::class)->assess(['opportunity_choices' => $choices, 'fields' => $fields]);
$hash = hash_hmac('sha256', json_encode(Arr::sortRecursive([$actor->id, $data, $plan]), JSON_THROW_ON_ERROR), config('app.key'));
return [...$plan, 'preview_hash' => $hash];
@@ -435,14 +539,16 @@ final class InvestorContext
foreach ($plan['review_steps'] as $step) {
$review[$step] = ['revision' => $revision, 'reason' => 'O contexto mudou; reveja os pressupostos e a evidência aplicável.'];
}
$context = ['preparation_documents' => $plan['preparation_documents'], 'preparation_snapshot' => $plan['private_investment']['after'] ?? $before['preparation_snapshot'] ?? null, 'revision' => $revision, 'selection' => $plan['selection'], 'fields' => $plan['fields'], 'provenance' => $plan['provenance'], 'review_steps' => $review,
'dependency_hash' => $this->dependencyHash(['selection' => $plan['selection'], 'fields' => Arr::except($plan['fields'], ['project_title', 'project_summary'])]), 'updated_at' => now()->toIso8601String(), 'updated_by' => $actor->id];
$context = ['opportunity_choices' => $plan['opportunity_choices'], 'preparation_documents' => $plan['preparation_documents'], 'preparation_snapshot' => $plan['private_investment']['after'] ?? $before['preparation_snapshot'] ?? null, 'revision' => $revision, 'selection' => $plan['selection'], 'fields' => $plan['fields'], 'provenance' => $plan['provenance'], 'review_steps' => $review,
'dependency_hash' => $this->dependencyHash([...($plan['opportunity_choices'] !== [] ? ['opportunity_choices' => $plan['opportunity_choices']] : []), 'selection' => $plan['selection'], 'fields' => Arr::except($plan['fields'], ['project_title', 'project_summary'])]), 'updated_at' => now()->toIso8601String(), 'updated_by' => $actor->id];
$context['requirements_assessment'] = $plan['requirements_assessment'];
if ($plan['calculation_inputs_changed']) {
foreach ($payload['investor_path']['results'] ?? [] as $i => $r) {
$payload['investor_path']['results'][$i] = [...$r, 'context_state' => 'review_required', 'context_invalidated_revision' => $revision, 'context_invalidated_at' => now()->toIso8601String()];
}
}
$payload['investor_path']['context'] = $context;
unset($payload['investor_path']['context_drafts'][(string)$actor->id]);
DB::table('desk_cases')->where('id', $id)->update(['payload' => $this->desk->encode($payload), 'title' => $context['fields']['project_title'] ?? $case->title, 'version' => $case->version + 1, 'updated_at' => now()]);
$this->desk->event($this->desk->case($actor, $id), $actor, 'investment_context_changed', ['before' => $before, 'after' => $context, 'affected_result_ids' => array_column($plan['dependent_results'], 'id'), 'preserved_request_ids' => array_column($plan['requests'], 'id')]);
$result = ['case_id' => $id, 'version' => (int) $case->version + 1, 'revision' => $revision, 'replayed' => false];
@@ -494,6 +600,8 @@ final class InvestorContext
'version' => 1, 'context_revision' => $ctx['revision'],
'zone' => $zone ? Arr::only($zone, ['id', 'title', 'href', 'version', 'sha256', 'fields', 'analysis']) : null,
'provenance' => $ctx['provenance'],
'opportunity_choices' => $ctx['opportunity_choices'] ?? [],
'requirements_assessment' => $ctx['requirements_assessment'] ?? null,
'path' => $ctx['path_applicability'] ?? null,
'preparation' => isset($ctx['preparation_assessment']) ? Arr::except($ctx['preparation_assessment'], ['questions']) : null,
'fields' => Arr::only($f, ['investor_origin', 'tax_residency_country', 'entity_stage', 'currency', 'expected_start_date', 'investment_regime']),
+3
View File
@@ -78,6 +78,9 @@ final class LegacyContent
$image = $this->publicResources()->where('r.id', $adaptation['image_resource_id'])->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp'])->first();
}
}
if ($slug === 'agronegocio') {
$localHtml = app(CorridorAgribusiness::class)->enrich($localHtml, app(CorridorAgribusinessOpportunities::class)->articleLinks());
}
preg_match_all('~href="([^"]+)"~i', $localHtml, $existingLinks);
$alreadyLinked = array_map(fn ($href) => html_entity_decode($href, ENT_QUOTES | ENT_HTML5, 'UTF-8'), $existingLinks[1]);
$relatedArticles = [];
@@ -0,0 +1,55 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
/** Read-only grouping of the existing public catalogue. */
final class OpportunityCorridorExplorer
{
public function groups(array $filters): array
{
$catalogue = app(InvestmentCatalogue::class);
$groups = [];
foreach ($catalogue->query($filters)->get() as $record) {
$context = $catalogue->context($record->id);
$classification = $context['classification'] ?? [];
$corridors = collect($context['corridors'])->mapWithKeys(fn ($c) => ['corridor:'.$c->id => $c->name])->all();
foreach ($classification as $relation) {
if ($relation['target_type'] === 'corridor' && ! in_array($relation['purpose'], ['proximity', 'administrative_boundary'], true)) {
$corridors['corridor:'.$relation['target_id']] = $relation['label'];
}
}
// The approved source names are not aliases for similarly named master records.
$source = data_get($record->workflow_context, 'corridor_agribusiness');
$chain = null;
if (is_array($source) && ($source['source_sha256'] ?? null) === CorridorAgribusinessOpportunities::SOURCE_HASH) {
$corridors['source:'.hash('sha256', $source['corridor'])] = $source['corridor'];
$chain = $source['chain'];
}
$chains = collect($classification)->where('target_type', 'chain')->pluck('label')->all();
if ($chain) $chains[] = $chain;
$stages = collect($classification)->pluck('production_stage')->filter()->unique()->values()->all();
// Keep the source's actual activity description rather than inventing stage labels.
if ($stages === [] && $chain && ! empty($source['summary'])) $stages = [$source['summary']];
$path = collect($context['primary_territory_path'] ?? []);
$province = $path->firstWhere('location_type', 'province')->name ?? $record->province;
$district = $path->firstWhere('location_type', 'district')->name ?? $record->district;
$item = ['id' => $record->id, 'title' => $record->title, 'slug' => $record->slug, 'summary' => $record->summary,
'province' => $province, 'district' => $district, 'chains' => array_values(array_unique($chains)),
'stages' => $stages, 'maturity_label' => $record->maturity_label];
foreach ($corridors ?: ['other' => 'Outras localizações'] as $key => $name) {
$groups[$key] ??= ['id' => $key, 'name' => $name, 'opportunities' => []];
$groups[$key]['opportunities'][$record->id] = $item;
}
}
foreach ($groups as &$group) {
$group['opportunities'] = array_values($group['opportunities']);
$group['count'] = count($group['opportunities']);
$group['locations'] = array_values(array_unique(array_filter(array_map(fn ($r) => implode(' / ', array_filter([$r['province'], $r['district']])), $group['opportunities']))));
}
unset($group);
uasort($groups, fn ($a, $b) => ($a['id'] === 'other' ? 1 : 0) <=> ($b['id'] === 'other' ? 1 : 0) ?: strnatcasecmp($a['name'], $b['name']));
return array_values($groups);
}
}
+3
View File
@@ -27,6 +27,9 @@ class OpportunityManagement
public function values(Opportunity $record): array
{
$base = $record->only(self::FIELDS);
if (data_get($record->workflow_context, 'publication.purpose') === OpportunityPromotion::PURPOSE) {
$base = [...$base, ...($record->workflow_context['promotional_private_base'] ?? [])];
}
$draft = $record->management_draft ? json_decode($record->management_draft, true, 512, JSON_THROW_ON_ERROR) : [];
return [...$base, ...($this->closed($record) ? $draft : array_intersect_key($draft, array_flip(self::PRIVATE_DRAFT_FIELDS)))];
+168
View File
@@ -0,0 +1,168 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
/** Tempo's promotional disclosure, independent of investment execution approval. */
final class OpportunityPromotion
{
public const PURPOSE = 'promotional_preparation';
public const NOTICE = 'Em preparação. A divulgação não confirma financiamento, disponibilidade de terreno, licenças ou autorização de execução do investimento.';
public function allowed(User $actor, Opportunity $record): bool
{
$access = app(PortalProfileAccess::class);
if ($record->trashed() || $record->owner_user_id === null || ! $access->canView($actor, $record)
|| $access->has($actor, 'auditor') || in_array($record->status, ['archived', 'rejected'], true)) return false;
// Never overwrite a normal approved publication or its workflow decisions.
if ($record->published_at && data_get($record->workflow_context, 'publication.purpose') !== self::PURPOSE) return false;
$internal = $access->internalAssignment($actor, $record->opportunity_category);
return ($internal && $access->promoterRecordScope($actor, $record) && $access->operational($actor, 'edit', $record->id))
|| ($access->scoped($actor, 'publisher', $record->organization_id, $record->opportunity_category)
&& $access->operational($actor, 'publish', $record->id));
}
private function authorize(User $actor, Opportunity $record): void
{
abort_unless($this->allowed($actor, $record), 403, 'A designação e o âmbito existentes não autorizam esta divulgação.');
if (! app(PortalProfileAccess::class)->mfa($actor)) {
throw new \Illuminate\Http\Exceptions\HttpResponseException(response()->json(['message' => 'Confirme a entrada normal com MFA recente para divulgar.'], 403)->header('X-Portal-Reauthentication', 'required'));
}
}
public function editor(User $actor, Opportunity $record): array
{
abort_unless($this->allowed($actor, $record), 403);
$saved = data_get($record->workflow_context, 'promotional_summary', []);
// Only previously public text is recovered automatically. No private contact/document is copied.
$existing = data_get($record->workflow_context, 'publication.purpose') === self::PURPOSE;
$form = $saved['input'] ?? ['title' => $existing ? $record->title : '', 'summary' => $existing ? $record->summary : '',
'description' => $existing ? $record->description : '', 'source_reference' => '', 'edition' => '', 'source_date' => '',
'limitations' => '', 'territory_ids' => $existing ? DB::table('opportunity_locations')->where('opportunity_id', $record->id)->pluck('geo_location_id')->all() : [],
'sector_id' => $record->sector_id];
return ['record' => ['id' => $record->id, 'reference' => $record->reference], 'etag' => app(OpportunityManagement::class)->etag($record),
'initial' => $form, 'publicNow' => $existing && $record->status === 'published',
'reauthenticationRequired' => ! app(PortalProfileAccess::class)->mfa($actor),
'sectors' => \App\Models\Sector::catalog()->orderBy('name')->get(['id', 'name']),
'territories' => app(InvestmentGeography::class)->publicReferences()->orderBy('name')->get(['id', 'name', 'location_type']),
'history' => DB::table('audit_events')->where('source_system', 'tempo-preparation-publication')
->where('after_data->record_id', $record->id)->orderByDesc('occurred_at')->get(['id', 'action', 'actor_user_id', 'occurred_at'])];
}
public function preview(User $actor, Opportunity $record, array $input): array
{
$this->authorize($actor, $record);
$data = Validator::make($input, ['etag' => 'required|string|size:64', 'action' => 'required|in:disclose,withdraw',
'title' => 'required_if:action,disclose|nullable|string|max:255', 'summary' => 'required_if:action,disclose|nullable|string|max:499',
'description' => 'nullable|string|max:6000', 'limitations' => 'nullable|string|max:2500',
'source_reference' => 'nullable|string|max:2000', 'edition' => 'nullable|string|max:150', 'source_date' => 'nullable|date_format:Y-m-d',
'sector_id' => ['nullable', 'integer', Rule::in(\App\Models\Sector::catalog()->pluck('id')->all())],
'territory_ids' => 'sometimes|array|max:30', 'territory_ids.*' => 'required|uuid|distinct',
])->validate();
abort_unless(hash_equals(app(OpportunityManagement::class)->etag($record), $data['etag']), 409, 'A ficha mudou. Reabra antes de preparar outra prévia.');
if ($data['action'] === 'withdraw') abort_unless(data_get($record->workflow_context, 'publication.purpose') === self::PURPOSE, 409);
$paths = [];
foreach ($data['territory_ids'] ?? [] as $id) {
$path = app(InvestmentGeography::class)->path($id, true);
abort_unless(count($path) > 0 && collect($path)->contains('id', $id), 422, 'Seleccione apenas territórios públicos existentes.');
$paths[] = $path;
}
$text = fn ($key) => trim(strip_tags($data[$key] ?? ''));
$body = implode("\n\n", array_filter([$text('description'), self::NOTICE,
'Limitações e lacunas: '.($text('limitations') ?: 'Informação ainda por completar.'),
'Fonte: '.($text('source_reference') ?: 'Não indicada.'), 'Edição: '.($text('edition') ?: 'Não indicada.'),
'Data-base: '.($data['source_date'] ?? 'Não indicada.')]));
$body = OpportunityPublicText::description($record, $body);
$projection = ['title' => $text('title'), 'summary' => $text('summary'), 'description' => $body,
'sector_id' => $data['sector_id'] ?? null, 'maturity_label' => 'Em preparação', 'notice' => self::NOTICE,
'territories' => array_map(fn ($p) => ['id' => end($p)->id, 'label' => implode(' / ', array_column($p, 'name'))], $paths)];
if ($data['action'] === 'disclose') abort_unless($projection['title'] !== '' && $projection['summary'] !== '', 422, 'Indique título e resumo em texto simples.');
if ($data['action'] === 'withdraw') $projection = [...$projection, ...$record->only(['title', 'summary', 'description', 'sector_id', 'maturity_label'])];
$payload = ['actor_id' => $actor->id, 'record_id' => $record->id, 'etag' => $data['etag'], 'action' => $data['action'],
'input' => $data, 'projection' => $projection, 'expires' => now()->addMinutes(15)->timestamp];
return ['action' => $data['action'], 'projection' => $projection, 'token' => Crypt::encryptString(json_encode($payload, JSON_THROW_ON_ERROR)),
'current' => $record->only(['title', 'summary', 'description', 'status']), 'writes' => false];
}
public function confirm(User $actor, int $id, array $input): array
{
$data = Validator::make($input, ['token' => 'required|string|max:300000', 'operation_key' => 'required|uuid',
'confirm' => 'required|accepted', 'reason' => 'required|string|min:10|max:1000'])->validate();
try { $preview = json_decode(Crypt::decryptString($data['token']), true, flags: JSON_THROW_ON_ERROR); }
catch (\Throwable) { abort(422, 'Prévia inválida. Prepare outra prévia.'); }
abort_unless(($preview['actor_id'] ?? null) === $actor->id && ($preview['record_id'] ?? null) === $id, 403);
return DB::transaction(function () use ($actor, $id, $data, $preview) {
DB::select('SELECT pg_advisory_xact_lock(hashtext(?))', ['promotional-operation:'.$data['operation_key']]);
$record = Opportunity::whereKey($id)->lockForUpdate()->firstOrFail();
$this->authorize($actor, $record);
$digest = hash('sha256', $data['token'].'|'.$data['reason']);
$replay = DB::table('audit_events')->where('source_system', 'tempo-preparation-publication')
->where('after_data->operation_key', $data['operation_key'])->first();
if ($replay) {
$prior = json_decode($replay->after_data, true);
abort_unless($prior['record_id'] === $id && (int) $replay->actor_user_id === $actor->id && hash_equals($prior['request_hash'], $digest), 409, 'Chave usada noutra operação.');
return ['id' => $id, 'replayed' => true, 'message' => 'Operação já registada; nenhuma alteração repetida.'];
}
abort_unless(($preview['expires'] ?? 0) >= now()->timestamp, 409, 'A prévia expirou. Prepare outra prévia.');
abort_unless(hash_equals(app(OpportunityManagement::class)->etag($record), $preview['etag']), 409, 'Alteração concorrente: a ficha foi preservada. Reabra e reveja a nova versão.');
$before = $record->getRawOriginal();
$oldLocations = DB::table('opportunity_locations')->where('opportunity_id', $id)->pluck('geo_location_id')->all();
$context = $record->workflow_context ?? [];
if ($preview['action'] === 'withdraw') {
$record->status = 'suspended';
$record->published_at = null;
$context['publication']['visibility'] = 'withdrawn';
$action = 'promotional_summary_withdrawn';
} else {
$p = $preview['projection'];
if ($p['sector_id'] !== null) abort_unless(\App\Models\Sector::catalog()->whereKey($p['sector_id'])->exists(), 409, 'O sector deixou de estar disponível no catálogo. Prepare outra prévia.');
$paths = [];
foreach ($preview['input']['territory_ids'] ?? [] as $territory) {
$path = app(InvestmentGeography::class)->path($territory, true);
abort_unless(count($path) && collect($path)->contains('id', $territory), 409, 'Um território deixou de estar disponível. Prepare outra prévia.');
$paths[] = $path;
}
$currentTerritories = array_map(fn ($path) => ['id' => end($path)->id, 'label' => implode(' / ', array_column($path, 'name'))], $paths);
abort_unless($currentTerritories === $p['territories'], 409, 'O enquadramento territorial mudou. Prepare outra prévia.');
// Preserve the original private draft bytes; retain its former base
// columns in the existing hidden context before projecting public text.
$context['promotional_private_base'] ??= $record->only(OpportunityManagement::FIELDS);
$context['working_state'] ??= app(PortalProfileAccess::class)->state($record);
$context['promotional_summary'] = ['input' => $preview['input'], 'projection' => $p];
$context['publication'] = ['visibility' => 'public', 'purpose' => self::PURPOSE, 'actor_id' => $actor->id,
'at' => now()->toIso8601String(), 'execution_approved' => false, 'private_draft_preserved' => true];
$action = data_get($before, 'status') === 'published' ? 'promotional_summary_updated' : 'promotional_summary_published';
foreach (['title', 'summary', 'description', 'sector_id', 'maturity_label'] as $field) $record->{$field} = $p[$field];
foreach (['promoter_name', 'promoter_type', 'financing_modality', 'expected_impact', 'maturity_level', 'estimated_investment_amount', 'estimated_investment_currency'] as $field) $record->{$field} = null;
$main = $paths[0] ?? [];
$record->primary_territory_id = $main ? end($main)->id : null;
$record->province = collect($main)->firstWhere('location_type', 'province')?->name;
$record->district = collect($main)->firstWhere('location_type', 'district')?->name;
$record->geography_scope = count($paths) > 1 ? 'multiple' : ($main ? 'specific' : 'unspecified');
DB::table('opportunity_locations')->where('opportunity_id', $id)->delete();
foreach ($preview['input']['territory_ids'] ?? [] as $territory) DB::table('opportunity_locations')->insert(['opportunity_id' => $id, 'geo_location_id' => $territory]);
$record->status = 'published';
$record->is_featured = false;
$record->last_validated_at = null;
$record->published_at = now();
}
$record->workflow_context = $context;
$record->management_version++;
$record->save();
DB::table('audit_events')->insert(['source_system' => 'tempo-preparation-publication', 'entity_type' => 'opportunity',
'actor_user_id' => $actor->id, 'action' => $action, 'data_classification' => 'restricted', 'correlation_id' => (string) Str::uuid(),
'before_data' => json_encode(['record_id' => $id, 'record' => $before, 'territories' => $oldLocations], JSON_THROW_ON_ERROR),
'after_data' => json_encode(['record_id' => $id, 'operation_key' => $data['operation_key'], 'request_hash' => $digest,
'reason' => $data['reason'], 'projection' => $preview['projection'], 'execution_approved' => false,
'record' => $record->getRawOriginal()], JSON_THROW_ON_ERROR)]);
return ['id' => $id, 'replayed' => false, 'message' => $preview['action'] === 'withdraw' ? 'Resumo retirado; cadastro e histórico preservados.' : 'Resumo divulgado como Em preparação. Não autoriza execução do investimento.'];
});
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
/** Presentation only: originals, editorial fields and audit records remain intact. */
final class OpportunityPublicText
{
public static function description(Opportunity $record, string $text): string
{
$source = data_get($record->workflow_context, 'corridor_agribusiness');
if (! is_array($source) || ($source['source_sha256'] ?? null) !== CorridorAgribusinessOpportunities::SOURCE_HASH) return $text;
$hash = CorridorAgribusinessOpportunities::SOURCE_HASH;
$sourceLine = 'Fonte: '.$source['source'].'; SHA-256 '.$hash;
$paragraphs = explode("\n\n", $text);
$result = [];
foreach ($paragraphs as $paragraph) {
$paragraph = trim($paragraph);
if (in_array($paragraph, [$sourceLine, $sourceLine.'.', 'Edição: Não indicada.', 'Data-base: Não indicada.',
'Limitações e lacunas: '.CorridorAgribusinessOpportunities::LIMITATIONS,
OpportunityPromotion::NOTICE], true)) continue;
if ($paragraph === 'Enquadramento documental: '.$source['corridor'].'.') $paragraph = $source['corridor'].'.';
if ($paragraph === CorridorAgribusinessOpportunities::LIMITATIONS) {
$paragraph = 'A localização exacta, a disponibilidade de terreno e as condições do investimento serão definidas durante a preparação do projecto.';
}
if ($paragraph !== '') $result[] = $paragraph;
}
return implode("\n\n", $result);
}
}
+13
View File
@@ -0,0 +1,13 @@
<?php
// Functional configuration expressly defined by Tempo, 23/10/2026.
// Codes identify the existing national territorial registry; no geometry is inferred.
return [
'pemba-lichinga' => ['name' => 'Corredor de Pemba–Lichinga', 'provinces' => ['02', '01']],
'nacala' => ['name' => 'Corredor de Nacala', 'provinces' => ['03']],
'vale-zambeze' => ['name' => 'Corredor do Vale do Zambeze', 'provinces' => ['05', '04']],
'beira' => ['name' => 'Corredor da Beira', 'provinces' => ['07', '06']],
'limpopo' => ['name' => 'Corredor do Limpopo', 'provinces' => ['09']],
// Tempo's final clarification: both Maputo Province and Maputo City.
'maputo' => ['name' => 'Corredor de Maputo', 'provinces' => ['10', '11']],
];
@@ -0,0 +1,181 @@
{
"source": "investimentos nos corredores.docx",
"source_sha256": "1473b06c48aa234e771660e3f2a51b9d2e4e1943bd52d878e0ae854ee6657055",
"introduction": "Os corredores de desenvolvimento integram cadeias de valor prioritárias que podem ser apresentadas no portal InvesteMoz como oportunidades concretas de investimento na produção, transformação, logística e comercialização. Para cada corredor, são destacadas abaixo as oportunidades associadas aos produtos com maior potencial.",
"segments": [
"Produção primária e fornecimento de insumos",
"Processamento e transformação agro-industrial",
"Armazenagem, cadeia de frio e logística",
"Embalagem, distribuição, comercialização e exportação",
"Infraestruturas e serviços de apoio às cadeias de valor"
],
"groups": [
{
"name": "Corredor de Pemba–Lichinga",
"opportunities": [
{
"chain": "Batata, trigo, feijão, milho e soja",
"description": "Produção comercial, armazenamento e processamento de batata, trigo, feijão, milho e soja."
},
{
"chain": "Algodão",
"description": "Descaroçamento, fiação e produção de óleo e derivados de algodão."
},
{
"chain": "Sésamo",
"description": "Limpeza, prensagem, embalagem e exportação de sésamo."
},
{
"chain": "Florestas",
"description": "Viveiros, plantações comerciais, madeira processada e produtos florestais sustentáveis."
},
{
"chain": "Avicultura",
"description": "Produção de rações, incubação, criação, abate e cadeia de frio para avicultura."
}
]
},
{
"name": "Corredor de Nacala",
"opportunities": [
{
"chain": "Mandioca",
"description": "Produção e transformação de mandioca em farinha, amido e outros derivados."
},
{
"chain": "Milho, amendoim e sésamo",
"description": "Produção, armazenagem e processamento de milho, amendoim e sésamo."
},
{
"chain": "Algodão",
"description": "Descaroçamento e transformação de algodão."
},
{
"chain": "Frutas e caju",
"description": "Pomares, processamento, embalagem e exportação de frutas e caju."
},
{
"chain": "Florestas",
"description": "Silvicultura comercial, madeira processada e produtos florestais."
},
{
"chain": "Avicultura",
"description": "Produção de rações, criação, abate e distribuição de produtos avícolas."
}
]
},
{
"name": "Corredor do Vale do Zambeze",
"opportunities": [
{
"chain": "Arroz",
"description": "Produção irrigada, moagem, embalagem e comercialização de arroz."
},
{
"chain": "Milho e batata",
"description": "Produção, secagem, armazenagem e transformação de milho e batata."
},
{
"chain": "Sésamo",
"description": "Limpeza, prensagem e exportação de sésamo."
},
{
"chain": "Algodão",
"description": "Descaroçamento e transformação de algodão."
},
{
"chain": "Avicultura",
"description": "Produção de rações, incubação, criação e abate de aves."
},
{
"chain": "Bovinos e caprinos",
"description": "Criação, engorda, abate, processamento de carne e cadeia de frio para bovinos e caprinos."
}
]
},
{
"name": "Corredor da Beira",
"opportunities": [
{
"chain": "Milho, trigo e arroz",
"description": "Produção, silos, moagem e processamento de milho, trigo e arroz."
},
{
"chain": "Soja",
"description": "Esmagamento de soja, produção de óleo vegetal e fabrico de rações."
},
{
"chain": "Hortícolas",
"description": "Produção irrigada, conservação, embalagem e distribuição de hortícolas."
},
{
"chain": "Sésamo",
"description": "Limpeza, prensagem e exportação de sésamo."
},
{
"chain": "Açúcar",
"description": "Produção e refinação de açúcar e aproveitamento de subprodutos."
},
{
"chain": "Florestas",
"description": "Plantações comerciais, processamento de madeira e produtos florestais."
},
{
"chain": "Carne bovina",
"description": "Criação, engorda, abate, processamento e cadeia de frio para carne bovina."
}
]
},
{
"name": "Corredor do Limpopo",
"opportunities": [
{
"chain": "Arroz",
"description": "Produção irrigada, moagem, embalagem e comercialização de arroz."
},
{
"chain": "Hortícolas",
"description": "Produção em estufas e campo aberto, conservação, embalagem e distribuição de hortícolas."
},
{
"chain": "Carne vermelha",
"description": "Criação, engorda, abate, processamento e cadeia de frio para carne vermelha."
},
{
"chain": "Avicultura",
"description": "Produção de rações, incubação, criação, abate e distribuição de produtos avícolas."
},
{
"chain": "Infraestruturas e serviços de apoio",
"description": "Infraestruturas de irrigação, armazenagem, transporte refrigerado e centros de comercialização."
}
]
},
{
"name": "Corredor de Maputo",
"opportunities": [
{
"chain": "Arroz",
"description": "Produção irrigada, moagem, embalagem e fornecimento de arroz aos mercados urbanos e regionais."
},
{
"chain": "Hortícolas",
"description": "Produção, conservação, embalagem, transformação e distribuição de hortícolas."
},
{
"chain": "Carne vermelha",
"description": "Criação, engorda, abate, processamento, distribuição e exportação regional de carne vermelha."
},
{
"chain": "Avicultura",
"description": "Produção de rações, incubação, criação, abate e comercialização de produtos avícolas."
},
{
"chain": "Infraestruturas e serviços de apoio",
"description": "Plataformas logísticas, centros de distribuição, cadeia de frio e serviços de exportação."
}
]
}
],
"sector": "Agronegócio"
}
@@ -4,6 +4,10 @@ Data: 2026-10-03. Âmbito: prompt master recebido em `Pasted text.txt`, document
## Estado inicial e ambiente
**Orientação de publicação e percurso do lote, 23/10/2026:** as 34 oportunidades de Agronegócio ficam publicáveis sem relações obrigatórias com corredores/clusters/projectos. Lacuna encontrada: a comparação múltipla existente não era transportada ao dossier. Correcção aditiva no contexto cifrado existente, com escolhas identificadas e localização por ficha, confirmação de alternativa, requisitos/fontes/documentos/entidades por contexto, reutilização no simulador e conservação de resultados/histórico. Sete testes do contexto (132 asserções) e um do lote pela sessão HTTP (15) passaram. Publicação QA efectuada; instalação no destino separa código, cadastro privado e divulgação autenticada. Ver [orientação e guia no manual](unification/traceability-and-manual.md). Não altera Turismo de Inhambane nem concede benefícios por localização. Lacunas de modalidade/dimensão/acto concreto permanecem explícitas, sem nova revalidação de fontes oficiais aceites.
**Correcção de âmbito, 23/10/2026 — agronegócio e percurso existente:** a lista informativa instalada não encerrava o cadastro. Preparadas e efectivamente cadastradas 34 oportunidades privadas em QA, com as seis designações documentais intactas, sector, fonte/hash e lacunas explícitas. Reutilizada a candidata de divulgação promocional `9d3bfa89` no fluxo necessário, sem alterações independentes de administração de contas nem novos papéis. Equipa edita/recupera e divulga/actualiza/retira pela interface; público acede à ficha individual, manifestação e roteiro com referência confirmada no mesmo dossier. Três testes específicos, 553 asserções; tipos/build concluídos; tabelas/linhas preexistentes comparadas e preservadas. As divulgações dos testes foram revertidas; as 34 fichas permanecem privadas. Sem alteração da homologação nesta correcção. Carregamento inicial técnico QA já executado; não é dependência das operações correntes. Guia, limites e recibo na [secção de correcção do manual](unification/traceability-and-manual.md#correcção-de-âmbito--34-oportunidades-cadastradas-e-roteiro-em-qa-23102026). Não encerra viabilidade, implantação, financiamento ou execução das oportunidades.
| Item | Evidência observada |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Branch / commit | `main` / `4f35313d06ccd597a4ebf9ed043964d898c95813` |
@@ -334,8 +338,18 @@ Proposta de entrega da candidata `1bcf34c0`: ver «Proposta de instalação comp
Nos requisitos existentes de gestão/publicação `MASTER-9f6dd1d9-0001`, `MASTER-9f6dd1d9-0003` e `MASTER-02f44baf-0002`, registar o recorte solicitado pela Tempo: procedimentos com regime/edição/fontes, lotes, rascunhos recuperáveis, prévia, actos versionados, catálogo/ficha/anexos anónimos, filtros, impressão e acompanhamento por conta simples. Evidência: secção «Concursos e anúncios — implementação em QA» do manual existente e `tests/Feature/ProcurementTest.php`, com passagem adicional no navegador dos três regimes, prorrogação, cancelamento, download e acompanhamento. Reutilizadas autorizações e biblioteca; não foram criados papéis ou aprovadores. Origem funcional: pedido expresso da Tempo; flag, prévia assinada e controlo de versão são escolhas técnicas. Entrega delimitada a QA: integração em main, migração/activação no destino e anúncios reais seguem o processo existente. Não fecha requisitos integrais de contratação/recepção de propostas, nem declara parametrizado todo o articulado legal. Geometrias permanecem no recorte separado já entregue.
### Preservação do concluído e reposição — 23/10/2026
Origem: pedido expresso da Tempo de inventariar o concluído e repor funcionalidades desaparecidas antes de outra ronda de testes/validações. Inventariados os mesmos 43 componentes do manual e os 17 percursos da matriz executável existente; os componentes de interface referenciados estão presentes. Estados históricos foram reconciliados com entregas posteriores, sem revogar aceitações por falta de nova prova. Não se criou nova matriz/backlog nem se promoveu uma funcionalidade parcial a concluída.
Perda confirmada: carteira e projectos âncora. Os 29 dossiers existiam em homologação, todos em rascunho, apesar de os exemplares locais idênticos estarem publicados com aprovação documental do proprietário de 26/09. Conteúdo, fonte e título conferidos por identidade/código e hashes nos 29; o commit `e65cb269` de 06/10 retirou o caminho de publicação com essa aprovação do importador. Isso explica a diferença do processo de instalação; não prova quando a visibilidade desapareceu de um endereço específico. Reposta a visibilidade dos 15 projectos, 8 clusters e 6 corredores em QA e homologação, com versões e 29 eventos de reposição; sem importação, reescrita de conteúdos, alteração dos mestres ou novas aprovações/papéis.
Backup/restauro fresco de 174 tabelas antes da escrita activa; depois da reposição, 171 tabelas inalteradas. Diferenças limitadas a dossiers, auditoria e sessões. Biblioteca, 20 artigos públicos, 28 privados, geometrias e permissões preservados. Conferência pública delimitada: carteira 29, projectos 15, clusters 8, corredores 6. Sem suite geral de testes nesta passagem. Evidência, limites e regra de preservação em `unification/preservation-inventory-20261023.json`, secção «Preservação do concluído — inventário e reposição» do manual e instrução permanente de 23/10 em `AGENTS.md`.
### Acervo legado — correspondência e preparação QA, 22/10/2026
Fecho do delta privado na homologação: candidata `fb4e7d89` integrada em `65eddf6b`; backup/restauro isolado, transporte privado e cadastro autenticado dos 28 concluídos, sem publicação. Pesquisa/editor/prévia/recuperação conferidos para os 28; gravação/recuperação visual da revisão 3 pela conta real no recurso 32. Originais, registos anteriores e permissões preservados. Recibo `unification/legacy-editorial-installation-receipt-20261022.json` e secção «Legado — cadastro privado concluído na homologação» do manual. Publicação e revisão editorial efectiva cabem à equipa pela interface; dois originais continuam incompletos. Não fecha nem diagnostica a falha separada da carteira/projectos âncora, nem constitui aceitação do commit/pacote pela Tempo.
Actualização do mesmo requisito: os 28 rascunhos têm edição, leitura privada, prévia sem guardar, recuperação e publicação/retirada pela interface em QA, preservando originais, origem e revisões. Seis testes/1.000 asserções, TypeScript e build passaram; publicação positiva apenas em transacções revertidas. Pacote privado v2 preparado com 28 originais e proveniência; não transportado nem publicado na homologação. Guia, permissões existentes, lacunas de imagens, dependências da entrega e reversão na secção «Legado — edição e leitura dos 28 rascunhos em QA» do manual. Pedido funcional expresso da Tempo; hash de âmbito, prévia e controlo de versão são escolhas técnicas, sem novo papel/aprovador. Conserva o saldo de 20 públicos aceites e dois originais incompletos, sem repetir provas ou fechar a integração integral.
Referência do acervo legado, 22/10/2026: a lista única `v2/auditoria-portal/legado-correspondencia-integral.md` e o CSV existente reconciliam 50 identidades (20 publicados, 28 por integrar no destino, um vazio, um sem título). 20/20 páginas conferidas por HTTP anónimo/identidade/origem; cartões de Turismo observados no destino. Os 28 restantes avançaram para rascunhos internos QA, com ClamAV real e repetição idempotente, sem publicação. Recibo e limites no manual, secção «Legado — correspondência integral e avanço privado QA». As duas lacunas editoriais foram confirmadas no original. Não fecha a integração integral nem substitui revisão editorial por prova HTTP; nenhuma alteração activa nesta passagem.
@@ -0,0 +1,34 @@
{
"functional_revision": "20349299",
"catalogue_url": "https://teste-investidor.tempo.co.mz/oportunidades?sector=agronegocio&view=corridors",
"homologation_browser_confirmed": true,
"public_opportunities": 34,
"groups": {
"Corredor de Pemba–Lichinga": 5,
"Corredor de Nacala": 6,
"Corredor do Vale do Zambeze": 6,
"Corredor da Beira": 7,
"Corredor do Limpopo": 5,
"Corredor de Maputo": 5
},
"browser_check": {
"selected_ids": [54, 64],
"corridors": ["Corredor da Beira", "Corredor de Maputo"],
"chain_filter": "Soja",
"filtered_beira_opportunities": 1,
"selection_retained_after_filter": true,
"existing_path": "/investimentos/iniciar?opportunities[]=54&opportunities[]=64",
"agribusiness_top_link_confirmed": true,
"screenshot": "outputs/preservation-inventory-20261023/agribusiness-corridor-explorer-homologation.png"
},
"qa_checks": {"tests": 2, "assertions": 26, "types": "passed", "build": "passed", "comparison_between_corridors": "confirmed in browser"},
"data_writes": false,
"migrations": 0,
"imports": 0,
"republication": false,
"limitations": [
"Province and district of implantation remain unidentified for these 34 records; no corridor boundary or administrative location is inferred.",
"Comparison reuses its existing capacity of four records; preparation can include more choices.",
"Production activities use the accepted source text rather than invented stage classifications."
]
}
@@ -0,0 +1,326 @@
{
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"changed_tables": {
"audit_events": {
"before": {
"rows": 520,
"checksum": "abeaf35ec4463ed7458f2e329a321edd"
},
"after": {
"rows": 622,
"checksum": "3518cc7405c62ad9be2f90da444fd3fe"
}
},
"cache": {
"before": {
"rows": 101,
"checksum": "6fdb8f22e7c00074aba9e7e2c7167ec0"
},
"after": {
"rows": 102,
"checksum": "d57b633a1293ed831a702d26f58f133c"
}
},
"opportunities": {
"before": {
"rows": 30,
"checksum": "8b55b9b474aa78562b40380698981fb6"
},
"after": {
"rows": 64,
"checksum": "6407d8192bb667003087a06aa3f0930f"
}
},
"sessions": {
"before": {
"rows": 24,
"checksum": "ee7deebc29696fe68a4bb1ab98c81215"
},
"after": {
"rows": 25,
"checksum": "0f41a35219cea6347427275b32897ad8"
}
}
},
"registered": 34,
"published": 34,
"records": [
{
"id": 31,
"title": "Batata, trigo, feijão, milho e soja — Corredor de Pemba–Lichinga",
"slug": "inv-mz-gen-7676707848914068",
"key": "80858ef1-42ad-5bc6-88ee-0a4a6253f9e2",
"status": "published"
},
{
"id": 32,
"title": "Algodão — Corredor de Pemba–Lichinga",
"slug": "inv-mz-gen-9477691804857755",
"key": "29990fe3-2453-5308-8a23-27622209ab02",
"status": "published"
},
{
"id": 33,
"title": "Sésamo — Corredor de Pemba–Lichinga",
"slug": "inv-mz-gen-7401258130600878",
"key": "9e79c4ac-01d5-5d20-abf3-b49df6ef8206",
"status": "published"
},
{
"id": 36,
"title": "Mandioca — Corredor de Nacala",
"slug": "inv-mz-gen-1439048955084540",
"key": "4be5f275-3504-5a7e-8ba9-d51a51efd534",
"status": "published"
},
{
"id": 38,
"title": "Algodão — Corredor de Nacala",
"slug": "inv-mz-gen-9644546880756388",
"key": "b337b1cf-01ae-5c35-9949-90704ea68f0f",
"status": "published"
},
{
"id": 39,
"title": "Frutas e caju — Corredor de Nacala",
"slug": "inv-mz-gen-2468979899503991",
"key": "1e9d0e7a-9c63-58cb-9951-349c9cc236c6",
"status": "published"
},
{
"id": 40,
"title": "Florestas — Corredor de Nacala",
"slug": "inv-mz-gen-7039993456771493",
"key": "ebd761cb-e793-5d11-809a-dc04e4baeb9d",
"status": "published"
},
{
"id": 41,
"title": "Avicultura — Corredor de Nacala",
"slug": "inv-mz-gen-5080757788800956",
"key": "69d7e89a-bd72-574c-8ce1-104f4b8448d4",
"status": "published"
},
{
"id": 42,
"title": "Arroz — Corredor do Vale do Zambeze",
"slug": "inv-mz-gen-5601915696649995",
"key": "405f0e8a-973f-5a2f-bbe8-f923944bcde1",
"status": "published"
},
{
"id": 43,
"title": "Milho e batata — Corredor do Vale do Zambeze",
"slug": "inv-mz-gen-2709717524887763",
"key": "7002d77b-2df6-5373-91b0-a67abed64378",
"status": "published"
},
{
"id": 44,
"title": "Sésamo — Corredor do Vale do Zambeze",
"slug": "inv-mz-gen-9164411293252209",
"key": "4bfe5b57-ea81-564e-a6ec-8867de5b79f7",
"status": "published"
},
{
"id": 45,
"title": "Algodão — Corredor do Vale do Zambeze",
"slug": "inv-mz-gen-3014063241101625",
"key": "40c73a69-8724-5552-9612-ecd9ec50d6d8",
"status": "published"
},
{
"id": 46,
"title": "Avicultura — Corredor do Vale do Zambeze",
"slug": "inv-mz-gen-6214131825033367",
"key": "d8ab3e05-a180-5a0a-877e-c9b4fab34931",
"status": "published"
},
{
"id": 48,
"title": "Milho, trigo e arroz — Corredor da Beira",
"slug": "inv-mz-gen-6048328347519124",
"key": "a80dc6b8-1c9b-53ef-bf31-ec37fa22561f",
"status": "published"
},
{
"id": 49,
"title": "Soja — Corredor da Beira",
"slug": "inv-mz-gen-4587508237495307",
"key": "59726827-4fe9-5256-af12-10bd56dab0e3",
"status": "published"
},
{
"id": 52,
"title": "Açúcar — Corredor da Beira",
"slug": "inv-mz-gen-1634854290375763",
"key": "bc1ee2df-33f9-5262-9ad4-1af961393c88",
"status": "published"
},
{
"id": 53,
"title": "Florestas — Corredor da Beira",
"slug": "inv-mz-gen-8326396601945337",
"key": "aaf5661e-0a45-561a-b74e-c5cbfaad7721",
"status": "published"
},
{
"id": 55,
"title": "Arroz — Corredor do Limpopo",
"slug": "inv-mz-gen-4222404773242970",
"key": "0ebbae53-7331-5360-b704-3060f2f52548",
"status": "published"
},
{
"id": 37,
"title": "Milho, amendoim e sésamo — Corredor de Nacala",
"slug": "inv-mz-gen-5107565297512781",
"key": "7887e378-6d59-5acc-94e1-41f320e690f6",
"status": "published"
},
{
"id": 56,
"title": "Hortícolas — Corredor do Limpopo",
"slug": "inv-mz-gen-2333485246312757",
"key": "5ead8334-a1ea-5710-b5ae-751e1a97bc18",
"status": "published"
},
{
"id": 58,
"title": "Avicultura — Corredor do Limpopo",
"slug": "inv-mz-gen-9065431632626708",
"key": "7b4070c4-59f9-59f3-ae3a-ef897998e5ae",
"status": "published"
},
{
"id": 59,
"title": "Infraestruturas e serviços de apoio — Corredor do Limpopo",
"slug": "inv-mz-gen-5245892626712728",
"key": "09fa3da3-96c0-562c-8b3d-1010841fac16",
"status": "published"
},
{
"id": 60,
"title": "Arroz — Corredor de Maputo",
"slug": "inv-mz-gen-8724580943323815",
"key": "8b3cd51b-d51a-5a60-9ec3-9222db943bbb",
"status": "published"
},
{
"id": 63,
"title": "Avicultura — Corredor de Maputo",
"slug": "inv-mz-gen-4404538462410084",
"key": "a15d68d3-02c8-50d9-a03b-63f0478733ff",
"status": "published"
},
{
"id": 34,
"title": "Florestas — Corredor de Pemba–Lichinga",
"slug": "inv-mz-gen-2816022300638626",
"key": "ccde9a38-0a27-5b46-a158-b2013128baaf",
"status": "published"
},
{
"id": 35,
"title": "Avicultura — Corredor de Pemba–Lichinga",
"slug": "inv-mz-gen-6844264076753489",
"key": "1748aee6-cf7a-5e16-acde-d37777578d3a",
"status": "published"
},
{
"id": 47,
"title": "Bovinos e caprinos — Corredor do Vale do Zambeze",
"slug": "inv-mz-gen-5894491385867554",
"key": "8a493e37-5d26-5cc7-9937-aab3e7ad0f40",
"status": "published"
},
{
"id": 50,
"title": "Hortícolas — Corredor da Beira",
"slug": "inv-mz-gen-3954947238505605",
"key": "2d0fb383-6d02-5df6-a24a-57474ab15ad0",
"status": "published"
},
{
"id": 51,
"title": "Sésamo — Corredor da Beira",
"slug": "inv-mz-gen-8142311444413640",
"key": "791e2921-92cf-5e08-9ff7-99a275bd6f34",
"status": "published"
},
{
"id": 54,
"title": "Carne bovina — Corredor da Beira",
"slug": "inv-mz-gen-3963957640266320",
"key": "45423b00-4673-5595-b3ac-cc4ab8e1dc8a",
"status": "published"
},
{
"id": 57,
"title": "Carne vermelha — Corredor do Limpopo",
"slug": "inv-mz-gen-4521723858186670",
"key": "fbbb0961-e5b0-5900-ad33-4efb5fc7bfc5",
"status": "published"
},
{
"id": 61,
"title": "Hortícolas — Corredor de Maputo",
"slug": "inv-mz-gen-3403417739078882",
"key": "14b76956-6afa-5c52-8d56-db402dbbd099",
"status": "published"
},
{
"id": 62,
"title": "Carne vermelha — Corredor de Maputo",
"slug": "inv-mz-gen-6923224180891809",
"key": "bd07739d-e0b8-5561-8baa-14f67571ecf5",
"status": "published"
},
{
"id": 64,
"title": "Infraestruturas e serviços de apoio — Corredor de Maputo",
"slug": "inv-mz-gen-7371026296970534",
"key": "eb5bad23-5ea2-5f81-bb2e-85609853ae1b",
"status": "published"
}
],
"resources": 59,
"geometries": 408,
"preexisting_opportunities_preserved": true,
"comparison_reader": "postgres, same identity as backup; RLS-filtered application counts are not used as loss evidence",
"served_revision": {
"commit": "e12ef6ad426ff6ebc4e7421a1ddbe7f184d77a55",
"branch": "main",
"built_at": "2026-10-23T09:01:54.733542+00:00",
"manifest_sha256": "a7fb08d79db71f19f0dde06c8ebb9329cfaf8e93c2f5a80f460aef98aa885398"
},
"installation_complete": true,
"registration_complete": true,
"publication_complete": true,
"pending": null,
"backup_restore": {
"verified": true,
"tables": 174,
"files": 369,
"dump_sha256": "318fcdce6623f1032fa319372a08ff4219f4def509f64cf73b39674e8b85260e",
"files_sha256": "b0903725916a9b523a0f90c10ae6c42877f4374fb711f900f19e0b2053606536"
},
"management_url": "https://teste-investidor.tempo.co.mz/minhas-oportunidades/lotes/agronegocio",
"comparison_correction": "Initial application read was RLS-filtered; equivalent postgres read confirmed all simulation records preserved. No data restoration or security policy changes executed.",
"execution": "Ordinary authenticated real-account browser interface, preview and confirmation, existing recent MFA. No console registration or publication.",
"public_url": "https://teste-investidor.tempo.co.mz/oportunidades?sector=agronegocio",
"browser_proof": {
"results": 34,
"selected_ids": [
64,
63
],
"path": "/investimentos/iniciar?opportunities[]=64&opportunities[]=63",
"screenshot": "outputs/preservation-inventory-20261023/agribusiness-homologation-published.png"
},
"unchanged_tables": 170
}
@@ -0,0 +1,214 @@
{
"target": {
"name": "simulator_fiscal_delta_20261021_test",
"port": 55441
},
"source_sha256": "1473b06c48aa234e771660e3f2a51b9d2e4e1943bd52d878e0ae854ee6657055",
"records": [
{
"id": 269,
"created": true,
"key": "80858ef1-42ad-5bc6-88ee-0a4a6253f9e2"
},
{
"id": 270,
"created": true,
"key": "29990fe3-2453-5308-8a23-27622209ab02"
},
{
"id": 271,
"created": true,
"key": "9e79c4ac-01d5-5d20-abf3-b49df6ef8206"
},
{
"id": 272,
"created": true,
"key": "ccde9a38-0a27-5b46-a158-b2013128baaf"
},
{
"id": 273,
"created": true,
"key": "1748aee6-cf7a-5e16-acde-d37777578d3a"
},
{
"id": 274,
"created": true,
"key": "4be5f275-3504-5a7e-8ba9-d51a51efd534"
},
{
"id": 275,
"created": true,
"key": "7887e378-6d59-5acc-94e1-41f320e690f6"
},
{
"id": 276,
"created": true,
"key": "b337b1cf-01ae-5c35-9949-90704ea68f0f"
},
{
"id": 277,
"created": true,
"key": "1e9d0e7a-9c63-58cb-9951-349c9cc236c6"
},
{
"id": 278,
"created": true,
"key": "ebd761cb-e793-5d11-809a-dc04e4baeb9d"
},
{
"id": 279,
"created": true,
"key": "69d7e89a-bd72-574c-8ce1-104f4b8448d4"
},
{
"id": 280,
"created": true,
"key": "405f0e8a-973f-5a2f-bbe8-f923944bcde1"
},
{
"id": 281,
"created": true,
"key": "7002d77b-2df6-5373-91b0-a67abed64378"
},
{
"id": 282,
"created": true,
"key": "4bfe5b57-ea81-564e-a6ec-8867de5b79f7"
},
{
"id": 283,
"created": true,
"key": "40c73a69-8724-5552-9612-ecd9ec50d6d8"
},
{
"id": 284,
"created": true,
"key": "d8ab3e05-a180-5a0a-877e-c9b4fab34931"
},
{
"id": 285,
"created": true,
"key": "8a493e37-5d26-5cc7-9937-aab3e7ad0f40"
},
{
"id": 286,
"created": true,
"key": "a80dc6b8-1c9b-53ef-bf31-ec37fa22561f"
},
{
"id": 287,
"created": true,
"key": "59726827-4fe9-5256-af12-10bd56dab0e3"
},
{
"id": 288,
"created": true,
"key": "2d0fb383-6d02-5df6-a24a-57474ab15ad0"
},
{
"id": 289,
"created": true,
"key": "791e2921-92cf-5e08-9ff7-99a275bd6f34"
},
{
"id": 290,
"created": true,
"key": "bc1ee2df-33f9-5262-9ad4-1af961393c88"
},
{
"id": 291,
"created": true,
"key": "aaf5661e-0a45-561a-b74e-c5cbfaad7721"
},
{
"id": 292,
"created": true,
"key": "45423b00-4673-5595-b3ac-cc4ab8e1dc8a"
},
{
"id": 293,
"created": true,
"key": "0ebbae53-7331-5360-b704-3060f2f52548"
},
{
"id": 294,
"created": true,
"key": "5ead8334-a1ea-5710-b5ae-751e1a97bc18"
},
{
"id": 295,
"created": true,
"key": "fbbb0961-e5b0-5900-ad33-4efb5fc7bfc5"
},
{
"id": 296,
"created": true,
"key": "7b4070c4-59f9-59f3-ae3a-ef897998e5ae"
},
{
"id": 297,
"created": true,
"key": "09fa3da3-96c0-562c-8b3d-1010841fac16"
},
{
"id": 298,
"created": true,
"key": "8b3cd51b-d51a-5a60-9ec3-9222db943bbb"
},
{
"id": 299,
"created": true,
"key": "14b76956-6afa-5c52-8d56-db402dbbd099"
},
{
"id": 300,
"created": true,
"key": "bd07739d-e0b8-5561-8baa-14f67571ecf5"
},
{
"id": 301,
"created": true,
"key": "a15d68d3-02c8-50d9-a03b-63f0478733ff"
},
{
"id": 302,
"created": true,
"key": "eb5bad23-5ea2-5f81-bb2e-85609853ae1b"
}
],
"total": 34,
"new": 34,
"published": 0,
"active_writes": 0,
"status": "QA private registration complete; homologation unchanged",
"preservation": {
"target": {
"name": "simulator_fiscal_delta_20261021_test",
"port": 55441
},
"records": 34,
"private_drafts": 34,
"preserved": {
"opportunities": true,
"audit_events": true,
"development_corridors": true,
"portal_role_assignments": true,
"portal_resources": true,
"documents": true
},
"active_writes": 0
},
"checks": {
"feature_tests": 3,
"assertions": 553,
"types": "passed",
"frontend_build": "passed",
"test_disclosures_rolled_back": true
},
"management_url": "http://127.0.0.1:18574/gestao-conteudos",
"individual_editor_example": "http://127.0.0.1:18574/minhas-oportunidades/269/edit",
"reused_promotional_candidate": "9d3bfa89",
"schema_changes": 0,
"new_roles": 0,
"new_dependencies": 0
}
@@ -0,0 +1,246 @@
{
"target": {
"name": "simulator_fiscal_delta_20261021_test",
"port": 55441
},
"published": 34,
"authentication": "QA role simulation only; no production authentication claimed",
"source_sha256": "1473b06c48aa234e771660e3f2a51b9d2e4e1943bd52d878e0ae854ee6657055",
"records": [
{
"id": 269,
"title": "Batata, trigo, feijão, milho e soja — Corredor de Pemba–Lichinga",
"corridor": "Corredor de Pemba–Lichinga",
"url": "/oportunidades/inv-mz-gen-5150397406444731"
},
{
"id": 270,
"title": "Algodão — Corredor de Pemba–Lichinga",
"corridor": "Corredor de Pemba–Lichinga",
"url": "/oportunidades/inv-mz-gen-1647249176453799"
},
{
"id": 271,
"title": "Sésamo — Corredor de Pemba–Lichinga",
"corridor": "Corredor de Pemba–Lichinga",
"url": "/oportunidades/inv-mz-gen-3352774267583285"
},
{
"id": 272,
"title": "Florestas — Corredor de Pemba–Lichinga",
"corridor": "Corredor de Pemba–Lichinga",
"url": "/oportunidades/inv-mz-gen-7850139886806206"
},
{
"id": 273,
"title": "Avicultura — Corredor de Pemba–Lichinga",
"corridor": "Corredor de Pemba–Lichinga",
"url": "/oportunidades/inv-mz-gen-3839727014705762"
},
{
"id": 274,
"title": "Mandioca — Corredor de Nacala",
"corridor": "Corredor de Nacala",
"url": "/oportunidades/inv-mz-gen-8963722873273976"
},
{
"id": 275,
"title": "Milho, amendoim e sésamo — Corredor de Nacala",
"corridor": "Corredor de Nacala",
"url": "/oportunidades/inv-mz-gen-9998208319499345"
},
{
"id": 276,
"title": "Algodão — Corredor de Nacala",
"corridor": "Corredor de Nacala",
"url": "/oportunidades/inv-mz-gen-6731688736856562"
},
{
"id": 277,
"title": "Frutas e caju — Corredor de Nacala",
"corridor": "Corredor de Nacala",
"url": "/oportunidades/inv-mz-gen-2325832878312017"
},
{
"id": 278,
"title": "Florestas — Corredor de Nacala",
"corridor": "Corredor de Nacala",
"url": "/oportunidades/inv-mz-gen-8943819075565910"
},
{
"id": 279,
"title": "Avicultura — Corredor de Nacala",
"corridor": "Corredor de Nacala",
"url": "/oportunidades/inv-mz-gen-3960434222994703"
},
{
"id": 280,
"title": "Arroz — Corredor do Vale do Zambeze",
"corridor": "Corredor do Vale do Zambeze",
"url": "/oportunidades/inv-mz-gen-4676568685660682"
},
{
"id": 281,
"title": "Milho e batata — Corredor do Vale do Zambeze",
"corridor": "Corredor do Vale do Zambeze",
"url": "/oportunidades/inv-mz-gen-9955994100950689"
},
{
"id": 282,
"title": "Sésamo — Corredor do Vale do Zambeze",
"corridor": "Corredor do Vale do Zambeze",
"url": "/oportunidades/inv-mz-gen-5272341950046110"
},
{
"id": 283,
"title": "Algodão — Corredor do Vale do Zambeze",
"corridor": "Corredor do Vale do Zambeze",
"url": "/oportunidades/inv-mz-gen-5628419400094441"
},
{
"id": 284,
"title": "Avicultura — Corredor do Vale do Zambeze",
"corridor": "Corredor do Vale do Zambeze",
"url": "/oportunidades/inv-mz-gen-8668117557933061"
},
{
"id": 285,
"title": "Bovinos e caprinos — Corredor do Vale do Zambeze",
"corridor": "Corredor do Vale do Zambeze",
"url": "/oportunidades/inv-mz-gen-6651453468338687"
},
{
"id": 286,
"title": "Milho, trigo e arroz — Corredor da Beira",
"corridor": "Corredor da Beira",
"url": "/oportunidades/inv-mz-gen-8128691124566423"
},
{
"id": 287,
"title": "Soja — Corredor da Beira",
"corridor": "Corredor da Beira",
"url": "/oportunidades/inv-mz-gen-5563232446855414"
},
{
"id": 288,
"title": "Hortícolas — Corredor da Beira",
"corridor": "Corredor da Beira",
"url": "/oportunidades/inv-mz-gen-5715109945209502"
},
{
"id": 289,
"title": "Sésamo — Corredor da Beira",
"corridor": "Corredor da Beira",
"url": "/oportunidades/inv-mz-gen-6307033318408482"
},
{
"id": 290,
"title": "Açúcar — Corredor da Beira",
"corridor": "Corredor da Beira",
"url": "/oportunidades/inv-mz-gen-8123001467176624"
},
{
"id": 291,
"title": "Florestas — Corredor da Beira",
"corridor": "Corredor da Beira",
"url": "/oportunidades/inv-mz-gen-5629890674429876"
},
{
"id": 292,
"title": "Carne bovina — Corredor da Beira",
"corridor": "Corredor da Beira",
"url": "/oportunidades/inv-mz-gen-2472671405287788"
},
{
"id": 293,
"title": "Arroz — Corredor do Limpopo",
"corridor": "Corredor do Limpopo",
"url": "/oportunidades/inv-mz-gen-5995177607070005"
},
{
"id": 294,
"title": "Hortícolas — Corredor do Limpopo",
"corridor": "Corredor do Limpopo",
"url": "/oportunidades/inv-mz-gen-7967808283045554"
},
{
"id": 295,
"title": "Carne vermelha — Corredor do Limpopo",
"corridor": "Corredor do Limpopo",
"url": "/oportunidades/inv-mz-gen-5036463681202017"
},
{
"id": 296,
"title": "Avicultura — Corredor do Limpopo",
"corridor": "Corredor do Limpopo",
"url": "/oportunidades/inv-mz-gen-5524442722730781"
},
{
"id": 297,
"title": "Infraestruturas e serviços de apoio — Corredor do Limpopo",
"corridor": "Corredor do Limpopo",
"url": "/oportunidades/inv-mz-gen-2099729870926704"
},
{
"id": 298,
"title": "Arroz — Corredor de Maputo",
"corridor": "Corredor de Maputo",
"url": "/oportunidades/inv-mz-gen-1866403697817634"
},
{
"id": 299,
"title": "Hortícolas — Corredor de Maputo",
"corridor": "Corredor de Maputo",
"url": "/oportunidades/inv-mz-gen-6293243388893029"
},
{
"id": 300,
"title": "Carne vermelha — Corredor de Maputo",
"corridor": "Corredor de Maputo",
"url": "/oportunidades/inv-mz-gen-9330026487459372"
},
{
"id": 301,
"title": "Avicultura — Corredor de Maputo",
"corridor": "Corredor de Maputo",
"url": "/oportunidades/inv-mz-gen-1761515912486377"
},
{
"id": 302,
"title": "Infraestruturas e serviços de apoio — Corredor de Maputo",
"corridor": "Corredor de Maputo",
"url": "/oportunidades/inv-mz-gen-2643789930780297"
}
],
"active_writes": 0,
"checks": {
"context_tests": 7,
"context_assertions": 132,
"batch_tests": 1,
"batch_assertions": 15,
"frontend_types": "passed",
"frontend_build": "passed",
"browser_catalogue_results": 34,
"browser_selected_opportunities": 2
},
"preservation": {
"target": {
"name": "simulator_fiscal_delta_20261021_test",
"port": 55441
},
"records": 34,
"private_drafts": 0,
"preserved": {
"opportunities": true,
"audit_events": true,
"development_corridors": true,
"portal_role_assignments": true,
"portal_resources": true,
"documents": true
},
"active_writes": 0,
"published_in_qa": 34
},
"qa_catalogue_url": "http://127.0.0.1:18574/oportunidades?sector=agronegocio",
"homologation_status": "Backup/restore verified; code delivery and authenticated registration/disclosure still separate."
}
@@ -0,0 +1,36 @@
{
"url": "https://teste-investidor.tempo.co.mz/agronegocio",
"status": 200,
"served_revision": "20a4099d10400496e19f03589b6383f512b48d9d",
"sections": [
{
"name": "Corredor de Pemba–Lichinga",
"entries": 5
},
{
"name": "Corredor de Nacala",
"entries": 6
},
{
"name": "Corredor do Vale do Zambeze",
"entries": 6
},
{
"name": "Corredor da Beira",
"entries": 7
},
{
"name": "Corredor do Limpopo",
"entries": 5
},
{
"name": "Corredor de Maputo",
"entries": 5
}
],
"entries": 34,
"original_html_preserved": true,
"metadata_image_version_source_preserved": true,
"article_sha256": "0929184a6d4645b9046512675394ad4f60575273f6dab0955f71cc7474a6a4e2",
"database_writes": 0
}
@@ -0,0 +1,358 @@
{
"format": "investmoz-approved-portfolio-visibility-recovery-v1",
"request": "Tempo, 23/10/2026: inventariar funcionalidades concluídas, inventariar desaparecidas e repor, preservando o aprovado",
"scope": "Restore visibility of exact unchanged previously owner-approved dossiers, not approve new or modified content",
"source_database": "investemoz",
"source_snapshot_sha256": "c27a34e30617ce56164daab0aea5cdd7e43b8bec9b2fa197ef616e6c87e70575",
"historic_snapshot_sha256": "6904486ee9c3895ee5e42d9ef19e6cb5f223930f7734a7af18051053d019cda6",
"items": [
{
"code": "A01",
"title": "MozParks – 20 Parques Industriais",
"source_record_id": "219e1dbb-939c-4ef0-92b7-7f78f8561fa0",
"target_record_id": "9871a8c0-d562-420b-a8f7-174c95db93f0",
"expected_target_version": 1,
"content_sha256": "2adcbe741777d4352c47eb31281dc6b2e2d04903fcfd3e59778ddff4e1342977",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A02",
"title": "Linha Ferroviária Norte–Sul",
"source_record_id": "1125f069-61e2-4071-99f3-dd103caf3156",
"target_record_id": "64b824a0-3527-4024-a1a2-5234f5b4caaa",
"expected_target_version": 1,
"content_sha256": "3ad808813909f1475f44a5fcf2a4e50c5d01e25ad8ea39d906c52519532cf0ee",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A03",
"title": "Programa de Desenvolvimento Integrado do Corredor de Nacala",
"source_record_id": "39f5973c-f4cd-49d0-aeea-1c0c71783550",
"target_record_id": "6c03e980-c455-49cc-a3be-99d29014e91d",
"expected_target_version": 1,
"content_sha256": "75266ff89da58e4d6e5422e49e4641c62dae4f171fa358b70e210c5883a1fd07",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A04",
"title": "Crusse Jamali – Zona Económica Especial de Turismo",
"source_record_id": "0dccdd26-9796-4ef7-947b-5a2970ace379",
"target_record_id": "8bd83cc4-b36c-46cd-9287-b47e1162b578",
"expected_target_version": 1,
"content_sha256": "f6a63e2ee2f2e7c98f1030d206996ad57b0d92129d021ed3c6bb53f161d56f5b",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A05",
"title": "Linha de Transmissão Namialo–Metoro (400 kV)",
"source_record_id": "361789ad-1e14-4b64-8f1f-fad053886d5a",
"target_record_id": "d8a88bac-4684-43fa-aea6-e54fef9b8a47",
"expected_target_version": 1,
"content_sha256": "ea0f6b7843289d81dc2852327432721f8677e28ad8b41d754abc8c91307303d3",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A06",
"title": "Cadeia de Valor do Arroz por Projecto de Processamento",
"source_record_id": "15474e6a-90a3-4db4-b456-eb1c1c66227c",
"target_record_id": "57a4ee7a-4c07-4e26-b8f5-e07726e41512",
"expected_target_version": 1,
"content_sha256": "c7fae7b2ca541e734e587589dace8dc85dee2494876de6e30ecd91a7177a985d",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A07",
"title": "Parque Têxtil Integrado",
"source_record_id": "22323abb-91d9-43ed-98f3-1194a5250c9e",
"target_record_id": "70ae731e-fdef-473f-b495-14f319b28d60",
"expected_target_version": 1,
"content_sha256": "3eb01ce3dd2cc68b43b816708f7e5f990c48f1aea6555cdfd169a286e11b9bd4",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A08",
"title": "Zona Económica Especial de Mocuba",
"source_record_id": "81d775e5-5dff-4fa2-98b1-72affb0a1082",
"target_record_id": "b30ecd8c-220d-4c7a-b1a7-704dc24d0933",
"expected_target_version": 1,
"content_sha256": "bca089a4bb2601ca34c50e2c48068b4c2f9fa7a873955cf0587f261a83c2a146",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A09",
"title": "Construção da Cidadela Parlamentar de Mocuba",
"source_record_id": "67263220-6849-468f-82f4-d5e1f5617190",
"target_record_id": "dc8892ff-fdda-480c-81f1-2ffe0bfcb40b",
"expected_target_version": 1,
"content_sha256": "7e3bb071f65e49245fbfd070f4123ac49985004e865c475bf7e34c85cc708aea",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A10",
"title": "Mphanda Nkuwa HPP – Hidroeléctrica",
"source_record_id": "cad01a02-6072-4a11-823a-1ae379bc65da",
"target_record_id": "77b685f0-848f-4800-83f8-a29539ed8f31",
"expected_target_version": 1,
"content_sha256": "02dc0fb152908e81b11304f6bc0c2252805ebd2ad1860b1a6bfa918e2cbcd5bb",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A11",
"title": "Corredor Ferroviário e Portuário de Macuse–Moatize",
"source_record_id": "72c13e83-e8dd-465d-99a9-eb0ccaa4fd0b",
"target_record_id": "cb125f84-6f75-48e5-a0de-2f5e6bd537ed",
"expected_target_version": 1,
"content_sha256": "736fc41d941740f41697c579ffe6c4208d45005d7177b7c42f006554a5dde480",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A12",
"title": "Programa de Conectividade e Resiliência Costeira (Compacto II)",
"source_record_id": "a023d6b2-1fa2-4fe7-9709-f93ae1f10e99",
"target_record_id": "71b96599-09c2-4809-b98f-acbf0c2b6f38",
"expected_target_version": 1,
"content_sha256": "9dbdb468b8644e07fabdc943ecde2f11ea561d5174c00559228ed29b2a29b1fe",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A13",
"title": "Vilanculos – Região Integrada de Turismo",
"source_record_id": "bb15487f-1617-49e6-86b7-d617812b658b",
"target_record_id": "5ce2d415-1c84-4625-a4cd-0f6738454318",
"expected_target_version": 1,
"content_sha256": "7a62afdda8e2c3fcc47b1c9032359906ff75dff9b5d56c71ba7d88781a8f8620",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A14",
"title": "Zona Económica Especial de Agronegócio do Limpopo",
"source_record_id": "6d973bb4-ab8a-49bc-92ed-286ed5b96fc4",
"target_record_id": "88111fb4-ab20-4393-bd1b-3a1694fb4ac4",
"expected_target_version": 1,
"content_sha256": "930836392126133499fa69313a4718ce2ec1f6c8f0839c184e9b5cc229460d1c",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "A15",
"title": "Regadio na Bacia Hidrográfica do Rio Maputo",
"source_record_id": "1468b8d2-1b08-4c84-8000-ece7662edbf6",
"target_record_id": "88e37c63-e785-446f-9074-84b000bffa59",
"expected_target_version": 1,
"content_sha256": "d19d27451296b9816351e2d340f2aaff9fabf9732fb580d179e1c69ceb9fc512",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "CLU-01",
"title": "Agro-indústria e segurança alimentar",
"source_record_id": "ca6a1427-0e2b-406e-94bd-da23630d5ec4",
"target_record_id": "0c63d8de-18fd-451f-a7ca-1ea04dd5906c",
"expected_target_version": 1,
"content_sha256": "ccd16f969474dcc23b2ddf27eb4cf3ca090f22e418e0e8f33499f349e884d042",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "CLU-02",
"title": "Energia e industrialização",
"source_record_id": "3cd11616-9099-477c-bf3e-09cddca74053",
"target_record_id": "fc1355f5-1473-4fe2-b3e2-b32d1f0b1042",
"expected_target_version": 1,
"content_sha256": "78c50659068301be0db94e8f4c9e77a20a4a052639dc4553291ff3568d3c0c4a",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "CLU-03",
"title": "Logística, corredores e exportação",
"source_record_id": "ec9494a2-22cc-423e-8a9e-efa1e05ac2b4",
"target_record_id": "99bf7c4c-e23b-47d5-8490-53082384043f",
"expected_target_version": 1,
"content_sha256": "99af7bb35b6769d84bee2175427b3a03027fea65a91dd894338fd7aa72db3820",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "CLU-04",
"title": "Turismo costeiro e economia azul",
"source_record_id": "5f0ff662-dc74-41de-adcd-de784a595321",
"target_record_id": "816b7c26-827b-475a-bf98-647b46afe88b",
"expected_target_version": 1,
"content_sha256": "a75f532e2464dadd13dd2ff815d99acfb2f05d3a0264fcf82dfe8e3db7db3a1f",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "CLU-05",
"title": "Têxtil, vestuário e algodão",
"source_record_id": "b9b1dc01-dca1-42d8-a9aa-40148dccfaf7",
"target_record_id": "8eb7da82-1f1e-442b-9b1e-57b948c3f057",
"expected_target_version": 1,
"content_sha256": "fe2f37be8e3f20ccc35da91aa86872b960e9820f2e0de84200c157072b3c7b11",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "CLU-06",
"title": "Mineração e transformação mineral",
"source_record_id": "0f29da56-b74a-4a69-afaa-b9a0d349580c",
"target_record_id": "65d709f5-20ed-4beb-8cf1-4a7fbd459e8f",
"expected_target_version": 1,
"content_sha256": "097498df28f63b614914cc171e4d58c6154442d0d6625185b3759878829528de",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "CLU-07",
"title": "Tecnologia e serviços digitais",
"source_record_id": "523d2aa1-4c7d-4a84-97fc-220f4e845fd7",
"target_record_id": "a795cde3-3cfe-456b-ba8d-7ff3730024ec",
"expected_target_version": 1,
"content_sha256": "6c5407281d18069e05b84e1e7997d07fd79680e2b0e2a5b0e7d86cbfc3c2ca35",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "CLU-08",
"title": "Financiamento do investimento",
"source_record_id": "ed2ea4e4-fca7-4cc8-bb8c-f99a1dfda73e",
"target_record_id": "05dc87a8-e1ab-41c9-a312-5b14b8ff16ce",
"expected_target_version": 1,
"content_sha256": "f59505944a91a849c27c16455001ad4a1d39aa58e59e8d5403cb0dc197c2faf8",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "COR-01",
"title": "Corredor de Nacala e Norte",
"source_record_id": "dc8f048a-c0bd-476e-9ff2-460dfb12eddc",
"target_record_id": "986af8c5-2f90-40ab-a62a-4c37a5f42e30",
"expected_target_version": 1,
"content_sha256": "26db6621cae0e76d2871f56926062bc0be5bb41e21521d2536655e809b6dff20",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "COR-02",
"title": "Corredor da Beira e Centro",
"source_record_id": "fd5e7b2d-cb48-49e4-bb96-1520263144f2",
"target_record_id": "a7271336-808b-42b4-8bfd-5b49c72dbe2b",
"expected_target_version": 1,
"content_sha256": "0e6b80849fcb0746aa1a53133ee0d5ccc3df8c847243a1134922247ce3d9e1b8",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "COR-03",
"title": "Corredor Zambeze–Macuse",
"source_record_id": "18f3a86c-af85-4fbb-b045-9c3e03c4a610",
"target_record_id": "d9ccddb5-e6aa-4347-a481-37b694013ac1",
"expected_target_version": 1,
"content_sha256": "64c8eba636661e6ebb56e2dd8dd6e978c405dd96c0c7b46bdd62c805018a6c4a",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "COR-04",
"title": "Corredor Maputo–Limpopo",
"source_record_id": "36d72f82-ff0a-468c-89bf-5dc9ae12eddf",
"target_record_id": "ae26d529-5341-4b37-ad08-662c9d09a0cf",
"expected_target_version": 1,
"content_sha256": "ce5b89974e1d2937e4901ab5603245cf2465afbe0a44a224c43f726069cdabd8",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "COR-05",
"title": "Corredor Turístico Inhambane–Bazaruto",
"source_record_id": "06b2d5d7-98ad-48db-b732-8a70b2f5eb4c",
"target_record_id": "69767dcc-4c22-4046-8f81-3797bc44572e",
"expected_target_version": 1,
"content_sha256": "343ba56efeef5514f531cf61126596a8c65f882656da5f95390eb661a0810a7c",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
},
{
"code": "COR-06",
"title": "Corredor Industrial Nacional Norte–Sul",
"source_record_id": "6727e46b-98e1-47a7-be04-dfdb1c6375cb",
"target_record_id": "fb85ebfc-798c-42df-a267-d4b771c443f8",
"expected_target_version": 1,
"content_sha256": "465ff9717def3bad42efb25d1ffa04812f871e8b167adcbb20f68f5ef9460b57",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"approval_evidence": "26/09/2026 — Aprovação expressa do proprietário nesta sessão: inserir a informação do documento upgrade do portal de investimentos v4 programacao sobre clusters, corredores e projectos ancora nas tabelas e criar os caminhos para a sua execução; eu e que aprovo e estou a aprovar.",
"approval_sha256": "0cbc4b7a3f01dfb6c28659a11597f7e10f87f8c3119bf44ea92b97bec033f3eb",
"original_published_at": "2026-09-26 16:22:52+00"
}
]
}
@@ -0,0 +1,25 @@
{
"decision_owner": "Tempo, Lda.",
"decision_date": "2026-10-23",
"configuration": "config/investment_corridors.php",
"functional_revision": "0025309b",
"maputo_final_decision": ["Maputo Província", "Maputo Cidade"],
"automatic_province": {"nacala": "Nampula", "limpopo": "Gaza"},
"existing_territorial_ids_reused": true,
"server_validation": ["corridor and territory", "documented zone compatibility", "actor and dossier access", "draft request ordering", "dossier concurrency"],
"recovery": "Encrypted pending draft in the existing dossier payload, per actor; distinct from confirmed context.",
"qa": {
"database": "simulator_fiscal_delta_20261021_test",
"port": 55441,
"focused_tests": 5,
"assertions": 90,
"existing_opportunity_continuity_tests": "passed",
"types": "passed",
"build": "passed",
"browser": ["Beira offers Sofala and Manica", "Nacala selects Nampula", "Maputo offers both units", "Sofala/Dondo recovers after reload", "normal context confirmation succeeds"],
"browser_account_and_dossier": "synthetic and private, QA only",
"screenshot": "outputs/preservation-inventory-20261023/corridor-adaptive-territory-QA.png"
},
"homologation": {"git_integrated": true, "public_read_check": "Maputo province endpoint returns exactly the two existing units", "real_dossier_test_writes": false},
"installation": {"migrations": 0, "imports": 0, "republication": false, "new_roles": false, "geometry_changes": false, "automatic_fiscal_calculation": false}
}
@@ -0,0 +1,657 @@
{
"scope": "homologation private registration, not publication or editorial acceptance",
"functional_revision": "65eddf6bc7025c81cbd7b0c5918b6ae8bdb1c1f6",
"candidate": "fb4e7d897083957486385aa517969afd1a10b417",
"checked_utc": "2026-10-22T21:54:25+00:00",
"checked_Africa_Johannesburg": "2026-10-22T23:54:25+02:00",
"management_url": "https://teste-investidor.tempo.co.mz/gestao-conteudos",
"catalogue_url": "https://teste-investidor.tempo.co.mz/management/portal-services?state=draft",
"actor_id": 15,
"account": "Osmane Nala",
"real_password_MFA_session": true,
"MFA_fabricated_or_extended": false,
"mechanism": "Existing authenticated HTTPS upload, metadata and editorial endpoints using the transported server originals; no direct SQL data writes",
"archive_retransported": false,
"archive_sha256": "177c50d1cc3b1610e62123a2f8b532711a15f875aac2ee0e372636c2f747e8a2",
"backup_restore": {
"restored_tables": 174,
"files_verified": 341,
"dump_sha256": "8658b5fa0d1ef16c9fc9be90969badde6007443aa474fe4a9377f16d80fe6e92",
"files_archive_sha256": "1d98b6200ffae11bb07dc600daa6416b3b1b90735de42791858a07a0caa63552"
},
"preservation": {
"target": {
"name": "teste_investidor",
"port": 5432
},
"existing_rows_preserved": {
"documents": 32,
"portal_resources": 31,
"portal_resource_revisions": 63,
"portal_resource_links": 19,
"users": 17,
"geo_locations": 1921,
"geo_geometries": 408
},
"grants_preserved": {
"portal_role_assignments": true,
"portal_superuser_pair": true,
"portal_security_approvals": true
},
"new_private_articles": 28,
"new_publications": 0,
"new_originals": 28,
"clean_scans_matching_bytes": 28,
"original_sha256_unchanged": true,
"checked_utc": "2026-10-22T21:54:25+00:00"
},
"rows": [
{
"external_id": "legacy-tempo-post-62413-20170626",
"legacy_id": 62413,
"title": "15/30 costa do sol com dua na zona de mupulene muito lindo",
"source_url": "https://investemoz.tempo.co.mz/1530-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo",
"resource_id": 32,
"document_id": "c20a1729-0a93-4b9e-beab-13b1320f6587",
"sha256": "b471c1afd7235f359acdcc16a93088f77e1f988706c8d3c4d4f11c5d560aea47",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 3,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-73945-20170731",
"legacy_id": 73945,
"title": "Banco Mundial classifica de proibitivos juros praticados em Moçambique",
"source_url": "https://investemoz.tempo.co.mz/banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique",
"resource_id": 33,
"document_id": "5c550542-79c4-4b86-bb12-3db3e8daa631",
"sha256": "2aa0ce0eb305bfdf93e390a978d3694d0fbc0129034077b68cebce418f878415",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-76474-20170808",
"legacy_id": 76474,
"title": "Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador",
"source_url": "https://investemoz.tempo.co.mz/coloque-o-seu-numero-para-o-grupo-de-whatsapp-venda-de-acessorios-de-computador",
"resource_id": 34,
"document_id": "baff8e03-3327-40a0-af01-3dd11d163871",
"sha256": "8f769aec4715449d056c8c25294060b2ff290ec0893c28e9bdcc4e8092fc75f5",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 2,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-62414-20170626",
"legacy_id": 62414,
"title": "Frelimo e Zanu-PF: Evocados laços de irmandade",
"source_url": "https://investemoz.tempo.co.mz/frelimo-e-zanu-pf-evocados-lacos-de-irmandade",
"resource_id": 35,
"document_id": "a5050bd9-e868-4347-9a24-03c2b6c04ab9",
"sha256": "a040c0b7cb95dd7f053f4d13662dd58b2b06453b6fa61a2d531d0257a8db8c17",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-62418-20170626",
"legacy_id": 62418,
"title": "Governo dará todo O apoio à PGR no seguimento da auditoria",
"source_url": "https://investemoz.tempo.co.mz/governo-dara-todo-o-apoio-a-pgr-no-seguimento-da-auditoria",
"resource_id": 36,
"document_id": "c3d4031c-62c8-4bbf-ab6c-193412036888",
"sha256": "e8ccafa68f0d1aa80f2e41d9e09f7b13e7c653a8472a731798cfd5e04ce2963e",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-75002-20170804",
"legacy_id": 75002,
"title": "Governo pretende construir 100 mil habitações em dois anos",
"source_url": "https://investemoz.tempo.co.mz/governo-pretende-construir-100-mil-habitacoes-em-dois-anos",
"resource_id": 37,
"document_id": "97eeceb3-f61e-4980-a884-3228f4707af8",
"sha256": "7b6fbd998be2b47b96e9a4724560c192c502709fa308d6590c0797ddcdb10544",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-73246-20170728",
"legacy_id": 73246,
"title": "Rofino Licuco preso cinco meses depois de condenado por agressão",
"source_url": "https://investemoz.tempo.co.mz/rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao",
"resource_id": 38,
"document_id": "409b9017-d89e-42b3-a7ec-741f2f1f7683",
"sha256": "430ee8674c71104fc126bed2911d676f150ac623857a1ada75662987fd9ac390",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-77232-20170811",
"legacy_id": 77232,
"title": "Sete indivíduos mortos a tiro na Matola",
"source_url": "https://investemoz.tempo.co.mz/sete-individuos-mortos-a-tiro-na-matola",
"resource_id": 39,
"document_id": "5d0a813f-9001-4d04-9b84-865977c2f1f2",
"sha256": "27544d3127803b7495bef9fd633147d0225d8c31816c4d59ed05a2edd59de070",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-62416-20170626",
"legacy_id": 62416,
"title": "Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia",
"source_url": "https://investemoz.tempo.co.mz/sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india",
"resource_id": 40,
"document_id": "3856ae7f-be39-4926-b653-cfd67aeaf003",
"sha256": "ac575ce340571192552c89b63f0bd62a84dbc47828e6930133af5ff70e249319",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-62929-20170627",
"legacy_id": 62929,
"title": "Daúde Razaque já não é treinador da Liga Desportiva de Maputo",
"source_url": "https://investemoz.tempo.co.mz/daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo",
"resource_id": 41,
"document_id": "8f8b749d-1a2b-4e87-93b9-f89a70bdb6a8",
"sha256": "488017b062c6760659d9147b7f12aea4afd8d824121adb9462e2c7a2ae58437b",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-62649-20170626",
"legacy_id": 62649,
"title": "Daviz Simango não se incomoda com possível sucessão na Beira",
"source_url": "https://investemoz.tempo.co.mz/daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira",
"resource_id": 42,
"document_id": "3060923e-c1c0-4b9c-bafb-15f61d53fcc9",
"sha256": "38a858713472759a2d20a308bdd9d8afa9cfb76dcaf8d11ca709e89261573e42",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-62739-20170626",
"legacy_id": 62739,
"title": "“Exigimos responsabilização dos agentes do crime”, Daviz Simango",
"source_url": "https://investemoz.tempo.co.mz/exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango-2",
"resource_id": 43,
"document_id": "674b3cbf-d7ff-4521-8650-b420837dbdd5",
"sha256": "5870fc0fad9bb7af537b7b1468151cde138b1b886ce846c7be25647b630245dd",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-62854-20170627",
"legacy_id": 62854,
"title": "Governo e parceiros reforçam mecanismos de controlo de HIV/Sida",
"source_url": "https://investemoz.tempo.co.mz/governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida",
"resource_id": 44,
"document_id": "a2469350-35d7-4d70-8574-a46975360016",
"sha256": "44b1ba9d593bb625cf53de8909e78eb0b3129742c3ec9d58ec68c984e8930bce",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-63128-20170627",
"legacy_id": 63128,
"title": "Graça Machel diz que desnutrição é um problema de desenvolvimento",
"source_url": "https://investemoz.tempo.co.mz/graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento",
"resource_id": 45,
"document_id": "f07797a0-4dcc-4706-acfd-2424b6bd6130",
"sha256": "74be8f29e5053f53ab1a39a2f63208145c30f23357ca6d78b637dd02bf9c1fb4",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-63181-20170627",
"legacy_id": 63181,
"title": "In dependência",
"source_url": "https://investemoz.tempo.co.mz/in-dependencia",
"resource_id": 46,
"document_id": "34d11ba7-086e-4290-9181-0c6adebc6658",
"sha256": "3d0f9ac14d36156d8178e33f8616d6406f31ea4cd69c8308cbf4227586d7ccb3",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-63146-20170627",
"legacy_id": 63146,
"title": "Kroll não descobriu como foram gastos 2 biliões de dólares; Governo de Nyusi não apoiou a Auditoria; criação da Proindicus, EMATUM e MAM não foi para proteção da Zona Económica Exclusiva",
"source_url": "https://investemoz.tempo.co.mz/kroll-nao-descobriu-como-foram-gastos-2-bilioes-de-dolares-governo-de-nyusi-nao-apoiou-a-auditoria-criacao-da-proindicus-ematum-e-mam-nao-foi-para-protecao-da-zona-economica-exclusiva-2",
"resource_id": 47,
"document_id": "27d98ca7-b59f-478f-8560-a51db4354069",
"sha256": "542353466cc6d82b651619c495f138b0576a4be41d21aad194ae2005050cb1bc",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-62688-20170626",
"legacy_id": 62688,
"title": "O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ...",
"source_url": "https://investemoz.tempo.co.mz/o-instituto-nacional-de-meteorologia-preve-o-seguinte-estado-do-tempo-para-esta-29",
"resource_id": 48,
"document_id": "200a6292-c01b-4c83-bf3c-959379676651",
"sha256": "a210a789b06d425822f4124f74226a2b27246c086c5ec5f041f1b2237d7c2b65",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-63248-20170628",
"legacy_id": 63248,
"title": "Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (...",
"source_url": "https://investemoz.tempo.co.mz/dois-alunos-da-9a-classe-cairam-nas-maos-da-policia-da-republica-de-mocambique",
"resource_id": 49,
"document_id": "fc19fc89-4589-48b3-8328-9398ad367650",
"sha256": "6c30e61197b8568332af6d9b19bbba7ad8665b3873bb031a8c8aedd41536b060",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-173220-20260616",
"legacy_id": 173220,
"title": "Alumínio “Verde”",
"source_url": "https://investemoz.tempo.co.mz/aluminio-verde",
"resource_id": 50,
"document_id": "9b3b5f7e-904e-4ac0-a389-b93fbc4f5ef6",
"sha256": "5b76c3d84dcf7f9a489686d90e3857ae6536705c918e841310bb42b354e80976",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-173222-20260616",
"legacy_id": 173222,
"title": "Energia e Recursos Naturais",
"source_url": "https://investemoz.tempo.co.mz/energia-recursos-naturais",
"resource_id": 51,
"document_id": "7a4a544f-8159-47e7-b69c-b7a83f8324b1",
"sha256": "e64d7063d1ac4dda028c97e1ba64938d2a9e426a0b630c57ee5df52a41312cc7",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-173482-20260915",
"legacy_id": 173482,
"title": "Checklist para Contratação e Direitos do Trabalho Doméstico",
"source_url": "https://investemoz.tempo.co.mz/checklist-para-contratacao-e-direitos-do-trabalho-domestico",
"resource_id": 52,
"document_id": "bbe4154b-c1d1-4ab3-8a36-92c4764df0a3",
"sha256": "6f888e133a779c719073246f89bcae150198e5897c0e7d9b7ba75f54c54a7830",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-173484-20260915",
"legacy_id": 173484,
"title": "Direitos Especiais da Trabalhadora Doméstica no Regulamento",
"source_url": "https://investemoz.tempo.co.mz/direitos-especiais-da-trabalhadora-domestica-no-regulamento",
"resource_id": 53,
"document_id": "712ed069-72de-4cab-bc81-6d589aa22cb9",
"sha256": "297df455a9c6fd1f0ab7ca7bbe124ce483c86fe55be26baa695f03089b3ac049",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-173478-20260915",
"legacy_id": 173478,
"title": "Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico",
"source_url": "https://investemoz.tempo.co.mz/guia-pratico-para-empregadores-sobre-contratacao-e-direitos-no-trabalho-domestico",
"resource_id": 54,
"document_id": "ba35f2e7-3d75-4dfc-b2e8-3e18425419ec",
"sha256": "d4e320ed99dd9d53d205e47932f73651976d43081d5d39f2bfc2996901408644",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-173480-20260915",
"legacy_id": 173480,
"title": "Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias",
"source_url": "https://investemoz.tempo.co.mz/modelo-de-contrato-de-trabalho-domestico-para-pequenas-familias",
"resource_id": 55,
"document_id": "e48a87d1-36fd-4e03-aece-a5184e390eff",
"sha256": "c3ee6401eda5b582c61969b5e3b74fdf26ef34ca481b1aca8c4c309d845147ae",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-173476-20260915",
"legacy_id": 173476,
"title": "Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique",
"source_url": "https://investemoz.tempo.co.mz/procedimentos-para-rescisao-do-contrato-de-trabalho-domestico-segundo-o-regulamento-de-mocambique",
"resource_id": 56,
"document_id": "57dd9068-c5c1-406a-bbc1-d0fdb79f038e",
"sha256": "72fbf28391db4804e0637b64e7f59e9fa597812a2681b4562dc3d6dfb4093a30",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-173470-20260915",
"legacy_id": 173470,
"title": "Direitos e Deveres do Trabalhador Doméstico",
"source_url": "https://investemoz.tempo.co.mz/direitos-e-deveres-do-trabalhador-domestico",
"resource_id": 57,
"document_id": "de254617-49c2-407d-9e3c-e466488dd46b",
"sha256": "26feeae6b8d04972c7a64ee360583cccdcaeb4b0d8795fd7bc2fd3c38866cc19",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-173474-20260915",
"legacy_id": 173474,
"title": "Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique",
"source_url": "https://investemoz.tempo.co.mz/sancoes-disciplinares-aplicaveis-a-trabalhadores-domesticos-segundo-o-regulamento-de-mocambique",
"resource_id": 58,
"document_id": "17e4a9cb-286a-4c87-a5bc-9f1e91a5da44",
"sha256": "9fa741a17b746bfa2f3ce7b6ce1d2bb34d3a35d3b58330b0554f9e0a6844f049",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
},
{
"external_id": "legacy-tempo-post-173463-20260915",
"legacy_id": 173463,
"title": "Regulamento do Trabalho Doméstico",
"source_url": "https://investemoz.tempo.co.mz/regulamento-do-trabalho-domestico",
"resource_id": 59,
"document_id": "20ce1dd9-729f-458f-b650-f5eb55c56d60",
"sha256": "4f34b7bac4b3030c0614844d379f6e3cfad1b7f6ea3db575a58c33ae033b0e73",
"scan": "clean",
"scanned_sha256_matches": true,
"private": true,
"metadata_version": 1,
"search_http": 200,
"edit_http": 200,
"preview_http": 200,
"anonymous_article_http": 404,
"image_href": "/documentos/27/view",
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"edition_recovered": true
}
],
"UI_demonstration": {
"management_search": "15/30",
"resource_id": 32,
"save_and_recover_version": 3,
"body_changed_in_destination_UI": false,
"private_preview": true,
"qa_note_preserved_for_team_review": true
},
"public20_HTTP_repeated": false,
"new_publications": 0,
"QA_tests_repeated": false,
"new_roles_or_approvers": false,
"unresolved_originals": 2,
"inline_image_references_preserved": 16,
"existing_original_image_reused_by_exact_hash": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa",
"anchor_projects_and_empty_portfolio": "Separate failure; cause remains unconfirmed; not resolved by this delivery",
"user_review_of_commit_package_or_guide_claimed": false,
"private_delivery_executor_sha256": "308ac6e0c5deb99e4176af5891e8e084aa327864b460d5d523931c6e2379691c",
"private_verifier_sha256": "a669324009315e44271d5d536a08a4049e9e2ba68d1a3f52f3a0921e5a3a0fb1"
}
@@ -0,0 +1,935 @@
{
"date": "2026-10-23",
"operation": "Inventory before further acceptance tests; no active data changed",
"baseline_commit": "37a8eb015ac5022fd34bcd89cfe47c9fc61903b0",
"existing_43_components": [
{
"number": 1,
"component": "Documentos públicos",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Disponível: 29 recursos públicos; recibo editorial 22/10. Os 20 artigos conservam a aceitação anterior.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/documentos) · 29 fichas privadas; zero publicação adicional. Consulta pública do acervo permanece fechada."
},
{
"number": 2,
"component": "Ficha integral dos parques",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Disponibilizado localmente em 18/10; destino conserva 16 fichas, 8 publicadas. Recorte integral não é reaprovado por este inventário.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/zonas) · 16 fichas privadas/pendentes, 19 relações territoriais; publicação e gestão autorizada separadas."
},
{
"number": 3,
"component": "Navegação contextual e manifestação de interesse",
"historic_status": "Disponível",
"current_preservation_status": "Navegação/percurso preservados; carteira documental reposta em 23/10: 29 dossiers, incluindo 15 projectos âncora.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/investimentos/iniciar) · Início, contexto e navegação abrem; gravação/recuperação aceites em QA reutilizadas. Sem dossier real no destino."
},
{
"number": 4,
"component": "Referências económicas — lote mínimo",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Código e referências presentes; manter o âmbito da autorização anterior, sem inferir publicação de todas as opções.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/management/investment/references) · 11 actividades presentes; cinco novas referências transportadas. Activação/publicação do lote não executada."
},
{
"number": 5,
"component": "Sectores e duplicação visual",
"historic_status": "Disponível",
"current_preservation_status": "Entrega de 18/10 conservada no código/histórico; sem remoção constatada nesta leitura.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/sectores) · Ecrã aberto: dez sectores principais, especialização Fintech sem cartão principal duplicado; 12 registos conservados."
},
{
"number": 6,
"component": "Duplicados distintos — deteção e consolidação",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/management/sector-reconciliation) · Código presente; consolidação de registos distintos não demonstrada no destino."
},
{
"number": 7,
"component": "Fintech — enquadramento específico",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Fintech público no lote aceite; especialização preservada. Não reabrir a organização sectorial aprovada.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/sectores/mercado-financeiro/fintech) · Código instalado; artigo de origem permanece privado, sem publicação adicional."
},
{
"number": 8,
"component": "Legado — conteúdo restante",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "20 artigos públicos e 28 privados cadastrados no destino; dois originais incompletos. Recibo 37a8eb01.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/sectores) · Adaptador habilitado; artigos/imagens transportados privadamente, sem os publicar."
},
{
"number": 9,
"component": "Piloto agronegócio",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Piloto Agronegócio concluído: artigo e imagem preservados; não é uma oportunidade empresarial concreta.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/sectores) · Originais privados; seis oportunidades sintéticas excluídas. Nenhuma oportunidade real publicada."
},
{
"number": 10,
"component": "Percurso do investidor — 19 etapas",
"historic_status": "Disponível",
"current_preservation_status": "Percurso e preparação privada habilitados no destino; entrega adaptativa de 22/10. Zero dossiers pessoais não é perda de função.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/investimentos) · Início e lista própria abrem; definição de 19 etapas instalada. Não repetidas as 19 etapas aceites."
},
{
"number": 11,
"component": "Fiscal/contributivo e exportações",
"historic_status": "Não demonstrado",
"current_preservation_status": "Tesouraria/exportações e consumidor IVA têm entregas delimitadas em 21–22/10; restantes variantes não promovidas a concluídas.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Formulário aberto; cenários fiscais/contributivos/exportação e parâmetros efectivos não certificados nesta execução."
},
{
"number": 12,
"component": "Negócios existentes e classificação",
"historic_status": "Disponível",
"current_preservation_status": "Módulo habilitado e fluxos conservados. Ausência de anúncios não demonstra desaparecimento de código.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/negocios) · Catálogo abre e módulo habilitado; zero negócios copiados. Gestão própria sujeita às permissões existentes."
},
{
"number": 13,
"component": "Negócios similares",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/negocios) · Código instalado; comparação com negócios reais não demonstrada."
},
{
"number": 14,
"component": "Importação de empresas/empreendimentos",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/management/negocios) · Mecanismo presente; nenhuma empresa/transacção local ou QA transferida. Operador de gestão por definir."
},
{
"number": 15,
"component": "Fundos",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Fontes instaladas; critérios específicos de fundos não demonstrados no destino."
},
{
"number": 16,
"component": "Comparador societário e modelos",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Fontes instaladas; comparação societária/modelos não demonstrados nesta execução."
},
{
"number": 17,
"component": "Capitalização/private equity e Bolsa",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Fontes instaladas; cenários específicos de capitalização/Bolsa não demonstrados no destino."
},
{
"number": 18,
"component": "Checklists versionadas",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/servicos) · Definições presentes; checklist aplicada a dossier legítimo continua por demonstrar."
},
{
"number": 19,
"component": "Indicadores de utilização",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/dashboard) · Código presente; indicadores com dados reais e permissões adequadas não demonstrados."
},
{
"number": 20,
"component": "Jornadas educativas",
"historic_status": "Disponível",
"current_preservation_status": "Jornadas habilitadas; cartões educativos disponibilizados. Mantido o âmbito parcial da educação.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/educacao) · Área abre e flag habilitada; nenhum percurso educativo completo foi repetido."
},
{
"number": 21,
"component": "Partilha documental individual e variantes de sala",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/parcerias/painel) · Estruturas de salas/partilha instaladas; participantes, consentimentos e partilha real não demonstrados."
},
{
"number": 22,
"component": "Restauro, modalidades e SLA",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/painel) · Backup/restauro coberto separadamente; modalidades/SLA não homologados. Escalonamento continua desligado como local."
},
{
"number": 23,
"component": "Cartografia e consumidores territoriais restantes",
"historic_status": "Não demonstrado",
"current_preservation_status": "Demarcação reposta: 408 geometrias. Polígonos de localidades e correspondências já pendentes não são nova regressão.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Catálogos/mapas abrem. 1 921 referências geográficas no alvo versus 1 990 locais; diferença não reconciliada por item fora do manifesto."
},
{
"number": 24,
"component": "Acessibilidade e restantes consumidores",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Mensagens R2 preservadas; não se declara certificação integral de acessibilidade de todos os módulos."
},
{
"number": 25,
"component": "Fechos de operação/avaliação documental",
"historic_status": "Não demonstrado",
"current_preservation_status": "Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/painel) · Sem processo operacional legítimo para demonstrar fecho/avaliação documental."
},
{
"number": 26,
"component": "Conta simples, login e MFA privilegiado",
"historic_status": "Disponível",
"current_preservation_status": "Login/MFA e designações reais documentados; sem alteração de papéis nesta passagem.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/login) · Login e desafio MFA reais concluídos; conta simples R2 e controlos privilegiados preservados."
},
{
"number": 27,
"component": "Manifestação simples, recibo e acompanhamento do interessado — R2",
"historic_status": "Disponível",
"current_preservation_status": "R2 e percursos posteriores conservados; reutilizar as provas aceites.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/investidor/manifestacoes) · Recorte R2 conservado, com provas aceites reutilizadas; nenhuma manifestação fictícia criada."
},
{
"number": 28,
"component": "Pesquisa — estados do recorte R2",
"historic_status": "Disponível",
"current_preservation_status": "Pesquisa e selectores corrigidos em 22/10; a carteira vazia é tratada como perda separada.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Catálogos abrem; quatro estados e protecção contra respostas antigas preservados do R2, sem repetir ensaios aceites."
},
{
"number": 29,
"component": "Biblioteca privada própria, scanner e recuperação — DOC01",
"historic_status": "Disponível",
"current_preservation_status": "Biblioteca, scan e recuperação disponíveis: 59 recursos, 29 públicos e 30 privados.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/management/portal-services) · Conta de custódia vê 30 ficheiros limpos. Novo original recuperado no navegador com SHA-256 igual à fonte; sem gestão global."
},
{
"number": 30,
"component": "Backup/restauro e reversão do recorte R2 + DOC01",
"historic_status": "Disponível",
"current_preservation_status": "Backup/restauro 22/10 documentado: 174 tabelas. Reposição activa terá backup próprio antes da escrita.",
"evidence": "Backup fresco consistente: 144 tabelas restauradas iguais, 34 ficheiros/configuração conferidos, recuperação portável e metadados Linux/PG protegidos. Reversão de apresentação preparada."
},
{
"number": 31,
"component": "Balcão Virtual",
"historic_status": "Disponível",
"current_preservation_status": "Balcão e definições instalados; zero casos reais no destino não é perda de funcionalidade.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/painel) · Painel e serviço existente abrem; dez tabelas base instaladas, definição interna project-preparation v5 transportada."
},
{
"number": 32,
"component": "Vínculo positivo e recuperação do dossier",
"historic_status": "Não demonstrado",
"current_preservation_status": "Recuperação de contexto demonstrada em QA nas entregas posteriores; ausência de caso real não reabre a prova aceite.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/investimentos) · Vínculo documental positivo pendente: zero dossiers da conta no destino. Não foram criados dados fictícios."
},
{
"number": 33,
"component": "Cadastro canónico e recursos de oportunidade",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Cadastro e recursos disponibilizados; 30 oportunidades com resumos em preparação publicados.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/management/opportunities) · Editor/schema instalados; zero oportunidades. Gestão/revisão exigem atribuições existentes ainda não configuradas."
},
{
"number": 34,
"component": "Perfis, revisão independente e publicação",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Perfis e atribuições existentes preservados; inventário não cria decisão organizacional nova.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/perfis/gestao) · Schema e fluxos presentes; zero atribuições/titulares. Nenhum papel ou privilégio concedido automaticamente."
},
{
"number": 35,
"component": "Bolsa de parcerias e salas internas",
"historic_status": "Disponível",
"current_preservation_status": "Bolsa e percursos existentes preservados; variantes com participantes reais mantêm saldo próprio.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/parcerias) · Catálogo e mapa abrem, nove tabelas de relações/salas instaladas; colaboração com participantes reais não demonstrada."
},
{
"number": 36,
"component": "Onde se localiza / associações territoriais e produtivas",
"historic_status": "Ausente",
"current_preservation_status": "Estado Ausente superado: integração territorial entregue em 20–22/10; catálogos e 408 limites conservados.",
"evidence": "Harmonização territorial apenas QA, expressamente excluída da revisão autorizada."
},
{
"number": 37,
"component": "Lote privado Inhambane —30 fichas",
"historic_status": "Ausente",
"current_preservation_status": "Estado Ausente superado: 30 fichas Inhambane transportadas e resumos divulgados em 22/10.",
"evidence": "30 fichas Inhambane apenas QA, não importadas nem publicadas no destino."
},
{
"number": 38,
"component": "Enquadramento das12 fichas de programas/carteira",
"historic_status": "Ausente",
"current_preservation_status": "Estado Ausente superado: enquadramento de 11 programas e uma carteira incluído na entrega posterior.",
"evidence": "Enquadramento das 12 fichas permanece no incremento QA separado."
},
{
"number": 39,
"component": "Originais partilhados e referência documental no dossier — Inhambane",
"historic_status": "Ausente",
"current_preservation_status": "Estado Ausente superado: originais privados/referências e contexto incluídos na entrega posterior; não reimportar.",
"evidence": "Reutilização documental Inhambane/dossier permanece no incremento QA separado."
},
{
"number": 40,
"component": "Orientação assistida/IA",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Sem regressão demonstrada: integração externa não fechada; não inventar credencial nem activar fornecedor.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/management/ai) · Código presente; integração desligada. Credencial própria do destino/chamada externa não confirmadas."
},
{
"number": 41,
"component": "Integração externa SuiteCRM",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Desabilitada também no local por opção anterior; não desapareceu por efeito da entrega editorial.",
"evidence": "Permanece desligada como na versão local; nenhuma credencial ou envio externo copiado/executado."
},
{
"number": 42,
"component": "Operação administrativa e resposta da equipa na homologação",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Estado antigo superado: conta real e gestão autorizada demonstradas nas entregas posteriores. Sem novos papéis.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/management/interests) · Nenhuma conta com gestão global/atribuições operacionais. Custódia documental não autoriza resposta/revisão da equipa."
},
{
"number": 43,
"component": "Gestão editorial da biblioteca",
"historic_status": "Instalado mas desabilitado",
"current_preservation_status": "Gestão autónoma entregue; edição, prévia, gravação e recuperação dos 28 privados demonstradas no destino.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/management/portal-services) · Schema editorial instalado; publicação/edição pública não concedida à conta de custódia."
}
],
"existing_executable_surfaces": [
{
"surface": "------------------------------",
"component": "-------------------------------------------",
"routes": "-------------------------------------------------------------------------",
"accepted_evidence": "---------------------------------------------------------",
"code_files": []
},
{
"surface": "Início",
"component": "`PortalInvestidor`",
"routes": "`/`, APIs existentes de homepage",
"accepted_evidence": "`PublicPortalNavigationTest`, navegador",
"code_files": []
},
{
"surface": "Catálogo / Educação",
"component": "`investment/catalogue`",
"routes": "`/oportunidades`, `/educacao`; `/api/v1/investment/search`",
"accepted_evidence": "`InvestmentUnificationTest`",
"code_files": [
{
"path": "resources\\js\\pages\\investment\\catalogue.tsx",
"exists": true
}
]
},
{
"surface": "Cluster / Corredor / Âncora",
"component": "`portfolio/index`, `portfolio/show`",
"routes": "`/clusters`, `/corredores`, `/projectos-ancora`, `/carteira/{id}`",
"accepted_evidence": "`InvestmentPortfolioTest`, testes territoriais",
"code_files": [
{
"path": "resources\\js\\pages\\portfolio\\index.tsx",
"exists": true
},
{
"path": "resources\\js\\pages\\portfolio\\show.tsx",
"exists": true
}
]
},
{
"surface": "Ficha",
"component": "`investment/detail`",
"routes": "`/oportunidades/{slug}`; `/api/v1/investment/opportunities/{slug}`",
"accepted_evidence": "`PublicPortalNavigationTest`, `InvestmentUnificationTest`",
"code_files": [
{
"path": "resources\\js\\pages\\investment\\detail.tsx",
"exists": true
}
]
},
{
"surface": "Mapa",
"component": "Componente `Map` em catálogo",
"routes": "`/api/v1/investment/map`",
"accepted_evidence": "Teste PostGIS e estados vazios",
"code_files": []
},
{
"surface": "Comparar / exportar / sugerir",
"component": "`investment/catalogue`",
"routes": "`/compare`, `/export`, `/suggest` sob prefixo da API",
"accepted_evidence": "Teste de publicação e fórmula CSV",
"code_files": [
{
"path": "resources\\js\\pages\\investment\\catalogue.tsx",
"exists": true
}
]
},
{
"surface": "Área do investidor",
"component": "`investment/workspace`",
"routes": "`/investidor/manifestacoes`; `/api/v1/investment/submissions`",
"accepted_evidence": "Isolamento por dono",
"code_files": [
{
"path": "resources\\js\\pages\\investment\\workspace.tsx",
"exists": true
}
]
},
{
"surface": "Perfil / empresas",
"component": "`investment/profile`",
"routes": "`/investidor/profile`; API `/profile`, `/companies/{id?}`",
"accepted_evidence": "`InvestmentWorkspaceTest` e navegador",
"code_files": [
{
"path": "resources\\js\\pages\\investment\\profile.tsx",
"exists": true
}
]
},
{
"surface": "Conversa / versões",
"component": "`investment/conversation`",
"routes": "API `/submissions/{id}/messages`, `/submissions/{id}/revisions/{version}`",
"accepted_evidence": "Testes de isolamento, encriptação e reenvio; navegador",
"code_files": [
{
"path": "resources\\js\\pages\\investment\\conversation.tsx",
"exists": true
}
]
},
{
"surface": "Notificações",
"component": "`investment/notifications`",
"routes": "`/investidor/notifications`; API `/notifications`, `/{id}/read`",
"accepted_evidence": "Testes de mudança de estado e leitura; navegador",
"code_files": [
{
"path": "resources\\js\\pages\\investment\\notifications.tsx",
"exists": true
}
]
},
{
"surface": "Manifestação",
"component": "`investment/submission`",
"routes": "`PUT /submissions/{id}`, `POST /submissions/{id}/submit`",
"accepted_evidence": "Testes de conflito, validação e reenvio",
"code_files": [
{
"path": "resources\\js\\pages\\investment\\submission.tsx",
"exists": true
}
]
},
{
"surface": "Anexos",
"component": "Etapa 4 da manifestação",
"routes": "`/submissions/{id}/attachments`",
"accepted_evidence": "Teste de anexo privado e adulteração",
"code_files": []
},
{
"surface": "Contexto da oportunidade",
"component": "`investment/context`",
"routes": "`/management/opportunities/{id}/context`",
"accepted_evidence": "Teste de gestão, conflito e educação",
"code_files": [
{
"path": "resources\\js\\pages\\investment\\context.tsx",
"exists": true
}
]
},
{
"surface": "Referências e formulários",
"component": "`investment/references`",
"routes": "`/management/investment/references`",
"accepted_evidence": "Teste de referências e reexecução do seed",
"code_files": [
{
"path": "resources\\js\\pages\\investment\\references.tsx",
"exists": true
}
]
},
{
"surface": "Atendimento / CRM",
"component": "`management/interest`, gestão CRM existente",
"routes": "`/management/interests/{id}`",
"accepted_evidence": "Testes de intake e CRM existentes",
"code_files": [
{
"path": "resources\\js\\pages\\management\\interest.tsx",
"exists": true
}
]
},
{
"surface": "Apoio / documentos / parcerias",
"component": "`portal/services`, `portal/manage`",
"routes": "`/apoio`, `/documentos`, `/parcerias`, `/balcao-virtual`",
"accepted_evidence": "`PublicPortalServicesTest`",
"code_files": [
{
"path": "resources\\js\\pages\\portal\\services.tsx",
"exists": true
},
{
"path": "resources\\js\\pages\\portal\\manage.tsx",
"exists": true
}
]
}
],
"additional_approved_increment": "Concursos e anúncios: instalado e habilitado em 22/10; gestão autorizada e consulta, sem anúncio real publicado.",
"source_inventory_sha256": {
"local": "135bdc35b23d05e239f9c44ef9762af11111c880b4ef78faaacb63ebeb9dfdc2",
"qa": "632a488d2a0a7841babceb2242f6be61d534b54b64958db0d639185aabb80104",
"homologation": "a247f521b512654206a1fbf4fde03a46233d8e2d98122d119417bc0a2f70df23"
},
"confirmed_loss": {
"portfolio_and_anchor_visibility": {
"expected_published": 29,
"current_target_published": 0,
"records_present": 29,
"deletion_claimed": false,
"local_QA_content_source_matches": 29,
"target_hash_match": 29,
"recovery_status": "restored in QA and homologation",
"target_visible_after": 29
}
},
"historic_change": {
"commit": "e65cb26901a5ca18862134b20e4c17b1f1003ec2",
"date": "2026-10-06",
"change": "Removed portfolio:import --approval and document_owner publication path; import now creates drafts",
"does_not_prove_date_of_disappearance_from_particular_address": true
},
"qa_tests_run": false,
"facts_before_recovery": {
"local": {
"dossiers": 29,
"portfolio_visible": 29,
"projects": 16,
"clusters": 8,
"corridors": 6,
"resources": 29,
"geometries": 0
},
"qa": {
"dossiers": 29,
"portfolio_visible": 0,
"projects": 16,
"clusters": 8,
"corridors": 6,
"resources": 61,
"geometries": 408
},
"homologation": {
"dossiers": 29,
"portfolio_visible": 0,
"projects": 16,
"clusters": 8,
"corridors": 6,
"resources": 59,
"geometries": 408
}
},
"inventory_data_writes": 0,
"qa_recovery": {
"database": {
"name": "simulator_fiscal_delta_20261021_test",
"port": 55441
},
"qa": true,
"mode": "applied",
"manifest_sha256": "8d07007a2e1e8758d4741b4ac594f78d5943f71ad78b2daae7f85aefa9d2de4a",
"preview_sha256": "fbb9ba70df67ef349cb673a683f051f21a8ae62d192f09fc35f2abac7c45b35d",
"scope": 29,
"restored": 29,
"visible": 29,
"data_content_changed": false,
"new_dossiers_imported": 0,
"fake_editor_or_reviewer_assigned": false,
"plan": [
{
"id": "9871a8c0-d562-420b-a8f7-174c95db93f0",
"code": "A01",
"version": 1,
"status": "draft",
"content_sha256": "2adcbe741777d4352c47eb31281dc6b2e2d04903fcfd3e59778ddff4e1342977",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "64b824a0-3527-4024-a1a2-5234f5b4caaa",
"code": "A02",
"version": 1,
"status": "draft",
"content_sha256": "3ad808813909f1475f44a5fcf2a4e50c5d01e25ad8ea39d906c52519532cf0ee",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "6c03e980-c455-49cc-a3be-99d29014e91d",
"code": "A03",
"version": 1,
"status": "draft",
"content_sha256": "75266ff89da58e4d6e5422e49e4641c62dae4f171fa358b70e210c5883a1fd07",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "8bd83cc4-b36c-46cd-9287-b47e1162b578",
"code": "A04",
"version": 1,
"status": "draft",
"content_sha256": "f6a63e2ee2f2e7c98f1030d206996ad57b0d92129d021ed3c6bb53f161d56f5b",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "d8a88bac-4684-43fa-aea6-e54fef9b8a47",
"code": "A05",
"version": 1,
"status": "draft",
"content_sha256": "ea0f6b7843289d81dc2852327432721f8677e28ad8b41d754abc8c91307303d3",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "57a4ee7a-4c07-4e26-b8f5-e07726e41512",
"code": "A06",
"version": 1,
"status": "draft",
"content_sha256": "c7fae7b2ca541e734e587589dace8dc85dee2494876de6e30ecd91a7177a985d",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "70ae731e-fdef-473f-b495-14f319b28d60",
"code": "A07",
"version": 1,
"status": "draft",
"content_sha256": "3eb01ce3dd2cc68b43b816708f7e5f990c48f1aea6555cdfd169a286e11b9bd4",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "b30ecd8c-220d-4c7a-b1a7-704dc24d0933",
"code": "A08",
"version": 1,
"status": "draft",
"content_sha256": "bca089a4bb2601ca34c50e2c48068b4c2f9fa7a873955cf0587f261a83c2a146",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "dc8892ff-fdda-480c-81f1-2ffe0bfcb40b",
"code": "A09",
"version": 1,
"status": "draft",
"content_sha256": "7e3bb071f65e49245fbfd070f4123ac49985004e865c475bf7e34c85cc708aea",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "77b685f0-848f-4800-83f8-a29539ed8f31",
"code": "A10",
"version": 1,
"status": "draft",
"content_sha256": "02dc0fb152908e81b11304f6bc0c2252805ebd2ad1860b1a6bfa918e2cbcd5bb",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "cb125f84-6f75-48e5-a0de-2f5e6bd537ed",
"code": "A11",
"version": 1,
"status": "draft",
"content_sha256": "736fc41d941740f41697c579ffe6c4208d45005d7177b7c42f006554a5dde480",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "71b96599-09c2-4809-b98f-acbf0c2b6f38",
"code": "A12",
"version": 1,
"status": "draft",
"content_sha256": "9dbdb468b8644e07fabdc943ecde2f11ea561d5174c00559228ed29b2a29b1fe",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "5ce2d415-1c84-4625-a4cd-0f6738454318",
"code": "A13",
"version": 1,
"status": "draft",
"content_sha256": "7a62afdda8e2c3fcc47b1c9032359906ff75dff9b5d56c71ba7d88781a8f8620",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "88111fb4-ab20-4393-bd1b-3a1694fb4ac4",
"code": "A14",
"version": 1,
"status": "draft",
"content_sha256": "930836392126133499fa69313a4718ce2ec1f6c8f0839c184e9b5cc229460d1c",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "88e37c63-e785-446f-9074-84b000bffa59",
"code": "A15",
"version": 1,
"status": "draft",
"content_sha256": "d19d27451296b9816351e2d340f2aaff9fabf9732fb580d179e1c69ceb9fc512",
"source_sha256": "4919cd8aae6230e576947b38e5ff839b2661166fb2a8598bea1d662f15bd170a",
"already_restored": false
},
{
"id": "0c63d8de-18fd-451f-a7ca-1ea04dd5906c",
"code": "CLU-01",
"version": 1,
"status": "draft",
"content_sha256": "ccd16f969474dcc23b2ddf27eb4cf3ca090f22e418e0e8f33499f349e884d042",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"already_restored": false
},
{
"id": "fc1355f5-1473-4fe2-b3e2-b32d1f0b1042",
"code": "CLU-02",
"version": 1,
"status": "draft",
"content_sha256": "78c50659068301be0db94e8f4c9e77a20a4a052639dc4553291ff3568d3c0c4a",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"already_restored": false
},
{
"id": "99bf7c4c-e23b-47d5-8490-53082384043f",
"code": "CLU-03",
"version": 1,
"status": "draft",
"content_sha256": "99af7bb35b6769d84bee2175427b3a03027fea65a91dd894338fd7aa72db3820",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"already_restored": false
},
{
"id": "816b7c26-827b-475a-bf98-647b46afe88b",
"code": "CLU-04",
"version": 1,
"status": "draft",
"content_sha256": "a75f532e2464dadd13dd2ff815d99acfb2f05d3a0264fcf82dfe8e3db7db3a1f",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"already_restored": false
},
{
"id": "8eb7da82-1f1e-442b-9b1e-57b948c3f057",
"code": "CLU-05",
"version": 1,
"status": "draft",
"content_sha256": "fe2f37be8e3f20ccc35da91aa86872b960e9820f2e0de84200c157072b3c7b11",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"already_restored": false
},
{
"id": "65d709f5-20ed-4beb-8cf1-4a7fbd459e8f",
"code": "CLU-06",
"version": 1,
"status": "draft",
"content_sha256": "097498df28f63b614914cc171e4d58c6154442d0d6625185b3759878829528de",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"already_restored": false
},
{
"id": "a795cde3-3cfe-456b-ba8d-7ff3730024ec",
"code": "CLU-07",
"version": 1,
"status": "draft",
"content_sha256": "6c5407281d18069e05b84e1e7997d07fd79680e2b0e2a5b0e7d86cbfc3c2ca35",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"already_restored": false
},
{
"id": "05dc87a8-e1ab-41c9-a312-5b14b8ff16ce",
"code": "CLU-08",
"version": 1,
"status": "draft",
"content_sha256": "f59505944a91a849c27c16455001ad4a1d39aa58e59e8d5403cb0dc197c2faf8",
"source_sha256": "70688ba4623298f5ec073331c06c28ca5b0a9c552578e22ccebe20c27d1ca8cf",
"already_restored": false
},
{
"id": "986af8c5-2f90-40ab-a62a-4c37a5f42e30",
"code": "COR-01",
"version": 1,
"status": "draft",
"content_sha256": "26db6621cae0e76d2871f56926062bc0be5bb41e21521d2536655e809b6dff20",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"already_restored": false
},
{
"id": "a7271336-808b-42b4-8bfd-5b49c72dbe2b",
"code": "COR-02",
"version": 1,
"status": "draft",
"content_sha256": "0e6b80849fcb0746aa1a53133ee0d5ccc3df8c847243a1134922247ce3d9e1b8",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"already_restored": false
},
{
"id": "d9ccddb5-e6aa-4347-a481-37b694013ac1",
"code": "COR-03",
"version": 1,
"status": "draft",
"content_sha256": "64c8eba636661e6ebb56e2dd8dd6e978c405dd96c0c7b46bdd62c805018a6c4a",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"already_restored": false
},
{
"id": "ae26d529-5341-4b37-ad08-662c9d09a0cf",
"code": "COR-04",
"version": 1,
"status": "draft",
"content_sha256": "ce5b89974e1d2937e4901ab5603245cf2465afbe0a44a224c43f726069cdabd8",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"already_restored": false
},
{
"id": "69767dcc-4c22-4046-8f81-3797bc44572e",
"code": "COR-05",
"version": 1,
"status": "draft",
"content_sha256": "343ba56efeef5514f531cf61126596a8c65f882656da5f95390eb661a0810a7c",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"already_restored": false
},
{
"id": "fb85ebfc-798c-42df-a267-d4b771c443f8",
"code": "COR-06",
"version": 1,
"status": "draft",
"content_sha256": "465ff9717def3bad42efb25d1ffa04812f871e8b167adcbb20f68f5ef9460b57",
"source_sha256": "09a6a7664f6a910dbc22190ab85d832f5405dd3eaf19e712f313c4241b873b55",
"already_restored": false
}
]
},
"destination_recovery": {
"database": {
"name": "teste_investidor",
"port": 5432
},
"qa": false,
"mode": "applied",
"manifest_sha256": "8d07007a2e1e8758d4741b4ac594f78d5943f71ad78b2daae7f85aefa9d2de4a",
"preview_sha256": "6302eee1c69b44e726fc1e0b2c5a63ac0d5eb76b23eaf97295475ab411c1151e",
"scope": 29,
"restored": 29,
"visible": 29,
"data_content_changed": false,
"new_dossiers_imported": 0,
"fake_editor_or_reviewer_assigned": false
},
"preservation_after": {
"changed_tables": [
"audit_events",
"investment_dossiers",
"sessions"
],
"expected_recovery_changes": [
"investment_dossiers",
"audit_events"
],
"unchanged_tables": 171,
"table_count": 174,
"portal_resources_unchanged": true,
"documents_unchanged": true,
"geometries_unchanged": true,
"role_assignments_unchanged": true,
"new_dossiers": 0,
"deployment_watcher": "active"
},
"backup": {
"stage": "/var/backups/investmoz-preservation-inventory-20261023/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "7b7a3a082e1259c53c321617eb84d10b544e5a211f5f708199026c4205d1c511",
"files_sha256": "0cc28141a081ce9d097735c7815b46f55d99300adf7361d936b857a24f897b86",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "preservation_restore_20261023",
"port": 55441,
"source_dump_sha256": "7b7a3a082e1259c53c321617eb84d10b544e5a211f5f708199026c4205d1c511",
"active_database_writes": 0
},
"public_recovery": {
"checked_utc": "2026-10-23T07:12:24.984213+00:00",
"results": [
{
"url": "https://teste-investidor.tempo.co.mz/carteira",
"http": 200,
"component": "portfolio/index",
"total": 29,
"authenticated": false
},
{
"url": "https://teste-investidor.tempo.co.mz/carteira?kind=project",
"http": 200,
"component": "portfolio/index",
"total": 15,
"authenticated": false
},
{
"url": "https://teste-investidor.tempo.co.mz/carteira?kind=cluster",
"http": 200,
"component": "portfolio/index",
"total": 8,
"authenticated": false
},
{
"url": "https://teste-investidor.tempo.co.mz/carteira?kind=corridor",
"http": 200,
"component": "portfolio/index",
"total": 6,
"authenticated": false
}
]
},
"new_contents_imported": 0,
"executed_recovery_source_sha256": "f4f76fa8b41bb5cf241093709ea8044592a54f8bafd0df9ca15b0c8745c45bcc",
"active_recovery_changes": {
"investment_dossiers": 29,
"audit_events": 29,
"credentials_stored": false,
"new_roles_or_approvers": false,
"new_content_approval": false
},
"qa_recovery_preparation_note": "An initial QA audit-key collision rolled back atomically. Audit identity was scoped per original before the successful QA and destination recovery; no active attempt used the faulty key."
}
@@ -1,5 +1,146 @@
# Rastreabilidade, utilização e formação
## Território adaptado ao corredor — decisão funcional da Tempo, 23/10/2026
Revisão funcional `0025309b` integrada pelo Git e disponível na homologação. Conferência do destino apenas de leitura: o serviço territorial para Maputo devolve exactamente as duas unidades existentes, sem consultar ou gravar um dossier real. A prova de recuperação e confirmação de Sofala/Dondo foi feita no dossier sintético QA, com indicação **Dados confirmados**. A prévia apresenta nomes e alterações úteis ao investidor, omitindo campos de identificadores internos.
Aplicada a tabela da Tempo como configuração do percurso existente (`config/investment_corridors.php`), usando os códigos e identificadores do cadastro territorial já aceite. Pemba–Lichinga: Cabo Delgado/Niassa; Nacala: Nampula; Vale do Zambeze: Tete/Zambézia; Beira: Sofala/Manica; Limpopo: Gaza; Maputo: **Maputo Província e Maputo Cidade**, conforme o esclarecimento final da Tempo. Só Nacala e Limpopo têm uma única província e a seleccionam automaticamente quando ainda não existe localização. Maputo exige escolher entre as duas unidades. Esta configuração funcional não declara novos limites geográficos nem altera os mestres, as associações ou as fichas publicadas.
Na preparação, cada oportunidade mantém a sua localização separada. O corredor inicial vem da fonte da ficha quando disponível; o investidor pode escolher outro corredor para o seu investimento, sem alterar a associação publicada da oportunidade. Uma mudança conserva o caminho ainda compatível; se a província deixar de pertencer ao corredor, retira os níveis territoriais dependentes e explica a alteração. A província única é proposta automaticamente; um território documentado ou previamente confirmado continua protegido pela confirmação de alternativa aplicável. A localização da primeira oportunidade alimenta os campos gerais existentes; outras escolhas permanecem identificadas separadamente.
Zonas e parques deste percurso só aparecem com território público documentado compatível, reutilizando a visibilidade, validade e vínculos existentes. Influência/proximidade não equivale a implantação. Uma indicação provincial de localização não é inventada como cobertura de todos os distritos; apenas âmbito legal documentado permite esse alargamento. Ausência de opções é distinta de erro de consulta, com nova tentativa. Ao mudar a localização, um parque que deixe de ser compatível é retirado e a razão aparece no formulário. Consulta não confirma lotes disponíveis, admissão ou benefícios; nenhum cálculo é activado.
Recuperação: o rascunho do formulário é guardado no payload cifrado do mesmo dossier, por actor, sem confirmar contexto, aumentar a versão funcional ou activar cálculos. Recupera escolhas, actividades e dados ao regressar, actualizar ou autenticar-se novamente. A gravação automática tem indicação de progresso/sucesso/erro e nova tentativa. Pedidos atrasados não substituem rascunhos mais recentes; conflito com alteração do dossier conserva o rascunho para revisão. Retirar uma ficha não a faz reaparecer ao actualizar a mesma entrada; referências novas vindas do catálogo continuam a ser acrescentadas. A confirmação normal guarda o contexto, preserva o histórico e retira o rascunho desse actor. Não há nova tabela, migration, papel, aprovador ou alteração da autorização existente.
Validação no servidor: recusa território fora do corredor tanto na prévia/confirmação como no rascunho; recusa parques sem compatibilidade documentada. Os filtros da API territorial aplicam a mesma configuração. A gravação protege o dossier e o actor, com controlo de concorrência, sem aceitar combinações só porque foram enviadas directamente à API.
Provas QA: suite de cinco testes de configuração, validação, recuperação/autenticação, conflitos, zonas e mudança de corredor — **90 asserções**; quatro testes de continuidade de oportunidades também passaram na passagem completa anterior. Testes usam exclusivamente `simulator_fiscal_delta_20261021_test:55441`, com transacções revertidas. Tipos e build passaram. Navegador com conta/dossier **sintéticos privados em QA**: Beira oferece Sofala/Manica; Nacala selecciona Nampula; Maputo oferece as duas unidades; Sofala/Dondo recuperado depois de actualizar. Captura: `outputs/preservation-inventory-20261023/corridor-adaptive-territory-QA.png`. Nenhum dossier real foi usado para provas de gravação. As 34 oportunidades, Turismo de Inhambane, permissões e geometrias não foram alterados por esta implementação.
## Continuidade entre escolha e preparação — 23/10/2026
Falha reportada pela Tempo: depois de criar o dossier para Florestas/Beira, o editor começava por uma avaliação do estado ainda não confirmado (`contexto v0`). A escolha solicitada vinha separadamente em `source`/`requestedChoices`; não era outro investimento, mas a avaliação do estado guardado vazio. A ligação do quadro voltava ao editor sem os parâmetros da escolha pendente, permitindo perder essa referência antes de confirmar. Não foi identificada nem corrigida por escrita uma troca de dados entre dossiers.
O editor passa a começar por **Preparar investimento**, pela oportunidade e pela localização por ficha. Retirado o quadro de avaliação do estado guardado deste ecrã de edição, incluindo a ligação que descartava a escolha pendente. Requisitos guardados só são apresentados quando correspondem às escolhas que estão no formulário. Botões coerentes: **Criar dossier e preparar investimento**, **Rever dados antes de guardar**, **Guardar dados do investimento**. A confirmação continua necessária para guardar alterações; abrir uma referência não altera o dossier.
Nos consumidores de avaliação, retirados números internos de contexto/versão, explicações de implementação, quadro genérico de ausência de zona e elementos sem título na lista de etapas. Mantidas condições úteis, fontes oficiais e limites efectivos do simulador. O exemplo real foi recuperado por GET com `source=opportunity:53` no dossier indicado pela Tempo, sem guardar ou criar dados. Teste QA isolado: 20 asserções sobre recuperação da escolha e igualdade do contexto antes/depois da abertura. Tipos e build conferidos; sem migrations ou alterações de cálculo, autorização ou dados activos.
Revisão funcional `72262875` integrada pelo Git e conferida no navegador da homologação: título **Preparar investimento**, Florestas/Beira identificada, localização por escolher e botão **Rever dados antes de guardar**; o quadro de contexto v0 já não aparece. Mantido aberto o dossier existente com a referência solicitada recuperada, sem confirmar alterações. Captura: `outputs/preservation-inventory-20261023/investment-preparation-continuity-homologation.png`.
## Dossier orientado ao investidor — 23/10/2026
Correcção da apresentação solicitada pela Tempo: o componente partilhado de documentos do contexto mostrava, por defeito, identidade técnica, versões, hashes, notas de permissões e mensagens de ausência de suporte. Era reutilizado na entrada, edição e consulta do dossier; a entrada repetia ainda a mesma oportunidade num bloco de origem técnica.
O investidor vê agora a escolha pelo título e respectiva ligação. **Documentos de apoio** só aparece quando existem documentos, com título, edição disponível, referência de secção e consulta do documento. Sem documentos, não se apresenta uma caixa vazia nem uma pendência genérica da biblioteca. Retirados também UUID, motor de cálculo, versões internas e chaves de origem dos resumos, prévia e consulta do dossier. Mantidas as informações operacionais relevantes: escolhas, localização, impactos da alteração, resultados que precisam de revisão, documentos e pedidos identificados por protocolo. As rotas e verificações de acesso são as mesmas; não há mudança de dados, histórico, fontes, permissões, cálculos ou publicações.
Tipos e build passaram. Revisão funcional `98474777` integrada pelo Git. Reproduzido o exemplo Florestas/Beira (`opportunity:53`) na homologação antes e depois da integração, sem criar ou alterar um dossier: agora apresenta apenas **A sua escolha** com o título e ligação, sem caixa vazia de documentos, versões ou chave técnica. Captura: `outputs/preservation-inventory-20261023/investor-dossier-clean-presentation-homologation.png`. Esta é uma correcção de apresentação nos componentes e páginas do percurso, não uma declaração de revisão integral do portal.
## Explorar oportunidades por corredor — 23/10/2026
Disponível e conferido no navegador da homologação, revisão funcional `20349299`: [explorar Agronegócio por corredor](https://teste-investidor.tempo.co.mz/oportunidades?sector=agronegocio&view=corridors). Conferidos os seis grupos, 34 resultados, acesso no início de Agronegócio e escolha dos IDs 54/64 de corredores diferentes, mantida depois do filtro Soja. [Recibo da passagem](agribusiness-corridor-explorer-20261023.json).
Decisão expressa da Tempo: acrescentar o corredor como forma de explorar o catálogo, preservando vistas por sector, território e cadeia de valor, fichas únicas e percurso existente. Nova vista `/oportunidades?sector=agronegocio&view=corridors`, com acesso destacado no início de Agronegócio. Não há migration, cadastro duplicado ou alteração de publicações, associações, permissões, Turismo de Inhambane ou geometrias.
Cada grupo apresenta nome, número de oportunidades publicadas, localizações identificadas, cadeias e etapas/actividades. O lote usa as seis designações exactas da fonte aceite; não as funde com mestres semelhantes. Outras fichas usam as relações públicas já disponibilizadas pelo catálogo; proximidade não é tratada como pertença. Sem associação pública identificada, a ficha aparece em **Outras localizações**. Uma ficha em vários grupos mantém o mesmo ID e a selecção é única. Contagens de grupos podem sobrepor-se; não significam cadastros distintos.
Dentro do grupo, filtrar província, distrito e cadeia de valor; filtros mantêm escolhas anteriores, inclusive de outros grupos. **Comparar as escolhidas** reutiliza a comparação existente de até quatro fichas; essa capacidade não limita a escolha para preparar investimento. **Preparar investimento com as oportunidades escolhidas** envia todos os IDs ao mesmo dossier, onde se confirma a localização por ficha e se reutilizam os dados em licenciamento, terra e simulação. Filtrar a pesquisa não altera a localização da ficha nem escolhe silenciosamente uma implantação.
Lacunas reais: as 34 fichas não têm província/distrito de implantação identificados; a vista indica abrangência por indicar e não transforma nomes de corredores em limites territoriais. As actividades produtivas são apresentadas com o texto da fonte, sem inventar uma classificação de etapa. Etapas adicionais vêm apenas das relações públicas existentes. Os originais e a rastreabilidade permanecem internos.
Delta conferido: dois testes, 26 asserções (seis grupos e 34 IDs sem truncar à primeira página; relação múltipla com um ID; grupo residual; localizações conhecidas sem inventar faltantes). Build e tipos verificados. Navegador QA: escolha de duas fichas de Beira e Maputo, filtro Soja mantendo as escolhas e comparação das duas identidades. Reutilizadas as provas aceites da confirmação territorial e continuidade do dossier.
## Apresentação sem notas internas — 23/10/2026
Correcção solicitada pela Tempo: a interface deve comunicar a tarefa e o conteúdo, sem narrar decisões de implementação. Simplificados o cabeçalho da gestão do lote, a entrada no roteiro e as escolhas de oportunidades. Na ficha pública, removido o alerta genérico de falta de data de validação; mantém-se o estado **Em preparação** e a indicação de que a execução depende das condições e autorizações aplicáveis.
A apresentação das 34 fichas elimina exclusivamente os parágrafos automáticos conhecidos de nome de ficheiro, hash e metadados vazios. Conserva a actividade, o corredor e a informação útil sobre definição de localização e condições. A mesma apresentação é usada na serialização HTML/API e na prévia. Não há alteração de dados, fontes, versões, permissões, auditoria ou publicação; textos posteriormente revistos pela equipa são preservados. As notas e originais continuam no cadastro interno. Esta correcção não declara revista a totalidade das páginas do portal.
Verificação: teste novo de apresentação/preservação (7 asserções), quatro testes do ciclo promocional e controlo de acesso passaram; tipos e build passaram; ficha conferida no navegador QA. A execução alargada encontrou três testes históricos incompatíveis com o estado actual da fixture (lote já divulgado e directório de contas excluído da candidata anterior); não são declarados aprovados nesta passagem nem foram alterados para ocultar essas diferenças.
## Orientação do lote de Agronegócio — catálogo e selecção múltipla, 23/10/2026
**Homologacao concluida, 23/10/2026:** 34/34 fichas cadastradas e divulgadas como **Em preparação**, pela interface da conta real, com previa, motivo, confirmacao e MFA recente. Revisao servida `e12ef6ad426ff6ebc4e7421a1ddbe7f184d77a55` (funcional `c641b267`), integrada pelo Git, sem migration. [Catalogo publico](https://teste-investidor.tempo.co.mz/oportunidades?sector=agronegocio), [gestao unica](https://teste-investidor.tempo.co.mz/gestao-conteudos) e [gestao do lote](https://teste-investidor.tempo.co.mz/minhas-oportunidades/lotes/agronegocio). A divulgacao nao autoriza execucao. [Recibo final](agribusiness-homologation-20261023.json).
**Delta final:** IDs 31-64, sem duplicados; 34 resultados e escolha de duas fichas, IDs 64 e 63, no percurso existente. As 30 oportunidades anteriores, incluindo Turismo de Inhambane, permanecem exactamente iguais ao backup. Das 174 tabelas, 170 mantem checksum integral; alteracoes apenas em oportunidades (+34), auditoria (+102 eventos), cache e sessoes. Biblioteca (59 recursos), 408 geometrias, permissoes e simulacoes preservadas. Backup/restauro isolado verificado antes da operacao. Cadastro, edicao, recuperacao, previa, divulgacao, actualizacao e retirada usam o portal, sem comandos ou Codex nas operacoes correntes. Reutilizadas as provas QA do percurso, regras e historico; sem dossiers ficticios na homologacao.
**Preservação conferida antes do cadastro:** 172/174 tabelas iguais ao backup; apenas cache e sessões diferem. As 30 oportunidades preexistentes, biblioteca com 59 recursos, 408 geometrias, permissões e tabelas de simulação permanecem preservadas. A primeira comparação da aplicação, sem contexto de actor, mostrava vazias as tabelas de simulação sujeitas a RLS e originou um alerta incorrecto. A comparação posterior usou a mesma identidade de leitura do backup e confirmou igualdade integral dessas tabelas. Nenhuma reposição, eliminação ou alteração de política foi executada; a pausa técnica do observador foi desfeita e o deploy está activo.
Decisão expressa da Tempo nesta passagem: publicar as 34 fichas no catálogo de Agronegócio e permitir escolher uma ou várias, confirmar a localização por ficha, preparar o investimento com reutilização dos dados e consultar requisitos/documentos/entidades, simular e acompanhar no dossier autenticado. Corredores, clusters e projectos âncora enriquecem a análise e não são pré-condição de publicação; localização não activa benefícios fiscais. Não alterar Turismo de Inhambane. Esta orientação supera o estado privado do recibo QA anterior, conservado como histórico.
**Conferência do existente e delta:** o catálogo já comparava quatro fichas e o dossier já tinha 19 etapas, prévia/confirmação de contexto, mapas, reutilização no simulador/terra/Balcão, pedidos e histórico. Faltava transportar uma escolha múltipla identificada para esse mesmo dossier. Acrescentado `opportunity_choices` no contexto cifrado existente, sem tabela, migration, novo dossier paralelo ou novo papel. Cada escolha conserva ID, título, versão/hash, fonte, corredor documental e referência territorial própria. A escolha do catálogo persiste ao mudar de página; ao continuar um dossier, referências novas são acrescentadas às existentes, sem eliminar silenciosamente as anteriores. A comparação de quatro fichas permanece independente da escolha de investimento. A guarda de 100 referências por pedido é uma escolha técnica de tamanho, não nova decisão organizacional.
**Percurso da equipa e do interessado:**
1. Na gestão única, abrir **Rever o lote das 34 oportunidades de Agronegócio** (`/minhas-oportunidades/lotes/agronegocio`). Conferir o manifesto e cadastrar/recuperar privadamente. Depois, preparar a prévia dos 34 textos, rever por ficha e confirmar a divulgação com motivo e MFA recente. A publicação não depende de relações com mestres. Edição, actualização ou retirada individual continuam na divulgação promocional existente.
2. No catálogo, marcar **Escolher para preparar investimento** em uma ou várias fichas e usar **Preparar investimento com as oportunidades escolhidas**. Entrar normalmente, continuar um dossier autorizado ou criar um novo. Confirmar cada ficha e a localização no editor do mesmo contexto.
3. Localização documentada é recuperada. Uma alternativa exige confirmação explícita e motivo; a ficha de origem fica intacta. Uma alternativa já confirmada não exige repetir a decisão enquanto se mantiver. Sem informação de implantação, escolher o nível territorial conhecido ou conservar a lacuna identificada; o mapa não inventa limite, parcela ou DUAT.
4. Declarar as actividades efectivas por ficha. A prévia e o dossier apresentam requisitos por oportunidade: localização/geolocalização, acesso à terra/DUAT, ambiente, enquadramento sectorial e ramos industrial/comercial quando declarados, com fundamento, documentos, entidade e ligação à etapa existente. Reutilizadas as condições e fontes da preparação do investimento privado. Fontes adicionais de consulta: [BAU — legislação](https://www.bau.gov.mz/legislacao/), [serviços BAU](https://www.bau.gov.mz/nossos-servicos/) e [quadro ambiental oficial](https://sibmoz.gov.mz/legal-framework/). Categoria ambiental, modalidade de licença e competência concreta dependem de actividade, dimensão e local; não são deduzidas de um corredor. Água, florestas, pecuária e transporte mantêm visível a necessidade do procedimento sectorial específico quando não identificado no acervo aplicado. Não é nova validação genérica da fonte nem dispensa de licença.
5. Confirmar a prévia. Título próprio e dados declarados são preservados; resumo/sector/local da referência principal são reutilizados. As outras fichas e localizações mantêm-se individualizadas: não se somam investimentos ou benefícios presumidos. Abrir as ferramentas e o acompanhamento pelas ligações do roteiro. O snapshot da simulação conserva o conjunto de escolhas, fontes e requisitos; a guarda textual foi aumentada de 20.000 para 1.000.000 caracteres para comportar o lote, sem mudança de schema. Mudança de actividade/local/escolha identifica resultados para revisão e preserva os valores e o histórico anteriores.
**Provas do delta QA:** sete testes específicos/de continuidade, 132 asserções; selecção múltipla, localizações distintas, recusa de alteração territorial silenciosa, não repetição da confirmação já aceite, recusa de fonte alterada após prévia, escopo de acesso, regras por actividade, histórico/resultados preservados e guarda das 34 escolhas no simulador. Prova adicional da operação de lote pela sessão HTTP normal: um teste, 15 asserções, incluindo manifesto divergente, prévia exacta de 34, repetição idempotente, recusa sem MFA/âmbito e preservação das restantes oportunidades. As 34 fichas foram efectivamente divulgadas **em QA**, como Em preparação; a simulação inicial de papéis QA não constitui autenticação real de homologação. Conferidos também no navegador 34 resultados e escolha de duas fichas com acção de preparação. Não repetidas as suites gerais aceites.
**Disponibilização no destino:** revisão servida inicial `761035ae`; 30 oportunidades preexistentes preservadas no inventário. Conta real de cadastro e organização operadora localizadas pelas designações existentes, sem criar papéis ou contas. Backup/restauro fresco em `/var/backups/investmoz-agribusiness-opportunities-20261023/backup`: 174 tabelas e 369 ficheiros conferidos. A integração Git de código é separada do cadastro/divulgação autenticados pela página do lote. Sem migrations ou importação de ficheiros privados; os originais e artigos existentes permanecem no armazenamento. Reversão de visibilidade usa retirada auditada pela interface, sem restaurar a base nem apagar manifestações/dossiers posteriores; reversão de código deve preservar o novo contexto cifrado e as referências adicionadas. A conferência final do destino e o recibo devem ser registados abaixo após execução.
## Correcção de âmbito — 34 oportunidades cadastradas e roteiro em QA, 23/10/2026
A lista informativa anteriormente instalada no artigo não cumpria o cadastro pedido pela Tempo. Esta correcção cria **34 fichas privadas reais na base QA isolada**, recuperáveis pela gestão existente, com título, resumo e descrição da entrada, sector Agronegócio, nome exacto do corredor documental, fonte e hash do DOCX. Conserva as seis secções e os totais 5/6/6/7/5/5. Não modifica a homologação, os corredores mestres, dossiers anteriores ou o original do artigo. Não transforma a organização operadora no promotor dos investimentos. Implantação, área, montantes, promotores, viabilidade e licenças ausentes ficam explicitamente por completar; nenhuma correspondência com corredores de nomes mais amplos foi inferida.
Reutilizada a implementação QA de divulgação promocional da candidata `9d3bfa89`, limitada ao fluxo funcional necessário. Não transportadas as alterações independentes da administração de contas. A prévia, divulgação, actualização e retirada usam as designações, âmbito e MFA existentes, sem novos papéis ou aprovadores. O resumo público é seleccionado explicitamente; preparação, contactos e documentos privados não são copiados automaticamente. Divulgação identifica **Em preparação** e não autoriza execução. Publicação documental e aprovação/publicação de uma ficha completa continuam operações distintas.
**Guia curto da equipa em QA:**
1. Abrir a [gestão única QA](http://127.0.0.1:18574/gestao-conteudos), entrar normalmente com a conta designada e abrir [Minhas oportunidades](http://127.0.0.1:18574/minhas-oportunidades). Pesquisar o título ou corredor; as fichas iniciais são privadas.
2. Abrir **Editar**, completar/corrigir os dados disponíveis, guardar e reabrir. A origem documental aparece separadamente; seleccionar localização apenas quando houver informação suficiente. A referência textual de corredor não é uma parcela.
3. Abrir **Divulgação promocional**, rever o texto público e a fonte, preparar a prévia e confirmar com motivo e MFA recente. A prévia conserva as lacunas e o estado **Em preparação**. Alterar a ficha privada não copia automaticamente dados para o resumo público: rever a selecção na divulgação.
4. Depois de divulgar, a entrada correspondente no artigo aponta para a ficha individual. Nela, o interessado pode preparar uma manifestação de interesse ou escolher **Iniciar ou continuar o roteiro deste investimento**. O percurso existente permite seleccionar um dossier ou criar um novo, comparar e confirmar a referência; preserva o título que o interessado já deu ao seu investimento.
5. Para corrigir o resumo divulgado ou retirá-lo, usar a mesma área de divulgação, com prévia e auditoria. A retirada remove a consulta pública e a ligação do artigo, preservando cadastro, preparação e histórico.
**Provas do delta:** dois testes sobre as 34 fichas, 534 asserções: abrir/editar, prévia, divulgação, ficha pública, origem de roteiro, correspondência das seis listas, actualização/retirada e repetição sem duplicados nem perda da edição. Teste adicional de interessado: 19 asserções, criação de dossier, comparação/confirmação da oportunidade, recuperação de título próprio/resumo/sector, abertura do roteiro e preparação da manifestação. Escritas desses testes revertidas por transacção: as **34 fichas permanecem privadas**, não divulgadas como efeito do cadastro. Conferidos por comparação os registos preexistentes de oportunidades/auditoria, corredores, permissões, biblioteca e documentos. Verificação de tipos e build passaram. Trata-se de prova HTTP dos percursos usados pela interface, sem afirmar uma nova sessão manual de navegador ou repetir as suites gerais aceites.
Carregamento inicial executado uma vez por `tools/register-corridor-agribusiness-qa.php`, com guarda exacta de base/porta QA, actor e organização já designados, snapshot privado e chaves estáveis por entrada. A repetição recupera os mesmos IDs sem sobrescrever edições posteriores ou reactivar uma retirada. Esse carregamento técnico de instalação não é uma operação corrente da equipa. **Editar, guardar/recuperar, pré-visualizar, divulgar, actualizar, retirar e iniciar/continuar o roteiro não exigem comandos nem Codex.** Não há migration ou nova dependência. Disponibilização na homologação e transporte das 34 fichas continuam separados desta entrega QA; não foram executados nem autorizados por esta correcção. [Recibo QA](agribusiness-opportunities-qa-20261023.json).
## Agronegócio nos corredores — complemento de apresentação, 23/10/2026
Entrega QA recebida em `entrega-agronegocio-corredores-20261023`: cinco ficheiros conferidos pelos hashes do manifesto. Complementa exclusivamente `/agronegocio`, nas seis secções existentes: Pemba–Lichinga (5), Nacala (6), Vale do Zambeze (6), Beira (7), Limpopo (5) e Maputo (5), total 34 entradas. Reutilizadas as provas QA entregues (dois testes, 63 asserções e verificador offline do exemplar preservado); não constituem prova HTTP do destino.
Delta: serviço `CorridorAgribusiness`, fonte JSON com hash do DOCX e chamada adicional em `LegacyContent::article`. O ficheiro anterior de `LegacyContent` na homologação corresponde exactamente à base local; não há alterações posteriores a sobrescrever. Sem migration, importação, escrita de conteúdo, publicação de dossiers ou alteração dos nomes/cadastros de corredores. Originais e versões da biblioteca permanecem preservados; estas entradas são conteúdo informativo do artigo, não 34 novos dossiers executáveis.
Disponibilização pelo Git e mecanismo automático existente, com cópia privada do código/recibo anteriores em `/var/backups/investmoz-agronegocio-corredores-20261023`. Backup/restauro de dados já verificados nesta sessão em `/var/backups/investmoz-preservation-inventory-20261023/backup`; esta entrega não escreve na base. Reversão delimitada: retirar apenas a chamada de complemento, preservando alterações posteriores; não restaurar a base de dados. Conferir apenas o delta HTTP após a promoção da revisão.
**Instalação concluída na homologação:** revisão funcional `20a4099d10400496e19f03589b6383f512b48d9d`, promoção automática terminada às 09h57 de 23/10/2026 (África/Johannesburgo). [Página pública](https://teste-investidor.tempo.co.mz/agronegocio) respondeu HTTP 200 com as seis listas e 34 entradas exactas. Remover apenas os acrescentos recupera exactamente o HTML anterior; imagem, metadados, origem, versão e hash do artigo permanecem iguais. Recibo do pipeline: zero migrations e zero importações. [Recibo do delta HTTP](agronegocio-corredores-installation-20261023.json). Nenhum dossier ou corredor foi criado, renomeado, fundido ou publicado por esta instalação.
### Registo da prova QA anterior — agronegócio nos seis corredores
**Registo histórico: a pendência de instalação indicada nesta prova foi resolvida pela conferência HTTP acima.**
Fonte fornecida pela Tempo: `investimentos nos corredores.docx`, SHA-256 `1473b06c48aa234e771660e3f2a51b9d2e4e1943bd52d878e0ae854ee6657055`. Extraídas 34 entradas, conservando o texto das oportunidades e as seis designações do documento: Pemba–Lichinga (5), Nacala (6), Vale do Zambeze (6), Beira (7), Limpopo (5) e Maputo (5). Preparação em `database/data/corridor-investment-opportunities.json`; os rótulos de cadeia servem apenas para organizar as entradas. Âmbito confirmado pela Tempo: **agronegócio**; outros sectores serão acrescentados quando a informação estiver disponível.
**Preservar os nomes dos corredores actualmente cadastrados, os dossiers, relações, aprovações e informações anteriores.** Retiradas as associações inicialmente inferidas entre os seis nomes do documento e os quatro dossiers de âmbito mais amplo; a apresentação experimental na carteira foi retirada. A Tempo confirmou expressamente as seis designações separadas. Foram localizadas, com essas designações exactas e as letras a)–f), nas secções do artigo existente `/agronegocio`. A integração acrescenta a cada secção a sua lista de oportunidades logo após o parágrafo de cadeias prioritárias; a fonte do complemento é identificada em cada lista. Não renomeia, funde ou cria corredores, não altera os dossiers da carteira e não preenche outros sectores.
`App\Services\CorridorAgribusiness` complementa apenas a apresentação do artigo de agronegócio a partir do JSON; o exemplar original e a sua versão/hash permanecem intactos. Só corresponde a nomes exactos, seguidos pelo parágrafo existente de cadeias prioritárias. Não infere relações, limites, geometrias, projectos ou oportunidades cadastradas a partir de semelhança de nomes. A operação é idempotente e não escreve na base de dados. Artigos de outros sectores continuam no percurso anterior.
Conferência do delta: dois testes unitários, 63 asserções, incluindo separação de listas, nomes e texto anterior preservados, repetição sem duplicação e recusa de nomes de âmbito mais amplo. Verificador offline `tools/verify-corridor-agribusiness.php` executado sobre o exemplar real de Agronegócio, SHA-256 `0929184a6d4645b9046512675394ad4f60575273f6dab0955f71cc7474a6a4e2`: seis listas, 34 entradas, original inalterado e recuperação exacta da apresentação anterior ao remover apenas os acrescentos. A leitura do artigo pela biblioteca desta base QA devolveu 404; por isso, esta prova é sobre o exemplar real preservado e não demonstra consulta HTTP da biblioteca nem instalação na homologação. Sem suite geral repetida, migrations, publicação ou alteração remota. Para instalar basta o delta PHP/JSON; não há alteração de frontend ou necessidade de nova compilação. Estado: implementação QA concluída; disponibilização na homologação por executar.
## Preservação do concluído — inventário e reposição, 23/10/2026
**Prioridade expressa da Tempo:** inventariar o que já estava concluído, identificar o que desapareceu e repor, antes de avançar com outras rondas de testes/validações. Actualizado o [inventário existente dos 43 componentes](#saldo-dos-43-componentes) com uma coluna de saldo actual; conservada também a matriz executável dos 17 percursos. Os componentes de interface ali referenciados existem no código actual. As entregas posteriores prevalecem sobre estados históricos: por exemplo, os incrementos 36–39 já não podem ser apresentados como ausentes, e o acervo editorial já não está genericamente desabilitado. Não se criou outra matriz/backlog nem se usou o inventário para exigir novamente aceitações anteriores.
**Recortes concluídos a preservar**, com os limites e recibos das secções próprias: gestão única e editorial documental; 20 artigos públicos e 28 rascunhos privados; sectores/Fintech e cartões educativos; navegação contextual e percurso adaptativo privado; recortes entregues de parques; cadastro e recursos das oportunidades; divulgação dos 30 resumos Inhambane em preparação; perfis/login/MFA; demarcação recuperada; recortes de tesouraria/exportações e consumidor IVA já entregues; instalação de Concursos e anúncios; e carteira documental agora reposta. A presença de código não encerra os critérios parciais de educação, integrações externas, participantes reais ou variantes fiscais. Não se criam dados de exemplo para preencher catálogos vazios, nem se transformam essas pendências em funcionalidades desaparecidas.
**Perdas e reposições identificadas:**
- **Carteira, clusters, corredores e projectos âncora:** 29 dossiers existiam em QA e homologação, todos em rascunho, enquanto os exemplares anteriores estavam publicados com aprovação `document_owner`. Reposta a visibilidade de **15 projectos, 8 clusters e 6 corredores**, sem nova importação. O catálogo público mostra novamente os 29 dossiers. Isto é divulgação documental informativa, não confirmação de execução, disponibilidade, financiamento ou promotor de cada projecto.
- **Demarcação territorial:** a diferença anterior de geometrias já foi reposta em 22/10; a leitura actual conserva **408 limites**. Não voltar a importar nem reabrir a prova aceite. As 26+147 correspondências pendentes e a inexistência de polígonos próprios de localidades permanecem lacunas reais, não novos desaparecimentos.
**Causa delimitada da carteira:** o importador actual cria os dossiers como rascunhos. O commit `e65cb26901a5ca18862134b20e4c17b1f1003ec2`, de 06/10/2026, retirou a opção `portfolio:import --approval` e o caminho que aplicava a aprovação documental do proprietário. A instalação noutro ambiente deixou de transportar/reconciliar essa decisão de divulgação. A leitura de 23/10 encontrou os 29 registos, 16 projectos, 8 clusters e 6 corredores preservados; não ocorreu eliminação desses mestres. Conteúdo, título e fonte dos 29 dossiers coincidem com os exemplares aprovados em 26/09 e conservados no snapshot de 07/10. Não há base para atribuir a um commit recente a data exacta em que desapareceram de um endereço específico.
**Reposição executada:** manifesto nominal de 29 originais, SHA-256 `8d07007a2e1e8758d4741b4ac594f78d5943f71ad78b2daae7f85aefa9d2de4a`; guarda contra exemplares arquivados, editados ou com versão/hash divergentes; reposição primeiro na base QA isolada e depois na homologação, pela sessão SSH autenticada. Mantidos IDs, conteúdos, fontes, mestres e relações. Apenas estado de divulgação, fundamento anterior, versão e data da reposição foram actualizados. **29 eventos auditados**, sem atribuir uma nova aprovação ou um revisor fictício; a evidência original da Tempo é conservada. `tools/restore-approved-portfolio-visibility.php` é uma operação de recuperação delimitada, não um importador que publica automaticamente novos conteúdos e não uma tarefa editorial corrente.
Antes da escrita activa: backup fresco SHA-256 `7b7a3a082e1259c53c321617eb84d10b544e5a211f5f708199026c4205d1c511`; arquivo de ficheiros/configuração `0cc28141a081ce9d097735c7815b46f55d99300adf7361d936b857a24f897b86`; restauro isolado de **174 tabelas**, com **369 ficheiros** conferidos. Depois: **171 tabelas inalteradas**; diferenças somente em dossiers, auditoria e sessões. Biblioteca/documentos, 20 artigos públicos, 28 privados, geometrias e atribuições de papéis preservados. O observador do deploy foi retomado. A ponte de acesso antiga tinha processos locais concorrentes; foram encerrados os clientes desta tarefa e usada uma única ligação autenticada. Não se registaram credenciais.
**Conferência limitada da reposição, sem suite geral:** consulta anónima `/carteira` com 29 dossiers, projectos com 15, clusters com 8 e corredores com 6, todos HTTP 200. A antiga mensagem de carteira vazia fica superada por esta reposição. Links: [carteira](https://teste-investidor.tempo.co.mz/carteira), [projectos âncora](https://teste-investidor.tempo.co.mz/projectos-ancora), [clusters](https://teste-investidor.tempo.co.mz/clusters), [corredores](https://teste-investidor.tempo.co.mz/corredores). Recibo/inventário: [preservation-inventory-20261023.json](preservation-inventory-20261023.json); manifesto de proveniência: [approved-portfolio-visibility-20261023.json](approved-portfolio-visibility-20261023.json). Não se repetiram as provas funcionais aceites de outros módulos.
**Preservação nas próximas entregas:** usar este inventário e a instrução de 23/10 em `AGENTS.md` como referência anterior à alteração. Conferir o delta de código, schema, dados, configuração e permissões, explicando qualquer redução de disponibilidade. Uma reposição não apaga edições posteriores nem revoga aprovações antigas por omissão. Reversão deve preservar as novas versões e a auditoria; não substituir toda a base por um backup anterior. O conjunto parcial da matriz continua parcial no seu âmbito, sem retirar o que já foi entregue.
## Guia curto — entrada única de gestão
**Link da equipa:** https://teste-investidor.tempo.co.mz/gestao-conteudos. Entre com a conta habitual e o seu MFA. As funções e âmbitos aprovados determinam os botões apresentados; não é necessário acesso à linha de comandos.
@@ -1020,53 +1161,53 @@ Reversão preparada em `REVERSAO-APRESENTACAO-INTEGRAL.json` e `reverse-authoriz
## Saldo dos 43 componentes
**12 disponíveis; 12 instalados mas desabilitados/por disponibilizar; 15 não demonstrados; 4 ausentes por serem incrementos QA excluídos.** “Disponível” tem o âmbito e limite indicado na linha; não certifica todos os critérios históricos do componente. Acesso aponta para o ecrã existente e não concede permissões: os acessos administrativos requerem as autorizações/MFA já existentes.
**Saldo histórico de 19/10/2026 — não representa o estado actual.** Conservado para rastreabilidade. A coluna final reconcilia as entregas posteriores e a leitura de 23/10, sem retirar aceitações por falta de nova prova. Disponibilidade, conclusão integral e ausência de dados são estados distintos.
| Nº | Componente | Estado | Acesso e limitação |
|---:|---|---|---|
| 1 | Documentos públicos | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/documentos) · 29 fichas privadas; zero publicação adicional. Consulta pública do acervo permanece fechada. |
| 2 | Ficha integral dos parques | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/zonas) · 16 fichas privadas/pendentes, 19 relações territoriais; publicação e gestão autorizada separadas. |
| 3 | Navegação contextual e manifestação de interesse | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/investimentos/iniciar) · Início, contexto e navegação abrem; gravação/recuperação aceites em QA reutilizadas. Sem dossier real no destino. |
| 4 | Referências económicas — lote mínimo | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/management/investment/references) · 11 actividades presentes; cinco novas referências transportadas. Activação/publicação do lote não executada. |
| 5 | Sectores e duplicação visual | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/sectores) · Ecrã aberto: dez sectores principais, especialização Fintech sem cartão principal duplicado; 12 registos conservados. |
| 6 | Duplicados distintos — deteção e consolidação | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/management/sector-reconciliation) · Código presente; consolidação de registos distintos não demonstrada no destino. |
| 7 | Fintech — enquadramento específico | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/sectores/mercado-financeiro/fintech) · Código instalado; artigo de origem permanece privado, sem publicação adicional. |
| 8 | Legado — conteúdo restante | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/sectores) · Adaptador habilitado; artigos/imagens transportados privadamente, sem os publicar. |
| 9 | Piloto agronegócio | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/sectores) · Originais privados; seis oportunidades sintéticas excluídas. Nenhuma oportunidade real publicada. |
| 10 | Percurso do investidor — 19 etapas | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/investimentos) · Início e lista própria abrem; definição de 19 etapas instalada. Não repetidas as 19 etapas aceites. |
| 11 | Fiscal/contributivo e exportações | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Formulário aberto; cenários fiscais/contributivos/exportação e parâmetros efectivos não certificados nesta execução. |
| 12 | Negócios existentes e classificação | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/negocios) · Catálogo abre e módulo habilitado; zero negócios copiados. Gestão própria sujeita às permissões existentes. |
| 13 | Negócios similares | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/negocios) · Código instalado; comparação com negócios reais não demonstrada. |
| 14 | Importação de empresas/empreendimentos | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/management/negocios) · Mecanismo presente; nenhuma empresa/transacção local ou QA transferida. Operador de gestão por definir. |
| 15 | Fundos | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Fontes instaladas; critérios específicos de fundos não demonstrados no destino. |
| 16 | Comparador societário e modelos | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Fontes instaladas; comparação societária/modelos não demonstrados nesta execução. |
| 17 | Capitalização/private equity e Bolsa | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Fontes instaladas; cenários específicos de capitalização/Bolsa não demonstrados no destino. |
| 18 | Checklists versionadas | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/servicos) · Definições presentes; checklist aplicada a dossier legítimo continua por demonstrar. |
| 19 | Indicadores de utilização | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/dashboard) · Código presente; indicadores com dados reais e permissões adequadas não demonstrados. |
| 20 | Jornadas educativas | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/educacao) · Área abre e flag habilitada; nenhum percurso educativo completo foi repetido. |
| 21 | Partilha documental individual e variantes de sala | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/parcerias/painel) · Estruturas de salas/partilha instaladas; participantes, consentimentos e partilha real não demonstrados. |
| 22 | Restauro, modalidades e SLA | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/painel) · Backup/restauro coberto separadamente; modalidades/SLA não homologados. Escalonamento continua desligado como local. |
| 23 | Cartografia e consumidores territoriais restantes | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Catálogos/mapas abrem. 1 921 referências geográficas no alvo versus 1 990 locais; diferença não reconciliada por item fora do manifesto. |
| 24 | Acessibilidade e restantes consumidores | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Mensagens R2 preservadas; não se declara certificação integral de acessibilidade de todos os módulos. |
| 25 | Fechos de operação/avaliação documental | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/painel) · Sem processo operacional legítimo para demonstrar fecho/avaliação documental. |
| 26 | Conta simples, login e MFA privilegiado | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/login) · Login e desafio MFA reais concluídos; conta simples R2 e controlos privilegiados preservados. |
| 27 | Manifestação simples, recibo e acompanhamento do interessado — R2 | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/investidor/manifestacoes) · Recorte R2 conservado, com provas aceites reutilizadas; nenhuma manifestação fictícia criada. |
| 28 | Pesquisa — estados do recorte R2 | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Catálogos abrem; quatro estados e protecção contra respostas antigas preservados do R2, sem repetir ensaios aceites. |
| 29 | Biblioteca privada própria, scanner e recuperação — DOC01 | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/management/portal-services) · Conta de custódia vê 30 ficheiros limpos. Novo original recuperado no navegador com SHA-256 igual à fonte; sem gestão global. |
| 30 | Backup/restauro e reversão do recorte R2 + DOC01 | Disponível | Backup fresco consistente: 144 tabelas restauradas iguais, 34 ficheiros/configuração conferidos, recuperação portável e metadados Linux/PG protegidos. Reversão de apresentação preparada. |
| 31 | Balcão Virtual | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/painel) · Painel e serviço existente abrem; dez tabelas base instaladas, definição interna project-preparation v5 transportada. |
| 32 | Vínculo positivo e recuperação do dossier | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/investimentos) · Vínculo documental positivo pendente: zero dossiers da conta no destino. Não foram criados dados fictícios. |
| 33 | Cadastro canónico e recursos de oportunidade | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/management/opportunities) · Editor/schema instalados; zero oportunidades. Gestão/revisão exigem atribuições existentes ainda não configuradas. |
| 34 | Perfis, revisão independente e publicação | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/perfis/gestao) · Schema e fluxos presentes; zero atribuições/titulares. Nenhum papel ou privilégio concedido automaticamente. |
| 35 | Bolsa de parcerias e salas internas | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/parcerias) · Catálogo e mapa abrem, nove tabelas de relações/salas instaladas; colaboração com participantes reais não demonstrada. |
| 36 | Onde se localiza / associações territoriais e produtivas | Ausente | Harmonização territorial apenas QA, expressamente excluída da revisão autorizada. |
| 37 | Lote privado Inhambane —30 fichas | Ausente | 30 fichas Inhambane apenas QA, não importadas nem publicadas no destino. |
| 38 | Enquadramento das12 fichas de programas/carteira | Ausente | Enquadramento das 12 fichas permanece no incremento QA separado. |
| 39 | Originais partilhados e referência documental no dossier — Inhambane | Ausente | Reutilização documental Inhambane/dossier permanece no incremento QA separado. |
| 40 | Orientação assistida/IA | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/management/ai) · Código presente; integração desligada. Credencial própria do destino/chamada externa não confirmadas. |
| 41 | Integração externa SuiteCRM | Instalado mas desabilitado | Permanece desligada como na versão local; nenhuma credencial ou envio externo copiado/executado. |
| 42 | Operação administrativa e resposta da equipa na homologação | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/management/interests) · Nenhuma conta com gestão global/atribuições operacionais. Custódia documental não autoriza resposta/revisão da equipa. |
| 43 | Gestão editorial da biblioteca | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/management/portal-services) · Schema editorial instalado; publicação/edição pública não concedida à conta de custódia. |
| Nº | Componente | Estado histórico | Acesso e limitação históricos | Saldo de preservação em 23/10/2026 |
|---:|---|---|---|---|
| 1 | Documentos públicos | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/documentos) · 29 fichas privadas; zero publicação adicional. Consulta pública do acervo permanece fechada. | Disponível: 29 recursos públicos; recibo editorial 22/10. Os 20 artigos conservam a aceitação anterior. |
| 2 | Ficha integral dos parques | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/zonas) · 16 fichas privadas/pendentes, 19 relações territoriais; publicação e gestão autorizada separadas. | Disponibilizado localmente em 18/10; destino conserva 16 fichas, 8 publicadas. Recorte integral não é reaprovado por este inventário. |
| 3 | Navegação contextual e manifestação de interesse | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/investimentos/iniciar) · Início, contexto e navegação abrem; gravação/recuperação aceites em QA reutilizadas. Sem dossier real no destino. | Navegação/percurso preservados; carteira reposta em 23/10: 29 dossiers, incluindo 15 projectos âncora. |
| 4 | Referências económicas — lote mínimo | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/management/investment/references) · 11 actividades presentes; cinco novas referências transportadas. Activação/publicação do lote não executada. | Código e referências presentes; manter o âmbito da autorização anterior, sem inferir publicação de todas as opções. |
| 5 | Sectores e duplicação visual | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/sectores) · Ecrã aberto: dez sectores principais, especialização Fintech sem cartão principal duplicado; 12 registos conservados. | Entrega de 18/10 conservada no código/histórico; sem remoção constatada nesta leitura. |
| 6 | Duplicados distintos — deteção e consolidação | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/management/sector-reconciliation) · Código presente; consolidação de registos distintos não demonstrada no destino. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 7 | Fintech — enquadramento específico | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/sectores/mercado-financeiro/fintech) · Código instalado; artigo de origem permanece privado, sem publicação adicional. | Fintech público no lote aceite; especialização preservada. Não reabrir a organização sectorial aprovada. |
| 8 | Legado — conteúdo restante | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/sectores) · Adaptador habilitado; artigos/imagens transportados privadamente, sem os publicar. | 20 artigos públicos e 28 privados cadastrados no destino; dois originais incompletos. Recibo 37a8eb01. |
| 9 | Piloto agronegócio | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/sectores) · Originais privados; seis oportunidades sintéticas excluídas. Nenhuma oportunidade real publicada. | Piloto Agronegócio concluído: artigo e imagem preservados; não é uma oportunidade empresarial concreta. |
| 10 | Percurso do investidor — 19 etapas | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/investimentos) · Início e lista própria abrem; definição de 19 etapas instalada. Não repetidas as 19 etapas aceites. | Percurso e preparação privada habilitados no destino; entrega adaptativa de 22/10. Zero dossiers pessoais não é perda de função. |
| 11 | Fiscal/contributivo e exportações | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Formulário aberto; cenários fiscais/contributivos/exportação e parâmetros efectivos não certificados nesta execução. | Tesouraria/exportações e consumidor IVA têm entregas delimitadas em 21–22/10; restantes variantes não promovidas a concluídas. |
| 12 | Negócios existentes e classificação | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/negocios) · Catálogo abre e módulo habilitado; zero negócios copiados. Gestão própria sujeita às permissões existentes. | Módulo habilitado e fluxos conservados. Ausência de anúncios não demonstra desaparecimento de código. |
| 13 | Negócios similares | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/negocios) · Código instalado; comparação com negócios reais não demonstrada. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 14 | Importação de empresas/empreendimentos | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/management/negocios) · Mecanismo presente; nenhuma empresa/transacção local ou QA transferida. Operador de gestão por definir. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 15 | Fundos | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Fontes instaladas; critérios específicos de fundos não demonstrados no destino. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 16 | Comparador societário e modelos | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Fontes instaladas; comparação societária/modelos não demonstrados nesta execução. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 17 | Capitalização/private equity e Bolsa | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/simulador-fiscal) · Fontes instaladas; cenários específicos de capitalização/Bolsa não demonstrados no destino. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 18 | Checklists versionadas | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/servicos) · Definições presentes; checklist aplicada a dossier legítimo continua por demonstrar. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 19 | Indicadores de utilização | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/dashboard) · Código presente; indicadores com dados reais e permissões adequadas não demonstrados. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 20 | Jornadas educativas | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/educacao) · Área abre e flag habilitada; nenhum percurso educativo completo foi repetido. | Jornadas habilitadas; cartões educativos disponibilizados. Mantido o âmbito parcial da educação. |
| 21 | Partilha documental individual e variantes de sala | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/parcerias/painel) · Estruturas de salas/partilha instaladas; participantes, consentimentos e partilha real não demonstrados. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 22 | Restauro, modalidades e SLA | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/painel) · Backup/restauro coberto separadamente; modalidades/SLA não homologados. Escalonamento continua desligado como local. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 23 | Cartografia e consumidores territoriais restantes | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Catálogos/mapas abrem. 1 921 referências geográficas no alvo versus 1 990 locais; diferença não reconciliada por item fora do manifesto. | Demarcação reposta: 408 geometrias. Polígonos de localidades e correspondências já pendentes não são nova regressão. |
| 24 | Acessibilidade e restantes consumidores | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Mensagens R2 preservadas; não se declara certificação integral de acessibilidade de todos os módulos. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 25 | Fechos de operação/avaliação documental | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/painel) · Sem processo operacional legítimo para demonstrar fecho/avaliação documental. | Sem desaparecimento demonstrado; conserva o âmbito parcial/não demonstrado anterior, sem promover conclusão nem reabrir provas aceites. |
| 26 | Conta simples, login e MFA privilegiado | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/login) · Login e desafio MFA reais concluídos; conta simples R2 e controlos privilegiados preservados. | Login/MFA e designações reais documentados; sem alteração de papéis nesta passagem. |
| 27 | Manifestação simples, recibo e acompanhamento do interessado — R2 | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/investidor/manifestacoes) · Recorte R2 conservado, com provas aceites reutilizadas; nenhuma manifestação fictícia criada. | R2 e percursos posteriores conservados; reutilizar as provas aceites. |
| 28 | Pesquisa — estados do recorte R2 | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Catálogos abrem; quatro estados e protecção contra respostas antigas preservados do R2, sem repetir ensaios aceites. | Pesquisa e selectores corrigidos em 22/10; a carteira vazia é tratada como perda separada. |
| 29 | Biblioteca privada própria, scanner e recuperação — DOC01 | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/management/portal-services) · Conta de custódia vê 30 ficheiros limpos. Novo original recuperado no navegador com SHA-256 igual à fonte; sem gestão global. | Biblioteca, scan e recuperação disponíveis: 59 recursos, 29 públicos e 30 privados. |
| 30 | Backup/restauro e reversão do recorte R2 + DOC01 | Disponível | Backup fresco consistente: 144 tabelas restauradas iguais, 34 ficheiros/configuração conferidos, recuperação portável e metadados Linux/PG protegidos. Reversão de apresentação preparada. | Backup/restauro 22/10 documentado: 174 tabelas. Reposição activa terá backup próprio antes da escrita. |
| 31 | Balcão Virtual | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/balcao-virtual/painel) · Painel e serviço existente abrem; dez tabelas base instaladas, definição interna project-preparation v5 transportada. | Balcão e definições instalados; zero casos reais no destino não é perda de funcionalidade. |
| 32 | Vínculo positivo e recuperação do dossier | Não demonstrado | [Abrir](https://teste-investidor.tempo.co.mz/investimentos) · Vínculo documental positivo pendente: zero dossiers da conta no destino. Não foram criados dados fictícios. | Recuperação de contexto demonstrada em QA nas entregas posteriores; ausência de caso real não reabre a prova aceite. |
| 33 | Cadastro canónico e recursos de oportunidade | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/management/opportunities) · Editor/schema instalados; zero oportunidades. Gestão/revisão exigem atribuições existentes ainda não configuradas. | Cadastro e recursos disponibilizados; 30 oportunidades com resumos em preparação publicados. |
| 34 | Perfis, revisão independente e publicação | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/perfis/gestao) · Schema e fluxos presentes; zero atribuições/titulares. Nenhum papel ou privilégio concedido automaticamente. | Perfis e atribuições existentes preservados; inventário não cria decisão organizacional nova. |
| 35 | Bolsa de parcerias e salas internas | Disponível | [Abrir](https://teste-investidor.tempo.co.mz/parcerias) · Catálogo e mapa abrem, nove tabelas de relações/salas instaladas; colaboração com participantes reais não demonstrada. | Bolsa e percursos existentes preservados; variantes com participantes reais mantêm saldo próprio. |
| 36 | Onde se localiza / associações territoriais e produtivas | Ausente | Harmonização territorial apenas QA, expressamente excluída da revisão autorizada. | Estado Ausente superado: integração territorial entregue em 20–22/10; catálogos e 408 limites conservados. |
| 37 | Lote privado Inhambane —30 fichas | Ausente | 30 fichas Inhambane apenas QA, não importadas nem publicadas no destino. | Estado Ausente superado: 30 fichas Inhambane transportadas e resumos divulgados em 22/10. |
| 38 | Enquadramento das12 fichas de programas/carteira | Ausente | Enquadramento das 12 fichas permanece no incremento QA separado. | Estado Ausente superado: enquadramento de 11 programas e uma carteira incluído na entrega posterior. |
| 39 | Originais partilhados e referência documental no dossier — Inhambane | Ausente | Reutilização documental Inhambane/dossier permanece no incremento QA separado. | Estado Ausente superado: originais privados/referências e contexto incluídos na entrega posterior; não reimportar. |
| 40 | Orientação assistida/IA | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/management/ai) · Código presente; integração desligada. Credencial própria do destino/chamada externa não confirmadas. | Sem regressão demonstrada: integração externa não fechada; não inventar credencial nem activar fornecedor. |
| 41 | Integração externa SuiteCRM | Instalado mas desabilitado | Permanece desligada como na versão local; nenhuma credencial ou envio externo copiado/executado. | Desabilitada também no local por opção anterior; não desapareceu por efeito da entrega editorial. |
| 42 | Operação administrativa e resposta da equipa na homologação | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/management/interests) · Nenhuma conta com gestão global/atribuições operacionais. Custódia documental não autoriza resposta/revisão da equipa. | Estado antigo superado: conta real e gestão autorizada demonstradas nas entregas posteriores. Sem novos papéis. |
| 43 | Gestão editorial da biblioteca | Instalado mas desabilitado | [Abrir](https://teste-investidor.tempo.co.mz/management/portal-services) · Schema editorial instalado; publicação/edição pública não concedida à conta de custódia. | Gestão autónoma entregue; edição, prévia, gravação e recuperação dos 28 privados demonstradas no destino. |
## Operação corrente e pendências
@@ -2481,3 +2622,19 @@ O leitor mantém a estrutura HTML sanitizada do original enquanto o corpo não f
5. A equipa decide e executa a publicação individual no portal, após rever/corrigir/pré-visualizar. Transporte privado, autorização dos metadados e publicação são etapas distintas. Não publicar artigos como efeito da instalação ou da conferência do transporte. Verificar só o delta do destino, sem repetir os 20 aceites ou as provas QA.
**Reversão e dependências remanescentes.** Para retirar conteúdo, usar a retirada pela interface e preservar originais, revisões e auditoria. Se for necessário reverter código, manter dados e ficheiros; não restaurar um backup antigo por cima de edições/publicações posteriores. Preservar novo snapshot e reconciliar o delta antes de qualquer restauro. A revisão/integração Git, transporte privado, backup/restauro e upload/scan autenticado iniciais ainda são trabalho de entrega; não estão declarados concluídos nem constituem tarefas recorrentes de cada edição. Depois de disponibilizado este delta, rever, corrigir, pré-visualizar, guardar, recuperar, publicar e retirar estes conteúdos não exigem comandos ou Codex. A revisão editorial efectiva dos textos pela equipa continua distinta da demonstração do percurso. Geometrias não foram alteradas.
### Legado — cadastro privado concluído na homologação, 22/10/2026
**Actualização da entrega anterior:** a candidata `fb4e7d89` foi revista tecnicamente e integrada pelo Git em `65eddf6bc7025c81cbd7b0c5918b6ae8bdb1c1f6`, revisão funcional servida durante esta conferência. Sem migration ou novas dependências. Backup anterior às escritas: dump SHA-256 `8658b5fa0d1ef16c9fc9be90969badde6007443aa474fe4a9377f16d80fe6e92`, arquivo de ficheiros/configuração `1d98b6200ffae11bb07dc600daa6416b3b1b90735de42791858a07a0caa63552`; restauro isolado com 174 tabelas e 341 ficheiros conferidos. Backup e pacote continuam privados em `/var/backups/investmoz-legacy-editorial-20261022/`. O transporte já concluído não foi repetido nesta retoma.
**28 originais cadastrados, 28 recursos privados, zero publicações.** Reutilizado no servidor o pacote v2 com SHA-256 `177c50d1cc3b1610e62123a2f8b532711a15f875aac2ee0e372636c2f747e8a2`. A ingestão usou os endpoints HTTPS existentes de upload, cadastro e edição, com referência à sessão real recente de Osmane Nala (actor 15), obtida após login e MFA normais; sem criar sessão/MFA, atribuir papéis ou escrever directamente nas tabelas de conteúdo. O operador autenticado executou esta passagem inicial a partir dos ficheiros já transportados; a equipa não precisa deste executor para rever ou publicar os recursos agora disponíveis. O limite de uploads foi respeitado. Uma resposta intermédia não pôde ser descodificada pelo invólucro técnico; a retoma encontrou os originais por hash e continuou sem nova cópia dos já cadastrados. Não foi atribuída uma causa não demonstrada a essa interrupção.
Cada original foi resolvido por hash, com conferência de unicidade antes do cadastro; a classificação permaneceu `internal`, os direitos/estado documental anteriores não foram convertidos em autorização de publicação e os scans reais ficaram limpos, com hash analisado igual aos bytes actuais. IDs do destino 32–59, distintos dos IDs QA. A identidade de versão inclui o identificador do original, evitando colisões entre artigos da mesma data. Os snapshots QA permanecem como proveniência no pacote privado; o histórico activo foi criado pelos endpoints com o actor real, sem importar identidades QA como autores da auditoria. A edição QA do artigo 62413, incluindo a nota explicitamente marcada QA, foi conservada para revisão da equipa.
**Conferência operacional do delta, concluída às 23h54 de 22/10/2026 (África/Johannesburgo; 21h54 UTC):** 28/28 encontrados pela pesquisa de rascunhos; 28/28 editores e leituras privadas responderam 200, com identidade, fonte e corpo recuperado correspondentes; 28/28 endereços públicos `/artigos/{id}` devolveram 404 sem sessão. Na interface, a conta real pesquisou «15/30», abriu o artigo 62413, preparou a prévia, guardou o mesmo corpo como revisão 3 e recuperou essa revisão, sempre privada. A gravação de conferência não acrescentou texto de demonstração ao corpo. Não se repetiram as provas QA ou as consultas HTTP dos 20 artigos públicos.
Preservação por comparação dos registos preexistentes: **32 documentos, 31 recursos, 63 revisões e 19 associações**, incluindo os 20 artigos públicos, permaneceram iguais. Também preservados 17 utilizadores, atribuições de papéis, par de superutilizadores, aprovações de segurança, 1.921 entradas territoriais e 408 geometrias. Nenhuma publicação foi feita por esta entrega. As 16 referências de imagens no corpo permanecem discriminadas; a capa comum é o exemplar anterior, explicitamente referenciado nos originais e reutilizado pelo hash exacto `28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa`, não uma imagem presumida. Referências sem exemplar verificado não foram preenchidas com substitutos.
**Guia da equipa no destino:** abrir a [gestão única](https://teste-investidor.tempo.co.mz/gestao-conteudos) → **Gerir conteúdos, versões e histórico** → escolher **Rascunhos**, pesquisar o título e abrir **Editar artigo** ou **Ler / pré-visualizar artigo**. Corrigir o texto e o tratamento de imagem → **Pré-visualizar alterações** → **Guardar artigo como rascunho** → **Ler revisão guardada**. Usar **Voltar ao acervo para metadados e publicação** para corrigir título, descrição, origem, enquadramento, acesso e direitos. **Publicar** continua separado, conforme a autorização e os campos existentes, quando a equipa decidir publicar. Guardar uma edição de um artigo publicado retira-o até nova publicação expressa. Não há comandos ou intervenção do Codex neste percurso corrente.
Recibo: [cadastro, acessos e preservação no destino](legacy-editorial-installation-receipt-20261022.json). A [lista única dos 50](../v2/auditoria-portal/legado-correspondencia-integral.md) e o CSV existente contêm os endereços **privados** efectivos dos 28; não são links de artigos já publicados. Capturas locais em `outputs/legacy-editorial-install-20261022/`, incluindo `editor-recovered-homologation.png`. Mantêm-se dois originais incompletos e a revisão editorial dos textos pela equipa. A Tempo não declarou ter conferido commit, pacote ou guia. **A carteira vazia e os projectos âncora continuam como falha separada, sem causa confirmada; esta entrega não a resolve.**
@@ -1,26 +1,26 @@
ID legado,Título,Autor,Categoria,Publicado,Modificado,SHA256 conteúdo,URLs observadas,Recurso QA,Situação,Situação anterior à reconciliação 15/10/2026,Recurso ativo,Grupo restante,Imagem atual,Dependência concreta,Próxima ação,Evidência atual,Endereço no novo portal,Estado actual consolidado,Pendência actual,Conferência HTTP UTC,Grupo de preparação QA
171985,Agronegocio,tempo,Oportunidades,2026-04-06T09:19:07+00:00,2026-04-20T12:41:43+00:00,28383a11d95f13894381357d8f1227b33031d1d3ff74507da4ea8e5ce2470913,https://investemoz.tempo.co.mz/agronegocio,6,publicado,recurso único QA; não é oportunidade,13,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/12/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/agronegocio,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
62413,15/30 costa do sol com dua na zona de mupulene muito lindo,tempo,Categoria,2017-06-26T11:44:21+00:00,2017-06-26T11:44:21+00:00,c04ae821317ef556c01c3141ce75eeeeb5da7787e0c6849b1b3709b757edb9eb,https://investemoz.tempo.co.mz/1530-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo,43,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Rever/corrigir a nota de demonstração QA antes de publicar.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Rever/corrigir a nota de demonstração QA antes de publicar.,,historico_noticioso
173220,Alumínio “Verde”,tempo,Oportunidades,2026-06-16T12:41:02+00:00,2026-06-16T12:41:06+00:00,c61f05a56bb5a5f13d9d5d54dbefd270cf9ac40320917d77aaad76cac56c7b97,https://investemoz.tempo.co.mz/aluminio-verde,51,existente por integrar,inventariado; cadastro/versão por reconciliar,,setorial,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,setorial
73945,Banco Mundial classifica de proibitivos juros praticados em Moçambique,tempo,Nas Redes,2017-07-31T19:55:24+00:00,2017-07-31T19:55:24+00:00,36ba82b8885b00a4ea2fd9e4b1d8cf304a8e78e591972682f0aa53717f648d19,https://investemoz.tempo.co.mz/banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique,44,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
62413,15/30 costa do sol com dua na zona de mupulene muito lindo,tempo,Categoria,2017-06-26T11:44:21+00:00,2017-06-26T11:44:21+00:00,c04ae821317ef556c01c3141ce75eeeeb5da7787e0c6849b1b3709b757edb9eb,https://investemoz.tempo.co.mz/1530-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo,43,existente por integrar,inventariado; cadastro/versão por reconciliar,32,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Rever/corrigir a nota de demonstração QA antes de publicar.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/32/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Rever/corrigir a nota de demonstração QA antes de publicar.,,historico_noticioso
173220,Alumínio “Verde”,tempo,Oportunidades,2026-06-16T12:41:02+00:00,2026-06-16T12:41:06+00:00,c61f05a56bb5a5f13d9d5d54dbefd270cf9ac40320917d77aaad76cac56c7b97,https://investemoz.tempo.co.mz/aluminio-verde,51,existente por integrar,inventariado; cadastro/versão por reconciliar,50,setorial,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/50/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,setorial
73945,Banco Mundial classifica de proibitivos juros praticados em Moçambique,tempo,Nas Redes,2017-07-31T19:55:24+00:00,2017-07-31T19:55:24+00:00,36ba82b8885b00a4ea2fd9e4b1d8cf304a8e78e591972682f0aa53717f648d19,https://investemoz.tempo.co.mz/banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique,44,existente por integrar,inventariado; cadastro/versão por reconciliar,33,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/33/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
173213,Bens de Consumo e Franquias,tempo,Oportunidades,2026-06-16T11:31:06+00:00,2026-06-16T11:32:10+00:00,abd5f36a0c2b89d2989334137aae5d59b3158da38d556013ccd55deaa5069e92,https://investemoz.tempo.co.mz/bens-de-consumo-franquias,29,publicado,inventariado; cadastro/versão por reconciliar,29,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/bens-de-consumo-franquias,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
172223,"Cabo Delgado - Pemba, A capital do turismo costeiro do norte de Moçambique",tempo,Turismo,2026-04-14T10:21:20+00:00,2026-04-14T10:41:05+00:00,c96b2430c44b8edc9cc1d0a7974c23290dd0207cff366fea8326bb28bcab8285,https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique/ | https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique,20,publicado,RecursoQA20; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,25,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
173482,Checklist para Contratação e Direitos do Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T12:36:11+00:00,2026-09-15T12:36:14+00:00,309b51ebc53bf840f9014da733bc09f8d162138be4e6e9d5a72670e26cc8e482,https://investemoz.tempo.co.mz/checklist-para-contratacao-e-direitos-do-trabalho-domestico,52,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,trabalho_domestico
76474,"Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador",tempo,Categoria,2017-08-08T17:29:51+00:00,2017-08-08T17:29:51+00:00,c8beeb94f936b3bfc69c720770bd84376e9f19b668d96185aaefbada05727010,https://investemoz.tempo.co.mz/coloque-o-seu-numero-para-o-grupo-de-whatsapp-venda-de-acessorios-de-computador,45,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
173484,Direitos Especiais da Trabalhadora Doméstica no Regulamento,tempo,Trabalho Doméstico,2026-09-15T12:38:08+00:00,2026-09-15T12:38:11+00:00,34c31bb02a3ad0886f12ac2853283de2ffb89a925be3cda73b7ce9385c6caec4,https://investemoz.tempo.co.mz/direitos-especiais-da-trabalhadora-domestica-no-regulamento,64,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,trabalho_domestico
173482,Checklist para Contratação e Direitos do Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T12:36:11+00:00,2026-09-15T12:36:14+00:00,309b51ebc53bf840f9014da733bc09f8d162138be4e6e9d5a72670e26cc8e482,https://investemoz.tempo.co.mz/checklist-para-contratacao-e-direitos-do-trabalho-domestico,52,existente por integrar,inventariado; cadastro/versão por reconciliar,52,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/52/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,trabalho_domestico
76474,"Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador",tempo,Categoria,2017-08-08T17:29:51+00:00,2017-08-08T17:29:51+00:00,c8beeb94f936b3bfc69c720770bd84376e9f19b668d96185aaefbada05727010,https://investemoz.tempo.co.mz/coloque-o-seu-numero-para-o-grupo-de-whatsapp-venda-de-acessorios-de-computador,45,existente por integrar,inventariado; cadastro/versão por reconciliar,34,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/34/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
173484,Direitos Especiais da Trabalhadora Doméstica no Regulamento,tempo,Trabalho Doméstico,2026-09-15T12:38:08+00:00,2026-09-15T12:38:11+00:00,34c31bb02a3ad0886f12ac2853283de2ffb89a925be3cda73b7ce9385c6caec4,https://investemoz.tempo.co.mz/direitos-especiais-da-trabalhadora-domestica-no-regulamento,64,existente por integrar,inventariado; cadastro/versão por reconciliar,53,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/53/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,trabalho_domestico
171981,Energia & Mineração,tempo,Oportunidades,2026-04-06T09:17:46+00:00,2026-04-30T13:35:32+00:00,e9a95f0c8176eea48a75bd2c5bce69f15308806988fa5203a688af7c40305e9c,https://investemoz.tempo.co.mz/energia-mineracao,7,publicado,RecursoQA7; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,18,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/14/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/energia-mineracao,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
173222,Energia e Recursos Naturais,tempo,Oportunidades,2026-06-16T12:47:16+00:00,2026-06-16T12:51:30+00:00,6f8236b0441d61fce5171994ba6b82ffc8b5f2de3e8242de7be29248ed046ad2,https://investemoz.tempo.co.mz/energia-recursos-naturais,63,existente por integrar,inventariado; cadastro/versão por reconciliar,,setorial,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,setorial
62414,Frelimo e Zanu-PF: Evocados laços de irmandade,tempo,Categoria,2017-06-26T12:03:20+00:00,2017-06-26T12:03:20+00:00,013307965b8fcb349a0d936d844ed12437bda4c90389f8efe958d4ffdb9ce62b,https://investemoz.tempo.co.mz/frelimo-e-zanu-pf-evocados-lacos-de-irmandade,53,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
62418,Governo dará todo O apoio à PGR no seguimento da auditoria,tempo,Categoria,2017-06-26T12:30:37+00:00,2017-06-26T12:30:45+00:00,65299b6711499e417be778b51c7ab7880616b0ccbf362854370eb775fc54caf3,https://investemoz.tempo.co.mz/governo-dara-todo-o-apoio-a-pgr-no-seguimento-da-auditoria,54,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
75002,Governo pretende construir 100 mil habitações em dois anos,tempo,Nas Redes,2017-08-04T20:01:55+00:00,2017-08-04T20:01:55+00:00,b32ea95039c2af387687738ed601f0947384eb7e19ca4bd282d603c60ca26afa,https://investemoz.tempo.co.mz/governo-pretende-construir-100-mil-habitacoes-em-dois-anos,46,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
173478,Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T12:30:34+00:00,2026-09-15T12:30:37+00:00,8038d8c221ba3cbbc4712304a6b17a6bba8ad946c8bac1a7836d472944aaf930,https://investemoz.tempo.co.mz/guia-pratico-para-empregadores-sobre-contratacao-e-direitos-no-trabalho-domestico,65,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,trabalho_domestico
173222,Energia e Recursos Naturais,tempo,Oportunidades,2026-06-16T12:47:16+00:00,2026-06-16T12:51:30+00:00,6f8236b0441d61fce5171994ba6b82ffc8b5f2de3e8242de7be29248ed046ad2,https://investemoz.tempo.co.mz/energia-recursos-naturais,63,existente por integrar,inventariado; cadastro/versão por reconciliar,51,setorial,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/51/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,setorial
62414,Frelimo e Zanu-PF: Evocados laços de irmandade,tempo,Categoria,2017-06-26T12:03:20+00:00,2017-06-26T12:03:20+00:00,013307965b8fcb349a0d936d844ed12437bda4c90389f8efe958d4ffdb9ce62b,https://investemoz.tempo.co.mz/frelimo-e-zanu-pf-evocados-lacos-de-irmandade,53,existente por integrar,inventariado; cadastro/versão por reconciliar,35,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/35/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
62418,Governo dará todo O apoio à PGR no seguimento da auditoria,tempo,Categoria,2017-06-26T12:30:37+00:00,2017-06-26T12:30:45+00:00,65299b6711499e417be778b51c7ab7880616b0ccbf362854370eb775fc54caf3,https://investemoz.tempo.co.mz/governo-dara-todo-o-apoio-a-pgr-no-seguimento-da-auditoria,54,existente por integrar,inventariado; cadastro/versão por reconciliar,36,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/36/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
75002,Governo pretende construir 100 mil habitações em dois anos,tempo,Nas Redes,2017-08-04T20:01:55+00:00,2017-08-04T20:01:55+00:00,b32ea95039c2af387687738ed601f0947384eb7e19ca4bd282d603c60ca26afa,https://investemoz.tempo.co.mz/governo-pretende-construir-100-mil-habitacoes-em-dois-anos,46,existente por integrar,inventariado; cadastro/versão por reconciliar,37,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/37/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
173478,Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T12:30:34+00:00,2026-09-15T12:30:37+00:00,8038d8c221ba3cbbc4712304a6b17a6bba8ad946c8bac1a7836d472944aaf930,https://investemoz.tempo.co.mz/guia-pratico-para-empregadores-sobre-contratacao-e-direitos-no-trabalho-domestico,65,existente por integrar,inventariado; cadastro/versão por reconciliar,54,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/54/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,trabalho_domestico
173218,Imobiliário,tempo,Oportunidades,2026-06-16T11:34:45+00:00,2026-06-16T11:34:49+00:00,be8b606f087a939bd88a86f4436a0ff18c5fb774a179e6e915d4abb10a95f930,https://investemoz.tempo.co.mz/imobiliario,28,publicado,inventariado; cadastro/versão por reconciliar,7,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/imobiliario,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
171992,Infraestruturas,tempo,Oportunidades,2026-04-06T09:25:07+00:00,2026-04-30T12:44:37+00:00,9716da16aba58eec173343f0bbd582d62d23a5eee7d20522c080c2da5da8ba66,https://investemoz.tempo.co.mz/infraestruturas,22,publicado,RecursoQA22; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,17,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/16/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/infraestruturas,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
172240,"Maputo Cidade – Plataforma Estratégica de Turismo, Negócios e Investimento Sustentável",tempo,Turismo,2026-04-14T10:58:53+00:00,2026-04-14T11:03:28+00:00,0866639d09c5c0b3b00e8527554065587c793f60df978b66b6a578b3c741bc0d,https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel/ | https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel,16,publicado,RecursoQA16; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,21,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
171994,Mercado Financeiro,tempo,Oportunidades,2026-04-06T09:27:00+00:00,2026-04-17T09:53:42+00:00,e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,https://investemoz.tempo.co.mz/mercado-financeiro,23,vazio — dependência concreta,"RecursoQA23; original/hash/ClamD/replay demonstrados. Corpo vazio na origemHTML/Inertia200;privado,sem página publicada.",,mercado_financeiro,"{""status"": ""capturada mas não publicada no ativo"", ""sha256"": ""417b4a33468f360acef272ce3e4180c1d0a171980befa73ddb9a33de5a9d4c4e""}",Corpo do artigo vazio; imagem não substitui conteúdo.,"Manter pendente e separado, sem bloquear outros lotes.",outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,,Original vazio,Fornecer corpo editorial pela Tempo; imagem e Fintech não substituem o original. Sem novo endereço público.,,
173480,Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias,tempo,Trabalho Doméstico,2026-09-15T12:34:17+00:00,2026-09-15T12:34:19+00:00,5b95ad9010fcbdc1000052f47766ca54409d3e0649211729ced9ef142f5c6db0,https://investemoz.tempo.co.mz/modelo-de-contrato-de-trabalho-domestico-para-pequenas-familias,66,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,trabalho_domestico
173480,Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias,tempo,Trabalho Doméstico,2026-09-15T12:34:17+00:00,2026-09-15T12:34:19+00:00,5b95ad9010fcbdc1000052f47766ca54409d3e0649211729ced9ef142f5c6db0,https://investemoz.tempo.co.mz/modelo-de-contrato-de-trabalho-domestico-para-pequenas-familias,66,existente por integrar,inventariado; cadastro/versão por reconciliar,55,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/55/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,trabalho_domestico
172219,Niassa - O último grande destino virgem do turismo africano,tempo,Turismo,2026-04-14T10:17:14+00:00,2026-04-14T10:43:56+00:00,47d82a59a86c3cbdef04ea065e711e7139d50137e440f03efbd710e3c4220ef7,https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano/ | https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano,21,publicado,RecursoQA21; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,26,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
173476,Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique,tempo,Trabalho Doméstico,2026-09-15T11:39:21+00:00,2026-09-15T11:39:24+00:00,bb634a9021da9d7b46ed105317aa54e4af42a16dab042e0ceb2bdc0d702d1a67,https://investemoz.tempo.co.mz/procedimentos-para-rescisao-do-contrato-de-trabalho-domestico-segundo-o-regulamento-de-mocambique,67,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,trabalho_domestico
173476,Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique,tempo,Trabalho Doméstico,2026-09-15T11:39:21+00:00,2026-09-15T11:39:24+00:00,bb634a9021da9d7b46ed105317aa54e4af42a16dab042e0ceb2bdc0d702d1a67,https://investemoz.tempo.co.mz/procedimentos-para-rescisao-do-contrato-de-trabalho-domestico-segundo-o-regulamento-de-mocambique,67,existente por integrar,inventariado; cadastro/versão por reconciliar,56,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/56/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,trabalho_domestico
172263,"Província da Zambézia: Onde os Corredores de Moçambique Convergem com a Natureza, a Cultura e o Turismo Sustentável",tempo,Turismo,2026-04-14T14:21:52+00:00,2026-04-14T14:26:27+00:00,9e7ca4e9542135d5969f5c008ce8e29b037cc06a53875cfa7dc3e7452ec47744,https://investemoz.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel,11,publicado,RecursoQA11; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,3,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
172233,Província de Gaza: Oportunidades mais sólidas e estratégicas de investimento no turismo no sul de Moçambique.,tempo,Turismo,2026-04-14T10:52:30+00:00,2026-04-17T08:28:56+00:00,2bf2df9bd3b7ab8656209a48f4928b5d8bbf2959e77c292fc4c9987e67ba2fea,https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique/ | https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique,18,publicado,RecursoQA18; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,23,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
172253,Província de Inhambane: Um Destino Estratégico para Investimento Turístico,tempo,Turismo,2026-04-14T14:15:12+00:00,2026-04-14T14:25:44+00:00,2d1cc729481ce65a5e50898c0eea4a1eb2418273b03fc749009e2ffaaa72fe71,https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico/ | https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico,15,publicado,RecursoQA15; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,6,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
@@ -29,23 +29,23 @@
172230,Província de Nampula - Perfil de investimento no setor do turismo,tempo,Turismo,2026-04-14T10:50:32+00:00,2026-04-14T11:10:23+00:00,d18ccc1e036b3480605462ce7176be75153f6aa988bc9b37d8d395b01e555a7a,https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo/ | https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo,19,publicado,RecursoQA19; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,24,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
172256,"Província de Sofala: Onde a Natureza, a História e o Futuro do Turismo Convergem",tempo,Turismo,2026-04-14T14:16:47+00:00,2026-04-14T14:26:17+00:00,12b46a34ba61c6ef0058a6c410ebc17329d897fe4b06a13b4ea3fe3c85a28342,https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem/ | https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem,12,publicado,RecursoQA12; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,4,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
172261,"Província de Tete: Onde o Rio Zambeze, a Cultura Viva e a Conservação Comunitária Criam o Futuro do Turismo",tempo,Turismo,2026-04-14T14:19:48+00:00,2026-04-14T14:26:25+00:00,e78fce2931260a7d6f82270897e906feb640f65d084c2d4ffb5ba19303858275,https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo/ | https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo,13,publicado,RecursoQA13; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,5,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
73246,Rofino Licuco preso cinco meses depois de condenado por agressão,tempo,Nas Redes,2017-07-28T20:23:11+00:00,2017-07-28T20:23:11+00:00,806c54948641f4f5933a2ea4a6935dfb7a67202ab227960451d62435880289f6,https://investemoz.tempo.co.mz/rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao,47,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
77232,Sete indivíduos mortos a tiro na Matola,tempo,Nas Redes,2017-08-11T20:30:32+00:00,2017-08-11T20:30:32+00:00,e657a97d5d6db7fa0ea6b7d14029ff873ea5d36dfdadda5f8b9bc8f1ef5dd011,https://investemoz.tempo.co.mz/sete-individuos-mortos-a-tiro-na-matola,48,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
62416,Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia,tempo,Categoria,2017-06-26T12:14:48+00:00,2017-06-26T12:14:48+00:00,0fe20a9ca9dd99c58072f43b3dece1de347ef4063ee5f75bcffe8b2f4bf253b5,https://investemoz.tempo.co.mz/sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india,55,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
73246,Rofino Licuco preso cinco meses depois de condenado por agressão,tempo,Nas Redes,2017-07-28T20:23:11+00:00,2017-07-28T20:23:11+00:00,806c54948641f4f5933a2ea4a6935dfb7a67202ab227960451d62435880289f6,https://investemoz.tempo.co.mz/rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao,47,existente por integrar,inventariado; cadastro/versão por reconciliar,38,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/38/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
77232,Sete indivíduos mortos a tiro na Matola,tempo,Nas Redes,2017-08-11T20:30:32+00:00,2017-08-11T20:30:32+00:00,e657a97d5d6db7fa0ea6b7d14029ff873ea5d36dfdadda5f8b9bc8f1ef5dd011,https://investemoz.tempo.co.mz/sete-individuos-mortos-a-tiro-na-matola,48,existente por integrar,inventariado; cadastro/versão por reconciliar,39,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/39/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
62416,Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia,tempo,Categoria,2017-06-26T12:14:48+00:00,2017-06-26T12:14:48+00:00,0fe20a9ca9dd99c58072f43b3dece1de347ef4063ee5f75bcffe8b2f4bf253b5,https://investemoz.tempo.co.mz/sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india,55,existente por integrar,inventariado; cadastro/versão por reconciliar,40,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/40/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
173209,Fintech,tempo,Oportunidades,2026-06-16T11:24:22+00:00,2026-06-23T10:03:06+00:00,8db9206bf5192b68e7c9bdfb87e9dc9c7063a4b7eca56630685b0e6c294f55ab,https://investemoz.tempo.co.mz/tech-fintech,27,publicado,inventariado; cadastro/versão por reconciliar,28,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/tech-fintech,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
171990,Turismo,tempo,Oportunidades,2026-04-06T09:22:51+00:00,2026-06-16T13:07:59+00:00,604d30a740cc6ed20d24e3447806e733aa4aefb9f339f81d3dc57b644dd19fb7,https://investemoz.tempo.co.mz/turismo,10,publicado,RecursoQA10; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,19,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/15/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/turismo,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
74364,,tempo,Categoria,2017-07-26T21:20:33+00:00,2017-07-26T21:20:33+00:00,2a7f0a5b09e0136fec9eae357ac8a88a159ead23b25ed7bb735c75997b10ec5e,https://investemoz.tempo.co.mz/74364-2,,dependência concreta — título ausente,inventariado; cadastro/versão por reconciliar,,identidade_incompleta,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/1501695692_133_notitle.jpg | Referência não recolhida: https://www.facebook.com/179463555444013/posts/1552815684775453 | Título vazio no post 74364; corpo com 20 caracteres; identidade editorial a esclarecer sem inventar título.,Preservar exemplar e referências; delimitar recuperação editorial antes de integrar.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,,Original sem título,Identificação editorial pela Tempo para o post 74364; corpo com 21 caracteres úteis preservado. Sem título ou endereço novo inventado.,,
62929,Daúde Razaque já não é treinador da Liga Desportiva de Maputo,tempo,Nas Redes,2017-06-27T16:41:43+00:00,2017-06-27T16:41:43+00:00,c3b57ea685290bfb01c50403bc83db98cf1a42ad51c04d5b8d288c99b8c0a808,https://investemoz.tempo.co.mz/daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo,49,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
62649,Daviz Simango não se incomoda com possível sucessão na Beira,tempo,Nas Redes,2017-06-26T19:38:09+00:00,2017-06-26T19:38:09+00:00,090e5f41ed11c8e680d2e30ea5c8310b7c6b165ddec318a8b0cf94927f78da74,https://investemoz.tempo.co.mz/daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira,56,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
173470,Direitos e Deveres do Trabalhador Doméstico,tempo,Trabalho Doméstico,2026-09-15T11:28:25+00:00,2026-09-15T11:28:28+00:00,f69fd6fd8509913f2d79df0267c469dc7a9d0d30420ce8428749d53ba21446ab,https://investemoz.tempo.co.mz/direitos-e-deveres-do-trabalhador-domestico,68,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,trabalho_domestico
62929,Daúde Razaque já não é treinador da Liga Desportiva de Maputo,tempo,Nas Redes,2017-06-27T16:41:43+00:00,2017-06-27T16:41:43+00:00,c3b57ea685290bfb01c50403bc83db98cf1a42ad51c04d5b8d288c99b8c0a808,https://investemoz.tempo.co.mz/daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo,49,existente por integrar,inventariado; cadastro/versão por reconciliar,41,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/41/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
62649,Daviz Simango não se incomoda com possível sucessão na Beira,tempo,Nas Redes,2017-06-26T19:38:09+00:00,2017-06-26T19:38:09+00:00,090e5f41ed11c8e680d2e30ea5c8310b7c6b165ddec318a8b0cf94927f78da74,https://investemoz.tempo.co.mz/daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira,56,existente por integrar,inventariado; cadastro/versão por reconciliar,42,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/42/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
173470,Direitos e Deveres do Trabalhador Doméstico,tempo,Trabalho Doméstico,2026-09-15T11:28:25+00:00,2026-09-15T11:28:28+00:00,f69fd6fd8509913f2d79df0267c469dc7a9d0d30420ce8428749d53ba21446ab,https://investemoz.tempo.co.mz/direitos-e-deveres-do-trabalhador-domestico,68,existente por integrar,inventariado; cadastro/versão por reconciliar,57,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/57/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,trabalho_domestico
172679,Energia,tempo,Featured,2026-04-30T13:03:57+00:00,2026-04-30T13:28:48+00:00,e2a7eb4be0a2cf4139737f6428c147ac35de99899478ce79195dc5e1b0a960f3,https://investemoz.tempo.co.mz/energia | https://investemoz.tempo.co.mz/energia/,8,publicado,RecursoQA8; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,1,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/energia,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
62739,"“Exigimos responsabilização dos agentes do crime”, Daviz Simango",tempo,Nas Redes,2017-06-26T23:13:36+00:00,2017-06-26T23:13:36+00:00,e37ea18176246dab529d2ecec7734f0fb2b0a54cadc507fbd789033d5b8e5b93,https://investemoz.tempo.co.mz/exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango-2,57,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
62854,Governo e parceiros reforçam mecanismos de controlo de HIV/Sida,tempo,Nas Redes,2017-06-27T11:07:53+00:00,2017-06-27T11:07:53+00:00,0073816b1fa4bd50ec6417b07272da06565230d06a19079ca76cb006c882d2f1,https://investemoz.tempo.co.mz/governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida,58,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
63128,Graça Machel diz que desnutrição é um problema de desenvolvimento,tempo,Nas Redes,2017-06-27T22:01:59+00:00,2017-06-27T22:01:59+00:00,711f3707e3a0d72ec919216fc50823de9060349104ee98fe0a6b20d6684b6031,https://investemoz.tempo.co.mz/graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento,59,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
63181,In dependência,tempo,Nas Redes,2017-06-27T21:38:06+00:00,2017-06-27T21:38:06+00:00,b0d87c0d58d6d1343d102cd3141bda1215c5afd54f3780a1c6c262d786dbfe27,https://investemoz.tempo.co.mz/in-dependencia,60,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
63146,"Kroll não descobriu como foram gastos 2 biliões de dólares; Governo de Nyusi não apoiou a Auditoria; criação da Proindicus, EMATUM e MAM não foi para proteção da Zona Económica Exclusiva",tempo,Nas Redes,2017-06-27T19:30:01+00:00,2017-06-27T19:30:01+00:00,4ccbad5c92ddc3884f58181a4f1ed3c1d3d6a59f005bfd99b197a6fc1fc3c280,https://investemoz.tempo.co.mz/kroll-nao-descobriu-como-foram-gastos-2-bilioes-de-dolares-governo-de-nyusi-nao-apoiou-a-auditoria-criacao-da-proindicus-ematum-e-mam-nao-foi-para-protecao-da-zona-economica-exclusiva-2,61,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
62739,"“Exigimos responsabilização dos agentes do crime”, Daviz Simango",tempo,Nas Redes,2017-06-26T23:13:36+00:00,2017-06-26T23:13:36+00:00,e37ea18176246dab529d2ecec7734f0fb2b0a54cadc507fbd789033d5b8e5b93,https://investemoz.tempo.co.mz/exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango-2,57,existente por integrar,inventariado; cadastro/versão por reconciliar,43,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/43/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
62854,Governo e parceiros reforçam mecanismos de controlo de HIV/Sida,tempo,Nas Redes,2017-06-27T11:07:53+00:00,2017-06-27T11:07:53+00:00,0073816b1fa4bd50ec6417b07272da06565230d06a19079ca76cb006c882d2f1,https://investemoz.tempo.co.mz/governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida,58,existente por integrar,inventariado; cadastro/versão por reconciliar,44,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/44/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
63128,Graça Machel diz que desnutrição é um problema de desenvolvimento,tempo,Nas Redes,2017-06-27T22:01:59+00:00,2017-06-27T22:01:59+00:00,711f3707e3a0d72ec919216fc50823de9060349104ee98fe0a6b20d6684b6031,https://investemoz.tempo.co.mz/graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento,59,existente por integrar,inventariado; cadastro/versão por reconciliar,45,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/45/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
63181,In dependência,tempo,Nas Redes,2017-06-27T21:38:06+00:00,2017-06-27T21:38:06+00:00,b0d87c0d58d6d1343d102cd3141bda1215c5afd54f3780a1c6c262d786dbfe27,https://investemoz.tempo.co.mz/in-dependencia,60,existente por integrar,inventariado; cadastro/versão por reconciliar,46,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/46/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
63146,"Kroll não descobriu como foram gastos 2 biliões de dólares; Governo de Nyusi não apoiou a Auditoria; criação da Proindicus, EMATUM e MAM não foi para proteção da Zona Económica Exclusiva",tempo,Nas Redes,2017-06-27T19:30:01+00:00,2017-06-27T19:30:01+00:00,4ccbad5c92ddc3884f58181a4f1ed3c1d3d6a59f005bfd99b197a6fc1fc3c280,https://investemoz.tempo.co.mz/kroll-nao-descobriu-como-foram-gastos-2-bilioes-de-dolares-governo-de-nyusi-nao-apoiou-a-auditoria-criacao-da-proindicus-ematum-e-mam-nao-foi-para-protecao-da-zona-economica-exclusiva-2,61,existente por integrar,inventariado; cadastro/versão por reconciliar,47,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/47/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
172674,Mineração,tempo,Featured,2026-04-30T13:12:09+00:00,2026-04-30T13:30:13+00:00,8d3acc292ed806bc4cc7bcb6a3a6a5759f30b610766a5ef4b3d6a0b7c56d5861,https://investemoz.tempo.co.mz/mineracao,9,publicado,RecursoQA9; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,2,publicados,"{""scope"": ""homologação"", ""href"": ""/documentos/27/view"", ""status"": ""referência na ficha; binário não reensaiado""}",Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.,Preservar a publicação; gerir edições e versões pela biblioteca existente.,outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado,https://teste-investidor.tempo.co.mz/mineracao,Publicado; identidade e conteúdo consultáveis na homologação,Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.,2026-10-22T21:05:03.369388+00:00,
62688,O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ...,tempo,Nas Redes,2017-06-26T18:21:18+00:00,2017-06-26T18:21:18+00:00,396fe2575641622015505eb11d4c7152b6e3e1b741966f14c0cd1673fd455fd3,https://investemoz.tempo.co.mz/o-instituto-nacional-de-meteorologia-preve-o-seguinte-estado-do-tempo-para-esta-29,62,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
173474,Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique,tempo,Trabalho Doméstico,2026-09-15T11:37:04+00:00,2026-09-15T11:37:06+00:00,e09a0fe71397e2b060ff8435111117aa487b476a85ec522fffcdf9e23a6cdac2,https://investemoz.tempo.co.mz/sancoes-disciplinares-aplicaveis-a-trabalhadores-domesticos-segundo-o-regulamento-de-mocambique,69,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,trabalho_domestico
63248,Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (...,tempo,Nas Redes,2017-06-28T11:30:01+00:00,2017-06-28T11:30:01+00:00,2220ca2c07d10f10b2bd6fd0f103ee733b83570d436c751c449c85b42df46a13,https://investemoz.tempo.co.mz/dois-alunos-da-9a-classe-cairam-nas-maos-da-policia-da-republica-de-mocambique,50,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,historico_noticioso
173463,Regulamento do Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T10:56:07+00:00,2026-09-15T12:41:44+00:00,eb43b6c1f097631250f0b36d3d01b4d106db2fcae07a56bb154819143fff11e9,https://investemoz.tempo.co.mz/regulamento-do-trabalho-domestico,70,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.,legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados,,"Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada",Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso.,,trabalho_domestico
62688,O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ...,tempo,Nas Redes,2017-06-26T18:21:18+00:00,2017-06-26T18:21:18+00:00,396fe2575641622015505eb11d4c7152b6e3e1b741966f14c0cd1673fd455fd3,https://investemoz.tempo.co.mz/o-instituto-nacional-de-meteorologia-preve-o-seguinte-estado-do-tempo-para-esta-29,62,existente por integrar,inventariado; cadastro/versão por reconciliar,48,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/48/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
173474,Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique,tempo,Trabalho Doméstico,2026-09-15T11:37:04+00:00,2026-09-15T11:37:06+00:00,e09a0fe71397e2b060ff8435111117aa487b476a85ec522fffcdf9e23a6cdac2,https://investemoz.tempo.co.mz/sancoes-disciplinares-aplicaveis-a-trabalhadores-domesticos-segundo-o-regulamento-de-mocambique,69,existente por integrar,inventariado; cadastro/versão por reconciliar,58,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/58/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,trabalho_domestico
63248,Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (...,tempo,Nas Redes,2017-06-28T11:30:01+00:00,2017-06-28T11:30:01+00:00,2220ca2c07d10f10b2bd6fd0f103ee733b83570d436c751c449c85b42df46a13,https://investemoz.tempo.co.mz/dois-alunos-da-9a-classe-cairam-nas-maos-da-policia-da-republica-de-mocambique,50,existente por integrar,inventariado; cadastro/versão por reconciliar,49,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/49/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,historico_noticioso
173463,Regulamento do Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T10:56:07+00:00,2026-09-15T12:41:44+00:00,eb43b6c1f097631250f0b36d3d01b4d106db2fcae07a56bb154819143fff11e9,https://investemoz.tempo.co.mz/regulamento-do-trabalho-domestico,70,existente por integrar,inventariado; cadastro/versão por reconciliar,59,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,"Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.",docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas,https://teste-investidor.tempo.co.mz/management/portal-services/resources/59/article/preview,"Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos",Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.,,trabalho_domestico
1 ID legado Título Autor Categoria Publicado Modificado SHA256 conteúdo URLs observadas Recurso QA Situação Situação anterior à reconciliação 15/10/2026 Recurso ativo Grupo restante Imagem atual Dependência concreta Próxima ação Evidência atual Endereço no novo portal Estado actual consolidado Pendência actual Conferência HTTP UTC Grupo de preparação QA
2 171985 Agronegocio tempo Oportunidades 2026-04-06T09:19:07+00:00 2026-04-20T12:41:43+00:00 28383a11d95f13894381357d8f1227b33031d1d3ff74507da4ea8e5ce2470913 https://investemoz.tempo.co.mz/agronegocio 6 publicado recurso único QA; não é oportunidade 13 publicados {"scope": "homologação", "href": "/documentos/12/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/agronegocio Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
3 62413 15/30 costa do sol com dua na zona de mupulene muito lindo tempo Categoria 2017-06-26T11:44:21+00:00 2017-06-26T11:44:21+00:00 c04ae821317ef556c01c3141ce75eeeeb5da7787e0c6849b1b3709b757edb9eb https://investemoz.tempo.co.mz/1530-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo 43 existente por integrar inventariado; cadastro/versão por reconciliar 32 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Rever/corrigir a nota de demonstração QA antes de publicar. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Rever/corrigir a nota de demonstração QA antes de publicar. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/32/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Rever/corrigir a nota de demonstração QA antes de publicar. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Rever/corrigir a nota de demonstração QA antes de publicar. historico_noticioso
4 173220 Alumínio “Verde” tempo Oportunidades 2026-06-16T12:41:02+00:00 2026-06-16T12:41:06+00:00 c61f05a56bb5a5f13d9d5d54dbefd270cf9ac40320917d77aaad76cac56c7b97 https://investemoz.tempo.co.mz/aluminio-verde 51 existente por integrar inventariado; cadastro/versão por reconciliar 50 setorial {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/50/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. setorial
5 73945 Banco Mundial classifica de proibitivos juros praticados em Moçambique tempo Nas Redes 2017-07-31T19:55:24+00:00 2017-07-31T19:55:24+00:00 36ba82b8885b00a4ea2fd9e4b1d8cf304a8e78e591972682f0aa53717f648d19 https://investemoz.tempo.co.mz/banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique 44 existente por integrar inventariado; cadastro/versão por reconciliar 33 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/33/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
6 173213 Bens de Consumo e Franquias tempo Oportunidades 2026-06-16T11:31:06+00:00 2026-06-16T11:32:10+00:00 abd5f36a0c2b89d2989334137aae5d59b3158da38d556013ccd55deaa5069e92 https://investemoz.tempo.co.mz/bens-de-consumo-franquias 29 publicado inventariado; cadastro/versão por reconciliar 29 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/bens-de-consumo-franquias Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
7 172223 Cabo Delgado - Pemba, A capital do turismo costeiro do norte de Moçambique tempo Turismo 2026-04-14T10:21:20+00:00 2026-04-14T10:41:05+00:00 c96b2430c44b8edc9cc1d0a7974c23290dd0207cff366fea8326bb28bcab8285 https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique/ | https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique 20 publicado RecursoQA20; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 25 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
8 173482 Checklist para Contratação e Direitos do Trabalho Doméstico tempo Trabalho Doméstico 2026-09-15T12:36:11+00:00 2026-09-15T12:36:14+00:00 309b51ebc53bf840f9014da733bc09f8d162138be4e6e9d5a72670e26cc8e482 https://investemoz.tempo.co.mz/checklist-para-contratacao-e-direitos-do-trabalho-domestico 52 existente por integrar inventariado; cadastro/versão por reconciliar 52 trabalho_domestico {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/52/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. trabalho_domestico
9 76474 Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador tempo Categoria 2017-08-08T17:29:51+00:00 2017-08-08T17:29:51+00:00 c8beeb94f936b3bfc69c720770bd84376e9f19b668d96185aaefbada05727010 https://investemoz.tempo.co.mz/coloque-o-seu-numero-para-o-grupo-de-whatsapp-venda-de-acessorios-de-computador 45 existente por integrar inventariado; cadastro/versão por reconciliar 34 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/34/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
10 173484 Direitos Especiais da Trabalhadora Doméstica no Regulamento tempo Trabalho Doméstico 2026-09-15T12:38:08+00:00 2026-09-15T12:38:11+00:00 34c31bb02a3ad0886f12ac2853283de2ffb89a925be3cda73b7ce9385c6caec4 https://investemoz.tempo.co.mz/direitos-especiais-da-trabalhadora-domestica-no-regulamento 64 existente por integrar inventariado; cadastro/versão por reconciliar 53 trabalho_domestico {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/53/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. trabalho_domestico
11 171981 Energia & Mineração tempo Oportunidades 2026-04-06T09:17:46+00:00 2026-04-30T13:35:32+00:00 e9a95f0c8176eea48a75bd2c5bce69f15308806988fa5203a688af7c40305e9c https://investemoz.tempo.co.mz/energia-mineracao 7 publicado RecursoQA7; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 18 publicados {"scope": "homologação", "href": "/documentos/14/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/energia-mineracao Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
12 173222 Energia e Recursos Naturais tempo Oportunidades 2026-06-16T12:47:16+00:00 2026-06-16T12:51:30+00:00 6f8236b0441d61fce5171994ba6b82ffc8b5f2de3e8242de7be29248ed046ad2 https://investemoz.tempo.co.mz/energia-recursos-naturais 63 existente por integrar inventariado; cadastro/versão por reconciliar 51 setorial {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/51/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. setorial
13 62414 Frelimo e Zanu-PF: Evocados laços de irmandade tempo Categoria 2017-06-26T12:03:20+00:00 2017-06-26T12:03:20+00:00 013307965b8fcb349a0d936d844ed12437bda4c90389f8efe958d4ffdb9ce62b https://investemoz.tempo.co.mz/frelimo-e-zanu-pf-evocados-lacos-de-irmandade 53 existente por integrar inventariado; cadastro/versão por reconciliar 35 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/35/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
14 62418 Governo dará todo O apoio à PGR no seguimento da auditoria tempo Categoria 2017-06-26T12:30:37+00:00 2017-06-26T12:30:45+00:00 65299b6711499e417be778b51c7ab7880616b0ccbf362854370eb775fc54caf3 https://investemoz.tempo.co.mz/governo-dara-todo-o-apoio-a-pgr-no-seguimento-da-auditoria 54 existente por integrar inventariado; cadastro/versão por reconciliar 36 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/36/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
15 75002 Governo pretende construir 100 mil habitações em dois anos tempo Nas Redes 2017-08-04T20:01:55+00:00 2017-08-04T20:01:55+00:00 b32ea95039c2af387687738ed601f0947384eb7e19ca4bd282d603c60ca26afa https://investemoz.tempo.co.mz/governo-pretende-construir-100-mil-habitacoes-em-dois-anos 46 existente por integrar inventariado; cadastro/versão por reconciliar 37 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/37/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
16 173478 Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico tempo Trabalho Doméstico 2026-09-15T12:30:34+00:00 2026-09-15T12:30:37+00:00 8038d8c221ba3cbbc4712304a6b17a6bba8ad946c8bac1a7836d472944aaf930 https://investemoz.tempo.co.mz/guia-pratico-para-empregadores-sobre-contratacao-e-direitos-no-trabalho-domestico 65 existente por integrar inventariado; cadastro/versão por reconciliar 54 trabalho_domestico {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/54/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. trabalho_domestico
17 173218 Imobiliário tempo Oportunidades 2026-06-16T11:34:45+00:00 2026-06-16T11:34:49+00:00 be8b606f087a939bd88a86f4436a0ff18c5fb774a179e6e915d4abb10a95f930 https://investemoz.tempo.co.mz/imobiliario 28 publicado inventariado; cadastro/versão por reconciliar 7 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/imobiliario Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
18 171992 Infraestruturas tempo Oportunidades 2026-04-06T09:25:07+00:00 2026-04-30T12:44:37+00:00 9716da16aba58eec173343f0bbd582d62d23a5eee7d20522c080c2da5da8ba66 https://investemoz.tempo.co.mz/infraestruturas 22 publicado RecursoQA22; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 17 publicados {"scope": "homologação", "href": "/documentos/16/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/infraestruturas Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
19 172240 Maputo Cidade – Plataforma Estratégica de Turismo, Negócios e Investimento Sustentável tempo Turismo 2026-04-14T10:58:53+00:00 2026-04-14T11:03:28+00:00 0866639d09c5c0b3b00e8527554065587c793f60df978b66b6a578b3c741bc0d https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel/ | https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel 16 publicado RecursoQA16; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 21 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
20 171994 Mercado Financeiro tempo Oportunidades 2026-04-06T09:27:00+00:00 2026-04-17T09:53:42+00:00 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 https://investemoz.tempo.co.mz/mercado-financeiro 23 vazio — dependência concreta RecursoQA23; original/hash/ClamD/replay demonstrados. Corpo vazio na origemHTML/Inertia200;privado,sem página publicada. mercado_financeiro {"status": "capturada mas não publicada no ativo", "sha256": "417b4a33468f360acef272ce3e4180c1d0a171980befa73ddb9a33de5a9d4c4e"} Corpo do artigo vazio; imagem não substitui conteúdo. Manter pendente e separado, sem bloquear outros lotes. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado Original vazio Fornecer corpo editorial pela Tempo; imagem e Fintech não substituem o original. Sem novo endereço público.
21 173480 Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias tempo Trabalho Doméstico 2026-09-15T12:34:17+00:00 2026-09-15T12:34:19+00:00 5b95ad9010fcbdc1000052f47766ca54409d3e0649211729ced9ef142f5c6db0 https://investemoz.tempo.co.mz/modelo-de-contrato-de-trabalho-domestico-para-pequenas-familias 66 existente por integrar inventariado; cadastro/versão por reconciliar 55 trabalho_domestico {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/55/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. trabalho_domestico
22 172219 Niassa - O último grande destino virgem do turismo africano tempo Turismo 2026-04-14T10:17:14+00:00 2026-04-14T10:43:56+00:00 47d82a59a86c3cbdef04ea065e711e7139d50137e440f03efbd710e3c4220ef7 https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano/ | https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano 21 publicado RecursoQA21; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 26 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
23 173476 Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique tempo Trabalho Doméstico 2026-09-15T11:39:21+00:00 2026-09-15T11:39:24+00:00 bb634a9021da9d7b46ed105317aa54e4af42a16dab042e0ceb2bdc0d702d1a67 https://investemoz.tempo.co.mz/procedimentos-para-rescisao-do-contrato-de-trabalho-domestico-segundo-o-regulamento-de-mocambique 67 existente por integrar inventariado; cadastro/versão por reconciliar 56 trabalho_domestico {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/56/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. trabalho_domestico
24 172263 Província da Zambézia: Onde os Corredores de Moçambique Convergem com a Natureza, a Cultura e o Turismo Sustentável tempo Turismo 2026-04-14T14:21:52+00:00 2026-04-14T14:26:27+00:00 9e7ca4e9542135d5969f5c008ce8e29b037cc06a53875cfa7dc3e7452ec47744 https://investemoz.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel 11 publicado RecursoQA11; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 3 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
25 172233 Província de Gaza: Oportunidades mais sólidas e estratégicas de investimento no turismo no sul de Moçambique. tempo Turismo 2026-04-14T10:52:30+00:00 2026-04-17T08:28:56+00:00 2bf2df9bd3b7ab8656209a48f4928b5d8bbf2959e77c292fc4c9987e67ba2fea https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique/ | https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique 18 publicado RecursoQA18; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 23 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
26 172253 Província de Inhambane: Um Destino Estratégico para Investimento Turístico tempo Turismo 2026-04-14T14:15:12+00:00 2026-04-14T14:25:44+00:00 2d1cc729481ce65a5e50898c0eea4a1eb2418273b03fc749009e2ffaaa72fe71 https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico/ | https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico 15 publicado RecursoQA15; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 6 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
29 172230 Província de Nampula - Perfil de investimento no setor do turismo tempo Turismo 2026-04-14T10:50:32+00:00 2026-04-14T11:10:23+00:00 d18ccc1e036b3480605462ce7176be75153f6aa988bc9b37d8d395b01e555a7a https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo/ | https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo 19 publicado RecursoQA19; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 24 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
30 172256 Província de Sofala: Onde a Natureza, a História e o Futuro do Turismo Convergem tempo Turismo 2026-04-14T14:16:47+00:00 2026-04-14T14:26:17+00:00 12b46a34ba61c6ef0058a6c410ebc17329d897fe4b06a13b4ea3fe3c85a28342 https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem/ | https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem 12 publicado RecursoQA12; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 4 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
31 172261 Província de Tete: Onde o Rio Zambeze, a Cultura Viva e a Conservação Comunitária Criam o Futuro do Turismo tempo Turismo 2026-04-14T14:19:48+00:00 2026-04-14T14:26:25+00:00 e78fce2931260a7d6f82270897e906feb640f65d084c2d4ffb5ba19303858275 https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo/ | https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo 13 publicado RecursoQA13; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 5 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
32 73246 Rofino Licuco preso cinco meses depois de condenado por agressão tempo Nas Redes 2017-07-28T20:23:11+00:00 2017-07-28T20:23:11+00:00 806c54948641f4f5933a2ea4a6935dfb7a67202ab227960451d62435880289f6 https://investemoz.tempo.co.mz/rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao 47 existente por integrar inventariado; cadastro/versão por reconciliar 38 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/38/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
33 77232 Sete indivíduos mortos a tiro na Matola tempo Nas Redes 2017-08-11T20:30:32+00:00 2017-08-11T20:30:32+00:00 e657a97d5d6db7fa0ea6b7d14029ff873ea5d36dfdadda5f8b9bc8f1ef5dd011 https://investemoz.tempo.co.mz/sete-individuos-mortos-a-tiro-na-matola 48 existente por integrar inventariado; cadastro/versão por reconciliar 39 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/39/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
34 62416 Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia tempo Categoria 2017-06-26T12:14:48+00:00 2017-06-26T12:14:48+00:00 0fe20a9ca9dd99c58072f43b3dece1de347ef4063ee5f75bcffe8b2f4bf253b5 https://investemoz.tempo.co.mz/sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india 55 existente por integrar inventariado; cadastro/versão por reconciliar 40 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/40/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
35 173209 Fintech tempo Oportunidades 2026-06-16T11:24:22+00:00 2026-06-23T10:03:06+00:00 8db9206bf5192b68e7c9bdfb87e9dc9c7063a4b7eca56630685b0e6c294f55ab https://investemoz.tempo.co.mz/tech-fintech 27 publicado inventariado; cadastro/versão por reconciliar 28 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/tech-fintech Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
36 171990 Turismo tempo Oportunidades 2026-04-06T09:22:51+00:00 2026-06-16T13:07:59+00:00 604d30a740cc6ed20d24e3447806e733aa4aefb9f339f81d3dc57b644dd19fb7 https://investemoz.tempo.co.mz/turismo 10 publicado RecursoQA10; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 19 publicados {"scope": "homologação", "href": "/documentos/15/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/turismo Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
37 74364 tempo Categoria 2017-07-26T21:20:33+00:00 2017-07-26T21:20:33+00:00 2a7f0a5b09e0136fec9eae357ac8a88a159ead23b25ed7bb735c75997b10ec5e https://investemoz.tempo.co.mz/74364-2 dependência concreta — título ausente inventariado; cadastro/versão por reconciliar identidade_incompleta {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/1501695692_133_notitle.jpg | Referência não recolhida: https://www.facebook.com/179463555444013/posts/1552815684775453 | Título vazio no post 74364; corpo com 20 caracteres; identidade editorial a esclarecer sem inventar título. Preservar exemplar e referências; delimitar recuperação editorial antes de integrar. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado Original sem título Identificação editorial pela Tempo para o post 74364; corpo com 21 caracteres úteis preservado. Sem título ou endereço novo inventado.
38 62929 Daúde Razaque já não é treinador da Liga Desportiva de Maputo tempo Nas Redes 2017-06-27T16:41:43+00:00 2017-06-27T16:41:43+00:00 c3b57ea685290bfb01c50403bc83db98cf1a42ad51c04d5b8d288c99b8c0a808 https://investemoz.tempo.co.mz/daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo 49 existente por integrar inventariado; cadastro/versão por reconciliar 41 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/41/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
39 62649 Daviz Simango não se incomoda com possível sucessão na Beira tempo Nas Redes 2017-06-26T19:38:09+00:00 2017-06-26T19:38:09+00:00 090e5f41ed11c8e680d2e30ea5c8310b7c6b165ddec318a8b0cf94927f78da74 https://investemoz.tempo.co.mz/daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira 56 existente por integrar inventariado; cadastro/versão por reconciliar 42 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/42/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
40 173470 Direitos e Deveres do Trabalhador Doméstico tempo Trabalho Doméstico 2026-09-15T11:28:25+00:00 2026-09-15T11:28:28+00:00 f69fd6fd8509913f2d79df0267c469dc7a9d0d30420ce8428749d53ba21446ab https://investemoz.tempo.co.mz/direitos-e-deveres-do-trabalhador-domestico 68 existente por integrar inventariado; cadastro/versão por reconciliar 57 trabalho_domestico {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/57/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. trabalho_domestico
41 172679 Energia tempo Featured 2026-04-30T13:03:57+00:00 2026-04-30T13:28:48+00:00 e2a7eb4be0a2cf4139737f6428c147ac35de99899478ce79195dc5e1b0a960f3 https://investemoz.tempo.co.mz/energia | https://investemoz.tempo.co.mz/energia/ 8 publicado RecursoQA8; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 1 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/energia Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
42 62739 “Exigimos responsabilização dos agentes do crime”, Daviz Simango tempo Nas Redes 2017-06-26T23:13:36+00:00 2017-06-26T23:13:36+00:00 e37ea18176246dab529d2ecec7734f0fb2b0a54cadc507fbd789033d5b8e5b93 https://investemoz.tempo.co.mz/exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango-2 57 existente por integrar inventariado; cadastro/versão por reconciliar 43 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/43/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
43 62854 Governo e parceiros reforçam mecanismos de controlo de HIV/Sida tempo Nas Redes 2017-06-27T11:07:53+00:00 2017-06-27T11:07:53+00:00 0073816b1fa4bd50ec6417b07272da06565230d06a19079ca76cb006c882d2f1 https://investemoz.tempo.co.mz/governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida 58 existente por integrar inventariado; cadastro/versão por reconciliar 44 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/44/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
44 63128 Graça Machel diz que desnutrição é um problema de desenvolvimento tempo Nas Redes 2017-06-27T22:01:59+00:00 2017-06-27T22:01:59+00:00 711f3707e3a0d72ec919216fc50823de9060349104ee98fe0a6b20d6684b6031 https://investemoz.tempo.co.mz/graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento 59 existente por integrar inventariado; cadastro/versão por reconciliar 45 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/45/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
45 63181 In dependência tempo Nas Redes 2017-06-27T21:38:06+00:00 2017-06-27T21:38:06+00:00 b0d87c0d58d6d1343d102cd3141bda1215c5afd54f3780a1c6c262d786dbfe27 https://investemoz.tempo.co.mz/in-dependencia 60 existente por integrar inventariado; cadastro/versão por reconciliar 46 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/46/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
46 63146 Kroll não descobriu como foram gastos 2 biliões de dólares; Governo de Nyusi não apoiou a Auditoria; criação da Proindicus, EMATUM e MAM não foi para proteção da Zona Económica Exclusiva tempo Nas Redes 2017-06-27T19:30:01+00:00 2017-06-27T19:30:01+00:00 4ccbad5c92ddc3884f58181a4f1ed3c1d3d6a59f005bfd99b197a6fc1fc3c280 https://investemoz.tempo.co.mz/kroll-nao-descobriu-como-foram-gastos-2-bilioes-de-dolares-governo-de-nyusi-nao-apoiou-a-auditoria-criacao-da-proindicus-ematum-e-mam-nao-foi-para-protecao-da-zona-economica-exclusiva-2 61 existente por integrar inventariado; cadastro/versão por reconciliar 47 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/47/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
47 172674 Mineração tempo Featured 2026-04-30T13:12:09+00:00 2026-04-30T13:30:13+00:00 8d3acc292ed806bc4cc7bcb6a3a6a5759f30b610766a5ef4b3d6a0b7c56d5861 https://investemoz.tempo.co.mz/mineracao 9 publicado RecursoQA9; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 2 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Preservar a publicação; gerir edições e versões pela biblioteca existente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado https://teste-investidor.tempo.co.mz/mineracao Publicado; identidade e conteúdo consultáveis na homologação Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. 2026-10-22T21:05:03.369388+00:00
48 62688 O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ... tempo Nas Redes 2017-06-26T18:21:18+00:00 2017-06-26T18:21:18+00:00 396fe2575641622015505eb11d4c7152b6e3e1b741966f14c0cd1673fd455fd3 https://investemoz.tempo.co.mz/o-instituto-nacional-de-meteorologia-preve-o-seguinte-estado-do-tempo-para-esta-29 62 existente por integrar inventariado; cadastro/versão por reconciliar 48 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/48/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
49 173474 Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique tempo Trabalho Doméstico 2026-09-15T11:37:04+00:00 2026-09-15T11:37:06+00:00 e09a0fe71397e2b060ff8435111117aa487b476a85ec522fffcdf9e23a6cdac2 https://investemoz.tempo.co.mz/sancoes-disciplinares-aplicaveis-a-trabalhadores-domesticos-segundo-o-regulamento-de-mocambique 69 existente por integrar inventariado; cadastro/versão por reconciliar 58 trabalho_domestico {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/58/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. trabalho_domestico
50 63248 Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (... tempo Nas Redes 2017-06-28T11:30:01+00:00 2017-06-28T11:30:01+00:00 2220ca2c07d10f10b2bd6fd0f103ee733b83570d436c751c449c85b42df46a13 https://investemoz.tempo.co.mz/dois-alunos-da-9a-classe-cairam-nas-maos-da-policia-da-republica-de-mocambique 50 existente por integrar inventariado; cadastro/versão por reconciliar 49 historico_noticioso {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/49/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. historico_noticioso
51 173463 Regulamento do Trabalho Doméstico tempo Trabalho Doméstico 2026-09-15T10:56:07+00:00 2026-09-15T12:41:44+00:00 eb43b6c1f097631250f0b36d3d01b4d106db2fcae07a56bb154819143fff11e9 https://investemoz.tempo.co.mz/regulamento-do-trabalho-domestico 70 existente por integrar inventariado; cadastro/versão por reconciliar 59 trabalho_domestico {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas https://teste-investidor.tempo.co.mz/management/portal-services/resources/59/article/preview Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. trabalho_domestico
@@ -2,32 +2,32 @@
Conferência HTTP individual em 2026-10-22T21:05:03.369388+00:00. Lista por identidade editorial; imagens, recursos da biblioteca e variantes de URL não são artigos adicionais. Não altera publicações. Endereço em branco significa que não foi demonstrada uma página nova, não uma ligação a criar por suposição.
Actualização editorial QA: 28 com editor/leitor/prévia; pacote privado preparado, não transportado. Os 20 públicos conservam a conferência anterior, sem novas consultas. Guia e recibo: `legado-editorial-qa-20261022.json`.
Actualização de homologação, 22/10/2026: os 28 estão cadastrados privadamente, com pesquisa/editor/prévia/recuperação conferidos. Os seus endereços abaixo são privados e exigem conta autorizada; não são artigos publicados. Os 20 públicos conservam a conferência anterior, sem novas consultas. Recibo: `../../unification/legacy-editorial-installation-receipt-20261022.json`.
| ID | Título original | Endereço original | Endereço no novo portal | Estado | Pendência |
| --- | --- | --- | --- | --- | --- |
| 171985 | Agronegocio | https://investemoz.tempo.co.mz/agronegocio | https://teste-investidor.tempo.co.mz/agronegocio | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 62413 | 15/30 costa do sol com dua na zona de mupulene muito lindo | https://investemoz.tempo.co.mz/1530-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. Rever/corrigir a nota de demonstração QA antes de publicar. |
| 173220 | Alumínio “Verde” | https://investemoz.tempo.co.mz/aluminio-verde | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 73945 | Banco Mundial classifica de proibitivos juros praticados em Moçambique | https://investemoz.tempo.co.mz/banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 62413 | 15/30 costa do sol com dua na zona de mupulene muito lindo | https://investemoz.tempo.co.mz/1530-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo | https://teste-investidor.tempo.co.mz/management/portal-services/resources/32/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. Rever/corrigir a nota de demonstração QA antes de publicar. |
| 173220 | Alumínio “Verde” | https://investemoz.tempo.co.mz/aluminio-verde | https://teste-investidor.tempo.co.mz/management/portal-services/resources/50/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 73945 | Banco Mundial classifica de proibitivos juros praticados em Moçambique | https://investemoz.tempo.co.mz/banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique | https://teste-investidor.tempo.co.mz/management/portal-services/resources/33/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 173213 | Bens de Consumo e Franquias | https://investemoz.tempo.co.mz/bens-de-consumo-franquias | https://teste-investidor.tempo.co.mz/bens-de-consumo-franquias | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 172223 | Cabo Delgado - Pemba, A capital do turismo costeiro do norte de Moçambique | https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique/ \| https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique | https://teste-investidor.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 173482 | Checklist para Contratação e Direitos do Trabalho Doméstico | https://investemoz.tempo.co.mz/checklist-para-contratacao-e-direitos-do-trabalho-domestico | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 76474 | Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador | https://investemoz.tempo.co.mz/coloque-o-seu-numero-para-o-grupo-de-whatsapp-venda-de-acessorios-de-computador | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 173484 | Direitos Especiais da Trabalhadora Doméstica no Regulamento | https://investemoz.tempo.co.mz/direitos-especiais-da-trabalhadora-domestica-no-regulamento | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 173482 | Checklist para Contratação e Direitos do Trabalho Doméstico | https://investemoz.tempo.co.mz/checklist-para-contratacao-e-direitos-do-trabalho-domestico | https://teste-investidor.tempo.co.mz/management/portal-services/resources/52/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 76474 | Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador | https://investemoz.tempo.co.mz/coloque-o-seu-numero-para-o-grupo-de-whatsapp-venda-de-acessorios-de-computador | https://teste-investidor.tempo.co.mz/management/portal-services/resources/34/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 173484 | Direitos Especiais da Trabalhadora Doméstica no Regulamento | https://investemoz.tempo.co.mz/direitos-especiais-da-trabalhadora-domestica-no-regulamento | https://teste-investidor.tempo.co.mz/management/portal-services/resources/53/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 171981 | Energia & Mineração | https://investemoz.tempo.co.mz/energia-mineracao | https://teste-investidor.tempo.co.mz/energia-mineracao | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 173222 | Energia e Recursos Naturais | https://investemoz.tempo.co.mz/energia-recursos-naturais | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 62414 | Frelimo e Zanu-PF: Evocados laços de irmandade | https://investemoz.tempo.co.mz/frelimo-e-zanu-pf-evocados-lacos-de-irmandade | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 62418 | Governo dará todo O apoio à PGR no seguimento da auditoria | https://investemoz.tempo.co.mz/governo-dara-todo-o-apoio-a-pgr-no-seguimento-da-auditoria | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 75002 | Governo pretende construir 100 mil habitações em dois anos | https://investemoz.tempo.co.mz/governo-pretende-construir-100-mil-habitacoes-em-dois-anos | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 173478 | Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico | https://investemoz.tempo.co.mz/guia-pratico-para-empregadores-sobre-contratacao-e-direitos-no-trabalho-domestico | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 173222 | Energia e Recursos Naturais | https://investemoz.tempo.co.mz/energia-recursos-naturais | https://teste-investidor.tempo.co.mz/management/portal-services/resources/51/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 62414 | Frelimo e Zanu-PF: Evocados laços de irmandade | https://investemoz.tempo.co.mz/frelimo-e-zanu-pf-evocados-lacos-de-irmandade | https://teste-investidor.tempo.co.mz/management/portal-services/resources/35/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 62418 | Governo dará todo O apoio à PGR no seguimento da auditoria | https://investemoz.tempo.co.mz/governo-dara-todo-o-apoio-a-pgr-no-seguimento-da-auditoria | https://teste-investidor.tempo.co.mz/management/portal-services/resources/36/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 75002 | Governo pretende construir 100 mil habitações em dois anos | https://investemoz.tempo.co.mz/governo-pretende-construir-100-mil-habitacoes-em-dois-anos | https://teste-investidor.tempo.co.mz/management/portal-services/resources/37/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 173478 | Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico | https://investemoz.tempo.co.mz/guia-pratico-para-empregadores-sobre-contratacao-e-direitos-no-trabalho-domestico | https://teste-investidor.tempo.co.mz/management/portal-services/resources/54/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 173218 | Imobiliário | https://investemoz.tempo.co.mz/imobiliario | https://teste-investidor.tempo.co.mz/imobiliario | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 171992 | Infraestruturas | https://investemoz.tempo.co.mz/infraestruturas | https://teste-investidor.tempo.co.mz/infraestruturas | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 172240 | Maputo Cidade – Plataforma Estratégica de Turismo, Negócios e Investimento Sustentável | https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel/ \| https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel | https://teste-investidor.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 171994 | Mercado Financeiro | https://investemoz.tempo.co.mz/mercado-financeiro | | Original vazio | Fornecer corpo editorial pela Tempo; imagem e Fintech não substituem o original. Sem novo endereço público. |
| 173480 | Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias | https://investemoz.tempo.co.mz/modelo-de-contrato-de-trabalho-domestico-para-pequenas-familias | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 173480 | Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias | https://investemoz.tempo.co.mz/modelo-de-contrato-de-trabalho-domestico-para-pequenas-familias | https://teste-investidor.tempo.co.mz/management/portal-services/resources/55/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 172219 | Niassa - O último grande destino virgem do turismo africano | https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano/ \| https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano | https://teste-investidor.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 173476 | Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique | https://investemoz.tempo.co.mz/procedimentos-para-rescisao-do-contrato-de-trabalho-domestico-segundo-o-regulamento-de-mocambique | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 173476 | Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique | https://investemoz.tempo.co.mz/procedimentos-para-rescisao-do-contrato-de-trabalho-domestico-segundo-o-regulamento-de-mocambique | https://teste-investidor.tempo.co.mz/management/portal-services/resources/56/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 172263 | Província da Zambézia: Onde os Corredores de Moçambique Convergem com a Natureza, a Cultura e o Turismo Sustentável | https://investemoz.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel | https://teste-investidor.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 172233 | Província de Gaza: Oportunidades mais sólidas e estratégicas de investimento no turismo no sul de Moçambique. | https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique/ \| https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique | https://teste-investidor.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 172253 | Província de Inhambane: Um Destino Estratégico para Investimento Turístico | https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico/ \| https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico | https://teste-investidor.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
@@ -36,23 +36,23 @@ Actualização editorial QA: 28 com editor/leitor/prévia; pacote privado prepar
| 172230 | Província de Nampula - Perfil de investimento no setor do turismo | https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo/ \| https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo | https://teste-investidor.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 172256 | Província de Sofala: Onde a Natureza, a História e o Futuro do Turismo Convergem | https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem/ \| https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem | https://teste-investidor.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 172261 | Província de Tete: Onde o Rio Zambeze, a Cultura Viva e a Conservação Comunitária Criam o Futuro do Turismo | https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo/ \| https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo | https://teste-investidor.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 73246 | Rofino Licuco preso cinco meses depois de condenado por agressão | https://investemoz.tempo.co.mz/rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 77232 | Sete indivíduos mortos a tiro na Matola | https://investemoz.tempo.co.mz/sete-individuos-mortos-a-tiro-na-matola | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 62416 | Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia | https://investemoz.tempo.co.mz/sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 73246 | Rofino Licuco preso cinco meses depois de condenado por agressão | https://investemoz.tempo.co.mz/rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao | https://teste-investidor.tempo.co.mz/management/portal-services/resources/38/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 77232 | Sete indivíduos mortos a tiro na Matola | https://investemoz.tempo.co.mz/sete-individuos-mortos-a-tiro-na-matola | https://teste-investidor.tempo.co.mz/management/portal-services/resources/39/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 62416 | Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia | https://investemoz.tempo.co.mz/sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india | https://teste-investidor.tempo.co.mz/management/portal-services/resources/40/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 173209 | Fintech | https://investemoz.tempo.co.mz/tech-fintech | https://teste-investidor.tempo.co.mz/tech-fintech | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 171990 | Turismo | https://investemoz.tempo.co.mz/turismo | https://teste-investidor.tempo.co.mz/turismo | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 74364 | | https://investemoz.tempo.co.mz/74364-2 | | Original sem título | Identificação editorial pela Tempo para o post 74364; corpo com 21 caracteres úteis preservado. Sem título ou endereço novo inventado. |
| 62929 | Daúde Razaque já não é treinador da Liga Desportiva de Maputo | https://investemoz.tempo.co.mz/daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 62649 | Daviz Simango não se incomoda com possível sucessão na Beira | https://investemoz.tempo.co.mz/daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 173470 | Direitos e Deveres do Trabalhador Doméstico | https://investemoz.tempo.co.mz/direitos-e-deveres-do-trabalhador-domestico | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 62929 | Daúde Razaque já não é treinador da Liga Desportiva de Maputo | https://investemoz.tempo.co.mz/daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo | https://teste-investidor.tempo.co.mz/management/portal-services/resources/41/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 62649 | Daviz Simango não se incomoda com possível sucessão na Beira | https://investemoz.tempo.co.mz/daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira | https://teste-investidor.tempo.co.mz/management/portal-services/resources/42/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 173470 | Direitos e Deveres do Trabalhador Doméstico | https://investemoz.tempo.co.mz/direitos-e-deveres-do-trabalhador-domestico | https://teste-investidor.tempo.co.mz/management/portal-services/resources/57/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 172679 | Energia | https://investemoz.tempo.co.mz/energia \| https://investemoz.tempo.co.mz/energia/ | https://teste-investidor.tempo.co.mz/energia | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 62739 | “Exigimos responsabilização dos agentes do crime”, Daviz Simango | https://investemoz.tempo.co.mz/exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango-2 | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 62854 | Governo e parceiros reforçam mecanismos de controlo de HIV/Sida | https://investemoz.tempo.co.mz/governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 63128 | Graça Machel diz que desnutrição é um problema de desenvolvimento | https://investemoz.tempo.co.mz/graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 63181 | In dependência | https://investemoz.tempo.co.mz/in-dependencia | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 63146 | Kroll não descobriu como foram gastos 2 biliões de dólares; Governo de Nyusi não apoiou a Auditoria; criação da Proindicus, EMATUM e MAM não foi para proteção da Zona Económica Exclusiva | https://investemoz.tempo.co.mz/kroll-nao-descobriu-como-foram-gastos-2-bilioes-de-dolares-governo-de-nyusi-nao-apoiou-a-auditoria-criacao-da-proindicus-ematum-e-mam-nao-foi-para-protecao-da-zona-economica-exclusiva-2 | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 62739 | “Exigimos responsabilização dos agentes do crime”, Daviz Simango | https://investemoz.tempo.co.mz/exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango-2 | https://teste-investidor.tempo.co.mz/management/portal-services/resources/43/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 62854 | Governo e parceiros reforçam mecanismos de controlo de HIV/Sida | https://investemoz.tempo.co.mz/governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida | https://teste-investidor.tempo.co.mz/management/portal-services/resources/44/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 63128 | Graça Machel diz que desnutrição é um problema de desenvolvimento | https://investemoz.tempo.co.mz/graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento | https://teste-investidor.tempo.co.mz/management/portal-services/resources/45/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 63181 | In dependência | https://investemoz.tempo.co.mz/in-dependencia | https://teste-investidor.tempo.co.mz/management/portal-services/resources/46/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 63146 | Kroll não descobriu como foram gastos 2 biliões de dólares; Governo de Nyusi não apoiou a Auditoria; criação da Proindicus, EMATUM e MAM não foi para proteção da Zona Económica Exclusiva | https://investemoz.tempo.co.mz/kroll-nao-descobriu-como-foram-gastos-2-bilioes-de-dolares-governo-de-nyusi-nao-apoiou-a-auditoria-criacao-da-proindicus-ematum-e-mam-nao-foi-para-protecao-da-zona-economica-exclusiva-2 | https://teste-investidor.tempo.co.mz/management/portal-services/resources/47/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 172674 | Mineração | https://investemoz.tempo.co.mz/mineracao | https://teste-investidor.tempo.co.mz/mineracao | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 62688 | O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ... | https://investemoz.tempo.co.mz/o-instituto-nacional-de-meteorologia-preve-o-seguinte-estado-do-tempo-para-esta-29 | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 173474 | Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique | https://investemoz.tempo.co.mz/sancoes-disciplinares-aplicaveis-a-trabalhadores-domesticos-segundo-o-regulamento-de-mocambique | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 63248 | Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (... | https://investemoz.tempo.co.mz/dois-alunos-da-9a-classe-cairam-nas-maos-da-policia-da-republica-de-mocambique | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 173463 | Regulamento do Trabalho Doméstico | https://investemoz.tempo.co.mz/regulamento-do-trabalho-domestico | | Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada | Revisão editorial pela equipa; integração Git e transporte privado autenticado para homologação; publicação separada pelo portal. Imagens não verificadas mantêm referência/aviso. |
| 62688 | O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ... | https://investemoz.tempo.co.mz/o-instituto-nacional-de-meteorologia-preve-o-seguinte-estado-do-tempo-para-esta-29 | https://teste-investidor.tempo.co.mz/management/portal-services/resources/48/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 173474 | Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique | https://investemoz.tempo.co.mz/sancoes-disciplinares-aplicaveis-a-trabalhadores-domesticos-segundo-o-regulamento-de-mocambique | https://teste-investidor.tempo.co.mz/management/portal-services/resources/58/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 63248 | Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (... | https://investemoz.tempo.co.mz/dois-alunos-da-9a-classe-cairam-nas-maos-da-policia-da-republica-de-mocambique | https://teste-investidor.tempo.co.mz/management/portal-services/resources/49/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
| 173463 | Regulamento do Trabalho Doméstico | https://investemoz.tempo.co.mz/regulamento-do-trabalho-domestico | https://teste-investidor.tempo.co.mz/management/portal-services/resources/59/article/preview | Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos | Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas. |
+5 -27
View File
@@ -1,4 +1,3 @@
import { Link } from '@inertiajs/react';
import type { ContextReference } from '@/lib/investor-context';
export default function ContextDocuments({
@@ -6,49 +5,28 @@ export default function ContextDocuments({
}: {
source?: ContextReference;
}) {
if (!source) return null;
if (!source?.documents?.length) return null;
return (
<section
aria-label="Fonte e documentos do contexto"
aria-label="Documentos de apoio"
className="space-y-2 rounded border p-4"
>
<h2 className="font-semibold">Fonte e documentos do contexto</h2>
<p>
<Link className="underline" href={source.href}>
{source.title}
</Link>{' '}
· versão da oportunidade {source.version ?? 'não indicada'} ·{' '}
{source.visibility === 'private'
? 'Preparação privada — não publicada'
: 'Referência pública'}
</p>
<h2 className="font-semibold">Documentos de apoio</h2>
{(source.documents ?? []).map((doc) => (
<article
key={doc.support_id}
className="space-y-1 rounded border p-3"
>
<p>
{doc.title} · {doc.edition ?? 'Edição não indicada'} ·
versão documental {doc.document_version} · metadados v
{doc.metadata_version}
{doc.title}{doc.edition ? ` · ${doc.edition}` : ''}
</p>
<p className="break-all">SHA256: {doc.sha256}</p>
{doc.section && <p>Referência utilizada: {doc.section}</p>}
<p>{doc.source_reference}</p>
<a className="underline" href={doc.download_url}>
Consultar original autorizado —{' '}
Consultar documento —{' '}
{doc.edition ?? doc.title}
</a>
</article>
))}
{!source.documents?.length && (
<p>Sem suporte da biblioteca associado nesta versão.</p>
)}
<p>
Referência guardada nesta versão do dossier. A consulta do
original continua sujeita às permissões actuais; esta ligação
não publica nem concede acesso adicional.
</p>
</section>
);
}
@@ -61,6 +61,8 @@ export function InvestmentContextAssessment({
if (!snapshot) return null;
const fields = snapshot.fields ?? {};
const zone = snapshot.zone;
const steps = (snapshot.path?.steps ?? []).filter(step => !!step.title?.trim());
if (!zone && !fields.investor_origin && !fields.tax_residency_country && !snapshot.preparation?.enabled) return null;
const regime = zone?.fields?.investment_regime ?? fields.investment_regime;
const names: Record<string, string> = {
zee: 'ZEE',
@@ -73,10 +75,9 @@ export function InvestmentContextAssessment({
aria-label="Aplicabilidade ao investimento"
>
<h3 className="font-semibold">
Aplicabilidade ao investimento · contexto v
{snapshot.context_revision}
Condições do investimento
</h3>
<p>
{(fields.investor_origin || fields.tax_residency_country) && <p>
Origem do investidor:{' '}
{{
national: 'nacional',
@@ -84,9 +85,8 @@ export function InvestmentContextAssessment({
mixed: 'misto',
}[fields.investor_origin] ?? 'informação em falta'}
. Residência fiscal declarada:{' '}
{fields.tax_residency_country || 'informação em falta'}. Estas
condições são distintas; uma não determina a outra.
</p>
{fields.tax_residency_country || 'Por preencher'}.
</p>}
{zone ? (
<>
<p>
@@ -95,8 +95,7 @@ export function InvestmentContextAssessment({
{names[regime ?? ''] ?? 'zona seleccionada'}.
</strong>{' '}
<Link className="underline" href={zone.href}>
{zone.title} · versão {zone.version} · consultar
ficha e fundamentos
{zone.title} · consultar condições
</Link>
.
</p>
@@ -162,39 +161,19 @@ export function InvestmentContextAssessment({
</p>
)}
<p role="status">
Benefício fiscal deste enquadramento: indeterminado. Não
existe neste consumidor uma regra executável ligada ao
reconhecimento e condições da zona. No simulador, o IVA
disponível corresponde apenas ao cenário geral sem
benefício, sobre vendas declaradas compatíveis; não
simula o regime especial. O cenário com benefício e o
apuramento final estão indisponíveis.
Os benefícios desta zona ainda não estão disponíveis no simulador. O cenário geral disponível não inclui benefícios especiais nem apuramento fiscal final.
</p>
</>
) : (
<p>
Enquadramento geral de preparação: sem ZEE, ZFI ou parque
seleccionado. Isso não confirma a elegibilidade para uma
operação fiscal. O cálculo mantém o âmbito e as exclusões da
versão publicada.
</p>
)}
<p>
Confirmado neste quadro significa apenas dado recuperado do
dossier; declarações e referências não são decisões jurídicas.
Requisitos específicos não documentados permanecem
indeterminados.
</p>
{snapshot.path && (
) : null}
{!!steps.length && (
<details>
<summary>
Passos adaptados pelo percurso existente · versão{' '}
{snapshot.path.definition_version}
Etapas a preparar
</summary>
<ul className="list-disc pl-5">
{snapshot.path.steps.map((step) => (
{steps.map((step) => (
<li key={step.code}>
{step.code} — {step.title}:{' '}
{step.title}:{' '}
{step.context_review_required
? 'informação alterada; rever fundamento'
: step.applicability ===
@@ -224,7 +203,7 @@ export function InvestmentContextAssessment({
className="underline"
href={`/investimentos/${contextId}/contexto/editar`}
>
Alterar contexto e comparar impacto antes de guardar
Rever dados do investimento
</Link>
)}
</section>
@@ -0,0 +1,54 @@
import { Link } from '@inertiajs/react';
import { TerritoryFields } from './investment-territory';
import type { OpportunityChoice } from '@/lib/investor-context';
import { card, input } from '@/pages/investment/shared';
import { useEffect, useState } from 'react';
import type { TerritoryOption } from './investment-territory';
export type CorridorOption = {key:string;name:string;provinces:TerritoryOption[]};
function ChoiceCard({c,i,corridors,disabled,update,remove}:{c:OpportunityChoice;i:number;corridors:CorridorOption[];disabled:boolean;update:(change:Partial<OpportunityChoice>)=>void;remove?:()=>void}) {
const [notice,setNotice]=useState('');
const corridor=corridors.find(r=>r.key===c.corridor_key)||corridors.find(r=>r.name===c.coverage);
const path=c.territory_path??[];
function location(next:TerritoryOption[], key=corridor?.key) {
update({corridor_key:key,territory_path:next,territory:next.length?{key:'territory:'+next.at(-1)!.id,kind:'territory',id:next.at(-1)!.id,title:next.map(p=>p.name).join(' / '),href:'/oportunidades',version:null,sha256:'',fields:{}}:null});
}
useEffect(()=>{
if (!remove || !corridor) return;
if (path.length && !corridor.provinces.some(p=>p.id===path[0].id)) {
setNotice('A localização anterior foi retirada porque não pertence ao corredor escolhido. Escolha uma localização compatível.');
location(corridor.provinces.length===1?corridor.provinces:[]);
} else if (!path.length && corridor.provinces.length===1) {setNotice('Província seleccionada automaticamente: '+corridor.provinces[0].name+'.');location(corridor.provinces);}
},[corridor?.key,JSON.stringify(corridor?.provinces),path[0]?.id,!!remove]);
return <article className={card+' space-y-3'}>
<h3 className="font-semibold"><Link className="underline" href={c.opportunity.href}>{i+1}. {c.opportunity.title}</Link></h3>
{remove && <label className="block">Corredor para este investimento<select className={input} disabled={disabled||!corridors.length} value={corridor?.key??''} onChange={e=>{
const next=corridors.find(r=>r.key===e.target.value);
if(!next)return;
const compatible=!path.length||next.provinces.some(p=>p.id===path[0].id);
const kept=compatible?path:[];
location(kept.length?kept:next.provinces.length===1?next.provinces:[],next.key);
setNotice(!path.length?(next.provinces.length===1?'Província seleccionada automaticamente: '+next.provinces[0].name+'.':'Escolha uma das províncias deste corredor.'):compatible?'A localização compatível foi conservada.':'A província e os níveis territoriais incompatíveis foram retirados.');
}}><option value="">Seleccione um corredor</option>{corridors.map(r=><option key={r.key} value={r.key}>{r.name}</option>)}</select></label>}
{!remove&&c.coverage&&<p>Abrangência: {c.coverage}</p>}
{notice&&<p role="status">{notice}</p>}
<p>Localização: {c.territory?.title??'Por escolher'}</p>
{remove&&<>
<fieldset disabled={disabled}><legend>Actividades que pretende realizar nesta oportunidade</legend>{Object.entries({production:'Produção agrícola',processing:'Transformação agroindustrial',trade:'Comercialização e exportação',transport:'Transporte e logística',water:'Captação/utilização de água',forestry:'Actividade florestal',animal:'Produção/serviços pecuários'}).map(([key,label])=><label key={key} className="mr-4 inline-block"><input type="checkbox" checked={c.activities?.includes(key)??false} onChange={e=>update({activities:e.target.checked?[...(c.activities??[]),key]:(c.activities??[]).filter(x=>x!==key)})}/>{label}</label>)}</fieldset>
<TerritoryFields initial={c.territory_path} corridor={corridor?.key} disabled={disabled} onChange={next=>location(next)}/>
<label className="block">Motivo da alternativa territorial<textarea className={input} disabled={disabled} value={c.location_reason} onChange={e=>update({location_reason:e.target.value})}/></label>
<label className="block"><input type="checkbox" disabled={disabled} checked={!!c.confirm_location_change} onChange={e=>update({confirm_location_change:e.target.checked})}/>Confirmo a alteração da localização anteriormente confirmada, quando existir.</label>
<button type="button" disabled={disabled} className="underline" onClick={remove}>Retirar esta ficha da escolha</button>
</>}
</article>;
}
export default function OpportunityChoices({choices, onChange, disabled = false, corridors=[]}: {choices: OpportunityChoice[]; onChange?: (choices: OpportunityChoice[]) => void; disabled?: boolean;corridors?:CorridorOption[]}) {
const update = (index: number, change: Partial<OpportunityChoice>) => onChange?.(choices.map((c,i) => i === index ? {...c,...change} : c));
return <section className="space-y-4" aria-label="Oportunidades e respectivas localizações">
<h2 className="text-xl font-bold">Oportunidades escolhidas e localização de cada ficha</h2>
<p>Escolha o corredor e confirme onde pretende realizar o investimento.</p>
{choices.map((c,i)=><ChoiceCard key={c.opportunity.key} c={c} i={i} corridors={corridors} disabled={disabled} update={change=>update(i,change)} remove={onChange?()=>onChange(choices.filter((_,index)=>index!==i)):undefined}/>)}
</section>;
}
@@ -0,0 +1,19 @@
import { Link } from '@inertiajs/react';
import type { RequirementsAssessment } from '@/lib/investor-context';
import { card } from '@/pages/investment/shared';
export default function InvestmentRequirements({assessment, contextId}: {assessment?: RequirementsAssessment | null; contextId: string}) {
if (!assessment?.requirements.length) return null;
const labels: Record<string,string> = {selected:'Localização escolhida; direito não inferido',missing:'Informação em falta',conditional:'Conforme as condições do projecto',declared:'Actividades declaradas; enquadrar modalidade',undetermined:'Procedimento específico por determinar'};
const groups = new Map<string, RequirementsAssessment['requirements']>();
for (const row of assessment.requirements) groups.set(row.opportunity_key,[...(groups.get(row.opportunity_key)??[]),row]);
return <section className="space-y-4" aria-label="Regras e documentos por oportunidade"><h2 className="text-xl font-bold">Requisitos por oportunidade e contexto</h2>
<p>{assessment.fiscal_notice}</p>
{[...groups.entries()].map(([key, rows])=><details key={key} className={card}><summary className="cursor-pointer font-semibold">{rows[0].opportunity_title} · {rows.length} aspectos a conferir</summary>{rows.map(r=><article key={r.opportunity_key+':'+r.code} className="my-3 space-y-2 border-t pt-3">
<h3 className="font-semibold">{r.title} — {r.opportunity_title}</h3><p>{labels[r.state] ?? r.state}</p><p>Entidade: {r.authority}</p><p>{r.basis}</p>
<ul className="list-disc pl-5">{r.documents.map(d=><li key={d}>{d}</li>)}</ul>
<a className="underline" href={r.source_url}>Consultar fundamento e procedimento</a>{' · '}<Link className="underline" href={`/investimentos/${contextId}#${r.step}`}>Preparar e acompanhar em {r.step}</Link>
<p>{r.decision}</p>
</article>)}</details>)}
</section>;
}
@@ -189,11 +189,13 @@ export function TerritoryFields({
onChange,
endpoint = '/api/v1/investment/territory-options',
disabled = false,
corridor,
}: {
initial?: TerritoryOption[];
onChange?: (path: TerritoryOption[]) => void;
endpoint?: string;
disabled?: boolean;
corridor?: string | null;
}) {
const [path, setPath] = useState(initial);
useEffect(() => setPath(initial), [initial]);
@@ -219,6 +221,7 @@ export function TerritoryFields({
parent={path[index - 1]?.id ?? ''}
selected={path[index]}
endpoint={endpoint}
corridor={corridor}
onChange={(value) => {
const next = replaceTerritoryPath(
path,
@@ -252,6 +255,7 @@ export function TerritoryLevel({
endpoint = '/management/territory-options',
fieldError,
disabled = false,
corridor,
}: {
index: number;
parent: string;
@@ -260,6 +264,7 @@ export function TerritoryLevel({
endpoint?: string;
fieldError?: string;
disabled?: boolean;
corridor?: string | null;
}) {
const id = useId();
const [page, setPage] = useState(1);
@@ -290,6 +295,7 @@ export function TerritoryLevel({
page: String(page),
q: search,
});
if (corridor) params.set('corridor', corridor);
const response = await fetch(`${endpoint}?${params}`, {
signal: controller.signal,
headers: { Accept: 'application/json' },
@@ -313,7 +319,7 @@ export function TerritoryLevel({
clearTimeout(timer);
controller.abort();
};
}, [index, parent, page, enabled, endpoint, retry, search]);
}, [index, parent, page, enabled, endpoint, retry, search, corridor]);
return (
<div className="space-y-2">
{enabled && (
@@ -345,7 +351,7 @@ export function TerritoryLevel({
aria-invalid={Boolean(fieldError)}
aria-describedby={fieldError ? `${id}-error` : undefined}
className={control}
disabled={!enabled || loading}
disabled={!enabled || loading || !!error}
value={selected?.id ?? ''}
onChange={(e) =>
onChange(options.find((o) => o.id === e.target.value))
@@ -0,0 +1,51 @@
import { Link } from '@inertiajs/react';
import { useState } from 'react';
import { button, card, input } from '@/pages/investment/shared';
type Item = {id:number;title:string;slug:string;summary:string|null;province:string|null;district:string|null;chains:string[];stages:string[];maturity_label:string|null};
export type CorridorGroup = {id:string;name:string;count:number;locations:string[];opportunities:Item[]};
type Props = {groups:CorridorGroup[];selected:number[];onSelect:(id:number,checked:boolean)=>void;onCompare:(ids:number[])=>void;onClear:()=>void};
function Group({group,selected,onSelect}: {group:CorridorGroup} & Pick<Props,'selected'|'onSelect'>) {
const [province,setProvince]=useState('');
const [district,setDistrict]=useState('');
const [chain,setChain]=useState('');
const provinces=[...new Set(group.opportunities.map(r=>r.province).filter((s):s is string=>!!s))].sort();
const districts=[...new Set(group.opportunities.filter(r=>!province||r.province===province).map(r=>r.district).filter((s):s is string=>!!s))].sort();
const chains=[...new Set(group.opportunities.flatMap(r=>r.chains))].sort();
const rows=group.opportunities.filter(r=>(!province||r.province===province)&&(!district||r.district===district)&&(!chain||r.chains.includes(chain)));
return <section className={card+' space-y-4'} aria-label={group.name}>
<header><h2 className="text-2xl font-bold">{group.name}</h2><p>{group.count} oportunidades publicadas</p>
<p>{group.locations.length ? 'Localizações identificadas: '+group.locations.join(' · ') : 'Abrangência territorial por indicar.'}</p></header>
<div className="grid gap-3 md:grid-cols-3">
<label>Província<select className={input} value={province} onChange={e=>{setProvince(e.target.value);setDistrict('');}}><option value="">Todas as províncias</option>{provinces.map(p=><option key={p}>{p}</option>)}</select></label>
<label>Distrito<select className={input} value={district} onChange={e=>setDistrict(e.target.value)}><option value="">Todos os distritos</option>{districts.map(d=><option key={d}>{d}</option>)}</select></label>
<label>Cadeia de valor<select className={input} value={chain} onChange={e=>setChain(e.target.value)}><option value="">Todas as cadeias</option>{chains.map(c=><option key={c}>{c}</option>)}</select></label>
</div>
<p role="status">{rows.length} oportunidades com estes filtros</p>
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">{rows.map(r=><article key={r.id} className="space-y-3 rounded-lg border p-4">
<h3 className="text-lg font-semibold"><Link href={'/oportunidades/'+r.slug}>{r.title}</Link></h3>
<p>{[r.province,r.district].filter(Boolean).join(' / ')||'Localização por escolher'}</p>
<p>Cadeia de valor: {r.chains.join(' · ')||'Por indicar'}</p>
{r.summary && !r.stages.includes(r.summary) && <p>{r.summary}</p>}
<p>Etapas e actividades: {r.stages.join(' · ')||'Por indicar'}</p><p>{r.maturity_label}</p>
<label className="flex gap-2"><input type="checkbox" checked={selected.includes(r.id)} onChange={e=>onSelect(r.id,e.target.checked)}/>Escolher para preparar investimento</label>
<Link className="underline" href={'/oportunidades/'+r.slug}>Ver ficha</Link>
</article>)}</div>
</section>;
}
export default function OpportunityCorridorGroups({groups,selected,onSelect,onCompare,onClear}:Props) {
return <div className="space-y-6">
<section className={card+' space-y-3'} aria-label="Escolhas entre corredores">
<h2 className="text-xl font-bold">Explore por corredor e escolha onde investir</h2>
<p>Pode escolher oportunidades de vários corredores e confirmar a localização de cada uma durante a preparação.</p>
<p>{selected.length} oportunidades escolhidas</p>
{!!selected.length&&<div className="flex flex-wrap gap-4"><Link className={button} href={'/investimentos/iniciar?'+selected.map(id=>'opportunities[]='+id).join('&')}>Preparar investimento com as oportunidades escolhidas</Link>
<button className={button} disabled={selected.length>4} onClick={()=>onCompare(selected)}>Comparar as escolhidas</button>
<button className="underline" onClick={onClear}>Limpar escolha</button>
{selected.length>4&&<p>A comparação apresenta até quatro fichas de cada vez. Pode preparar o investimento com todas as escolhidas.</p>}</div>}
</section>
{groups.map(group=><Group key={group.id} group={group} selected={selected} onSelect={onSelect}/>)}
</div>;
}
+22
View File
@@ -38,7 +38,25 @@ export type ContextReference = {
visibility?: 'private' | 'public';
state?: string | null;
};
export type RequirementsAssessment = {version: string; fiscal_notice: string; requirements: {opportunity_key: string; opportunity_title: string; code: string; title: string; state: string; step: string; authority: string; documents: string[]; basis: string; source_url: string; decision: string}[]};
export type OpportunityChoice = {
corridor_key?: string | null;
corridor_name?: string | null;
allowed_provinces?: import('@/components/investment-territory').TerritoryOption[];
activities?: string[];
territory_path?: import('@/components/investment-territory').TerritoryOption[];
confirm_location_change?: boolean;
opportunity: ContextReference;
territory: ContextReference | null;
location_reason: string;
location_state: string;
coverage?: string | null;
source?: string | null;
source_sha256?: string | null;
};
export type DossierContext = {
requirements_assessment?: RequirementsAssessment;
opportunity_choices?: OpportunityChoice[];
revision: number;
selection: Partial<
Record<
@@ -79,6 +97,8 @@ export type ContextView = {
notice: string;
};
export type ContextPlan = {
requirements_assessment?: RequirementsAssessment;
opportunity_choices?: OpportunityChoice[];
private_investment?: { before: Preparation; after: Preparation } | null;
preview_hash: string;
version: number;
@@ -102,8 +122,10 @@ export async function contextApi<T>(
url: string,
body?: unknown,
method = 'POST',
keepalive = false,
): Promise<T> {
const response = await fetch(url, {
keepalive,
method: body === undefined ? 'GET' : method,
credentials: 'same-origin',
headers: {
+22 -5
View File
@@ -1,4 +1,5 @@
import EducationalGuides from '@/components/educational-guides';
import OpportunityCorridorGroups, { type CorridorGroup } from '@/components/opportunity-corridor-groups';
import { searchTerritoryHref } from '@/lib/search-territory';
import type { EducationalArticle } from '@/components/educational-article-card';
import OpportunitySearchFilters from '@/components/opportunity-search-filters';
@@ -25,8 +26,10 @@ export default function Catalogue({
territorial,
territorySelection,
catalogueUrl,
corridorGroups = [],
}: {
guides?: EducationalArticle[];
corridorGroups?: CorridorGroup[];
filters: Record<string, string | string[] | boolean>;
references: References;
results: {
@@ -49,6 +52,13 @@ export default function Catalogue({
}) {
const page = usePage<{ auth: { user: unknown } }>();
const { auth } = page.props;
const [investmentSelection, setInvestmentSelection] = useState<number[]>(() => {
try { return JSON.parse(sessionStorage.getItem('investment-opportunity-selection') ?? '[]'); } catch { return []; }
});
function selectInvestment(id: number, checked: boolean) {
const next = checked ? [...new Set([...investmentSelection, id])] : investmentSelection.filter(x => x !== id);
setInvestmentSelection(next); sessionStorage.setItem('investment-opportunity-selection', JSON.stringify(next));
}
const form = useForm({
association_type: String(filters.association_type ?? ''),
association_target: String(filters.association_target ?? ''),
@@ -116,6 +126,10 @@ export default function Catalogue({
const [saved, setSaved] = useState(favourites);
const [selected, setSelected] = useState<number[]>([]);
const [comparison, setComparison] = useState<{ record: Opportunity }[]>([]);
const comparisonRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (view === 'corridors' && comparison.length) comparisonRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, [comparison, view]);
const [points, setPoints] = useState<Feature[] | null>(null);
const [areas, setAreas] = useState<InvestmentMapArea[]>([]);
const [unlocated, setUnlocated] = useState<
@@ -411,7 +425,7 @@ export default function Catalogue({
Alargar pesquisa (remover localização)
</button>
)}
{['grid', 'list', 'map', 'combined'].map((value, i) => (
{['grid', 'list', 'map', 'combined', 'corridors'].map((value, i) => (
<button
key={value}
disabled={searchLoading || !!searchError}
@@ -427,7 +441,7 @@ export default function Catalogue({
);
}}
>
{['Grelha', 'Lista', 'Mapa', 'Lista e mapa'][i]}
{['Grelha', 'Lista', 'Mapa', 'Lista e mapa', 'Por corredor'][i]}
</button>
))}
<a
@@ -561,7 +575,8 @@ export default function Catalogue({
</ul>
</section>
)}
{!searchLoading &&
{view === 'corridors' && !searchLoading && !searchError && <OpportunityCorridorGroups groups={corridorGroups} selected={investmentSelection} onSelect={selectInvestment} onClear={()=>{setInvestmentSelection([]);sessionStorage.removeItem('investment-opportunity-selection');}} onCompare={ids=>void api('/api/v1/investment/compare?'+ids.map(id=>'ids[]='+id).join('&')).then(data=>setComparison(data.records)).catch(e=>setError(e.message))}/>}
{view !== 'corridors' && !searchLoading &&
!searchError &&
(view !== 'map' || error || points?.length === 0) && (
<div
@@ -603,6 +618,7 @@ export default function Catalogue({
? 'Retirar favorito'
: 'Guardar favorito'}
</button>
<label className="flex gap-2"><input type="checkbox" checked={investmentSelection.includes(r.id)} onChange={e => selectInvestment(r.id,e.target.checked)} />Escolher para preparar investimento</label>
<label className="flex gap-2">
<input
type="checkbox"
@@ -639,7 +655,7 @@ export default function Catalogue({
.
</p>
)}
<nav aria-label="Paginação" className="flex gap-6">
<nav aria-label="Paginação" className={view === 'corridors' ? 'hidden' : 'flex gap-6'}>
{results.prev_page_url && (
<Link href={results.prev_page_url}>Anterior</Link>
)}
@@ -662,8 +678,9 @@ export default function Catalogue({
Comparar {selected.length} oportunidades
</button>
)}
{view !== 'corridors' && !!investmentSelection.length && <section className={card}><p>{investmentSelection.length} oportunidades escolhidas, conservadas ao mudar de página.</p><Link className={button} href={'/investimentos/iniciar?' + investmentSelection.map(id => 'opportunities[]='+id).join('&')}>Preparar investimento com as oportunidades escolhidas</Link><button className="ml-4 underline" onClick={() => {setInvestmentSelection([]);sessionStorage.removeItem('investment-opportunity-selection');}}>Limpar escolha</button></section>}
{comparison.length > 0 && (
<div className="overflow-x-auto">
<div ref={comparisonRef} className="overflow-x-auto">
<table className="w-full border-collapse text-left">
<caption className="p-3 text-left font-bold">
Comparação — montantes nas moedas de origem
+4 -8
View File
@@ -32,6 +32,7 @@ export default function Detail({
const [sharing, setSharing] = useState('');
return (
<Frame title={r.title}>
{r.maturity_label === 'Em preparação' && <p className="rounded border border-amber-700 bg-amber-50 p-4"><strong>Em preparação.</strong> Consulte a oportunidade e prepare o seu investimento. A execução depende das condições e autorizações aplicáveis ao projecto.</p>}
<Link
className={button}
href={'/investimentos/iniciar?source=opportunity:' + r.id}
@@ -55,14 +56,6 @@ export default function Detail({
<p>
{r.reference} · {r.sector?.name} · {r.province} {r.district}
</p>
{!r.last_validated_at && (
<p className="rounded border border-amber-700 bg-amber-50 p-4">
Esta ficha não regista data de validação documental.
Confirme a origem e as condições antes de agir. Preparar uma
manifestação expressa interesse; não confirma a oferta nem
representa aprovação.
</p>
)}
<p className="text-xl">{r.summary}</p>
<ClassificationSummary rows={c.classification ?? []} />
<TerritorialSources sources={c.source_evidence} />
@@ -97,6 +90,9 @@ export default function Detail({
</p>
)}
<div className="flex flex-wrap gap-4">
<Link className={button} href={`/investimentos/iniciar?source=opportunity:${r.id}`}>
Iniciar ou continuar o roteiro deste investimento
</Link>
{auth.user ? (
<button
className={button}
@@ -2,15 +2,17 @@ import ContextDocuments from '@/components/context-documents';
import { Link } from '@inertiajs/react';
import { useState } from 'react';
import { Frame, card, input, button } from '@/pages/investment/shared';
import { contextApi, type ContextReference } from '@/lib/investor-context';
import { contextApi, type ContextReference, type OpportunityChoice } from '@/lib/investor-context';
import { createOperationKey } from '@/lib/operation-key';
export default function ContextStart({
contexts,
source,
opportunityChoices = [],
step = null,
}: {
contexts: { id: string; title: string; version: number }[];
source: ContextReference | null;
opportunityChoices?: OpportunityChoice[];
step?: string | null;
}) {
const [chosen, setChosen] = useState('');
@@ -19,9 +21,11 @@ export default function ContextStart({
const [busy, setBusy] = useState(false);
const [error, setError] = useState('');
const [key] = useState(createOperationKey);
const suffix = source ? '?source=' + encodeURIComponent(source.key) : '';
const sourceSuffix = opportunityChoices.length ? '?' + opportunityChoices.map(c => `opportunities[]=${encodeURIComponent(c.opportunity.id)}`).join('&') : source ? '?source=' + encodeURIComponent(source.key) : '';
const suffix = sourceSuffix ? sourceSuffix+'&selection_key='+encodeURIComponent(key) : '';
return (
<Frame title="Iniciar ou continuar um investimento">
{!!opportunityChoices.length && <section className={card}><h2 className="font-bold">Oportunidades escolhidas</h2><ul>{opportunityChoices.map(c => <li key={c.opportunity.key}><Link className="underline" href={c.opportunity.href}>{c.opportunity.title}</Link> · {c.territory?.title ?? 'Localização por escolher'}</li>)}</ul><p>Confirme a localização de cada ficha na comparação do dossier.</p></section>}
<p>
Ideia, oportunidade, sector e localização convergem no mesmo
dossier. A referência é para preparação e não confirma direitos
@@ -30,14 +34,10 @@ export default function ContextStart({
<ContextDocuments source={source ?? undefined} />
{source && (
<section className={card}>
<h2 className="font-bold">Origem consultada</h2>
<h2 className="font-bold">A sua escolha</h2>
<Link className="underline" href={source.href}>
{source.title}
</Link>
<p>
{source.kind} · v{source.version ?? 'não exposta'} ·{' '}
{source.key}
</p>
</section>
)}
<section className={card + ' space-y-3'}>
@@ -63,14 +63,14 @@ export default function ContextStart({
<Link
className={button}
href={
step && !source
step && !source && !opportunityChoices.length
? `/investimentos/${chosen}#${step}`
: `/investimentos/${chosen}/contexto/editar${suffix}`
}
>
{step && !source
{step && !source && !opportunityChoices.length
? 'Abrir ' + step + ' no mesmo dossier'
: 'Comparar no mesmo dossier'}
: 'Preparar neste dossier'}
</Link>
)}
<p>
@@ -100,7 +100,7 @@ export default function ContextStart({
>
<h2 className="text-xl font-bold">Iniciar uma nova ideia</h2>
<p>
Utiliza o cadastro e as cinco fases/19 etapas já existentes.
Organize a sua ideia e acompanhe a preparação do investimento.
</p>
<label className="grid gap-1">
Título do investimento
@@ -121,7 +121,7 @@ export default function ContextStart({
Autorizo reutilizar o meu perfil neste dossier privado.
</label>
<button className={button} disabled={!consent || busy}>
Criar dossier e comparar a referência
Criar dossier e preparar investimento
</button>
{error && <p role="alert">{error}</p>}
</form>
+107 -56
View File
@@ -2,10 +2,9 @@ import {
PreparationEditor,
PreparationImpact,
} from '@/components/private-investment-preparation';
import { InvestmentContextAssessment } from '@/components/investment-context-assessment';
import ContextDocuments from '@/components/context-documents';
import { Link } from '@inertiajs/react';
import { useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { Frame, button, card, input } from '@/pages/investment/shared';
import {
TerritoryFields,
@@ -20,6 +19,10 @@ import {
} from '@/lib/investor-context';
import { useNavigationContext } from '@/components/navigation-context';
import { createOperationKey } from '@/lib/operation-key';
import OpportunityChoices from '@/components/investment-opportunity-choices';
import InvestmentRequirements from '@/components/investment-requirements';
import type { OpportunityChoice } from '@/lib/investor-context';
import type { CorridorOption } from '@/components/investment-opportunity-choices';
type Options = {
opportunities: { key: string; title: string; kind: string }[];
sectors: { id: number; name: string }[];
@@ -32,36 +35,91 @@ export default function ContextEditor({
options: initialOptions,
source,
territorySelection = [],
requestedChoices = null,
draft = null,
entrySources = [],
}: {
initial: ContextView;
options: Options;
source: ContextReference | null;
territorySelection?: TerritoryOption[];
requestedChoices?: OpportunityChoice[] | null;
entrySources?: string[];
draft?: {draft_sequence?:number;needs_review?:boolean;selection?:Partial<Record<Slot,string>>;declarations?:Record<string,string>;replace_fields?:string[];document_links?:Record<string,string|null>}|null;
}) {
const navigation = useNavigationContext();
const [choices, setChoices] = useState<OpportunityChoice[]>(requestedChoices ?? initial.context.opportunity_choices ?? []);
const [manageChoices, setManageChoices] = useState(requestedChoices !== null || !!initial.context.opportunity_choices?.length);
const [view, setView] = useState(initial);
const [preparation, setPreparation] = useState(initial.private_investment);
const [options, setOptions] = useState(initialOptions);
const [query, setQuery] = useState('');
const [changes, setChanges] = useState<Partial<Record<Slot, string>>>(() =>
source
draft?.selection ?? (source
? {
[source.kind === 'business' ? 'opportunity' : source.kind]:
source.key,
}
: {},
: {}),
);
const [declarations, setDeclarations] = useState<Record<string, string>>(
{},
draft?.declarations ?? {},
);
const [documentLinks, setDocumentLinks] = useState<
Record<string, string | null>
>({});
const [replace, setReplace] = useState<string[]>([]);
>(draft?.document_links ?? {});
const [replace, setReplace] = useState<string[]>(draft?.replace_fields ?? []);
const [plan, setPlan] = useState<ContextPlan | null>(null);
const [busy, setBusy] = useState(false);
const [error, setError] = useState('');
const [message, setMessage] = useState('');
const [corridors,setCorridors]=useState<CorridorOption[]>([]);
const [parks,setParks]=useState<Options['parks']>([]);
const [corridorLoading,setCorridorLoading]=useState(true);
const [corridorError,setCorridorError]=useState('');
const [corridorRetry,setCorridorRetry]=useState(0);
const [draftStatus,setDraftStatus]=useState('');
const [draftRetry,setDraftRetry]=useState(0);
const queue=useRef<Promise<unknown>>(Promise.resolve());
const firstCorridor=choices[0]?.corridor_key ?? corridors.find(c=>c.name===choices[0]?.coverage)?.key;
const firstTerritory=choices[0]?.territory?.id;
useEffect(()=>{
let active=true;setCorridorLoading(true);setCorridorError('');
const params=new URLSearchParams();if(firstCorridor)params.set('corridor',firstCorridor);if(firstTerritory)params.set('territory',firstTerritory);
void contextApi<{corridors:CorridorOption[];parks:Options['parks']}>('/investimentos/opcoes-corredor?'+params).then(data=>{
if(!active)return;setCorridors(data.corridors);setParks(data.parks);
const park=Object.hasOwn(changes,'park')?changes.park:view.context.selection.park?.key;
if(firstCorridor&&park&&!data.parks.some(p=>'park:'+p.id===park)){
setChanges(old=>({...old,park:''}));setPlan(null);setMessage('A zona ou parque anterior foi retirado porque não tem enquadramento compatível com a localização escolhida.');
}
}).catch(e=>{if(active)setCorridorError(e.message)}).finally(()=>{if(active)setCorridorLoading(false)});
return()=>{active=false};
},[firstCorridor,firstTerritory,corridorRetry]);
const draftBody=JSON.stringify({entry_sources:entrySources,version:view.case.version,selection:changes,declarations,replace_fields:replace,document_links:documentLinks,
...(manageChoices?{opportunity_choices:choices.map(c=>({source:c.opportunity.key,corridor_key:c.corridor_key,territory:c.territory?.key??null,location_reason:c.location_reason,confirm_location_change:!!c.confirm_location_change,activities:c.activities??[]}))}:{})});
const latestDraft=useRef(draftBody);latestDraft.current=draftBody;
const skipNextDraft=useRef(false);
const confirmedDraftBody=useRef<string|null>(null);
const sequence=useRef({body:'',value:Math.max(Date.now(),draft?.draft_sequence??0)});
if(sequence.current.body!==draftBody)sequence.current={body:draftBody,value:Math.max(Date.now(),sequence.current.value+1)};
useEffect(()=>{
if(busy||corridorLoading||corridorError)return;
if(skipNextDraft.current){skipNextDraft.current=false;confirmedDraftBody.current=draftBody;setDraftStatus('Dados confirmados.');return;}
if(draftBody===confirmedDraftBody.current)return;
setDraftStatus('A guardar rascunho…');
const timer=setTimeout(()=>{
const savedSequence=sequence.current.value;
queue.current=queue.current.catch(()=>{}).then(()=>contextApi('/investimentos/'+view.case.id+'/contexto/rascunho',{...JSON.parse(draftBody),draft_sequence:savedSequence},'POST',draftBody.length<60000))
.then(()=>{if(latestDraft.current===draftBody)setDraftStatus('Rascunho guardado.');})
.catch(e=>{if(latestDraft.current===draftBody)setDraftStatus('Rascunho não guardado: '+e.message)});
},400);
return()=>clearTimeout(timer);
},[draftBody,busy,corridorLoading,corridorError,draftRetry]);
useEffect(()=>{
const flush=()=>{const body=latestDraft.current;if(body!==confirmedDraftBody.current&&body.length<60000)void contextApi('/investimentos/'+initial.case.id+'/contexto/rascunho',{...JSON.parse(body),draft_sequence:sequence.current.value},'POST',true).catch(()=>{});};
window.addEventListener('pagehide',flush);
return()=>{window.removeEventListener('pagehide',flush);flush();};
},[initial.case.id]);
const [operation, setOperation] = useState(createOperationKey);
const [requestBody, setRequestBody] = useState<Record<
string,
@@ -107,6 +165,7 @@ export default function ContextEditor({
setError('');
setMessage('');
const body = {
...(manageChoices ? {opportunity_choices: choices.map(c => ({source:c.opportunity.key,corridor_key:c.corridor_key,territory:c.territory?.key ?? null,location_reason:c.location_reason,confirm_location_change:!!c.confirm_location_change,activities:c.activities??[]}))} : {}),
version: view.case.version,
selection: changes,
declarations,
@@ -134,6 +193,7 @@ export default function ContextEditor({
async function confirm() {
if (!plan || !requestBody) return;
setBusy(true);
await queue.current.catch(()=>{});
setError('');
try {
await contextApi(
@@ -148,7 +208,9 @@ export default function ContextEditor({
const next = await contextApi<ContextView>(
`/investimentos/${view.case.id}/contexto`,
);
skipNextDraft.current=true;
setView(next);
setChoices(next.context.opportunity_choices ?? []);
setPreparation(next.private_investment);
navigation.refresh();
setChanges({});
@@ -158,7 +220,7 @@ export default function ContextEditor({
setPlan(null);
setOperation(createOperationKey());
setMessage(
'Contexto guardado no mesmo dossier. Resultados afetados identificados para revisão; conteúdo submetido e histórico preservados.',
'Dados guardados. Pode continuar a preparação do investimento.',
);
} catch (e) {
setError(
@@ -171,28 +233,18 @@ export default function ContextEditor({
}
}
return (
<Frame title="Contexto do investimento">
<InvestmentContextAssessment
contextId={view.case.id}
raw={view.prefill.simulator?.context_applicability_snapshot}
/>
<ContextDocuments source={view.context.selection.opportunity} />
<Frame title="Preparar investimento">
<div className="space-y-5 [overflow-wrap:anywhere]">
<Link
className="underline"
href={`/investimentos/${view.case.id}`}
>
Voltar ao mesmo dossier
Voltar ao dossier
</Link>
<p>
{view.case.title} · UUID {view.case.id} · dossier v
{view.case.version} · contexto v{view.context.revision}
</p>
<p className="rounded border border-emerald-300 bg-emerald-50 p-3">
As referências apoiam a preparação. Associar uma
oportunidade, sector ou localização não confirma incentivos,
licença, terra disponível, reserva ou autorização.
{view.case.title}
</p>
<p>Confirme as oportunidades e a localização, complete os dados disponíveis e reveja antes de guardar.</p>
{error && (
<div
role="alert"
@@ -210,8 +262,17 @@ export default function ContextEditor({
)}
{message && <p role="status">{message}</p>}
<section className={card + ' space-y-4'}>
{corridorError&&<p role="alert">{corridorError} <button className="underline" onClick={()=>setCorridorRetry(v=>v+1)}>Tentar novamente</button></p>}
{corridorLoading&&<p role="status">A carregar opções do corredor…</p>}
<p role="status">{draftStatus}</p>
{draft?.needs_review&&<p role="status">O rascunho foi recuperado, mas o dossier recebeu outras alterações. Reveja os dados antes de confirmar.</p>}
{draftStatus.startsWith('Rascunho não guardado')&&<button type="button" className="underline" onClick={()=>setDraftRetry(v=>v+1)}>Tentar guardar novamente</button>}
<OpportunityChoices corridors={corridors} choices={choices} disabled={busy||corridorLoading||!!corridorError} onChange={next=>{setChoices(next);setManageChoices(true);setPlan(null);}}/>
<ContextDocuments source={source ?? view.context.selection.opportunity} />
{view.context.revision > 0 && !Object.keys(changes).length && JSON.stringify(choices) === JSON.stringify(view.context.opportunity_choices ?? []) && <InvestmentRequirements assessment={view.context.requirements_assessment} contextId={view.case.id}/>}
<label className="block">Acrescentar uma oportunidade à escolha<select className={input} value="" onChange={e=>{const o=options.opportunities.find(o=>o.key===e.target.value);if(o && !choices.some(c=>c.opportunity.key===o.key)){setChoices([...choices,{opportunity:{...o,id:o.key.split(':')[1],href:'/oportunidades',version:null,sha256:'',fields:{}},territory:null,location_reason:'',location_state:'undetermined'}]);setManageChoices(true);setPlan(null);}}}><option value="">Seleccionar ficha</option>{options.opportunities.filter(o=>o.kind==='opportunity'&&!choices.some(c=>c.opportunity.key===o.key)).map(o=><option key={o.key} value={o.key}>{o.title}</option>)}</select></label>
<h2 className="text-xl font-bold">
Escolher referências existentes
Dados do investimento
</h2>
<div className="flex flex-wrap gap-2">
<label className="min-w-0 flex-1">
@@ -241,11 +302,11 @@ export default function ContextEditor({
</button>
</div>
<label className="grid min-w-0 gap-1">
Oportunidade
Referência individual (sem selecção múltipla)
<select
className={input + ' max-w-full min-w-0'}
value={selected('opportunity')}
disabled={busy}
disabled={busy || manageChoices}
onChange={(e) =>
change('opportunity', e.target.value)
}
@@ -331,29 +392,30 @@ export default function ContextEditor({
</select>
</label>
<label className="grid min-w-0 gap-1">
ZEE, ZFI ou parque consultado
{choices.length>1?'Zona ou parque da primeira oportunidade':'ZEE, ZFI ou parque consultado'}
<select
className={input + ' max-w-full min-w-0'}
disabled={busy}
disabled={busy||corridorLoading||!!corridorError||(!!firstCorridor&&!firstTerritory)}
value={selected('park')}
onChange={(e) => change('park', e.target.value)}
>
<option value="">
Sem ZEE, ZFI ou parque seleccionado
</option>
{options.parks.map((p) => (
{(firstCorridor?parks:options.parks).map((p) => (
<option key={p.id} value={'park:' + p.id}>
{p.name} · v{p.version_no}
{p.name}
</option>
))}
</select>
</label>
<h3 className="font-semibold">
{firstCorridor&&!corridorLoading&&!corridorError&&<p>{!firstTerritory?'Escolha a localização para consultar zonas e parques.':!parks.length?'Não existem zonas ou parques com enquadramento documentado compatível nesta localização.':'A consulta não confirma disponibilidade de lotes, admissão ou incentivos.'}</p>}
{!manageChoices&&<><h3 className="font-semibold">
Localização — escolher até ao nível conhecido
</h3>
<TerritoryFields
initial={territorySelection}
disabled={busy}
disabled={busy || manageChoices}
endpoint="/api/v1/investment/territory-options"
onChange={(path) =>
change(
@@ -367,10 +429,10 @@ export default function ContextEditor({
{view.context.selection.territory && (
<p>
Referência guardada:{' '}
{view.context.selection.territory.title} · v
{view.context.selection.territory.version}.
{view.context.selection.territory.title}
</p>
)}
</>}
</section>
<section className={card + ' space-y-3'}>
<h2 className="text-xl font-bold">
@@ -563,7 +625,7 @@ export default function ContextEditor({
disabled={busy}
onClick={() => void preview()}
>
Comparar impacto antes de guardar
Rever dados antes de guardar
</button>
</section>
{plan && (
@@ -574,6 +636,8 @@ export default function ContextEditor({
<h2 className="text-xl font-bold">
Comparação antes da confirmação
</h2>
{!!plan.opportunity_choices?.length && <OpportunityChoices choices={plan.opportunity_choices}/>}
<InvestmentRequirements assessment={plan.requirements_assessment} contextId={view.case.id}/>
<div className="overflow-x-auto">
<table className="w-full min-w-[36rem] table-fixed text-left">
<thead>
@@ -588,10 +652,9 @@ export default function ContextEditor({
Mantido
</th>
<td className="p-2">
UUID, identidade e{' '}
{plan.documents_preserved}{' '}
documentos.{' '}
{plan.maintained.map((x) => (
{plan.maintained.filter(x=>!x.field.endsWith('_id')).map((x) => (
<p key={x.field}>
{contextFieldNames[
x.field
@@ -607,7 +670,7 @@ export default function ContextEditor({
Atualizado pela nova seleção
</th>
<td className="p-2">
{plan.updated.map((x) => (
{plan.updated.filter(x=>!x.field.endsWith('_id')).map((x) => (
<p key={x.field}>
{contextFieldNames[
x.field
@@ -633,11 +696,7 @@ export default function ContextEditor({
href={r.href}
>
{r.title}
</Link>{' '}
· {r.kind} · v
{r.version ??
'não exposta'}{' '}
· origem {r.key}
</Link>
</p>
),
)}
@@ -649,14 +708,7 @@ export default function ContextEditor({
</th>
<td className="p-2">
{plan.dependent_results.length}{' '}
resultados financeiros acessíveis
afetados:{' '}
{plan.dependent_results
.map((r) => r.id)
.join(', ') || 'nenhum'}
. Etapas:{' '}
{plan.review_steps.join(', ') ||
'nenhuma alteração de dependências'}
resultados financeiros afectados. Etapas a rever: {plan.review_steps.length}
. Dados já preenchidos nos
formulários conservam-se até à sua
conferência.
@@ -668,12 +720,11 @@ export default function ContextEditor({
</th>
<td className="p-2">
{plan.requests.length} pedidos e os
snapshots, decisões e resultados
dados, decisões e resultados
anteriores.{' '}
{plan.requests.map((r) => (
<p key={r.id}>
{r.protocol || r.id} · v
{r.version} · {r.status}
{r.protocol || 'Pedido guardado'}
</p>
))}
</td>
@@ -706,7 +757,7 @@ export default function ContextEditor({
disabled={busy}
onClick={() => void confirm()}
>
Confirmar e guardar o contexto
Guardar dados do investimento
</button>
</div>
</section>
@@ -717,7 +768,7 @@ export default function ContextEditor({
</h2>
{view.results.map((r) => (
<p key={r.id}>
{r.id} · {r.engine} ·{' '}
Resultado guardado —{' '}
{r.context_state === 'review_required'
? 'Desatualizado para o contexto atual — exige revisão/recálculo'
: 'Guardado para o contexto indicado no dossier'}
@@ -729,7 +780,7 @@ export default function ContextEditor({
className="underline"
href={'/balcao-virtual/pedidos/' + r.id}
>
{r.protocol || r.id}
{r.protocol || 'Consultar pedido'}
</Link>{' '}
· {r.status} ·{' '}
{r.context_state === 'historical_submission'
+2 -2
View File
@@ -36,7 +36,7 @@ export default function InvestmentContexts({
<main className="mx-auto max-w-5xl space-y-6 p-4 md:p-8">
<Head title="Os meus investimentos" />
<h1 className="text-2xl font-semibold">Os meus investimentos</h1>
{zoneSource && <section className="rounded border p-4"><h2>Parque consultado: {zoneSource.title} · versão {zoneSource.consulted_public_version}</h2><p>{zoneSource.notice}</p><Link className="underline" href={zoneSource.href}>Voltar à ficha pública</Link></section>}
{zoneSource && <section className="rounded border p-4"><h2>Parque escolhido: {zoneSource.title}</h2><Link className="underline" href={zoneSource.href}>Consultar parque</Link></section>}
{sectorSource && (
<p>
Preparar uma ideia em{' '}
@@ -53,7 +53,7 @@ export default function InvestmentContexts({
<Link className="underline" href={contentSource.href}>
{contentSource.title}
</Link>
. A fonte e a versão serão guardadas no dossier escolhido.
.
</p>
)}
<p>
+7 -14
View File
@@ -3,6 +3,8 @@ import {
type Preparation,
} from '@/components/private-investment-preparation';
import ContextDocuments from '@/components/context-documents';
import InvestmentRequirements from '@/components/investment-requirements';
import OpportunityChoices from '@/components/investment-opportunity-choices';
import type { DossierContext } from '@/lib/investor-context';
import FintechInvestment, {
type FintechView,
@@ -117,12 +119,9 @@ function Result({ result }: { result: PathResult }) {
</p>
<p className="text-sm">
Estimativa recalculada pelas fórmulas da ferramenta a partir
das entradas guardadas, versão {result.draft_version}. Não
dos dados preenchidos. Não
constitui decisão de financiamento.
</p>
<p className="text-xs break-all">
Evidência {result.id} · {result.engine}
</p>
</li>
);
} catch (error) {
@@ -449,16 +448,14 @@ export default function InvestmentPath(path: Path) {
{path.investment_context && (
<section className="space-y-2 rounded border border-emerald-300 bg-emerald-50 p-4">
<h2 className="font-semibold">
Contexto atual — revisão{' '}
{path.investment_context.revision}
As suas escolhas
</h2>
{Object.values(path.investment_context.selection).map(
(ref) => (
<p key={ref.key}>
<Link className="underline" href={ref.href}>
{ref.title}
</Link>{' '}
· versão {ref.version ?? 'não exposta'}
</Link>
</p>
),
)}
@@ -490,15 +487,9 @@ export default function InvestmentPath(path: Path) {
{zone.title}
</Link>
<p>
UUID {zone.zone_id} · versão consultada{' '}
{zone.consulted_public_version} ·{' '}
{zone.selected_at}
</p>
<p>{zone.notice}</p>
<p>
A ficha atual pode ter uma versão diferente;
esta referência conserva a consulta registada.
</p>
</article>
))}
</section>
@@ -539,6 +530,8 @@ export default function InvestmentPath(path: Path) {
}
/>
)}
{!!path.investment_context?.opportunity_choices?.length && <OpportunityChoices choices={path.investment_context.opportunity_choices}/>}
<InvestmentRequirements assessment={path.investment_context?.requirements_assessment} contextId={path.case.id}/>
{!!path.content_sources?.length && (
<section
className="space-y-2 rounded-xl border p-4"
@@ -18,6 +18,8 @@ export default function ContentHub({access, counts}: {access: Access; counts: Re
<p>Sector económico e modalidade são escolhas distintas. Pode guardar preparação incompleta; o editor identifica os campos e variantes ainda sem suporte de submissão.</p>
{access.opportunities.create && <Link className={button} href={access.opportunities.create}>Nova oportunidade</Link>}
<Link className="block underline" href={access.opportunities.index}>Gerir oportunidades e histórico</Link>
{access.opportunities.profileWorkflow && <Link className="block underline" href="/minhas-oportunidades/lotes/agronegocio">Rever o lote das 34 oportunidades de Agronegócio</Link>}
<p>Para divulgar um resumo ainda em preparação, abra a ficha e escolha <strong>Divulgação promocional</strong>: prepare o texto público, reveja a prévia e confirme divulgar, actualizar ou retirar. Esta operação não conclui a validação do investimento.</p>
<ul>{Object.entries(counts.opportunities ?? {}).map(([state, total]) => <li key={state}><Link className="underline" href={`${access.opportunities!.index}?status=${state}`}>{states[state] ?? state}: {total}</Link></li>)}</ul>
<p className="text-sm">As etapas e a independência já definidas para oportunidades mantêm-se. Esta entrada não atribui autorização para rever ou publicar.</p>
{!access.opportunities.profileWorkflow && <p>O seu acesso actual abre o cadastro legado de rascunhos. A submissão, revisão e publicação de novas oportunidades utilizam os perfis operacionais já existentes; a administração de conteúdos não substitui essa designação. Esta entrada não apresenta o rascunho legado como percurso completo de publicação.</p>}
@@ -0,0 +1,25 @@
import { Link, router } from '@inertiajs/react';
import { useState } from 'react';
import { profileJson } from '@/lib/profile-json';
import { createOperationKey } from '@/lib/operation-key';
import { Management, button, control } from './shared';
type Entry = {key:string;id:number|null;title:string;summary:string;description:string;corridor:string;status:string|null;href:string|null};
type Preview = {id:number;token:string;projection:{title:string;summary:string;description:string};operation_key:string};
export default function AgribusinessBatch({entries,manifestHash,canRegister}:{entries:Entry[];manifestHash:string;canRegister:boolean}) {
const [previews,setPreviews]=useState<Preview[]>([]); const [reason,setReason]=useState(''); const [confirmed,setConfirmed]=useState(false); const [busy,setBusy]=useState(false); const [message,setMessage]=useState('');
const base='/minhas-oportunidades/lotes/agronegocio';
async function run(action:'register'|'preview'|'disclose') {setBusy(true);setMessage('');try {
if(action==='register'){await profileJson(base+'/cadastrar',{manifest_hash:manifestHash,confirm:true});router.reload();}
if(action==='preview'){const result=await profileJson(base+'/previa',{}) as {previews:Preview[]};setPreviews(result.previews.map(p=>({...p,operation_key:createOperationKey()})));setConfirmed(false);}
if(action==='disclose'){await profileJson(base+'/divulgar',{previews:previews.map(({id,token,operation_key})=>({id,token,operation_key})),reason,confirm:confirmed});setPreviews([]);setMessage('As 34 fichas foram divulgadas como Em preparação; a execução não foi autorizada.');router.reload();}
}catch(e){setMessage(e instanceof Error?e.message:'Operação não concluída. A versão anterior foi preservada.');}finally{setBusy(false);}}
return <Management title="Oportunidades de Agronegócio"><p>Reveja as oportunidades, complete a informação disponível e confira a prévia antes de divulgar.</p>
<p>{entries.filter(e=>e.id).length} cadastradas · {entries.filter(e=>e.status==='published').length} divulgadas</p>
{canRegister && <button className={button} disabled={busy} onClick={()=>void run('register')}>Cadastrar ou recuperar as 34 fichas privadamente</button>}
{entries.every(e=>e.id) && <button className={button+' ml-3'} disabled={busy} onClick={()=>void run('preview')}>Pré-visualizar divulgação das 34 fichas</button>}
<ul className="my-5 space-y-3">{entries.map(e=><li key={e.key} className="rounded border p-3"><h2>{e.title}</h2><p>{e.summary}</p><p>{e.corridor} · {e.status??'Por cadastrar'}</p>{e.id&&<Link className="underline" href={`/minhas-oportunidades/${e.id}/edit`}>Rever e editar a ficha</Link>}</li>)}</ul>
{!!previews.length && <section aria-label="Prévia pública das 34 fichas"><h2>Conteúdo a divulgar — Em preparação</h2>{previews.map(p=><details key={p.id} className="my-3 rounded border p-3"><summary>{p.projection.title}</summary><p>{p.projection.summary}</p><p className="whitespace-pre-line">{p.projection.description}</p></details>)}<label className="block">Motivo<textarea className={control} value={reason} onChange={e=>setReason(e.target.value)}/></label><label className="block"><input type="checkbox" checked={confirmed} onChange={e=>setConfirmed(e.target.checked)}/>Confirmo a divulgação destes resumos em preparação; não é autorização de execução.</label><button className={button} disabled={busy||!confirmed||reason.trim().length<20} onClick={()=>void run('disclose')}>Divulgar as 34 oportunidades no catálogo</button></section>}
{message&&<p role="status">{message}</p>}<Link className="block underline" href="/oportunidades?sector=agronegocio">Consultar catálogo de Agronegócio</Link>
</Management>;
}
@@ -17,6 +17,7 @@ type Entry = {
updated_at: string;
deleted_at: string | null;
can_edit?: boolean;
can_promote?: boolean;
working_status?: string;
draft_title?: string;
publication?: { scope: string; label: string; public_catalog: boolean };
@@ -232,6 +233,7 @@ export default function Opportunities({
<p>Atualizado: {r.updated_at}</p>
<div className="flex flex-wrap gap-4">
<Link href={`${basePath}/${r.id}/view`}>Ver</Link>
{r.can_promote && <Link href={`/minhas-oportunidades/${r.id}/divulgacao`}>Divulgação promocional</Link>}
{r.can_edit !== false && (
<Link href={`${basePath}/${r.id}/edit`}>
{r.deleted_at || r.status === 'archived'
@@ -75,9 +75,11 @@ export default function OpportunityDraft({
workflowParticipants,
publicationPreview,
publicationState,
promotionHref,
auth,
canEditDraft = false,
} = usePage<{
promotionHref?: string | null;
basePath?: string;
profileMode?: boolean;
profileOrganization?: string | null;
@@ -246,6 +248,15 @@ export default function OpportunityDraft({
<Link href={basePath}>
{profileMode ? 'Minhas oportunidades' : 'Voltar à gestão'}
</Link>
{promotionHref && <Link className="ml-3 underline" href={promotionHref}>Divulgação promocional — Em preparação</Link>}
{!!profileContext?.corridor_agribusiness && (
<section className="my-4 space-y-2 rounded border p-4">
<h2 className="font-semibold">Origem e enquadramento da oportunidade</h2>
<p>{valueText((profileContext.corridor_agribusiness as Record<string, unknown>).corridor)}</p>
<p>Fonte: {valueText((profileContext.corridor_agribusiness as Record<string, unknown>).source)}</p>
<p>Em preparação. O corredor indicado na fonte não confirma implantação, promotor, viabilidade ou financiamento. Complete a ficha e reveja a prévia antes de divulgar.</p>
</section>
)}
{record && (
<Link
href={`/investimentos/iniciar?source=opportunity:${record.id}`}
@@ -0,0 +1,77 @@
import { Link, router } from '@inertiajs/react';
import { useState } from 'react';
import { createOperationKey } from '@/lib/operation-key';
import { profileJson, ProfileValidationError } from '@/lib/profile-json';
import { Management, Field, control, button } from './shared';
type Draft = {title: string; summary: string; description: string; limitations: string; source_reference: string; edition: string; source_date: string; sector_id: number | null; territory_ids: string[]};
type Projection = {title: string; summary: string; description: string; sector_id: number | null; maturity_label: string; territories: {id: string; label: string}[]};
type Preview = {token: string; action: 'disclose' | 'withdraw'; projection: Projection; current: {title: string; summary: string; description: string; status: string}};
export default function OpportunityPromotion({record, initial, etag, publicNow, reauthenticationRequired, sectors, territories, history}: {
record: {id: number; reference: string}; initial: Draft; etag: string; publicNow: boolean; reauthenticationRequired: boolean;
sectors: {id: number; name: string}[]; territories: {id: string; name: string; location_type: string}[];
history: {id: string; action: string; actor_user_id: number; occurred_at: string}[];
}) {
const [draft, setDraft] = useState<Draft>({...initial, source_date: initial.source_date ?? ''});
const [preview, setPreview] = useState<Preview | null>(null);
const [operationKey, setOperationKey] = useState(createOperationKey);
const [reason, setReason] = useState('');
const [confirmed, setConfirmed] = useState(false);
const [busy, setBusy] = useState(false);
const [message, setMessage] = useState('');
const [errors, setErrors] = useState<Record<string,string>>({});
const [needsMfa, setNeedsMfa] = useState(reauthenticationRequired);
function change<K extends keyof Draft>(key: K, value: Draft[K]) { setDraft(current => ({...current, [key]:value})); setPreview(null); setConfirmed(false); }
function report(error: unknown) {setMessage(error instanceof Error ? error.message : 'Não foi possível concluir. A ficha anterior foi preservada.'); setErrors(error instanceof ProfileValidationError ? error.fields : {}); if(error instanceof ProfileValidationError && error.reauthenticate)setNeedsMfa(true);}
function renewAuthentication() { router.post('/logout', {}, {onSuccess:()=>router.visit(`/minhas-oportunidades/${record.id}/divulgacao`)}); }
async function prepare(action: 'disclose' | 'withdraw') {
setBusy(true); setMessage(''); setErrors({}); setPreview(null); setConfirmed(false);
try { const result = await profileJson(`/minhas-oportunidades/${record.id}/divulgacao/previa`, {...draft, etag, action}); setPreview(result); setOperationKey(createOperationKey()); }
catch (error) { report(error); } finally { setBusy(false); }
}
async function publish() {
if (!preview || !confirmed) return;
setBusy(true); setErrors({});
try {const result = await profileJson(`/minhas-oportunidades/${record.id}/divulgacao/confirmar`, {token:preview.token, operation_key:operationKey, reason, confirm:confirmed});
setMessage(result.message); setPreview(null); setConfirmed(false); router.reload();
} catch (error) { report(error); } finally {setBusy(false);}
}
const labels: Record<string,string> = {promotional_summary_published:'Resumo divulgado', promotional_summary_updated:'Resumo actualizado', promotional_summary_withdrawn:'Resumo retirado'};
return <Management title={`Divulgação promocional — ${record.reference}`}>
<Link className="underline" href={`/minhas-oportunidades/${record.id}/view`}>Voltar à oportunidade</Link>
<p>Prepare o resumo público e reveja a prévia antes de confirmar. A divulgação fica identificada como <strong>Em preparação</strong> e não autoriza a execução do investimento. Documentos e contactos do cadastro continuam privados.</p>
<p role="status">{publicNow ? 'Resumo actualmente divulgado.' : 'Resumo não divulgado.'} {message}</p>
{needsMfa && <p role="alert">Entre novamente com a sua conta e MFA para confirmar esta operação. O cadastro guardado permanece disponível; a prévia ainda não confirmada terá de ser preparada novamente. <button className="underline" onClick={renewAuthentication}>Renovar entrada com MFA</button></p>}
{Object.entries(errors).map(([key,value]) => <p role="alert" key={key}>{key}: {value}</p>)}
<form className="space-y-4 rounded border p-5" onSubmit={e=>{e.preventDefault(); void prepare('disclose');}}>
<Field label="Título público"><input required className={control} maxLength={255} value={draft.title} onChange={e=>change('title',e.target.value)}/></Field>
<Field label="Resumo público"><textarea required className={control} maxLength={499} value={draft.summary} onChange={e=>change('summary',e.target.value)}/></Field>
<Field label="Descrição pública"><textarea className={control} maxLength={6000} value={draft.description} onChange={e=>change('description',e.target.value)}/></Field>
<Field label="Limitações e lacunas conhecidas"><textarea className={control} value={draft.limitations} onChange={e=>change('limitations',e.target.value)}/></Field>
<Field label="Fonte do resumo"><textarea className={control} value={draft.source_reference} onChange={e=>change('source_reference',e.target.value)}/></Field>
<Field label="Edição"><input className={control} value={draft.edition} onChange={e=>change('edition',e.target.value)}/></Field>
<Field label="Data-base"><input className={control} type="date" value={draft.source_date} onChange={e=>change('source_date',e.target.value)}/></Field>
<Field label="Sector divulgado"><select className={control} value={draft.sector_id ?? ''} onChange={e=>change('sector_id',e.target.value ? Number(e.target.value):null)}><option value="">Por indicar</option>{sectors.map(s=><option key={s.id} value={s.id}>{s.name}</option>)}</select></Field>
<Field label="Acrescentar abrangência territorial documentada"><select className={control} value="" onChange={e=>{if(e.target.value && !draft.territory_ids.includes(e.target.value))change('territory_ids',[...draft.territory_ids,e.target.value]);}}><option value="">Seleccionar território existente</option>{territories.map(t=><option key={t.id} value={t.id}>{t.name} · {t.location_type}</option>)}</select></Field>
<p>Seleccione apenas a abrangência que pretende divulgar e cuja origem está identificada. Abrangência não comprova implantação ou disponibilidade de terreno. Sem selecção, a localização fica por indicar.</p>
<ul>{draft.territory_ids.map(id=><li key={id}>{territories.find(t=>t.id===id)?.name ?? 'Referência anterior indisponível'} <button type="button" className="underline" onClick={()=>change('territory_ids',draft.territory_ids.filter(t=>t!==id))}>Remover abrangência</button></li>)}</ul>
<button className={button} disabled={busy || needsMfa}>{publicNow ? 'Rever actualização do resumo' : 'Preparar prévia de divulgação'}</button>
{publicNow && <button type="button" className={`${button} ml-3`} disabled={busy || needsMfa} onClick={()=>void prepare('withdraw')}>Preparar retirada do resumo</button>}
</form>
{preview && <section className="space-y-4 rounded border p-5" aria-label="Prévia da divulgação">
<h2 className="text-xl font-semibold">{preview.action === 'withdraw' ? 'Rever retirada do catálogo' : 'Prévia do conteúdo público'}</h2>
<p><strong>{preview.projection.maturity_label}</strong></p>
<h3>{preview.projection.title}</h3><p>{preview.projection.summary}</p><p className="whitespace-pre-wrap">{preview.projection.description}</p>
<p>Sector: {sectors.find(s=>s.id===preview.projection.sector_id)?.name ?? 'Por indicar'}</p>
<ul>{preview.projection.territories.map(t=><li key={t.id}>{t.label}</li>)}</ul>
{!preview.projection.territories.length && <p>Abrangência territorial por indicar.</p>}
<p>Esta prévia ainda não alterou o portal público. {preview.action === 'withdraw' ? 'A confirmação retira o resumo da consulta pública e preserva o cadastro.' : 'Só este texto e o enquadramento apresentado serão divulgados; os anexos e contactos não são incluídos.'}</p>
<Field label="Motivo da divulgação, alteração ou retirada"><textarea required className={control} minLength={10} maxLength={1000} value={reason} onChange={e=>setReason(e.target.value)}/></Field>
<label className="block"><input type="checkbox" checked={confirmed} onChange={e=>setConfirmed(e.target.checked)}/> Confirmo o conteúdo público desta prévia e a operação indicada.</label>
<button className={button} disabled={busy || !confirmed || reason.trim().length<10} onClick={()=>void publish()}>{preview.action === 'withdraw' ? 'Confirmar retirada do resumo' : 'Confirmar divulgação do resumo'}</button>
<button className="ml-3 underline" disabled={busy} onClick={()=>{setPreview(null);setConfirmed(false);}}>Cancelar prévia</button>
</section>}
<section aria-label="Histórico da divulgação"><h2 className="text-xl font-semibold">Histórico da divulgação</h2><ul>{history.map(h=><li key={h.id}>{labels[h.action] ?? h.action} · {h.occurred_at} · responsável {h.actor_user_id}</li>)}</ul></section>
</Management>;
}
+1
View File
@@ -105,6 +105,7 @@ export default function LegacySector({
? article.group.heading
: article.title}
</h1>
{article.sector?.slug === 'agronegocio' && <Link className="inline-flex rounded-lg bg-emerald-800 px-5 py-3 font-semibold text-white" href="/oportunidades?sector=agronegocio&view=corridors">Explorar oportunidades por corredor</Link>}
<p>
Explore o setor e prepare a sua ideia com o contexto
guardado no dossier.
+2
View File
@@ -13,8 +13,10 @@ Route::middleware(['auth', 'verified', PrivateInvestmentResponse::class, Virtual
Route::get('/contexto-atual', [InvestorContextController::class, 'current']);
Route::put('/contexto-atual', [InvestorContextController::class, 'focus']);
Route::get('/fontes-contexto', [InvestorContextController::class, 'options']);
Route::get('/opcoes-corredor', [InvestorContextController::class, 'corridorOptions']);
Route::get('/{id}/contexto', [InvestorContextController::class, 'show'])->whereUuid('id');
Route::get('/{id}/contexto/editar', [InvestorContextController::class, 'edit'])->whereUuid('id');
Route::post('/{id}/contexto/rascunho', [InvestorContextController::class, 'saveDraft'])->whereUuid('id');
Route::post('/{id}/contexto/previa', [InvestorContextController::class, 'preview'])->whereUuid('id');
Route::post('/{id}/contexto/confirmar', [InvestorContextController::class, 'commit'])->whereUuid('id');
Route::get('/a-partir-do-parque/{zoneId}', [Path::class, 'zoneStart'])->whereUuid('zoneId');
+7
View File
@@ -166,6 +166,10 @@ Route::middleware(['auth', 'verified', EnsurePortalProfileAdministration::class]
Route::middleware(['auth', 'verified', EnsurePortalProfiles::class])->group(function () {
$profiles = PortalProfileController::class;
Route::get('/minhas-oportunidades', [$profiles, 'opportunities']);
Route::get('/minhas-oportunidades/lotes/agronegocio', [\App\Http\Controllers\CorridorAgribusinessController::class, 'show']);
Route::post('/minhas-oportunidades/lotes/agronegocio/cadastrar', [\App\Http\Controllers\CorridorAgribusinessController::class, 'register']);
Route::post('/minhas-oportunidades/lotes/agronegocio/previa', [\App\Http\Controllers\CorridorAgribusinessController::class, 'preview']);
Route::post('/minhas-oportunidades/lotes/agronegocio/divulgar', [\App\Http\Controllers\CorridorAgribusinessController::class, 'disclose']);
Route::get('/minhas-oportunidades/territory-options', [InvestmentTerritoryController::class, 'options']);
Route::get('/minhas-oportunidades/territory-geometries', [InvestmentTerritoryController::class, 'geometries']);
Route::get('/minhas-oportunidades/create', [$profiles, 'edit']);
@@ -177,6 +181,9 @@ Route::middleware(['auth', 'verified', EnsurePortalProfiles::class])->group(func
Route::get('/minhas-oportunidades/{id}/classification', [OpportunityClassificationController::class, 'index'])->whereNumber('id');
Route::post('/minhas-oportunidades/{id}/classification/review', [OpportunityClassificationController::class, 'review'])->whereNumber('id');
Route::post('/minhas-oportunidades/{id}/workflow', [$profiles, 'workflow'])->whereNumber('id');
Route::get('/minhas-oportunidades/{id}/divulgacao', [\App\Http\Controllers\OpportunityPromotionController::class, 'show'])->whereNumber('id');
Route::post('/minhas-oportunidades/{id}/divulgacao/previa', [\App\Http\Controllers\OpportunityPromotionController::class, 'preview'])->whereNumber('id');
Route::post('/minhas-oportunidades/{id}/divulgacao/confirmar', [\App\Http\Controllers\OpportunityPromotionController::class, 'confirm'])->whereNumber('id');
Route::post('/minhas-oportunidades/{id}/contacts', [$profiles, 'contact'])->whereNumber('id');
Route::get('/minhas-oportunidades/{id}/resources', [OpportunityResourceController::class, 'index'])->whereNumber('id');
Route::post('/minhas-oportunidades/{id}/library-support', [OpportunityResourceController::class, 'reuseLibrary'])->whereNumber('id');
@@ -0,0 +1,47 @@
<?php
namespace Tests\Feature;
use App\Models\Opportunity;
use App\Models\User;
use App\Services\CorridorAgribusinessOpportunities;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tests\TestCase;
final class CorridorAgribusinessBatchTest extends TestCase
{
use DatabaseTransactions;
public function test_batch_uses_normal_scoped_session_preview_and_idempotent_disclosure_without_touching_other_opportunities(): void
{
$target = DB::selectOne('select current_database() as name, inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test', $target->name);
$this->assertSame(55441, (int) $target->port);
$this->withoutVite(); config(['portal.profile_access_enabled' => true]);
$entries = app(CorridorAgribusinessOpportunities::class)->entries();
$keys = array_column($entries, 'key');
$others = Opportunity::withTrashed()->whereNotIn('management_creation_key', $keys)->orWhereNull('management_creation_key')->orderBy('id')->get()->map(fn ($r) => $r->getRawOriginal())->all();
$count = Opportunity::withTrashed()->count();
$actor = User::findOrFail(295);
$this->actingAs($actor)->withSession(['portal.mfa_actor' => $actor->id, 'portal.mfa_at' => time(), 'portal.access_revision' => (int) $actor->portal_access_revision]);
$base = '/minhas-oportunidades/lotes/agronegocio';
$this->get($base)->assertOk();
$this->postJson($base.'/cadastrar', ['manifest_hash' => str_repeat('0', 64), 'confirm' => true])->assertConflict();
$this->postJson($base.'/cadastrar', ['manifest_hash' => hash('sha256', json_encode($entries, JSON_THROW_ON_ERROR)), 'confirm' => true])->assertOk();
$this->assertSame($count, Opportunity::withTrashed()->count());
$previews = $this->postJson($base.'/previa')->assertOk()->json('previews');
$this->assertCount(34, $previews);
$input = ['confirm' => true, 'reason' => 'QA: divulgação das fichas expressamente seleccionadas no lote de Agronegócio.',
'previews' => array_map(fn ($p) => ['id' => $p['id'], 'token' => $p['token'], 'operation_key' => (string) Str::uuid()], $previews)];
$bad = $input; array_pop($bad['previews']);
$this->postJson($base.'/divulgar', $bad)->assertUnprocessable();
$this->postJson($base.'/divulgar', $input)->assertOk();
$this->postJson($base.'/divulgar', $input)->assertOk();
$this->assertSame(34, Opportunity::whereIn('management_creation_key', $keys)->published()->count());
$this->assertSame($others, Opportunity::withTrashed()->whereNotIn('management_creation_key', $keys)->orWhereNull('management_creation_key')->orderBy('id')->get()->map(fn ($r) => $r->getRawOriginal())->all());
$this->withSession(['portal.mfa_at' => 0])->postJson($base.'/previa')->assertForbidden();
$this->actingAs(User::factory()->create())->get($base)->assertForbidden();
}
}
@@ -0,0 +1,57 @@
<?php
namespace Tests\Feature;
use App\Models\Opportunity;
use App\Models\User;
use App\Services\CorridorAgribusinessOpportunities;
use App\Services\OpportunityManagement;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tests\TestCase;
final class CorridorAgribusinessInvestorPathTest extends TestCase
{
use DatabaseTransactions;
public function test_interested_investor_recovers_the_opportunity_in_the_same_individual_path_and_interest_draft(): void
{
$target = DB::selectOne('select current_database() as name, inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test', $target->name);
$this->assertSame(55441, (int) $target->port);
$this->withoutVite();
config(['portal.profile_access_enabled' => true, 'portal.opportunity_specialized_drafts_enabled' => true,
'investor-path.enabled' => true, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
$actor = User::findOrFail(295);
$this->actingAs($actor)->withSession(['portal.mfa_actor' => $actor->id, 'portal.mfa_at' => time(), 'portal.access_revision' => (int) $actor->portal_access_revision]);
$entry = app(CorridorAgribusinessOpportunities::class)->entries()[0];
$record = Opportunity::where('management_creation_key', $entry['key'])->firstOrFail();
$base = '/minhas-oportunidades/'.$record->id.'/divulgacao';
$preview = $this->postJson($base.'/previa', [...$record->workflow_context['promotional_summary']['input'],
'action' => 'disclose', 'etag' => app(OpportunityManagement::class)->etag($record)])->assertOk()->json();
$this->postJson($base.'/confirmar', ['token' => $preview['token'], 'operation_key' => (string) Str::uuid(), 'confirm' => true,
'reason' => 'QA: conferir o roteiro de um interessado sem atribuir qualquer autorização.'])->assertOk();
$investor = User::factory()->create();
$this->actingAs($investor);
$this->get('/oportunidades/'.$record->slug)->assertOk();
$id = $this->postJson('/investimentos', ['title' => 'QA: investimento a partir de agronegócio', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
$view = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json();
$body = ['version' => $view['case']['version'], 'selection' => ['opportunity' => 'opportunity:'.$record->id]];
$plan = $this->postJson('/investimentos/'.$id.'/contexto/previa', $body)->assertOk()->json();
$this->postJson('/investimentos/'.$id.'/contexto/confirmar', [...$body, 'preview_hash' => $plan['preview_hash'],
'operation_key' => (string) Str::uuid(), 'confirm' => true])->assertOk();
$this->getJson('/investimentos/'.$id.'/contexto')->assertOk()
->assertJsonPath('context.selection.opportunity.key', 'opportunity:'.$record->id)
->assertJsonPath('context.fields.project_title', 'QA: investimento a partir de agronegócio')
->assertJsonPath('context.fields.project_summary', $record->summary)
->assertJsonPath('context.fields.sector_id', '1');
$this->get('/investimentos/'.$id)->assertOk();
$interestId = $this->postJson('/investidor/manifestacoes', ['opportunity_id' => $record->id])->assertCreated()->json('id');
$this->getJson('/investidor/manifestacoes/'.$interestId)->assertOk();
$this->assertSame(1, DB::table('desk_cases')->where('id', $id)->count());
$this->assertSame('opportunity:'.$record->id, app(\App\Services\InvestorContext::class)->view($investor, $id)['context']['selection']['opportunity']['key']);
// All synthetic investor/path/disclosure writes roll back with this test.
}
}
@@ -0,0 +1,92 @@
<?php
namespace Tests\Feature;
use App\Models\Opportunity;
use App\Models\User;
use App\Services\CorridorAgribusinessOpportunities;
use App\Services\OpportunityManagement;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tests\TestCase;
final class CorridorAgribusinessOpportunitiesTest extends TestCase
{
use DatabaseTransactions;
protected function setUp(): void
{
parent::setUp();
$target = DB::selectOne('select current_database() as name, inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test', $target->name);
$this->assertSame(55441, (int) $target->port);
$this->withoutVite();
config(['portal.profile_access_enabled' => true, 'portal.opportunity_specialized_drafts_enabled' => true, 'investor-path.enabled' => true]);
$actor = User::findOrFail(295); // Existing designated QA operator; no new role or account.
$this->actingAs($actor)->withSession(['portal.mfa_actor' => $actor->id, 'portal.mfa_at' => time(), 'portal.access_revision' => (int) $actor->portal_access_revision]);
}
public function test_all_34_records_have_editable_drafts_and_individual_disclosure_and_path(): void
{
$service = app(CorridorAgribusinessOpportunities::class);
$entries = $service->entries();
$this->assertCount(34, $entries);
$masters = DB::table('development_corridors')->orderBy('id')->get()->toJson();
$this->assertSame([], $service->articleLinks());
foreach ($entries as $entry) {
$record = Opportunity::where('management_creation_key', $entry['key'])->firstOrFail();
$this->assertSame('draft', $record->status);
$this->assertNull($record->primary_territory_id);
$this->assertNull($record->promoter_name);
$this->assertNull($record->estimated_investment_amount);
$this->assertSame($entry['corridor'], $record->workflow_context['corridor_agribusiness']['corridor']);
$base = '/minhas-oportunidades/'.$record->id;
$this->get($base.'/edit')->assertOk();
$this->get($base.'/divulgacao')->assertOk();
$input = $record->workflow_context['promotional_summary']['input'];
$preview = $this->postJson($base.'/divulgacao/previa', [...$input, 'action' => 'disclose', 'etag' => app(OpportunityManagement::class)->etag($record)])->assertOk()->json();
$this->assertStringContainsString($entry['corridor'], $preview['projection']['description']);
$this->postJson($base.'/divulgacao/confirmar', ['token' => $preview['token'], 'operation_key' => (string) Str::uuid(), 'confirm' => true,
'reason' => 'QA: conferir divulgação individual da fonte e ligação ao roteiro.'])->assertOk();
$this->getJson('/api/v1/opportunities/'.$record->slug)->assertOk()->assertJsonPath('data.maturity_label', 'Em preparação');
$this->get('/oportunidades/'.$record->slug)->assertOk();
$this->get('/investimentos/iniciar?source=opportunity:'.$record->id)->assertOk();
$this->assertSame($record->id, (int) app(\App\Services\InvestorContext::class)->reference('opportunity:'.$record->id)['id']);
}
$links = $service->articleLinks();
$this->assertSame([5, 6, 6, 7, 5, 5], array_map('count', $links));
$this->assertSame($masters, DB::table('development_corridors')->orderBy('id')->get()->toJson());
// DatabaseTransactions rolls back these QA disclosures; the 34 real-source drafts stay private.
}
public function test_edit_recover_preview_update_withdraw_and_idempotent_loading_preserve_editorial_work(): void
{
$record = Opportunity::where('management_creation_key', app(CorridorAgribusinessOpportunities::class)->entries()[0]['key'])->firstOrFail();
$base = '/minhas-oportunidades/'.$record->id;
$canonical = app(OpportunityManagement::class)->values($record)['canonical'];
$canonical['executive_summary'] .= ' Correcção editorial QA.';
$this->putJson($base.'/draft', ['etag' => app(OpportunityManagement::class)->etag($record), 'canonical' => $canonical,
'reason' => 'QA: corrigir e recuperar os dados através da gestão.'])->assertOk();
$this->assertSame($canonical['executive_summary'], app(OpportunityManagement::class)->values($record->fresh())['canonical']['executive_summary']);
$this->get($base.'/edit')->assertOk();
$input = $record->fresh()->workflow_context['promotional_summary']['input'];
foreach (['disclose', 'disclose', 'withdraw'] as $index => $action) {
$record->refresh();
if ($index === 1) $input['summary'] .= ' Actualização pública QA.';
$preview = $this->postJson($base.'/divulgacao/previa', [...$input, 'action' => $action, 'etag' => app(OpportunityManagement::class)->etag($record)])->assertOk()->json();
$this->postJson($base.'/divulgacao/confirmar', ['token' => $preview['token'], 'operation_key' => (string) Str::uuid(), 'confirm' => true,
'reason' => 'QA: conferir actualização ou retirada sem perder a preparação.'])->assertOk();
}
$this->getJson('/api/v1/opportunities/'.$record->slug)->assertNotFound();
$this->assertSame([], app(CorridorAgribusinessOpportunities::class)->articleLinks());
$this->assertSame($canonical['executive_summary'], app(OpportunityManagement::class)->values($record->fresh())['canonical']['executive_summary']);
$request = \Illuminate\Http\Request::create('/minhas-oportunidades/drafts', 'POST');
app()->instance('request', $request);
$repeat = app(CorridorAgribusinessOpportunities::class)->register(User::findOrFail(295), $record->organization_id);
$this->assertCount(34, $repeat);
$this->assertSame(0, count(array_filter($repeat, fn ($r) => $r['created'])));
$this->assertSame('suspended', $record->fresh()->status);
$this->assertSame($canonical['executive_summary'], app(OpportunityManagement::class)->values($record->fresh())['canonical']['executive_summary']);
}
}
@@ -0,0 +1,113 @@
<?php
namespace Tests\Feature;
use App\Models\Opportunity;
use App\Models\User;
use App\Services\CorridorAgribusinessOpportunities;
use App\Services\InvestmentCorridorContext;
use App\Services\InvestmentOpportunityChoices;
use App\Services\VirtualDesk;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tests\TestCase;
class InvestmentCorridorContextTest extends TestCase
{
use DatabaseTransactions;
private User $investor;
protected function setUp(): void
{
parent::setUp(); $this->withoutVite();
$t=DB::selectOne('select current_database() as name,inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test',$t->name);$this->assertSame(55441,(int)$t->port);
config(['investor-path.enabled'=>true,'investor-path.private_preparation'=>true,'suitecrm.enabled'=>false,'investmoz_ai.enabled'=>false]);
$this->investor=User::factory()->create();$this->actingAs($this->investor);
}
private function record(string $corridor): Opportunity
{
$entry=collect(app(CorridorAgribusinessOpportunities::class)->entries())->firstWhere('corridor',config('investment_corridors.'.$corridor.'.name'));
return Opportunity::where('management_creation_key',$entry['key'])->firstOrFail();
}
public function test_tempo_configuration_uses_existing_ids_and_maputo_includes_both_units(): void
{
foreach(config('investment_corridors') as $key=>$entry){
$provinces=app(InvestmentCorridorContext::class)->provinces($key);
$this->assertEqualsCanonicalizing($entry['provinces'],array_column($provinces,'source_code'));
$response=$this->getJson('/api/v1/investment/territory-options?type=province&corridor='.$key)->assertOk();
$this->assertEqualsCanonicalizing(array_column($provinces,'id'),array_column($response->json('data'),'id'));
}
$this->assertEqualsCanonicalizing(['Maputo Província','Maputo Cidade'],array_column(app(InvestmentCorridorContext::class)->provinces('maputo'),'name'));
foreach(['nacala','limpopo'] as $key){
$choice=app(InvestmentOpportunityChoices::class)->resolve([['source'=>'opportunity:'.$this->record($key)->id]])[0];
$this->assertSame(app(InvestmentCorridorContext::class)->provinces($key)[0]->id,$choice['territory']['id']);
}
}
public function test_server_refuses_incompatible_location_in_draft_and_confirmation_preview(): void
{
$id=$this->postJson('/investimentos',['title'=>'QA corridor guard','client_key'=>(string)Str::uuid(),'reuse_consent'=>true])->assertCreated()->json('id');
$version=$this->getJson('/investimentos/'.$id.'/contexto')->json('case.version');
$gaza=app(InvestmentCorridorContext::class)->provinces('limpopo')[0]->id;
$body=['version'=>$version,'selection'=>[],'opportunity_choices'=>[['source'=>'opportunity:'.$this->record('beira')->id,'corridor_key'=>'beira','territory'=>'territory:'.$gaza]]];
$this->postJson('/investimentos/'.$id.'/contexto/previa',$body)->assertUnprocessable();
$this->postJson('/investimentos/'.$id.'/contexto/rascunho',[...$body,'draft_sequence'=>1])->assertUnprocessable();
$this->getJson('/api/v1/investment/territory-options?type=district&corridor=beira&parent_id='.$gaza)->assertUnprocessable();
$this->getJson('/investimentos/'.$id.'/contexto')->assertJsonPath('context.revision',0);
}
public function test_encrypted_draft_survives_refresh_and_reauthentication_without_committing_context(): void
{
$id=$this->postJson('/investimentos',['title'=>'QA recovery','client_key'=>(string)Str::uuid(),'reuse_consent'=>true])->assertCreated()->json('id');
$before=$this->getJson('/investimentos/'.$id.'/contexto')->json();
$record=$this->record('beira');$province=app(InvestmentCorridorContext::class)->provinces('beira')[0]->id;
$body=['version'=>$before['case']['version'],'selection'=>[],'declarations'=>['currency'=>'MZN'],'opportunity_choices'=>[['source'=>'opportunity:'.$record->id,'corridor_key'=>'beira','territory'=>'territory:'.$province]]];
$this->postJson('/investimentos/'.$id.'/contexto/rascunho',[...$body,'draft_sequence'=>10])->assertOk();
$this->postJson('/investimentos/'.$id.'/contexto/rascunho',[...$body,'draft_sequence'=>9])->assertConflict();
$encrypted=DB::table('desk_cases')->where('id',$id)->value('payload');$this->assertStringNotContainsString($province,$encrypted);
$this->flushSession();$this->actingAs($this->investor);
$this->get('/investimentos/'.$id.'/contexto/editar')->assertOk()->assertInertia(fn(\Inertia\Testing\AssertableInertia $page)=>$page
->where('draft.declarations.currency','MZN')->where('requestedChoices.0.territory.id',$province)->where('requestedChoices.0.corridor_key','beira'));
$after=$this->getJson('/investimentos/'.$id.'/contexto')->json();
$this->assertSame($before['context'],$after['context']);$this->assertSame($before['case']['version'],$after['case']['version']);
$empty=[...$body,'opportunity_choices'=>[],'entry_sources'=>['opportunity:'.$record->id],'draft_sequence'=>11];
$this->postJson('/investimentos/'.$id.'/contexto/rascunho',$empty)->assertOk();
$this->get('/investimentos/'.$id.'/contexto/editar?source=opportunity:'.$record->id)->assertOk()->assertInertia(fn(\Inertia\Testing\AssertableInertia $page)=>$page->has('requestedChoices',0));
$new=$this->record('nacala');
$this->get('/investimentos/'.$id.'/contexto/editar?source=opportunity:'.$new->id)->assertOk()->assertInertia(fn(\Inertia\Testing\AssertableInertia $page)=>$page->where('requestedChoices.0.opportunity.key','opportunity:'.$new->id));
$this->actingAs(User::factory()->create());$this->postJson('/investimentos/'.$id.'/contexto/rascunho',[...$body,'draft_sequence'=>12])->assertForbidden();
}
public function test_zones_need_compatible_documented_territory_and_catalogue_presence_alone_is_insufficient(): void
{
$service=app(InvestmentCorridorContext::class);
$sofala=collect($service->provinces('beira'))->firstWhere('source_code','07')->id;
$gaza=$service->provinces('limpopo')[0]->id;
$base=app(\App\Services\InvestmentZones::class)->visible()->whereIn('category',['industrial_park','zee','zfi'])->firstOrFail();
$clones=[];
foreach([$sofala,$gaza,null] as $territory){$zone=$base->replicate();$zone->code='QA-'.Str::uuid();$zone->name='Synthetic corridor zone';$zone->primary_territory_id=$territory;$zone->save();$clones[]=$zone;}
$available=array_column($service->parks('beira',$sofala),'id');
$this->assertContains($clones[0]->id,$available);$this->assertNotContains($clones[1]->id,$available);$this->assertNotContains($clones[2]->id,$available);
$id=$this->postJson('/investimentos',['title'=>'QA zone guard','client_key'=>(string)Str::uuid(),'reuse_consent'=>true])->assertCreated()->json('id');
$version=$this->getJson('/investimentos/'.$id.'/contexto')->json('case.version');
$body=['version'=>$version,'selection'=>['park'=>'park:'.$clones[1]->id],'opportunity_choices'=>[['source'=>'opportunity:'.$this->record('beira')->id,'corridor_key'=>'beira','territory'=>'territory:'.$sofala]]];
$this->postJson('/investimentos/'.$id.'/contexto/previa',$body)->assertUnprocessable();
$this->postJson('/investimentos/'.$id.'/contexto/rascunho',[...$body,'draft_sequence'=>1])->assertUnprocessable();
$this->getJson('/investimentos/opcoes-corredor?corridor=beira&territory='.$sofala)->assertOk()->assertJsonFragment(['id'=>$clones[0]->id]);
}
public function test_corridor_change_keeps_compatible_paths_and_removes_only_incompatible_geography(): void
{
$service=app(InvestmentCorridorContext::class);$source='opportunity:'.$this->record('beira')->id;
$sofala=collect($service->provinces('beira'))->firstWhere('source_code','07')->id;
$district=app(\App\Services\InvestmentGeography::class)->publicReferences()->where('parent_id',$sofala)->where('location_type','district')->firstOrFail();
$resolver=app(InvestmentOpportunityChoices::class);
$old=$resolver->resolve([['source'=>$source,'corridor_key'=>'beira','territory'=>'territory:'.$district->id]]);
$same=$resolver->resolve([['source'=>$source,'corridor_key'=>'beira','territory'=>'territory:'.$district->id]],$old);
$this->assertSame($old,$same);
$changed=$resolver->resolve([['source'=>$source,'corridor_key'=>'limpopo']],$old);
$this->assertSame($service->provinces('limpopo')[0]->id,$changed[0]['territory']['id']);
$this->assertCount(1,$changed[0]['territory_path']);
$this->assertNull($this->record('beira')->primary_territory_id);
$this->getJson('/api/v1/investment/territory-options?type=locality')->assertOk()->assertJsonPath('data',[]);
config(['investment_corridors.nacala.provinces'=>['03','99']]);
$this->getJson('/api/v1/investment/territory-options?type=province&corridor=nacala')->assertStatus(503);
}
}
@@ -0,0 +1,138 @@
<?php
namespace Tests\Feature;
use App\Models\Opportunity;
use App\Models\User;
use App\Services\CorridorAgribusinessOpportunities;
use App\Services\InvestorContext;
use App\Services\VirtualDesk;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tests\TestCase;
final class InvestmentOpportunityChoicesTest extends TestCase
{
use DatabaseTransactions;
private User $investor;
protected function setUp(): void
{
parent::setUp();
$target = DB::selectOne('select current_database() as name, inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test', $target->name);
$this->assertSame(55441, (int) $target->port);
config(['investor-path.enabled' => true, 'investor-path.private_preparation' => true, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
$this->withoutVite();
$this->investor = User::factory()->create(); $this->actingAs($this->investor);
}
private function dossier(): string
{
return $this->postJson('/investimentos', ['title' => 'QA: investimento conjunto', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
}
public function test_edit_recovers_requested_opportunity_without_presenting_it_as_already_saved(): void
{
$record = Opportunity::where('management_creation_key', app(CorridorAgribusinessOpportunities::class)->entries()[0]['key'])->firstOrFail();
$id = $this->dossier();
$before = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json('context');
$this->get('/investimentos/'.$id.'/contexto/editar?source=opportunity:'.$record->id)->assertOk()
->assertInertia(fn (\Inertia\Testing\AssertableInertia $page) => $page->component('investor-path/context')
->where('source.key', 'opportunity:'.$record->id)
->where('requestedChoices.0.opportunity.key', 'opportunity:'.$record->id)
->where('requestedChoices.0.opportunity.title', $record->title));
$after = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json('context');
$this->assertSame($before, $after);
}
public function test_multiple_opportunities_keep_sites_sources_requirements_and_results_in_one_dossier(): void
{
$entries = array_slice(app(CorridorAgribusinessOpportunities::class)->entries(), 0, 2);
$records = Opportunity::whereIn('management_creation_key', array_column($entries, 'key'))->orderBy('id')->get();
$sites = collect(app(\App\Services\InvestmentCorridorContext::class)->provinces('pemba-lichinga'))->pluck('id');
$this->get('/investimentos/iniciar?opportunities[]='.$records[0]->id.'&opportunities[]='.$records[1]->id)->assertOk();
$id = $this->dossier();
$before = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json();
$input = ['version' => $before['case']['version'], 'selection' => [], 'opportunity_choices' => [
['source' => 'opportunity:'.$records[0]->id, 'territory' => 'territory:'.$sites[0], 'activities' => ['production', 'processing']],
['source' => 'opportunity:'.$records[1]->id, 'territory' => 'territory:'.$sites[1], 'activities' => ['trade']],
]];
$plan = $this->postJson('/investimentos/'.$id.'/contexto/previa', $input)->assertOk()->json();
$this->assertCount(2, $plan['opportunity_choices']);
$this->assertSame($sites[0], $plan['opportunity_choices'][0]['territory']['id']);
$this->assertSame($sites[1], $plan['opportunity_choices'][1]['territory']['id']);
$this->assertSame(CorridorAgribusinessOpportunities::SOURCE_HASH, $plan['opportunity_choices'][1]['source_sha256']);
$this->assertSame('QA: investimento conjunto', $plan['fields']['project_title']);
$this->assertSame($records[0]->summary, $plan['fields']['project_summary']);
$this->assertContains('processing', array_column($plan['requirements_assessment']['requirements'], 'code'));
$this->assertContains('trade', array_column($plan['requirements_assessment']['requirements'], 'code'));
$this->assertSame($before['case']['version'], $this->getJson('/investimentos/'.$id.'/contexto')->json('case.version'));
$control = [...$input, 'preview_hash' => $plan['preview_hash'], 'operation_key' => (string) Str::uuid(), 'confirm' => true];
$this->postJson('/investimentos/'.$id.'/contexto/confirmar', $control)->assertOk();
$this->postJson('/investimentos/'.$id.'/contexto/confirmar', $control)->assertOk()->assertJsonPath('replayed', true);
$after = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json();
$this->assertCount(2, $after['context']['opportunity_choices']);
$snapshot = json_decode($after['prefill']['simulator']['context_applicability_snapshot'], true);
$this->assertSame($after['context']['opportunity_choices'], $snapshot['opportunity_choices']);
$this->assertSame('general', $snapshot['fields']['investment_regime']);
$this->assertArrayNotHasKey('tax_benefit', $snapshot['fields']);
$this->get('/investimentos/'.$id)->assertOk();
$desk = app(VirtualDesk::class); $case = $desk->case($this->investor, $id);
$payload = $desk->decode($case->payload); $resultId = (string) Str::uuid();
$payload['investor_path']['results'] = [['id' => $resultId, 'engine' => 'synthetic-qa-history', 'context_state' => 'current', 'value' => 'preserve']];
DB::table('desk_cases')->where('id', $id)->update(['payload' => $desk->encode($payload)]);
$next = ['version' => $after['case']['version'], 'selection' => [], 'opportunity_choices' => [
['source' => 'opportunity:'.$records[0]->id, 'territory' => 'territory:'.$sites[0], 'activities' => ['production']],
['source' => 'opportunity:'.$records[1]->id, 'territory' => 'territory:'.$sites[0], 'confirm_location_change' => true, 'location_reason' => 'Alternativa territorial escolhida expressamente para comparar o investimento.', 'activities' => ['trade']],
]];
$impact = $this->postJson('/investimentos/'.$id.'/contexto/previa', $next)->assertOk()->json();
$this->assertSame($resultId, $impact['dependent_results'][0]['id']);
$this->postJson('/investimentos/'.$id.'/contexto/confirmar', [...$next, 'preview_hash' => $impact['preview_hash'], 'operation_key' => (string) Str::uuid(), 'confirm' => true])->assertOk();
$this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->assertJsonPath('results.0.value', 'preserve')->assertJsonPath('results.0.context_state', 'review_required');
$this->actingAs(User::factory()->create())->getJson('/investimentos/'.$id.'/contexto')->assertForbidden();
}
public function test_documented_location_cannot_change_silently_and_stale_source_cannot_be_confirmed(): void
{
$record = Opportunity::where('management_creation_key', app(CorridorAgribusinessOpportunities::class)->entries()[0]['key'])->firstOrFail();
$sites = collect(app(\App\Services\InvestmentCorridorContext::class)->provinces('pemba-lichinga'))->pluck('id');
$record->primary_territory_id = $sites[0]; $record->save();
$id = $this->dossier(); $version = $this->getJson('/investimentos/'.$id.'/contexto')->json('case.version');
$input = ['version' => $version, 'selection' => [], 'opportunity_choices' => [['source' => 'opportunity:'.$record->id, 'territory' => 'territory:'.$sites[1]]]];
$this->postJson('/investimentos/'.$id.'/contexto/previa', $input)->assertUnprocessable();
$this->postJson('/investimentos/'.$id.'/contexto/previa', ['version' => $version, 'selection' => ['opportunity' => 'opportunity:'.$record->id, 'territory' => 'territory:'.$sites[1]]])->assertUnprocessable();
$input['opportunity_choices'][0]['confirm_location_change'] = true;
$input['opportunity_choices'][0]['location_reason'] = 'Escolha explícita de implantação alternativa, sem alterar a origem.';
$plan = $this->postJson('/investimentos/'.$id.'/contexto/previa', $input)->assertOk()->json();
$this->assertSame($sites[0], $record->fresh()->primary_territory_id);
$this->postJson('/investimentos/'.$id.'/contexto/confirmar', [...$input, 'preview_hash' => $plan['preview_hash'], 'operation_key' => (string) Str::uuid(), 'confirm' => true])->assertOk();
$input['version'] = $this->getJson('/investimentos/'.$id.'/contexto')->json('case.version');
unset($input['opportunity_choices'][0]['confirm_location_change']);
$plan = $this->postJson('/investimentos/'.$id.'/contexto/previa', $input)->assertOk()->assertJsonPath('dependency_changed', false)->json();
$record->title .= ' QA source changed'; $record->save();
$this->postJson('/investimentos/'.$id.'/contexto/confirmar', [...$input, 'preview_hash' => $plan['preview_hash'], 'operation_key' => (string) Str::uuid(), 'confirm' => true])->assertConflict();
$this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->assertJsonPath('context.revision', 1);
}
public function test_the_34_choices_and_sources_fit_the_existing_simulation_draft_without_reentry(): void
{
$records = Opportunity::whereIn('management_creation_key', array_column(app(CorridorAgribusinessOpportunities::class)->entries(), 'key'))->orderBy('id')->get();
$this->assertCount(34, $records);
$id = $this->dossier();
$view = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json();
$input = ['version' => $view['case']['version'], 'selection' => [], 'opportunity_choices' => $records->map(fn ($r) => ['source' => 'opportunity:'.$r->id])->all()];
$plan = $this->postJson('/investimentos/'.$id.'/contexto/previa', $input)->assertOk()->json();
$this->postJson('/investimentos/'.$id.'/contexto/confirmar', [...$input, 'preview_hash' => $plan['preview_hash'], 'operation_key' => (string) Str::uuid(), 'confirm' => true])->assertOk();
$view = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json();
$snapshot = $view['prefill']['simulator']['context_applicability_snapshot'];
$this->assertCount(34, json_decode($snapshot, true)['opportunity_choices']);
$this->assertLessThan(1000000, strlen($snapshot));
$draft = $this->postJson('/api/v1/simulation-drafts', ['context' => $id, 'personal_snapshot' => [],
'economic_snapshot' => [...$view['prefill']['simulator'], 'purpose' => 'simulate_only', 'currency' => 'MZN']], ['Idempotency-Key' => (string) Str::uuid()])->assertCreated()->json();
$this->assertNotEmpty($draft);
$this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->assertJsonPath('context.opportunity_choices.33.opportunity.key', 'opportunity:'.$records[33]->id);
}
}
@@ -0,0 +1,30 @@
<?php
namespace Tests\Feature;
use Illuminate\Support\Facades\DB;
use Inertia\Testing\AssertableInertia as Assert;
use Tests\TestCase;
class OpportunityCorridorExplorerTest extends TestCase
{
public function test_the_public_agribusiness_catalogue_groups_all_34_records_without_page_truncation(): void
{
$target = DB::selectOne('select current_database() as name, inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test', $target->name);
$this->assertSame(55441, (int) $target->port);
$this->withoutVite();
$this->get('/oportunidades?sector=agronegocio&view=corridors')->assertOk()->assertInertia(fn (Assert $page) => $page
->component('investment/catalogue')
->has('corridorGroups', 6)
->where('results.total', 34)
->where('corridorGroups', function ($groups) {
$groups = collect($groups);
$ids = $groups->flatMap(fn ($g) => collect($g['opportunities'])->pluck('id'));
return $ids->count() === 34 && $ids->unique()->count() === 34
&& $groups->pluck('count', 'name')->get('Corredor da Beira') === 7
&& $groups->pluck('count', 'name')->get('Corredor de Maputo') === 5
&& ! str_contains(json_encode($groups), 'source_sha256');
}));
}
}
+170
View File
@@ -0,0 +1,170 @@
<?php
namespace Tests\Feature;
use App\Models\Opportunity;
use App\Models\User;
use App\Services\OpportunityManagement;
use App\Services\PortalProfileAdministration;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tests\TestCase;
final class OpportunityPromotionTest extends TestCase
{
use DatabaseTransactions;
private User $actor;
private Opportunity $record;
private string $org;
protected function setUp(): void
{
parent::setUp();
$target = DB::selectOne('select current_database() as name, inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test', $target->name);
$this->assertSame(55441, (int) $target->port);
$this->withoutVite();
config(['portal.profile_access_enabled' => true, 'portal.managers' => []]);
$this->actor = User::factory()->create();
$this->actor->forceFill(['two_factor_secret' => Crypt::encryptString('JBSWY3DPEHPK3PXP'), 'two_factor_confirmed_at' => now()])->save();
$this->org = (string) Str::uuid();
DB::table('organizations')->insert(['id' => $this->org, 'name' => 'SYNTHETIC QA Tempo operator', 'external_id' => '000000000', 'organization_type' => 'private']);
DB::table('audit_events')->insert(['source_system' => 'portal-profiles-v1', 'entity_type' => 'authorization', 'action' => 'operator_organization_registered', 'data_classification' => 'restricted',
'after_data' => json_encode(['organization_id' => $this->org, 'organization' => ['name' => 'SYNTHETIC QA Tempo operator', 'nuit' => '000000000'], 'source_reference' => 'Synthetic QA designation only'])]);
app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), User::factory()->create(), ['user_id' => $this->actor->id,
'role' => 'promoter', 'organization_id' => $this->org, 'opportunity_types' => OpportunityManagement::CATEGORIES, 'responsibilities' => [], 'source' => 'internal-portal-designation']);
$this->record = new Opportunity;
$this->record->forceFill(['title' => 'PRIVATE TITLE', 'slug' => 'qa-promo-'.Str::uuid(), 'reference' => 'QA-'.Str::uuid(), 'status' => 'draft',
'opportunity_category' => 'investment_project', 'owner_user_id' => $this->actor->id, 'organization_id' => $this->org, 'management_version' => 1,
'promoter_name' => 'PRIVATE CONTACT', 'description' => 'PRIVATE CONTENT', 'estimated_investment_amount' => '123456.00',
'workflow_context' => ['operator_organization_id' => $this->org, 'contributors' => [$this->actor->id]],
'management_draft' => json_encode(['canonical' => ['official_title' => 'PRIVATE TITLE', 'contact' => 'PRIVATE CONTACT', 'documents' => ['PRIVATE DOCUMENT']]])])->save();
$this->login($this->actor);
}
private function login(User $actor): void
{
$this->actingAs($actor)->withSession(['portal.mfa_actor' => $actor->id, 'portal.mfa_at' => time(), 'portal.access_revision' => (int) $actor->portal_access_revision]);
}
private function base(): string { return '/minhas-oportunidades/'.$this->record->id.'/divulgacao'; }
private function data(array $overrides = []): array
{
return [...['etag' => app(OpportunityManagement::class)->etag($this->record), 'action' => 'disclose', 'title' => 'SYNTHETIC QA public summary',
'summary' => 'Synthetic QA opportunity in preparation, no real investment.', 'description' => 'Only this deliberately selected public text.',
'source_reference' => 'Synthetic source provided for QA', 'edition' => 'QA-1', 'source_date' => '2026-10-22',
'limitations' => 'Financing and implementation not established.', 'territory_ids' => []], ...$overrides];
}
private function preview(array $overrides = []): array { return $this->postJson($this->base().'/previa', $this->data($overrides))->assertOk()->json(); }
private function confirm(array $preview, ?string $key = null): array
{
$data = ['token' => $preview['token'], 'operation_key' => $key ?? (string) Str::uuid(), 'confirm' => true, 'reason' => 'Synthetic QA operation reviewed in preview'];
$this->postJson($this->base().'/confirmar', $data)->assertOk();
return $data;
}
public function test_preview_publish_update_withdraw_and_redisclose_preserve_private_draft_and_audit(): void
{
$file = (string) Str::uuid();
$attachment = (string) Str::uuid();
DB::table('documents')->insert(['id' => $file, 'file_name' => 'PRIVATE-QA-DOCUMENT.txt', 'storage_key' => 'private-qa/'.$file,
'media_type' => 'text/plain', 'sha256' => hash('sha256', 'private QA only'), 'size_bytes' => 15,
'uploaded_by' => $this->actor->id, 'status' => 'quarantined', 'data_classification' => 'internal']);
DB::table('opportunity_documents')->insert(['id' => $attachment, 'opportunity_id' => $this->record->id, 'document_id' => $file,
'version' => 1, 'created_by' => $this->actor->id, 'payload' => json_encode(['title' => 'PRIVATE DOCUMENT', 'visibility' => 'internal'])]);
$documentBefore = DB::table('documents')->where('id', $file)->first();
$attachmentBefore = DB::table('opportunity_documents')->where('id', $attachment)->first();
DB::table('opportunity_profiles')->insert(['opportunity_id' => $this->record->id, 'business_model' => 'PRIVATE PROFILE', 'source_reference' => 'PRIVATE SOURCE']);
$before = $this->record->refresh()->getRawOriginal();
$private = $before['management_draft'];
$preview = $this->preview();
$this->assertSame($before, $this->record->fresh()->getRawOriginal());
$this->assertFalse($preview['writes']);
$this->assertStringContainsString('Em preparação', $preview['projection']['description']);
$this->assertStringNotContainsString('PRIVATE', json_encode($preview['projection']));
$key = (string) Str::uuid();
$request = $this->confirm($preview, $key);
$this->postJson($this->base().'/confirmar', $request)->assertOk()->assertJsonPath('replayed', true);
$this->record->refresh();
$this->assertSame('draft', $this->record->workflow_context['working_state']);
$this->assertSame($private, $this->record->management_draft);
$this->assertSame('PRIVATE CONTACT', app(OpportunityManagement::class)->values($this->record)['promoter_name']);
$public = $this->getJson('/api/v1/opportunities/'.$this->record->slug)->assertOk();
$this->assertStringNotContainsString('PRIVATE', $public->getContent());
$public->assertJsonPath('data.maturity_label', 'Em preparação')->assertJsonPath('data.estimated_investment_amount', null);
$context = app(\App\Services\InvestmentCatalogue::class)->context($this->record->id);
$this->assertNull($context['profile']);
$this->assertSame([], $context['source_evidence']);
$this->assertStringNotContainsString('PRIVATE', json_encode($context));
$this->confirm($this->preview(['summary' => 'Updated synthetic QA summary.']));
$this->getJson('/api/v1/opportunities/'.$this->record->slug)->assertOk()->assertJsonPath('data.summary', 'Updated synthetic QA summary.');
$this->get($this->base())->assertOk();
$this->confirm($this->preview(['action' => 'withdraw']));
$this->getJson('/api/v1/opportunities/'.$this->record->slug)->assertNotFound();
$this->get($this->base())->assertOk();
$this->confirm($this->preview());
$this->getJson('/api/v1/opportunities/'.$this->record->slug)->assertOk();
$events = DB::table('audit_events')->where('source_system', 'tempo-preparation-publication')->where('after_data->record_id', $this->record->id)->get();
$this->assertCount(4, $events);
$this->assertContains('promotional_summary_withdrawn', $events->pluck('action')->all());
foreach ($events as $event) { $this->assertSame($this->actor->id, (int) $event->actor_user_id); $this->assertFalse(json_decode($event->after_data, true)['execution_approved']); }
$this->assertEquals($documentBefore, DB::table('documents')->where('id', $file)->first());
$this->assertEquals($attachmentBefore, DB::table('opportunity_documents')->where('id', $attachment)->first());
}
public function test_stale_tampered_expired_and_foreign_preview_do_not_write(): void
{
$preview = $this->preview();
$payload = ['token' => $preview['token'].'broken', 'operation_key' => (string) Str::uuid(), 'confirm' => true, 'reason' => 'Synthetic QA invalid confirmation'];
$this->postJson($this->base().'/confirmar', $payload)->assertUnprocessable();
$this->record->title = 'Concurrent private edit'; $this->record->save();
$this->postJson($this->base().'/confirmar', [...$payload, 'token' => $preview['token']])->assertConflict();
$fresh = $this->preview();
$this->travel(16)->minutes();
$this->withSession(['portal.mfa_at' => time()]);
$this->postJson($this->base().'/confirmar', [...$payload, 'token' => $fresh['token']])->assertConflict();
$this->travelBack();
$this->login(User::factory()->create());
$this->get($this->base())->assertForbidden();
$this->postJson($this->base().'/confirmar', [...$payload, 'token' => $fresh['token']])->assertForbidden();
$this->assertSame('draft', $this->record->fresh()->status);
}
public function test_external_promoter_and_unrelated_internal_actor_cannot_disclose_and_no_ordinary_publication_is_overwritten(): void
{
$other = User::factory()->create();
$this->login($other);
$this->postJson($this->base().'/previa', $this->data())->assertForbidden();
$this->login($this->actor);
DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'organization_id' => $this->org, 'user_id' => $this->actor->id, 'role' => 'officer']);
DB::table('portal_role_assignments')->where('user_id', $this->actor->id)->update(['source' => 'approved-external-promoter']);
$this->postJson($this->base().'/previa', $this->data())->assertForbidden();
DB::table('portal_role_assignments')->where('user_id', $this->actor->id)->update(['source' => 'internal-portal-designation']);
$this->withSession(['portal.mfa_at' => time() - 901]);
$this->postJson($this->base().'/previa', $this->data())->assertForbidden();
$this->login($this->actor);
$this->record->forceFill(['status' => 'published', 'published_at' => now(), 'workflow_context' => [...$this->record->workflow_context, 'publication' => ['visibility' => 'public']]])->save();
$this->get($this->base())->assertForbidden();
}
public function test_existing_publisher_scope_can_use_the_same_action_without_new_role_or_approval(): void
{
$publisher = User::factory()->create();
$publisher->forceFill(['two_factor_secret' => Crypt::encryptString('JBSWY3DPEHPK3PXP'), 'two_factor_confirmed_at' => now()])->save();
app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $this->actor, ['user_id' => $publisher->id,
'role' => 'publisher', 'organization_id' => $this->org, 'opportunity_types' => ['investment_project'], 'responsibilities' => [], 'source' => 'synthetic-approved-designation']);
$roles = DB::table('portal_role_assignments')->count();
$this->login($publisher);
$access = app(\App\Services\PortalProfileAccess::class);
$this->assertTrue($access->canView($publisher, $this->record), 'Publisher read scope');
$this->assertTrue($access->scoped($publisher, 'publisher', $this->org, 'investment_project'), 'Publisher scope');
$this->assertTrue(app(\App\Services\OpportunityPromotion::class)->allowed($publisher, $this->record), 'Promotional action scope');
$this->confirm($this->preview());
$this->assertSame($roles, DB::table('portal_role_assignments')->count());
$this->assertArrayNotHasKey('approval', $this->record->fresh()->workflow_context);
}
public function test_profile_directory_uses_existing_accounts_without_exposing_authentication_secrets(): void
{
$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->get('/perfis/gestao')->assertOk()->assertInertia(fn (\Inertia\Testing\AssertableInertia $page) => $page
->has('staffAccounts')->where('staffAccounts', fn ($rows) => collect($rows)->contains(fn ($row) => $row['id'] === $this->actor->id && $row['email'] === $this->actor->email && $row['verified'] && $row['mfa'])
&& collect($rows)->every(fn ($row) => !isset($row['password']) && !isset($row['two_factor_secret']))));
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace Tests\Unit;
use App\Services\CorridorAgribusiness;
use DOMDocument;
use DOMXPath;
use PHPUnit\Framework\TestCase;
class CorridorAgribusinessTest extends TestCase
{
public function test_each_named_corridor_keeps_its_own_opportunities_and_original_content(): void
{
$data = json_decode(file_get_contents(__DIR__.'/../../database/data/corridor-investment-opportunities.json'), true, 512, JSON_THROW_ON_ERROR);
$original = '';
foreach ($data['groups'] as $index => $group) {
$original .= '<p><strong>'.chr(97 + $index).') '.$group['name'].'</strong></p><p>Cadeias de valor prioritárias:<br>Conteúdo original '.$index.'</p><p>Descrição preservada '.$index.'</p>';
}
$original .= '<p><strong>4. Âmbito de Investimento</strong></p><p>Outros sectores serão acrescentados.</p>';
$service = new CorridorAgribusiness;
$html = $service->enrich($original);
$doc = new DOMDocument;
$doc->loadHTML('<?xml encoding="UTF-8">'.$html);
$xpath = new DOMXPath($doc);
$this->assertCount(6, $xpath->query('//ul[starts-with(@id,"agronegocio-oportunidades-")]'));
$this->assertCount(34, $xpath->query('//ul[starts-with(@id,"agronegocio-oportunidades-")]/li'));
foreach ($data['groups'] as $index => $group) {
$list = $doc->getElementById('agronegocio-oportunidades-'.($index + 1));
$this->assertSame(count($group['opportunities']), $list->getElementsByTagName('li')->length);
foreach ($group['opportunities'] as $opportunity) {
$this->assertStringContainsString($opportunity['description'], $list->textContent);
}
$this->assertStringContainsString(chr(97 + $index).') '.$group['name'], $html);
$this->assertStringContainsString('Conteúdo original '.$index, $html);
$this->assertStringContainsString('Descrição preservada '.$index, $html);
}
$this->assertStringContainsString('4. Âmbito de Investimento', $html);
$this->assertSame($html, $service->enrich($html));
}
public function test_broader_corridor_names_and_incomplete_sections_are_left_unchanged(): void
{
$html = '<p>Corredor de Nacala e Norte</p><p>Cadeias de valor prioritárias: preservadas</p>'
.'<p>Corredor Maputo–Limpopo</p><p>Cadeias de valor prioritárias: preservadas</p>'
.'<p>Corredor de Nacala</p><p>Sem parágrafo de cadeias prioritárias.</p>';
$this->assertSame($html, (new CorridorAgribusiness)->enrich($html));
}
}
@@ -0,0 +1,36 @@
<?php
namespace Tests\Unit;
use App\Models\Opportunity;
use App\Services\InvestmentCatalogue;
use App\Services\OpportunityCorridorExplorer;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Mockery;
use Tests\TestCase;
class OpportunityCorridorExplorerTest extends TestCase
{
public function test_multiple_groups_keep_one_identity_and_unassociated_records_remain_accessible(): void
{
$first = new Opportunity(['title' => 'Primeira', 'province' => 'Sofala', 'district' => 'Dondo']);
$first->id = 101;
$other = new Opportunity(['title' => 'Outra']); $other->id = 102;
$query = Mockery::mock(Builder::class);
$query->shouldReceive('get')->once()->andReturn(new Collection([$first, $other]));
$catalogue = Mockery::mock(InvestmentCatalogue::class);
$filters = ['sector' => 'agronegocio', 'view' => 'corridors'];
$catalogue->shouldReceive('query')->with($filters)->once()->andReturn($query);
$catalogue->shouldReceive('context')->with(101)->once()->andReturn(['corridors' => collect([(object)['id'=>'a','name'=>'Corredor A'],(object)['id'=>'b','name'=>'Corredor B']])]);
$catalogue->shouldReceive('context')->with(102)->once()->andReturn(['corridors'=>collect()]);
$this->app->instance(InvestmentCatalogue::class, $catalogue);
$groups = app(OpportunityCorridorExplorer::class)->groups($filters);
$this->assertSame(['Corredor A','Corredor B','Outras localizações'], array_column($groups,'name'));
$this->assertSame([101,101,102], array_map(fn($g)=>$g['opportunities'][0]['id'], $groups));
$this->assertSame([1,1,1], array_column($groups,'count'));
$this->assertSame(['Sofala / Dondo'], $groups[0]['locations']);
$this->assertSame([], $groups[2]['locations']);
$this->assertSame([], $groups[0]['opportunities'][0]['stages']);
}
}
+28
View File
@@ -0,0 +1,28 @@
<?php
namespace Tests\Unit;
use App\Models\Opportunity;
use App\Services\CorridorAgribusinessOpportunities;
use App\Services\OpportunityPublicText;
use Tests\TestCase;
class OpportunityPublicTextTest extends TestCase
{
public function test_public_serialization_omits_generated_internal_notes_without_changing_original_or_other_content(): void
{
$source = ['source' => 'investimentos nos corredores.docx', 'source_sha256' => CorridorAgribusinessOpportunities::SOURCE_HASH, 'corridor' => 'Corredor de Maputo'];
$body = 'Produção de arroz.'."\n\nFonte: ".$source['source'].'; SHA-256 '.$source['source_sha256']."\n\n".CorridorAgribusinessOpportunities::LIMITATIONS;
$record = new Opportunity(['description' => $body]);
$record->workflow_context = ['corridor_agribusiness' => $source];
$public = $record->toArray();
$this->assertStringContainsString('Produção de arroz.', $public['description']);
$this->assertStringNotContainsString('SHA-256', $public['description']);
$this->assertStringNotContainsString('.docx', $public['description']);
$this->assertSame($body, $record->description);
$this->assertArrayNotHasKey('workflow_context', $public);
$other = new Opportunity(['description' => $body]);
$this->assertSame($body, OpportunityPublicText::description($other, $body));
$this->assertSame('Texto revisto pela equipa.', OpportunityPublicText::description($record, 'Texto revisto pela equipa.'));
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
// Local QA entry, ordinary login/MFA; never maps to homologation or the active DB.
foreach (['APP_ENV' => 'testing', 'APP_URL' => 'http://127.0.0.1:18574', 'DB_CONNECTION' => 'pgsql', 'DB_HOST' => '127.0.0.1',
'DB_PORT' => '55441', 'DB_DATABASE' => 'simulator_fiscal_delta_20261021_test', 'DB_USERNAME' => 'postgres', 'DB_PASSWORD' => '', 'DB_URL' => '',
'PORTAL_PROFILE_ACCESS_ENABLED' => 'true', 'PORTAL_OPPORTUNITY_SPECIALIZED_DRAFTS_ENABLED' => 'true',
'INVESTOR_PATH_ENABLED' => 'true', 'SESSION_DRIVER' => 'file', 'SESSION_COOKIE' => 'agribusiness_opportunities_qa',
'CACHE_STORE' => 'array', 'MAIL_MAILER' => 'array', 'QUEUE_CONNECTION' => 'sync'] as $k => $v) {
putenv($k.'='.$v); $_ENV[$k] = $_SERVER[$k] = $v;
}
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$public = realpath(__DIR__.'/../public');
$asset = realpath($public.rawurldecode($path));
if ($asset && str_starts_with($asset, $public.DIRECTORY_SEPARATOR) && is_file($asset) && pathinfo($asset, PATHINFO_EXTENSION) !== 'php') return false;
define('LARAVEL_START', microtime(true));
require __DIR__.'/../vendor/autoload.php';
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Illuminate\Contracts\Http\Kernel::class)->bootstrap();
$target = Illuminate\Support\Facades\DB::selectOne('SELECT current_database() AS name, inet_server_port() AS port');
if (! $app->environment('testing') || $target->name !== 'simulator_fiscal_delta_20261021_test' || (int) $target->port !== 55441) {
http_response_code(503); exit('QA target rejected');
}
$app->handleRequest(Illuminate\Http\Request::capture());
+19
View File
@@ -119,6 +119,13 @@ if editorial_receipt.exists():
editorial_rows = {int(re.search(r'post-(\d+)-', r['external_id'])[1]): r for r in editorial['rows']}
assert len(editorial_rows) == 28 and all(r['private'] for r in editorial_rows.values())
extra = ['Endereço no novo portal', 'Estado actual consolidado', 'Pendência actual', 'Conferência HTTP UTC', 'Grupo de preparação QA']
destination_receipt = ROOT / 'docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json'
destination_rows = {}
if destination_receipt.exists():
destination = json.loads(destination_receipt.read_text(encoding='utf-8'))
assert destination['new_publications'] == 0
destination_rows = {r['legacy_id']: r for r in destination['rows']}
assert len(destination_rows) == 28 and all(r['private'] for r in destination_rows.values())
for col in extra:
if col not in columns: columns.append(col)
articles = {a['legacy_id']: a for a in reconciliation['articles']}
@@ -157,6 +164,18 @@ for row in rows:
row['Dependência concreta'] = row['Pendência actual']
row['Próxima ação'] = 'Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites.'
row['Evidência atual'] = 'legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados'
if legacy_id in destination_rows:
item = destination_rows[legacy_id]
assert item['sha256'] == prepared[legacy_id]['sha256']
row['Endereço no novo portal'] = f"https://teste-investidor.tempo.co.mz/management/portal-services/resources/{item['resource_id']}/article/preview"
row['Recurso ativo'] = str(item['resource_id'])
row['Estado actual consolidado'] = 'Rascunho privado na homologação; pesquisa, editor, prévia e recuperação conferidos'
row['Pendência actual'] = 'Revisão editorial e publicação separada pela equipa no portal. As referências sem exemplar de imagem verificado permanecem explícitas.'
if legacy_id == 62413:
row['Pendência actual'] += ' Rever/corrigir a nota de demonstração QA antes de publicar.'
row['Dependência concreta'] = row['Pendência actual']
row['Próxima ação'] = 'Rever pela gestão; corrigir e pré-visualizar; publicar expressamente quando autorizado, sem comandos.'
row['Evidência atual'] = 'docs/investmoz/unification/legacy-editorial-installation-receipt-20261022.json; preservação dos registos anteriores conferida; provas QA reutilizadas'
assert len(rows) == 50 and len({row['ID legado'] for row in rows}) == 50
with path.open('w', encoding='utf-8-sig', newline='') as f:
writer = csv.DictWriter(f, columns); writer.writeheader(); writer.writerows(rows)
@@ -0,0 +1,45 @@
<?php
foreach (['APP_ENV' => 'testing', 'DB_CONNECTION' => 'pgsql', 'DB_HOST' => '127.0.0.1', 'DB_PORT' => '55441',
'DB_DATABASE' => 'simulator_fiscal_delta_20261021_test', 'DB_USERNAME' => 'postgres', 'DB_PASSWORD' => '', 'DB_URL' => '', 'SESSION_DRIVER' => 'array'] as $k => $v) {
putenv($k.'='.$v); $_ENV[$k] = $_SERVER[$k] = $v;
}
require __DIR__.'/../vendor/autoload.php';
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
use Illuminate\Support\Facades\DB;
use App\Models\Opportunity;
use App\Services\CorridorAgribusinessOpportunities;
use App\Services\OpportunityPromotion;
$target = DB::selectOne('SELECT current_database() AS name, inet_server_port() AS port');
if (! app()->environment('testing') || $target->name !== 'simulator_fiscal_delta_20261021_test' || (int) $target->port !== 55441) throw new RuntimeException('QA only');
config(['portal.profile_access_enabled' => true]);
$actor = App\Models\User::findOrFail(295);
// QA-role simulation, like the bounded tests; this is not evidence of a real production MFA login.
session(['portal.mfa_actor' => $actor->id, 'portal.mfa_at' => time(), 'login.id' => null]);
$request = Illuminate\Http\Request::create('/minhas-oportunidades', 'GET');
$request->setUserResolver(fn () => $actor); $app->instance('request', $request);
$entries = app(CorridorAgribusinessOpportunities::class)->entries();
$dir = storage_path('app/private/agribusiness-opportunities-20261023');
$records = Opportunity::whereIn('management_creation_key', array_column($entries, 'key'))->get();
if (! file_exists($dir.'/before-disclosure.json')) file_put_contents($dir.'/before-disclosure.json', json_encode($records->map(fn ($r) => $r->getRawOriginal())->all(), JSON_THROW_ON_ERROR));
$result = DB::transaction(function () use ($actor, $entries) {
DB::select('SELECT pg_advisory_xact_lock(231026, 34)');
$result = [];
foreach ($entries as $entry) {
$record = Opportunity::where('management_creation_key', $entry['key'])->lockForUpdate()->firstOrFail();
if ($record->status !== 'published') {
$values = app(App\Services\OpportunityManagement::class)->values($record);
if ($record->status !== 'draft' || ($values['canonical']['official_title'] ?? null) !== $entry['title'] || ($values['canonical']['executive_summary'] ?? null) !== $entry['summary']) throw new RuntimeException('Edited or withdrawn record requires individual review: '.$record->id);
$input = $record->workflow_context['promotional_summary']['input'];
$preview = app(OpportunityPromotion::class)->preview($actor, $record, [...$input, 'source_date' => null, 'action' => 'disclose', 'etag' => app(App\Services\OpportunityManagement::class)->etag($record)]);
app(OpportunityPromotion::class)->confirm($actor, $record->id, ['token' => $preview['token'], 'operation_key' => (string) Illuminate\Support\Str::uuid(), 'confirm' => true,
'reason' => 'QA automatizada: divulgação das 34 fichas de Agronegócio expressamente instruída pela Tempo; em preparação, sem autorização de execução.']);
} elseif (data_get($record->workflow_context, 'publication.purpose') !== OpportunityPromotion::PURPOSE) throw new RuntimeException('Different publication preserved');
$result[] = ['id' => $record->id, 'title' => $entry['title'], 'corridor' => $entry['corridor'], 'url' => '/oportunidades/'.$record->slug];
}
return $result;
});
$receipt = ['target' => $target, 'published' => count($result), 'authentication' => 'QA role simulation only; no production authentication claimed', 'source_sha256' => CorridorAgribusinessOpportunities::SOURCE_HASH, 'records' => $result, 'active_writes' => 0];
file_put_contents($dir.'/disclosure-receipt.json', json_encode($receipt, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
echo json_encode(['published' => count($result), 'target' => $target, 'active_writes' => 0]).PHP_EOL;
@@ -0,0 +1,34 @@
<?php
// Initial source loading only. Everyday editing and disclosure use the portal.
$options = getopt('', ['apply', 'actor:', 'organization:']);
foreach (['APP_ENV' => 'testing', 'DB_CONNECTION' => 'pgsql', 'DB_HOST' => '127.0.0.1', 'DB_PORT' => '55441',
'DB_DATABASE' => 'simulator_fiscal_delta_20261021_test', 'DB_USERNAME' => 'postgres', 'DB_PASSWORD' => '', 'DB_URL' => ''] as $k => $v) {
putenv($k.'='.$v); $_ENV[$k] = $_SERVER[$k] = $v;
}
require __DIR__.'/../vendor/autoload.php';
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
use Illuminate\Support\Facades\DB;
use App\Services\CorridorAgribusinessOpportunities;
$target = DB::selectOne('SELECT current_database() AS name, inet_server_port() AS port');
if (! app()->environment('testing') || $target->name !== 'simulator_fiscal_delta_20261021_test' || (int) $target->port !== 55441) throw new RuntimeException('Refusing non-QA target.');
config(['portal.profile_access_enabled' => true, 'portal.opportunity_specialized_drafts_enabled' => true]);
$service = app(CorridorAgribusinessOpportunities::class);
if (! isset($options['apply'])) {echo json_encode(['target' => $target, 'entries' => $service->entries(), 'writes' => 0], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); exit;}
$actor = App\Models\User::findOrFail($options['actor'] ?? 0);
$organization = $options['organization'] ?? '';
$request = Illuminate\Http\Request::create('/minhas-oportunidades/drafts', 'POST');
$request->setUserResolver(fn () => $actor); $app->instance('request', $request);
$dir = storage_path('app/private/agribusiness-opportunities-20261023');
if (! is_dir($dir)) mkdir($dir, 0700, true);
if (! file_exists($dir.'/before.json')) {
$before = [];
foreach (['opportunities', 'audit_events', 'development_corridors', 'portal_role_assignments', 'portal_resources', 'documents'] as $table) $before[$table] = DB::table($table)->orderBy('id')->get()->all();
file_put_contents($dir.'/before.json', json_encode($before, JSON_THROW_ON_ERROR));
}
$records = $service->register($actor, $organization);
$receipt = ['target' => $target, 'source_sha256' => $service::SOURCE_HASH, 'records' => $records, 'total' => count($records),
'new' => count(array_filter($records, fn ($r) => $r['created'])), 'published' => App\Models\Opportunity::whereIn('id', array_column($records, 'id'))->published()->count(), 'active_writes' => 0];
file_put_contents($dir.'/receipt.json', json_encode($receipt, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
echo json_encode($receipt, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE).PHP_EOL;
@@ -0,0 +1,96 @@
<?php
// Delimited recovery requested by Tempo, 23/10/2026. Never import or approve new/edited dossiers.
declare(strict_types=1);
ini_set('zend.exception_ignore_args', '1');
require getcwd().'/vendor/autoload.php';
$app = require getcwd().'/bootstrap/app.php';
(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);
(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
$args = getopt('', ['manifest:', 'output:', 'apply', 'preview-sha256:', 'backup:', 'qa']);
$manifestPath = $args['manifest'] ?? '';
$manifestHash = '8d07007a2e1e8758d4741b4ac594f78d5943f71ad78b2daae7f85aefa9d2de4a';
if (!is_file($manifestPath) || !hash_equals($manifestHash, hash_file('sha256', $manifestPath))) {
throw new RuntimeException('Exact reviewed 29-original recovery manifest required.');
}
$manifest = json_decode(file_get_contents($manifestPath), true, 512, JSON_THROW_ON_ERROR);
if (count($manifest['items']) !== 29 || count(array_unique(array_column($manifest['items'], 'target_record_id'))) !== 29) {
throw new RuntimeException('Exact original scope required.');
}
$qa = isset($args['qa']);
$c = config('database.connections.'.config('database.default'));
$expected = $qa ? 'simulator_fiscal_delta_20261021_test' : 'teste_investidor';
$port = $qa ? 55441 : 5432;
if ($c['driver'] !== 'pgsql' || !empty($c['url']) || !in_array($c['host'], ['127.0.0.1', 'localhost'], true) || $c['database'] !== $expected || (int)$c['port'] !== $port) {
throw new RuntimeException('Named target mismatch.');
}
if (!$qa && (!getenv('SSH_CONNECTION') || !function_exists('posix_geteuid') || posix_geteuid() !== 0 || rtrim(config('app.url'), '/') !== 'https://teste-investidor.tempo.co.mz')) {
throw new RuntimeException('Authenticated destination operator required.');
}
$output = $args['output'] ?? '';
if (!$output || str_contains(str_replace('\\', '/', $output), '/public/')) {
throw new RuntimeException('Private receipt path required.');
}
$pdo = new PDO('pgsql:host='.$c['host'].';port='.$c['port'].';dbname='.$expected, $c['username'], $c['password'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$apply = isset($args['apply']);
$pdo->exec($apply ? 'BEGIN ISOLATION LEVEL SERIALIZABLE' : 'BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY');
try {
$actual = $pdo->query('select current_database() as name,inet_server_port() as port')->fetch(PDO::FETCH_ASSOC);
if ($actual['name'] !== $expected || (int)$actual['port'] !== $port) throw new RuntimeException('Actual target mismatch.');
if ($apply) $pdo->query('select pg_advisory_xact_lock(231026,29)');
$plan = [];
$before = [];
foreach ($manifest['items'] as $item) {
$query = $pdo->prepare('select * from investment_dossiers where id = ?'.($apply ? ' for update' : ''));
$query->execute([$item['target_record_id']]);
$row = $query->fetch(PDO::FETCH_ASSOC);
if (!$row || $row['deleted_at'] !== null || $row['title'] !== $item['title'] || !hash_equals($item['content_sha256'], hash('sha256', $row['content'])) || !hash_equals($item['source_sha256'], hash('sha256', $row['source']))) {
throw new RuntimeException('Missing, archived or changed original: '.$item['code']);
}
if (!hash_equals($item['approval_sha256'], hash('sha256', $item['approval_evidence']))) throw new RuntimeException('Approval provenance changed.');
$replayed = $pdo->prepare("select count(*) from audit_events where source_system='portfolio-visibility-recovery-v1' and external_id=? and entity_id=? and action='approved_visibility_restored'");
$replayed->execute([$manifestHash.':'.$row['id'], $row['id']]);
$already = (int)$replayed->fetchColumn() === 1;
if ($already) {
if ($row['publication_status'] !== 'published' || $row['approval_basis'] !== 'document_owner' || $row['approval_evidence'] !== $item['approval_evidence']) throw new RuntimeException('Recovery subsequently changed: '.$item['code']);
} elseif ($row['publication_status'] !== 'draft' || $row['editor_id'] !== null || $row['reviewer_id'] !== null || (int)$row['version_no'] !== (int)$item['expected_target_version']) {
throw new RuntimeException('Preserve subsequent editorial decisions: '.$item['code']);
}
$before[] = $row;
$plan[] = ['id' => $row['id'], 'code' => $item['code'], 'version' => (int)$row['version_no'], 'status' => $row['publication_status'], 'content_sha256' => $item['content_sha256'], 'source_sha256' => $item['source_sha256'], 'already_restored' => $already];
}
$previewHash = hash('sha256', json_encode([$expected, $manifestHash, $plan], JSON_THROW_ON_ERROR));
if ($apply) {
if (!hash_equals($previewHash, $args['preview-sha256'] ?? '')) throw new RuntimeException('Preview changed; recover current state before writing.');
if (!$qa) {
$directory = $args['backup'] ?? '';
$backup = json_decode(file_get_contents($directory.'/backup-receipt.json'), true, 512, JSON_THROW_ON_ERROR);
$restore = json_decode(file_get_contents($directory.'/restore-receipt.json'), true, 512, JSON_THROW_ON_ERROR);
if (!$restore['restore_verified'] || $backup['target']['database'] !== $expected || (int)$backup['target']['port'] !== $port || !hash_equals($backup['sha256'], $restore['source_dump_sha256'])) throw new RuntimeException('Verified matching backup/restore required.');
}
$snapshot = $output.'.before.json';
if (is_file($snapshot)) throw new RuntimeException('Preserve earlier recovery snapshot; use a new receipt path.');
file_put_contents($snapshot, json_encode(['database' => $expected, 'rows' => $before], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR));
if (!$qa) chmod($snapshot, 0600);
foreach ($plan as $index => $entry) {
if ($entry['already_restored']) continue;
$item = $manifest['items'][$index];
$update = $pdo->prepare("update investment_dossiers set publication_status='published',approval_basis='document_owner',approval_evidence=?,published_at=now(),version_no=version_no+1,updated_at=now() where id=? and version_no=?");
$update->execute([$item['approval_evidence'], $entry['id'], $entry['version']]);
if ($update->rowCount() !== 1) throw new RuntimeException('Concurrent change.');
$event = $pdo->prepare("insert into audit_events(source_system,external_id,entity_type,entity_id,actor_user_id,action,before_data,after_data) values('portfolio-visibility-recovery-v1',?,'investment_dossiers',?,NULL,'approved_visibility_restored',?,?)");
$event->execute([$manifestHash.':'.$entry['id'], $entry['id'], json_encode(['version_no' => $entry['version'], 'publication_status' => 'draft', 'approval_basis' => $before[$index]['approval_basis']], JSON_THROW_ON_ERROR), json_encode(['code' => $item['code'], 'version_no' => $entry['version']+1, 'publication_status' => 'published', 'approval_basis' => 'document_owner', 'approval_sha256' => $item['approval_sha256'], 'content_sha256' => $item['content_sha256'], 'source_record_id' => $item['source_record_id'], 'source_published_at' => $item['original_published_at'], 'instruction' => 'Tempo 23/10/2026: preserve and restore completed approved functionality', 'authenticated_transport' => $qa ? 'isolated-QA' : 'SSH', 'not_a_new_editorial_approval' => true], JSON_THROW_ON_ERROR)]);
}
}
$visible = (int)$pdo->query("select count(*) from investment_dossiers d where publication_status='published' and (exists(select 1 from projects p where p.id=d.project_id and p.deleted_at is null) or exists(select 1 from economic_clusters c where c.id=d.cluster_id and c.deleted_at is null) or exists(select 1 from development_corridors r where r.id=d.corridor_id and r.deleted_at is null))")->fetchColumn();
$result = ['database' => $actual, 'qa' => $qa, 'mode' => $apply ? 'applied' : 'preview', 'manifest_sha256' => $manifestHash, 'preview_sha256' => $previewHash, 'scope' => count($plan), 'restored' => $apply ? count(array_filter($plan, fn($r) => !$r['already_restored'])) : 0, 'visible' => $visible, 'data_content_changed' => false, 'new_dossiers_imported' => 0, 'fake_editor_or_reviewer_assigned' => false, 'plan' => $plan];
if ($apply) $pdo->commit(); else $pdo->rollBack();
file_put_contents($output, json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR));
if (!$qa) chmod($output, 0600);
unset($result['plan']);
echo json_encode($result, JSON_THROW_ON_ERROR);
} catch (Throwable $error) {
if ($pdo->inTransaction()) $pdo->rollBack();
throw $error;
}
+33
View File
@@ -0,0 +1,33 @@
<?php
require __DIR__.'/../vendor/autoload.php';
// Offline verification against the preserved article exemplar; no database or source writes.
$path = $argv[1] ?? throw new RuntimeException('Pass the preserved agronegocio article JSON path.');
$sourceHash = hash_file('sha256', $path);
$source = json_decode(file_get_contents($path), true, 512, JSON_THROW_ON_ERROR);
if (($source['format'] ?? '') !== 'investmoz-legacy-article-v1' || ($source['slug'] ?? '') !== 'agronegocio') {
throw new RuntimeException('Unexpected source article.');
}
$original = (new App\Services\LegacyContent)->sanitize($source['content_html']);
$html = (new App\Services\CorridorAgribusiness)->enrich($original);
$doc = new DOMDocument;
$doc->loadHTML('<?xml encoding="UTF-8">'.$html);
$xpath = new DOMXPath($doc);
$groups = $xpath->query('//ul[starts-with(@id,"agronegocio-oportunidades-")]');
$entries = $xpath->query('//ul[starts-with(@id,"agronegocio-oportunidades-")]/li');
if ($groups->length !== 6 || $entries->length !== 34 || $sourceHash !== hash_file('sha256', $path)) {
throw new RuntimeException('Incomplete integration or source changed.');
}
// Removing only the additions must recover the exact sanitized original.
foreach (iterator_to_array($groups) as $group) {
$group->parentNode->removeChild($group->previousSibling);
$group->parentNode->removeChild($group->nextSibling);
$group->parentNode->removeChild($group);
}
$body = $doc->getElementsByTagName('body')->item(0);
$recovered = implode('', array_map(fn ($node) => $doc->saveHTML($node), iterator_to_array($body->childNodes)));
if ($recovered !== $original) {
throw new RuntimeException('Original displayed content was changed.');
}
echo json_encode(['source_sha256' => $sourceHash, 'source_unchanged' => true, 'original_display_preserved' => true,
'corridors' => 6, 'agribusiness_entries' => 34, 'database_writes' => 0], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE).PHP_EOL;