Compare commits

..
Author SHA1 Message Date
nala c83ab90c68 docs: record served management entry and actual operational limits 2026-10-22 21:06:29 +02:00
44 changed files with 153 additions and 4802 deletions
@@ -81,18 +81,31 @@ class EditorialArticleController extends Controller
app(\App\Services\DocumentManagementAccess::class)->assertEditableResource(request()->user(), $id);
$r = DB::table('portal_resources')->find($id);
abort_unless($r, 404);
$reading = app(\App\Services\EditorialReading::class);
$original = $reading->original($r);
$content = $reading->content($r, $original);
return Inertia::render('portal/article-editor', ['resource' => ['id' => $r->id, 'title' => $r->title, 'metadata_version' => $r->metadata_version, 'published' => (bool) $r->published],
'content' => $content, 'source' => $original ? array_intersect_key($original, array_flip(['source_url', 'published_at', 'modified_at', 'legacy_id', 'image_source_url'])) : null, 'images' => $this->publicResources()->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp'])->get(['r.id', 'r.title']),
'revisions' => DB::table('portal_resource_revisions')->where('resource_id', $id)->orderByDesc('revision_no')->get(['revision_no', 'change_type', 'created_at'])])->toResponse(request())->header('Cache-Control', 'private, no-store');
$content = $r->editorial_content ? json_decode($r->editorial_content, true) : null;
if ($content === null) {
$document = DB::table('documents')->find($r->document_id);
if ($document && $document->status === 'active' && $document->malware_scan_status === 'clean'
&& in_array($document->media_type, ['text/plain', 'application/json'], true)) {
$binary = app(VerifiedDocumentBinary::class)->respond($document);
$bytes = $binary instanceof \Symfony\Component\HttpFoundation\BinaryFileResponse
? file_get_contents($binary->getFile()->getPathname()) : $binary->getContent();
$original = json_decode($bytes, true);
if (is_array($original) && ($original['format'] ?? '') === 'investmoz-legacy-article-v1') {
$html = preg_replace('~</(?:p|div|li|h[1-6])>|<br\s*/?>~i', "\n\n", $original['content_html'] ?? '');
$content = ['body' => trim(html_entity_decode(strip_tags($html), ENT_QUOTES | ENT_HTML5, 'UTF-8')), 'image_resource_id' => null];
}
}
}
return Inertia::render('portal/article-editor', ['resource' => ['id' => $r->id, 'title' => $r->title, 'metadata_version' => $r->metadata_version],
'content' => $content, 'images' => $this->publicResources()->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp'])->get(['r.id', 'r.title']),
'revisions' => DB::table('portal_resource_revisions')->where('resource_id', $id)->orderByDesc('revision_no')->get(['revision_no', 'change_type', 'created_at'])]);
}
public function save(Request $request, int $id)
{
$this->installed();
$data = $this->validateContent($request);
$data = $request->validate(['body' => ['required', 'string', 'max:100000'], 'image_resource_id' => ['nullable', 'integer'], 'metadata_version' => ['required', 'integer', 'min:1']]);
DB::transaction(function () use ($request, $id, $data) {
$r = DB::table('portal_resources')->where('id', $id)->lockForUpdate()->first();
abort_unless($r, 404);
@@ -105,7 +118,7 @@ class EditorialArticleController extends Controller
if ($body === '') {
throw ValidationException::withMessages(['body' => 'Escreva o corpo do artigo.']);
}
$content = $this->edition($r, $data);
$content = ['format' => 1, 'body' => $body, 'image_resource_id' => $data['image_resource_id'] ?? null];
$revision = (int) $r->metadata_version + 1;
DB::table('portal_resources')->where('id', $id)->update(['editorial_content' => json_encode($content, JSON_THROW_ON_ERROR), 'published' => false, 'approved_by' => null, 'metadata_version' => $revision, 'last_reviewed_by' => $request->user()->id, 'last_reviewed_at' => now(), 'updated_at' => now()]);
$resource = DB::table('portal_resources')->find($id);
@@ -117,46 +130,16 @@ class EditorialArticleController extends Controller
return redirect('/management/portal-services/resources/'.$id.'/article')->with('success', 'Artigo guardado como rascunho. Publique expressamente no acervo quando estiver pronto.');
}
private function validateContent(Request $request): array
{
return $request->validate(['body' => ['required', 'string', 'max:100000'], 'image_resource_id' => ['nullable', 'integer'], 'image_mode' => ['nullable', 'in:original,selected,none'], 'metadata_version' => ['required', 'integer', 'min:1']]);
}
private function edition(object $resource, array $data): array
{
$reading = app(\App\Services\EditorialReading::class);
$original = $reading->original($resource);
$mode = $data['image_mode'] ?? (!empty($data['image_resource_id']) ? 'selected' : 'none');
if ($mode === 'selected') abort_unless(!empty($data['image_resource_id']) && $reading->publicResources()->where('r.id', $data['image_resource_id'])->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp'])->exists(), 422, 'Escolha uma imagem pública disponível na biblioteca.');
return ['format' => 1, 'body' => trim($data['body']), 'image_mode' => $mode, 'image_resource_id' => $mode === 'selected' ? (int)$data['image_resource_id'] : null,
'preserve_original_html' => $original && trim($data['body']) === $reading->plain($original['content_html'])];
}
public function preview(Request $request, int $id)
public function show(int $id)
{
$this->installed();
app(\App\Services\DocumentManagementAccess::class)->assertEditableResource($request->user(), $id);
$resource = DB::table('portal_resources')->find($id); abort_unless($resource, 404);
return Inertia::render('portal/article', ['article' => app(\App\Services\EditorialReading::class)->reading($resource, null, true)])
->toResponse($request)->header('Cache-Control', 'private, no-store')->header('X-Robots-Tag', 'noindex, nofollow');
}
$r = $this->publicResources()->where('r.id', $id)->first(['r.id', 'r.title', 'r.description', 'r.editorial_content', 'r.document_id', 'd.issuer']);
abort_unless($r && $r->editorial_content, 404);
$content = json_decode($r->editorial_content, true);
// Recheck the original bytes using the same binary gate as the library.
$binary = app(VerifiedDocumentBinary::class)->respond($this->publicResources()->where('r.id', $id)->first(['r.*', 'd.*']));
$image = ! empty($content['image_resource_id']) ? $this->publicResources()->where('r.id', $content['image_resource_id'])->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp'])->value('r.id') : null;
public function previewContent(Request $request, int $id)
{
$this->installed();
app(\App\Services\DocumentManagementAccess::class)->assertEditableResource($request->user(), $id);
$resource = DB::table('portal_resources')->find($id); abort_unless($resource, 404);
$data = $this->validateContent($request);
abort_unless((int)$resource->metadata_version === (int)$data['metadata_version'], 409, 'A revisão mudou; recupere antes de rever a prévia.');
return response()->json(['article' => app(\App\Services\EditorialReading::class)->reading($resource, $this->edition($resource, $data), true)])
->header('Cache-Control', 'private, no-store')->header('X-Robots-Tag', 'noindex, nofollow');
}
public function show(Request $request, int $id)
{
$this->installed();
$resource = app(\App\Services\EditorialReading::class)->publicResources()->where('r.id', $id)->first(['r.*']);
abort_unless($resource, 404);
return Inertia::render('portal/article', ['article' => app(\App\Services\EditorialReading::class)->reading($resource)])->toResponse($request)->header('Cache-Control', 'private, no-store');
return Inertia::render('portal/article', ['article' => ['id' => $id, 'title' => $r->title, 'description' => $r->description, 'author' => $r->issuer, 'body' => $content['body'], 'image_url' => $image ? '/documentos/'.$image.'/view' : null, 'original_url' => '/documentos/'.$id]]);
}
}
@@ -275,7 +275,7 @@ class PortalServicesController extends Controller
'resource' => $resource,
'backUrl' => $backUrl,
'downloadUrl' => route('services.download', ['id' => $id]),
'articleUrl' => $this->articleUrl($id),
'articleUrl' => Schema::hasColumn('portal_resources','editorial_content') && DB::table('portal_resources')->where('id',$id)->whereNotNull('editorial_content')->exists() ? '/artigos/'.$id : null,
]);
}
@@ -866,17 +866,4 @@ SQL, [$id]);
return $ids ?: [$id];
}
private function articleUrl(int $id): ?string
{
if (!Schema::hasColumn('portal_resources', 'editorial_content')) return null;
$resource = DB::table('portal_resources')->find($id);
if (!$resource) return null;
if ($resource->editorial_content !== null) return '/artigos/'.$id;
try {
return app(\App\Services\EditorialReading::class)->original($resource) ? '/artigos/'.$resource->id : null;
} catch (\Symfony\Component\HttpKernel\Exception\HttpException) {
return null;
}
}
}
@@ -1,138 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Services\Procurement;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
class ProcurementController extends Controller
{
private const STATE_SQL = "CASE WHEN v.payload->>'procedural_state' IN ('cancelled','results') THEN v.payload->>'procedural_state' WHEN ((v.payload->>'deadline')::timestamp AT TIME ZONE (v.payload->>'timezone'))<=CURRENT_TIMESTAMP THEN 'deadline_ended' WHEN v.payload->>'extended'='true' THEN 'extended' ELSE 'open' END";
private function query(Procurement $service)
{
abort_unless($service->available(), 404);
return DB::table('portal_tenders as t')->join('portal_tender_versions as v', fn ($q) => $q->on('v.id', '=', 't.published_version_id')->on('v.tender_id', '=', 't.id'))->whereNotNull('v.published_at');
}
public function index(Request $request, Procurement $service)
{
$filters = $request->validate(['q' => 'nullable|string|max:150', 'entity' => 'nullable|uuid', 'sector' => 'nullable|integer', 'territory' => 'nullable|uuid', 'modality' => 'nullable|string|max:200', 'financier' => 'nullable|string|max:200', 'state' => 'nullable|in:open,extended,deadline_ended,cancelled,results', 'deadline_before' => 'nullable|date_format:Y-m-d', 'regime' => 'nullable|in:state,external,private,other']);
$filters = array_filter($filters, fn ($value) => $value !== null && $value !== '');
$query = $this->query($service);
if (! empty($filters['q'])) {
$query->where(fn ($q) => $q->whereRaw("v.payload->>'title' ILIKE ?", ['%'.$filters['q'].'%'])->orWhereRaw("v.payload->>'object' ILIKE ?", ['%'.$filters['q'].'%'])->orWhereRaw("v.payload->>'reference' ILIKE ?", ['%'.$filters['q'].'%']));
}
foreach (['entity' => 'organization_id', 'sector' => 'sector_id', 'modality' => 'modality', 'financier' => 'financier', 'regime' => 'regime'] as $filter => $field) {
if (! empty($filters[$filter])) {
$query->whereRaw('v.payload->>? = ?', [$field, (string) $filters[$filter]]);
}
}
if (! empty($filters['territory'])) {
$query->whereRaw("v.payload->>'territory_id' IN (WITH RECURSIVE scope(id,depth) AS (SELECT id,0 FROM geo_locations WHERE id=? AND deleted_at IS NULL UNION ALL SELECT c.id,s.depth+1 FROM geo_locations c JOIN scope s ON c.parent_id=s.id WHERE c.deleted_at IS NULL AND s.depth<4) SELECT id::text FROM scope)", [$filters['territory']]);
}
if (! empty($filters['state'])) {
$query->whereRaw(self::STATE_SQL.' = ?', [$filters['state']]);
}
if (! empty($filters['deadline_before'])) {
$query->whereRaw("left(v.payload->>'deadline',10)<=?", [$filters['deadline_before']]);
}
$rows = $query->select('t.id', 'v.id as vid')->orderByDesc('v.published_at')->paginate(20)->withQueryString();
$rows->through(fn ($r) => ['id' => $r->id, ...$this->summary($service, $r->vid)]);
$facets = $this->query($service)->get(['v.payload'])->map(fn ($r) => json_decode($r->payload, true));
$options = [];
foreach (['entity' => ['organization_id', 'organization_name'], 'sector' => ['sector_id', 'sector_name'], 'territory' => ['territory_id', 'territory_name'], 'modality' => ['modality', 'modality'], 'financier' => ['financier', 'financier']] as $name => [$value,$label]) {
$options[$name] = $facets->filter(fn ($p) => ! empty($p[$value]))->map(fn ($p) => ['id' => (string) $p[$value], 'name' => $p[$label]])->unique('id')->values();
}
return Inertia::render('procurement/index', ['items' => $rows, 'filters' => $filters, 'options' => $options, 'regimes' => config('procurement.regimes'), 'management' => $service->access($request->user())])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
private function summary(Procurement $service, string $vid): array
{
$v = $service->publishedVersion($vid);
return ['publication' => $v, 'state' => $service->state($v)];
}
public function show(Request $request, string $id, Procurement $service)
{
return $this->detail($request, $id, $service, false);
}
public function print(Request $request, string $id, Procurement $service)
{
return $this->detail($request, $id, $service, true);
}
private function detail(Request $request, string $id, Procurement $service, bool $print)
{
$row = $this->query($service)->where('t.id', $id)->firstOrFail(['t.id', 'v.id as vid']);
$filters = $request->only(['q', 'entity', 'sector', 'territory', 'modality', 'financier', 'state', 'deadline_before', 'regime', 'page']);
return Inertia::render('procurement/show', ['id' => $id, ...$this->summary($service, $row->vid), 'printMode' => $print, 'backUrl' => '/concursos'.($filters ? '?'.http_build_query($filters) : ''),
'history' => DB::table('portal_tender_versions')->where('tender_id', $id)->whereNotNull('published_at')->orderBy('version')->pluck('id')->map(fn ($vid) => $service->publishedVersion($vid)),
'watching' => $request->user() && DB::table('portal_tender_watches')->where('tender_id', $id)->where('user_id', $request->user()->id)->exists()])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
public function manage(Request $request, Procurement $service)
{
$service->guard($request->user());
return Inertia::render('procurement/manage', ['items' => DB::table('portal_tenders')->orderByDesc('updated_at')->get(['id', 'draft', 'version', 'published_version_id'])->map(fn ($r) => ['id' => $r->id, 'title' => json_decode($r->draft, true)['title'] ?? 'Rascunho sem título', 'version' => $r->version, 'published' => (bool) $r->published_version_id])])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
public function edit(Request $request, Procurement $service, ?string $id = null)
{
$service->guard($request->user());
$r = $id ? $service->record($id) : null;
return Inertia::render('procurement/edit', ['record' => $r ? ['id' => $id, 'version' => $r->version, 'draft' => json_decode($r->draft, true), 'published' => (bool) $r->published_version_id] : null,
'references' => $service->references($request->user()), 'history' => $id ? DB::table('portal_tender_versions')->where('tender_id', $id)->orderByDesc('version')->get(['version', 'act', 'reason', 'actor_id', 'published_at', 'created_at']) : []])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
public function save(Request $request, Procurement $service, ?string $id = null)
{
$id = $service->save($request->user(), $id, $request->all());
return redirect('/management/concursos/'.$id)->with('success', 'Rascunho guardado. A publicação anterior permanece intacta.');
}
public function preview(Request $request, string $id, Procurement $service)
{
return response()->json($service->preview($request->user(), $id, (string) $request->input('act')))->header('Cache-Control', 'private, no-store');
}
public function publish(Request $request, string $id, Procurement $service)
{
$service->publish($request->user(), $id, $request->all());
return redirect('/management/concursos/'.$id)->with('success', 'Acto publicado, com versão e auditoria. Nenhuma proposta recebida pelo portal.');
}
public function watch(Request $request, string $id, Procurement $service)
{
$row = $this->query($service)->where('t.id', $id)->firstOrFail(['v.id']);
DB::table('portal_tender_watches')->updateOrInsert(['tender_id' => $id, 'user_id' => $request->user()->id], ['seen_version_id' => $row->id, 'created_at' => now(), 'updated_at' => now()]);
return back()->with('success', 'Concurso guardado para acompanhamento. Isto não apresenta uma proposta.');
}
public function unwatch(Request $request, string $id, Procurement $service)
{
abort_unless($service->available(), 404);
DB::table('portal_tender_watches')->where('tender_id', $id)->where('user_id', $request->user()->id)->delete();
return back();
}
public function watched(Request $request, Procurement $service)
{
$rows = $this->query($service)->join('portal_tender_watches as w', 'w.tender_id', '=', 't.id')->where('w.user_id', $request->user()->id)->get(['t.id', 'v.id as vid', 'w.seen_version_id'])->map(fn ($r) => ['id' => $r->id, 'changed' => $r->seen_version_id !== $r->vid, ...$this->summary($service, $r->vid)]);
return Inertia::render('procurement/manage', ['watched' => true, 'items' => $rows])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
}
@@ -14,7 +14,7 @@ class EnsureScopedEditorial
return $next($request);
}
abort_unless($access->editorial($actor), 403);
$allowed = in_array($request->route()->getName(), ['editorial.edit', 'editorial.save', 'editorial.preview', 'editorial.preview-content', 'services.resource', 'services.resource.update'], true)
$allowed = in_array($request->route()->getName(), ['editorial.edit', 'editorial.save', 'services.resource', 'services.resource.update'], true)
|| ($request->route()->getName() === 'services.moderate' && $request->route('type') === 'resources');
abort_unless($allowed, 403);
if ($request->route('id') !== null) {
@@ -19,8 +19,7 @@ final class EnsureScopedPortalAdministration
$path = $request->path();
$interests = $request->is('management/interests', 'management/interests/*', 'api/v1/investment/admin/interests/*');
// Fiscal maintenance reuses authorised administration; unrelated gates remain unchanged.
$catalogue = $request->is('management/territory-geometry-import', 'management/territory-geometry-import/*',
'management/economic-references/lot-01', 'management/economic-references/lot-01/*',
$catalogue = $request->is('management/economic-references/lot-01', 'management/economic-references/lot-01/*',
'management/education', 'management/education/*', 'management/investment/references', 'management/investment/references/*', 'api/v1/investment/admin/references', 'api/v1/investment/admin/references/*',
'management/investment/zones', 'management/investment/zones/*', 'api/v2/investment/admin/zones', 'api/v2/investment/admin/zones/*',
'management/balcao/atribuicoes', 'management/balcao/atribuicoes/*', 'management/balcao/servicos',
@@ -51,7 +51,6 @@ class HandleInertiaRequests extends Middleware
return [
...parent::share($request),
'name' => config('app.name'),
'procurementEnabled' => app(\App\Services\Procurement::class)->available(),
'homologationReserved' => (bool) config('portal.homologation_only', false),
'profileAccess' => app(PortalProfileAccess::class)->navigation($request->user()),
'contentManagementHref' => app(\App\Services\ContentManagement::class)->access($request->user()) !== [] ? '/gestao-conteudos' : null,
-1
View File
@@ -19,7 +19,6 @@ final class ContentManagement
$editor = $documents->full($actor) || $documents->editorial($actor);
$upload = $editor || $documents->limited($actor);
$result = [];
if (app(Procurement::class)->available() && app(Procurement::class)->access($actor)) $result['procurement'] = ['index' => '/management/concursos', 'create' => '/management/concursos/novo'];
if ($legacy || ($navigation['mine'] ?? null) || ($navigation['review'] ?? null)) {
$result['opportunities'] = ['index' => $legacy ? '/management/opportunities' : '/minhas-oportunidades',
'create' => $legacy ? '/management/opportunities/create' : ($navigation['create'] ?? null), 'profileWorkflow' => ! $legacy];
@@ -50,11 +50,6 @@ class DocumentManagementAccess
->where('d.external_id', $item['external_id']);
});
}
foreach (json_decode(file_get_contents(config_path('legacy_editorial_resources.json')), true, 512, JSON_THROW_ON_ERROR) as $item) {
// These exact original bytes contain the legacy identity/source.
// Destination upload IDs differ; the approved file scope does not.
$query->orWhere('d.sha256', $item['sha256']);
}
});
}
-130
View File
@@ -1,130 +0,0 @@
<?php
namespace App\Services;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\UriResolver;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpKernel\Exception\HttpException;
/** Reads verified originals without writing a derived edition or changing publication. */
final class EditorialReading
{
public function publicResources()
{
return DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')
->where('r.published', true)->where('r.rights_status', 'authorized')->where('d.rights_status', 'authorized')
->where('d.status', 'active')->where('d.data_classification', 'public')->whereNull('d.deleted_at')
->where('d.malware_scan_status', 'clean')->whereColumn('d.sha256', 'd.malware_scanned_sha256');
}
public function original(object $resource): ?array
{
$document = DB::table('documents')->find($resource->document_id);
if (! $document || $document->status !== 'active' || $document->malware_scan_status !== 'clean' || ! in_array($document->media_type, ['text/plain', 'application/json'], true)) {
return null;
}
$binary = app(VerifiedDocumentBinary::class)->respond($document);
$bytes = $binary instanceof BinaryFileResponse ? file_get_contents($binary->getFile()->getPathname()) : $binary->getContent();
if (! is_string($bytes) || strlen($bytes) > 10485760) {
return null;
}
$original = json_decode($bytes, true);
return is_array($original) && ($original['format'] ?? '') === 'investmoz-legacy-article-v1' && is_string($original['content_html'] ?? null) ? $original : null;
}
public function plain(string $html): string
{
return trim(html_entity_decode(strip_tags(preg_replace('~</(?:p|div|li|h[1-6]|tr)>|<br\s*/?>~i', "\n\n", $html)), ENT_QUOTES | ENT_HTML5, 'UTF-8'));
}
public function content(object $resource, ?array $original): array
{
return $resource->editorial_content ? json_decode($resource->editorial_content, true, 512, JSON_THROW_ON_ERROR)
: ['body' => $this->plain($original['content_html'] ?? ''), 'image_resource_id' => null, 'image_mode' => 'original', 'preserve_original_html' => true];
}
private function sourceUrl(mixed $url, ?string $base = null): ?string
{
if (! is_string($url) || trim($url) === '') {
return null;
}
try {
$absolute = $base ? (string) UriResolver::resolve(new Uri($base), new Uri($url)) : $url;
return filter_var($absolute, FILTER_VALIDATE_URL) && in_array(strtolower((string) parse_url($absolute, PHP_URL_SCHEME)), ['http', 'https'], true) ? $absolute : null;
} catch (\InvalidArgumentException) {
return null;
}
}
public function reading(object $resource, ?array $override = null, bool $private = false): array
{
$original = $this->original($resource);
$content = $override ?? $this->content($resource, $original);
abort_unless(trim($content['body'] ?? '') !== '', 404, 'Este documento não contém um artigo legível.');
$document = DB::table('documents')->find($resource->document_id);
// The original is verified above; ordinary text adaptations retain the binary gate too.
app(VerifiedDocumentBinary::class)->respond($document);
$mode = $content['image_mode'] ?? (! empty($content['image_resource_id']) ? 'selected' : 'none');
$originalImageUrl = $this->sourceUrl($original['image_source_url'] ?? null, $original['source_url'] ?? null);
$expectedImageSha = $original['image_sha256'] ?? null;
if (! $expectedImageSha && $originalImageUrl === 'https://investemoz.tempo.co.mz/images/tempo-background.png') {
foreach (json_decode(file_get_contents(config_path('legacy_editorial_resources.json')), true, 512, JSON_THROW_ON_ERROR) as $accepted) {
if ($accepted['sha256'] === $document->sha256) {
$expectedImageSha = $accepted['original_image_sha256'] ?? null;
break;
}
}
}
$images = $this->publicResources()->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp']);
$image = null;
if ($mode === 'selected' && ! empty($content['image_resource_id'])) {
$image = (clone $images)->where('r.id', $content['image_resource_id'])->first(['r.id', 'r.title']);
}
if ($mode === 'original' && $original) {
$image = (clone $images)->where(function ($q) use ($expectedImageSha, $originalImageUrl) {
$q->whereRaw('1=0');
if ($expectedImageSha) {
$q->orWhere('d.sha256', $expectedImageSha);
} elseif ($originalImageUrl) {
$q->orWhere('r.source_url', $originalImageUrl)->orWhere('d.original_source', $originalImageUrl);
}
})->first(['r.id', 'r.title']);
}
if ($image) {
// A public flag alone never licenses missing or changed image bytes.
$binary = (clone $images)->where('r.id', $image->id)->first(['d.*']);
try {
app(VerifiedDocumentBinary::class)->respond($binary);
} catch (HttpException) {
$image = null;
}
}
$originalFormat = $original && ($content['preserve_original_html'] ?? false) && $content['body'] === $this->plain($original['content_html']);
$html = $originalFormat ? app(LegacyContent::class)->sanitize($original['content_html'], true) : null;
$imageReferences = [];
if ($original) {
preg_match_all('~<img\b[^>]*\bsrc\s*=\s*([\'"])(.*?)\1~is', $original['content_html'], $matches);
foreach ($matches[2] as $source) {
$url = $this->sourceUrl(html_entity_decode($source, ENT_QUOTES | ENT_HTML5, 'UTF-8'), $original['source_url'] ?? null);
if ($url) {
$imageReferences[] = $url;
}
}
}
return ['id' => $resource->id, 'title' => $resource->title, 'description' => $resource->description,
'author' => $document->issuer, 'body' => $content['body'], 'html' => $html,
'image_url' => $image ? '/documentos/'.$image->id.'/view' : null,
'image_notice' => $mode === 'selected' && ! $image ? 'A imagem escolhida está indisponível para divulgação; a selecção mantém-se na edição.' : ($mode === 'original' && ! $image && ! empty($original['image_source_url']) ? 'Imagem de origem referenciada, mas sem exemplar público verificado na biblioteca. A referência original mantém-se preservada.' : null),
'source_url' => $this->sourceUrl($original['source_url'] ?? $resource->source_url),
'published_at' => $original['published_at'] ?? null, 'modified_at' => $original['modified_at'] ?? null,
'legacy_id' => $original['legacy_id'] ?? null, 'image_source_url' => $originalImageUrl, 'image_expected_sha256' => $expectedImageSha, 'image_references' => array_values(array_unique($imageReferences)),
'metadata_version' => $resource->metadata_version, 'private_preview' => $private,
'original_url' => $private ? '/management/documents/'.$resource->document_id.'/download' : '/documentos/'.$resource->id,
];
}
}
+3 -3
View File
@@ -279,7 +279,7 @@ final class LegacyContent
}
/** Allow presentation markup only. No scripts, styles, events, embeds or remote image execution. */
public function sanitize(string $html, bool $preserveStructure = false): string
public function sanitize(string $html): string
{
$doc = new DOMDocument;
$old = libxml_use_internal_errors(true);
@@ -296,7 +296,7 @@ final class LegacyContent
}
$headingOffset = 2 - (empty($sourceLevels) ? 2 : min($sourceLevels));
$previousHeading = 1;
$clean = function (DOMNode $node) use (&$clean, $doc, $headingOffset, &$previousHeading, $preserveStructure): void {
$clean = function (DOMNode $node) use (&$clean, $doc, $headingOffset, &$previousHeading): void {
foreach (iterator_to_array($node->childNodes) as $child) {
if (! $child instanceof DOMElement) {
continue;
@@ -311,7 +311,7 @@ final class LegacyContent
$node->replaceChild($section, $child);
$child = $section;
}
if (! in_array(strtolower($child->tagName), array_merge(['p', 'strong', 'b', 'em', 'i', 'ul', 'ol', 'li', 'br', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'a'], $preserveStructure ? ['div', 'span', 'small', 'section', 'table', 'caption', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'figure', 'figcaption'] : []), true)) {
if (! in_array(strtolower($child->tagName), ['p', 'strong', 'b', 'em', 'i', 'ul', 'ol', 'li', 'br', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'a'], true)) {
$node->removeChild($child);
continue;
-287
View File
@@ -1,287 +0,0 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
use App\Models\User;
use Carbon\CarbonImmutable;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
/** Publication of notices; never receives bids or changes the linked investment. */
final class Procurement
{
public const TEXT = ['title', 'reference', 'responsible_unit', 'modality', 'object', 'object_kind', 'quantities', 'financier', 'instrument', 'edition', 'rule_source', 'financing_agreement', 'eligibility', 'requirements', 'proposal_validity', 'guarantee_status', 'guarantees', 'delivery_channel', 'delivery_address', 'delivery_url', 'public_contact', 'dissemination', 'origin_url', 'origin_published_at', 'clarifications_at', 'deadline', 'opening_at', 'timezone', 'minimum_source', 'minimum_edition', 'minimum_modality', 'minimum_day_basis', 'result', 'internal_notes', 'public_reason', 'minimum_working_days', 'minimum_holidays', 'minimum_calendar_source'];
public function available(): bool
{
return config('procurement.enabled') && Schema::hasTable('portal_tenders');
}
public function access(?User $actor): bool
{
if (! $actor || ! $actor->hasVerifiedEmail()) {
return false;
}
$docs = app(DocumentManagementAccess::class);
return ! app(PortalProfileAccess::class)->has($actor, 'auditor') && ($docs->full($actor) || $docs->editorial($actor));
}
public function guard(?User $actor): void
{
abort_unless($this->available(), 404);
abort_unless($this->access($actor), 403, 'Use a autorização editorial já atribuída.');
}
public function references(User $actor): array
{
$this->guard($actor);
$editable = app(DocumentManagementAccess::class)->documents($actor)->select('id');
return ['regimes' => config('procurement.regimes'), 'acts' => config('procurement.acts'),
'organizations' => DB::table('organizations')->whereNull('deleted_at')->orderBy('name')->get(['id', 'name']),
'sectors' => DB::table('sectors')->orderBy('name')->get(['id', 'name']),
'territories' => app(InvestmentGeography::class)->references(true)->orderBy('name')->get(['id', 'name', 'location_type']),
'opportunities' => app(PortalProfileAccess::class)->scope(Opportunity::query(), $actor)->orderBy('title')->get(['id', 'title']),
'projects' => DB::table('projects')->whereNull('deleted_at')->whereIn('data_classification', ['internal', 'public'])->orderBy('name')->get(['id', 'name']),
'documents' => DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->whereNull('d.deleted_at')
->where(fn ($q) => $q->whereIn('d.id', $editable)->orWhere(fn ($p) => $p->where('r.published', true)->where('d.data_classification', 'public')))
->orderBy('r.title')->get(['r.id', 'r.title', 'r.published', 'd.malware_scan_status'])];
}
public function record(string $id): object
{
abort_unless($this->available(), 404);
return DB::table('portal_tenders')->where('id', $id)->firstOrFail();
}
public function save(User $actor, ?string $id, array $input): string
{
$this->guard($actor);
$v = Validator::make($input, ['version' => 'required|integer|min:0', 'reason' => 'required|string|min:20|max:1000', 'draft' => 'required|array']);
$v->validate();
$draft = $this->normalize($actor, $input['draft']);
return DB::transaction(function () use ($actor, $id, $input, $draft) {
$old = $id ? DB::table('portal_tenders')->where('id', $id)->lockForUpdate()->firstOrFail() : null;
abort_unless((int) ($old->version ?? 0) === (int) $input['version'], 409, 'A versão mudou; recupere o concurso antes de guardar.');
$id ??= (string) Str::uuid();
$version = ($old->version ?? 0) + 1;
if ($old) {
DB::table('portal_tenders')->where('id', $id)->update(['draft' => json_encode($draft, JSON_THROW_ON_ERROR), 'version' => $version, 'updated_at' => now()]);
} else {
DB::table('portal_tenders')->insert(['id' => $id, 'draft' => json_encode($draft, JSON_THROW_ON_ERROR), 'version' => $version, 'created_by' => $actor->id, 'created_at' => now(), 'updated_at' => now()]);
}
$this->version($actor, $id, $version, 'draft', $draft, $input['reason'], false);
return $id;
});
}
private function normalize(User $actor, array $input): array
{
$rules = array_fill_keys(self::TEXT, 'nullable|string|max:12000');
$rules = [...$rules, 'regime' => 'nullable|in:state,external,private,other', 'organization_id' => 'nullable|uuid|exists:organizations,id',
'opportunity_id' => 'nullable|integer|exists:opportunities,id', 'project_id' => 'nullable|uuid|exists:projects,id', 'sector_id' => 'nullable|integer|exists:sectors,id',
'territory_id' => 'nullable|uuid|exists:geo_locations,id', 'contact_authorized' => 'boolean', 'minimum_days' => 'nullable|integer|min:0|max:3650',
'lots' => 'array|max:100', 'lots.*' => 'array:code,description,quantities', 'lots.*.code' => 'required|string|max:80|distinct', 'lots.*.description' => 'required|string|max:3000', 'lots.*.quantities' => 'nullable|string|max:1500',
'attachments' => 'array|max:100', 'attachments.*' => 'array:resource_id,public,purpose', 'attachments.*.resource_id' => 'required|integer|exists:portal_resources,id', 'attachments.*.public' => 'required|boolean', 'attachments.*.purpose' => 'required|string|max:150'];
foreach (['origin_url', 'delivery_url', 'rule_source'] as $url) {
$rules[$url] = 'nullable|url:http,https|max:2000';
}
$data = Validator::make($input, $rules)->validate();
if (! empty($data['opportunity_id'])) {
abort_unless(app(PortalProfileAccess::class)->scope(Opportunity::query(), $actor)->whereKey($data['opportunity_id'])->exists(), 403);
}
if (! empty($data['project_id'])) {
abort_unless(DB::table('projects')->where('id', $data['project_id'])->whereNull('deleted_at')->whereIn('data_classification', ['internal', 'public'])->exists(), 422);
}
foreach ($data['attachments'] ?? [] as $attachment) {
$resource = DB::table('portal_resources')->where('id', $attachment['resource_id'])->firstOrFail();
abort_unless($this->publicDocuments()->where('r.id', $resource->id)->exists() || app(DocumentManagementAccess::class)->documents($actor)->where('id', $resource->document_id)->exists(), 403);
}
return $data;
}
public function preview(User $actor, string $id, string $act): array
{
$this->guard($actor);
$record = $this->record($id);
abort_unless(array_key_exists($act, config('procurement.acts')), 422);
$p = json_decode($record->draft, true, 512, JSON_THROW_ON_ERROR);
Validator::make($p, array_fill_keys(['title', 'reference', 'organization_id', 'modality', 'object', 'regime', 'instrument', 'edition', 'rule_source', 'origin_published_at', 'deadline', 'delivery_channel', 'timezone'], 'required'))->validate();
Validator::make($p, ['timezone' => 'timezone', 'object_kind' => 'nullable|in:works,goods,services,mixed,other', 'guarantee_status' => 'nullable|in:required,not_required,unknown'])->validate();
Validator::make($p, ['public_reason' => 'required|string|min:20|max:1000'])->validate();
$dates = [];
foreach (['origin_published_at', 'clarifications_at', 'deadline', 'opening_at'] as $field) {
if (empty($p[$field])) {
continue;
}
$validator = Validator::make([$field => $p[$field]], [$field => 'date_format:Y-m-d\TH:i']);
$validator->validate();
$dates[$field] = CarbonImmutable::createFromFormat('!Y-m-d\TH:i', $p[$field], $p['timezone']);
}
$this->require($dates['deadline']->greaterThan($dates['origin_published_at']), 'deadline', 'Entrega anterior à publicação de origem.');
if (isset($dates['clarifications_at'])) {
$this->require($dates['clarifications_at']->betweenIncluded($dates['origin_published_at'], $dates['deadline']), 'clarifications_at', 'Esclarecimentos fora do período de publicação/entrega.');
}
if (isset($dates['opening_at'])) {
$this->require($dates['opening_at']->greaterThanOrEqualTo($dates['deadline']), 'opening_at', 'A abertura indicada é anterior à entrega.');
}
if (($p['guarantee_status'] ?? '') === 'required') {
$this->require(! empty($p['guarantees']), 'guarantees', 'Descreva a garantia documentada exigida.');
}
if (isset($p['minimum_days'])) {
foreach (['minimum_source', 'minimum_edition', 'minimum_modality', 'minimum_day_basis'] as $field) {
$this->require(! empty($p[$field]), $field, 'Identifique fonte, edição, modalidade e contagem do prazo mínimo.');
}
$this->require($p['minimum_modality'] === $p['modality'], 'minimum_modality', 'A regra indicada pertence a outra modalidade.');
$earliest = $dates['origin_published_at'];
if ($p['minimum_day_basis'] === 'business') {
$this->require(! empty($p['minimum_calendar_source']), 'minimum_calendar_source', 'Identifique a fonte do calendário de dias úteis e feriados.');
$weekdays = array_filter(array_map('trim', explode(',', (string) ($p['minimum_working_days'] ?? ''))));
$this->require(count($weekdays) > 0 && ! array_diff($weekdays, ['1', '2', '3', '4', '5', '6', '7']), 'minimum_working_days', 'Indique os dias de trabalho documentados (1=segunda, 7=domingo).');
$holidays = array_values(array_filter(preg_split('/[\s,;]+/', (string) ($p['minimum_holidays'] ?? ''))));
Validator::make(['dates' => $holidays], ['dates' => 'array|max:1000', 'dates.*' => 'date_format:Y-m-d'])->validate();
for ($left = (int) $p['minimum_days'],$iterations = 0; $left > 0; $iterations++) {
$this->require($iterations < 36500, 'minimum_days', 'Calendário insuficiente para calcular o prazo indicado.');
$earliest = $earliest->addDay();
if (in_array((string) $earliest->isoWeekday(), $weekdays, true) && ! in_array($earliest->format('Y-m-d'), $holidays, true)) {
$left--;
}
}
} else {
$this->require($p['minimum_day_basis'] === 'calendar', 'minimum_day_basis', 'Identifique dias corridos ou calendário de dias úteis documentado.');
$earliest = $earliest->addDays((int) $p['minimum_days']);
}
$this->require($dates['deadline']->greaterThanOrEqualTo($earliest), 'deadline', 'Prazo inferior ao mínimo documentado para esta modalidade/edição/calendário.');
}
$previous = $record->published_version_id ? $this->publishedVersion($record->published_version_id) : null;
$this->require($previous ? $act !== 'initial' : $act === 'initial', 'act', $previous ? 'O anúncio inicial já existe; publique um acto associado.' : 'Publique primeiro o anúncio inicial.');
if ($previous) {
$before = $previous['payload'];
if (($before['deadline'] ?? '') !== $p['deadline'] || ($before['timezone'] ?? '') !== $p['timezone']) {
$this->require($act === 'extension', 'act', 'Uma mudança do prazo exige acto de prorrogação, com data anterior e nova.');
}
if ($act === 'extension') {
$this->require($dates['deadline']->greaterThan(CarbonImmutable::parse($before['deadline'], $before['timezone'])), 'deadline', 'A prorrogação deve avançar o prazo anterior.');
$p['deadline_previous'] = $before['deadline'];
$p['timezone_previous'] = $before['timezone'];
}
$p['extended'] = ($before['extended'] ?? false) || $act === 'extension';
$p['procedural_state'] = $before['procedural_state'] ?? null;
}
if ($act === 'award') {
$p['procedural_state'] = 'results';
}
if ($act === 'cancellation') {
$p['procedural_state'] = 'cancelled';
}
if (in_array($act, ['award', 'cancellation', 'other'], true)) {
$this->require(! empty($p['result']), 'result', 'Descreva o acto ou resultado documentado.');
}
$p['organization_name'] = DB::table('organizations')->where('id', $p['organization_id'])->whereNull('deleted_at')->value('name');
$this->require((bool) $p['organization_name'], 'organization_id', 'Entidade eliminada; recupere a referência.');
$p['sector_name'] = empty($p['sector_id']) ? null : DB::table('sectors')->where('id', $p['sector_id'])->value('name');
$p['territory_name'] = empty($p['territory_id']) ? null : app(InvestmentGeography::class)->references(true)->where('id', $p['territory_id'])->value('name');
if (! empty($p['territory_id'])) {
$this->require((bool) $p['territory_name'], 'territory_id', 'Referência territorial indisponível.');
}
unset($p['internal_notes']);
if (! ($p['contact_authorized'] ?? false)) {
unset($p['public_contact']);
}
$attachments = [];
foreach ($p['attachments'] ?? [] as $item) {
if (! $item['public']) {
continue;
}
$doc = $this->publicDocuments()->where('r.id', $item['resource_id'])->first(['r.id', 'r.title', 'd.sha256', 'd.id as document_id']);
$this->require((bool) $doc, 'attachments', 'Anexo público exige publicação autorizada, scan limpo e direitos sem restrição na biblioteca.');
$attachments[] = [...$item, 'title' => $doc->title, 'sha256' => trim($doc->sha256), 'document_id' => $doc->document_id];
}
$p['attachments'] = $attachments;
if (! empty($p['opportunity_id'])) {
$o = Opportunity::published()->whereKey($p['opportunity_id'])->first(['id', 'title', 'slug']);
$p['opportunity'] = $o ? ['title' => $o->title, 'url' => '/oportunidades/'.$o->slug] : null;
}
if (! empty($p['project_id'])) {
$p['project_name'] = DB::table('projects')->where('id', $p['project_id'])->whereNull('deleted_at')->where('data_classification', 'public')->value('name');
}
unset($p['opportunity_id'],$p['project_id']);
$plan = ['id' => $id, 'version' => $record->version, 'act' => $act, 'payload' => $p];
$plan['hash'] = hash_hmac('sha256', json_encode($plan, JSON_THROW_ON_ERROR), config('app.key'));
return $plan;
}
public function publish(User $actor, string $id, array $input): void
{
$this->guard($actor);
Validator::make($input, ['hash' => 'required|string|size:64', 'act' => 'required|string', 'reason' => 'required|string|min:20|max:1000'])->validate();
DB::transaction(function () use ($actor, $id, $input) {
$record = DB::table('portal_tenders')->where('id', $id)->lockForUpdate()->firstOrFail();
$plan = $this->preview($actor, $id, $input['act']);
abort_unless(hash_equals($plan['hash'], $input['hash']), 409, 'Prévia alterada; reveja o conteúdo antes de publicar.');
abort_unless($input['reason'] === $plan['payload']['public_reason'], 409, 'O motivo público deve coincidir com a prévia.');
$version = $record->version + 1;
$vid = $this->version($actor, $id, $version, $input['act'], $plan['payload'], $input['reason'], true);
DB::table('portal_tenders')->where('id', $id)->update(['published_version_id' => $vid, 'version' => $version, 'updated_at' => now()]);
});
}
private function version(User $actor, string $id, int $version, string $act, array $payload, string $reason, bool $published): string
{
$vid = (string) Str::uuid();
DB::table('portal_tender_versions')->insert(['id' => $vid, 'tender_id' => $id, 'version' => $version, 'act' => $act, 'payload' => json_encode($payload, JSON_THROW_ON_ERROR), 'reason' => $reason, 'actor_id' => $actor->id, 'published_at' => $published ? now() : null, 'created_at' => now()]);
DB::table('audit_events')->insert(['source_system' => 'procurement', 'entity_type' => 'portal_tenders', 'entity_id' => $id, 'actor_user_id' => $actor->id, 'action' => $published ? 'notice_published' : 'tender_draft_saved', 'data_classification' => 'internal', 'after_data' => json_encode(['version_id' => $vid, 'act' => $act, 'reason' => $reason], JSON_THROW_ON_ERROR)]);
return $vid;
}
public function publicDocuments(): Builder
{
return DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->where('r.published', true)->where('r.rights_status', '!=', 'restricted')->where('d.rights_status', '!=', 'restricted')->where('d.data_classification', 'public')->where('d.status', 'active')->whereNull('d.deleted_at')->where('d.malware_scan_status', 'clean')->whereColumn('d.sha256', 'd.malware_scanned_sha256')
->where(fn ($q) => $q->whereNull('d.source_system')->orWhereNotIn('d.source_system', ['opportunity-resources', 'opportunity-image-derivatives']))
->whereNotExists(fn ($q) => $q->selectRaw('1')->from('opportunity_documents as od')->whereColumn('od.document_id', 'd.id')->whereRaw("NOT jsonb_exists(COALESCE(od.payload,'{}'::jsonb),'library_source')"))
->whereNotExists(fn ($q) => $q->selectRaw('1')->from('opportunity_images as oi')->whereColumn('oi.document_id', 'd.id')->whereRaw("NOT jsonb_exists(COALESCE(oi.payload,'{}'::jsonb),'library_source')"));
}
public function publishedVersion(string $id): array
{
$v = DB::table('portal_tender_versions')->where('id', $id)->whereNotNull('published_at')->firstOrFail();
$p = json_decode($v->payload, true, 512, JSON_THROW_ON_ERROR);
foreach ($p['attachments'] ?? [] as $i => $item) {
$p['attachments'][$i]['available'] = $this->publicDocuments()->where('r.id', $item['resource_id'])->where('d.id', $item['document_id'])->where('d.sha256', $item['sha256'])->exists();
}
return ['id' => $v->id, 'version' => $v->version, 'act' => $v->act, 'payload' => $p, 'published_at' => $v->published_at, 'reason' => $v->reason];
}
public function state(array $version): string
{
$p = $version['payload'];
if (in_array($p['procedural_state'] ?? '', ['cancelled', 'results'], true)) {
return $p['procedural_state'];
}
if (CarbonImmutable::parse($p['deadline'], $p['timezone'])->isPast()) {
return 'deadline_ended';
}
return ($p['extended'] ?? false) ? 'extended' : 'open';
}
private function require(bool $condition, string $field, string $message): void
{
if (! $condition) {
throw ValidationException::withMessages([$field => $message]);
}
}
}
+1 -1
View File
@@ -20,7 +20,7 @@ class TerritoryGeometryImport
private function guard(User $actor, bool $write = false): void
{
abort_unless($actor->can('manage-portal') || app(ScopedPortalAdministration::class)->administrative($actor), 403);
abort_unless($actor->can('manage-portal'), 403);
abort_unless(config('geometry-import.enabled'), 503, 'Importação cartográfica não disponibilizada.');
if (! $write) {
return;
-170
View File
@@ -1,170 +0,0 @@
[
{
"external_id": "legacy-tempo-post-62413-20170626",
"sha256": "b471c1afd7235f359acdcc16a93088f77e1f988706c8d3c4d4f11c5d560aea47",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-73945-20170731",
"sha256": "2aa0ce0eb305bfdf93e390a978d3694d0fbc0129034077b68cebce418f878415",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-76474-20170808",
"sha256": "8f769aec4715449d056c8c25294060b2ff290ec0893c28e9bdcc4e8092fc75f5",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62414-20170626",
"sha256": "a040c0b7cb95dd7f053f4d13662dd58b2b06453b6fa61a2d531d0257a8db8c17",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62418-20170626",
"sha256": "e8ccafa68f0d1aa80f2e41d9e09f7b13e7c653a8472a731798cfd5e04ce2963e",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-75002-20170804",
"sha256": "7b6fbd998be2b47b96e9a4724560c192c502709fa308d6590c0797ddcdb10544",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-73246-20170728",
"sha256": "430ee8674c71104fc126bed2911d676f150ac623857a1ada75662987fd9ac390",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-77232-20170811",
"sha256": "27544d3127803b7495bef9fd633147d0225d8c31816c4d59ed05a2edd59de070",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62416-20170626",
"sha256": "ac575ce340571192552c89b63f0bd62a84dbc47828e6930133af5ff70e249319",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62929-20170627",
"sha256": "488017b062c6760659d9147b7f12aea4afd8d824121adb9462e2c7a2ae58437b",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62649-20170626",
"sha256": "38a858713472759a2d20a308bdd9d8afa9cfb76dcaf8d11ca709e89261573e42",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62739-20170626",
"sha256": "5870fc0fad9bb7af537b7b1468151cde138b1b886ce846c7be25647b630245dd",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62854-20170627",
"sha256": "44b1ba9d593bb625cf53de8909e78eb0b3129742c3ec9d58ec68c984e8930bce",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-63128-20170627",
"sha256": "74be8f29e5053f53ab1a39a2f63208145c30f23357ca6d78b637dd02bf9c1fb4",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-63181-20170627",
"sha256": "3d0f9ac14d36156d8178e33f8616d6406f31ea4cd69c8308cbf4227586d7ccb3",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-63146-20170627",
"sha256": "542353466cc6d82b651619c495f138b0576a4be41d21aad194ae2005050cb1bc",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62688-20170626",
"sha256": "a210a789b06d425822f4124f74226a2b27246c086c5ec5f041f1b2237d7c2b65",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-63248-20170628",
"sha256": "6c30e61197b8568332af6d9b19bbba7ad8665b3873bb031a8c8aedd41536b060",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173220-20260616",
"sha256": "5b76c3d84dcf7f9a489686d90e3857ae6536705c918e841310bb42b354e80976",
"kind": "setorial",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173222-20260616",
"sha256": "e64d7063d1ac4dda028c97e1ba64938d2a9e426a0b630c57ee5df52a41312cc7",
"kind": "setorial",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173482-20260915",
"sha256": "6f888e133a779c719073246f89bcae150198e5897c0e7d9b7ba75f54c54a7830",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173484-20260915",
"sha256": "297df455a9c6fd1f0ab7ca7bbe124ce483c86fe55be26baa695f03089b3ac049",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173478-20260915",
"sha256": "d4e320ed99dd9d53d205e47932f73651976d43081d5d39f2bfc2996901408644",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173480-20260915",
"sha256": "c3ee6401eda5b582c61969b5e3b74fdf26ef34ca481b1aca8c4c309d845147ae",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173476-20260915",
"sha256": "72fbf28391db4804e0637b64e7f59e9fa597812a2681b4562dc3d6dfb4093a30",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173470-20260915",
"sha256": "26feeae6b8d04972c7a64ee360583cccdcaeb4b0d8795fd7bc2fd3c38866cc19",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173474-20260915",
"sha256": "9fa741a17b746bfa2f3ce7b6ce1d2bb34d3a35d3b58330b0554f9e0a6844f049",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173463-20260915",
"sha256": "4f34b7bac4b3030c0614844d379f6e3cfad1b7f6ea3db575a58c33ae033b0e73",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
}
]
-7
View File
@@ -1,7 +0,0 @@
<?php
return [
'enabled' => (bool) env('PROCUREMENT_ENABLED', false),
'regimes' => ['state' => 'Contratação pública do Estado', 'external' => 'Financiamento externo', 'private' => 'Concurso privado', 'other' => 'Outro regime documentado'],
'acts' => ['initial' => 'Anúncio inicial', 'clarification' => 'Esclarecimento', 'correction' => 'Rectificação', 'extension' => 'Prorrogação', 'award' => 'Resultado / adjudicação', 'cancellation' => 'Cancelamento', 'other' => 'Outro acto'],
];
@@ -1,50 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('portal_tenders', function (Blueprint $t) {
$t->uuid('id')->primary();
$t->jsonb('draft');
$t->unsignedInteger('version')->default(1);
$t->uuid('published_version_id')->nullable();
$t->foreignId('created_by')->constrained('users')->restrictOnDelete();
$t->timestampsTz();
});
Schema::create('portal_tender_versions', function (Blueprint $t) {
$t->uuid('id')->primary();
$t->foreignUuid('tender_id')->constrained('portal_tenders')->restrictOnDelete();
$t->unsignedInteger('version');
$t->string('act', 24);
$t->jsonb('payload');
$t->text('reason');
$t->foreignId('actor_id')->constrained('users')->restrictOnDelete();
$t->timestampTz('published_at')->nullable();
$t->timestampTz('created_at')->useCurrent();
$t->unique(['tender_id', 'version']);
});
Schema::create('portal_tender_watches', function (Blueprint $t) {
$t->foreignUuid('tender_id')->constrained('portal_tenders')->restrictOnDelete();
$t->foreignId('user_id')->constrained('users')->restrictOnDelete();
$t->uuid('seen_version_id')->nullable();
$t->timestampsTz();
$t->primary(['tender_id', 'user_id']);
});
}
public function down(): void
{
if (DB::table('portal_tenders')->exists()) {
throw new RuntimeException('Preserve procedures, acts and history; use a reviewed data reversal.');
}
Schema::dropIfExists('portal_tender_watches');
Schema::dropIfExists('portal_tender_versions');
Schema::dropIfExists('portal_tenders');
}
};
@@ -319,23 +319,4 @@ Situação comum observada: `publication_status=draft`, `validation_status=valid
### Referência da entrada única de gestão — QA, 22/10/2026
Nos requisitos existentes `MASTER-9f6dd1d9-0001`, `MASTER-9f6dd1d9-0003` e `MASTER-02f44baf-0002`, acrescentar como evidência delimitada a secção «Entrada única de gestão — preparação em QA, 22/10/2026» do manual de rastreabilidade e `tests/Feature/ContentManagementEntryTest.php`: quatro testes/99 asserções, ClamAV real e reversão transaccional em QA. Origem do objectivo e das regras operacionais: decisão expressa da Tempo; navegação, filtros e recuperação do upload são escolhas de implementação. Reutilizados biblioteca, armazenamento, perfis e histórico. Não altera os critérios de aceitação nem fecha os requisitos integrais: integração/contas reais e categorias não demonstradas conservam o seu estado. Geometrias permanecem separadas.
AUD-GEO-02/03: Recuperação da demarcação territorial — QA, 22/10/2026. 408/581 limites recuperados em QA; cadeia territorial guardada/reaberta no portal. Homologacao ainda sem reposicao; consultar a nova secao no manual existente. Mantidas 173 correspondencias pendentes e ausencia de geometrias proprias das localidades. Origem: pedido expresso da Tempo de recuperar funcionalidade; enquadramento e mensagens sao escolhas tecnicas. Nao encerra o criterio de reposicao no destino.
AUD-GEO-02/03 - 22/10/2026: Demarcação territorial reposta na homologação — 22/10/2026. 408 limites (11/133/264) importados pela conta real/MFA, com tres recibos auditados; backup/restauro de 171 tabelas conferido, 333 ficheiros verificados. Consulta do mapa demonstrada na oportunidade real #30, sem a alterar. Acessos previstos e originais privados preservados. Reposicao no destino concluida; 26+147 correspondencias e ausencia de poligonos proprios de localidades mantidas como lacunas reais. Ver fecho e guia no manual existente; sem repetir provas QA aceites.
### Incremento Concursos e anúncios — QA, 22/10/2026
Instalação autorizada e concluída na homologação em 22/10/2026: integração funcional `f4d09709`, schema selectivo/contrato/activação conferidos após backup e restauro isolado de 171 tabelas. Gestão real com MFA: cadastro, recuperação e prévia de rascunho privado auditado; catálogo público 200, zero anúncios publicados. Preservados dados/permissões/originais e geometrias. Evidência e links finais em «Instalação concluída na homologação» no manual e `unification/procurement-installation-receipt-20261022.json`. Provas QA aceites reutilizadas. Este fecho substitui o estado de proposta pendente de instalação abaixo, sem declarar aceite pela Tempo o guia não conferido nem expandir o âmbito para recepção de propostas.
Proposta de entrega da candidata `1bcf34c0`: ver «Proposta de instalação compatível com deploy automático» no manual existente. Identificados três novos cadastros e o gate real de contrato de migrations do pipeline. Sequência proposta: revisão → coordenação do deploy → backup/restauro isolado → migration selectiva autenticada com flag desligada → contrato → integração/build/promoção → activação → conferência do delta no destino. Reversão conserva tabelas, actos, auditoria e originais posteriores; não restaura backup antigo sobre dados novos. Provas QA reutilizadas; nenhuma integração, migration remota, activação ou publicação real executada nesta passagem. A Tempo ainda não conferiu links locais/guia; não registar aceitação nem entrega no destino por essa razão.
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.
### Acervo legado — correspondência e preparação QA, 22/10/2026
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.
Conferência de integração de 22/10/2026 (requisitos documentais MASTER-9f6dd1d9-0001/0003 e reutilização MASTER-02f44baf-0002): 8286d750 servido, acesso real de Nala restituído removendo dependência indevida da reserva técnica do host; lista nominal, MFA e âmbito preservados. Ver secção «Entrada única — integração e conferência real» do manual. Não encerrar o fluxo integral das oportunidades: ausência de Publicador activo e publicação promocional ainda por executor privado são saldos explícitos; não condicionam os acessos já aprovados. Não foram criadas contas, matrizes ou papéis adicionais.
@@ -1,50 +0,0 @@
{
"functional_candidate": "1bcf34c0",
"installation_procedure": "e46f9731",
"installed_revision": "f4d0970917e7e8d141f74c136b66138b929141fc",
"activated_utc": "2026-10-22T20:51:27.874333+00:00",
"counts": {
"tenders": 1,
"versions": 1,
"published_versions": 0,
"watches": 0
},
"verification_draft": {
"id": "b970f0f0-9257-42e1-8365-3358237b55db",
"created_by": 15,
"version": 1,
"published_version_id": null
},
"verification": {
"real_account_id": 15,
"mfa_renewed_by_user": true,
"management_hub": true,
"draft_saved_recovered": true,
"preview_opened": true,
"publication_performed": false,
"qa_proofs_reused": "8 tests / 285 assertions; 6 navigation tests; build and TypeScript"
},
"links": {
"management": "https://teste-investidor.tempo.co.mz/gestao-conteudos",
"catalogue": "https://teste-investidor.tempo.co.mz/concursos"
},
"backup": {
"database_sha256": "69de817b288ecb25db4b341375475f2408a47642a8ba69d338b217dcc982854f",
"files_sha256": "7b75c22e730b5600d6e97e1c6dbb4cd93982bdd47e9dd2a63de2359974132674",
"tables_restored_verified": 171,
"files_archive_verified": 341
},
"preservation": {
"protected_tables_unchanged": [
"users",
"portal_role_assignments",
"documents",
"portal_resources",
"opportunities",
"geo_locations",
"geo_geometries"
],
"original_files_preserved": 340
},
"private_document_anonymous_status": 404
}
@@ -2255,229 +2255,16 @@ Verificação nova: quatro testes, 99 asserções, com transacções revertidas
No navegador, login e MFA normais da conta sintética de equipa; entrada → legislação; entrada → nova oportunidade → guardar preparação incompleta → recarregar, com título recuperado e ficha QA 241. Não foi repetido o workflow integral de revisão/publicação de oportunidades já existente; a prova nova cobre a entrada e a gravação/recuperação. O ensaio documental completo foi HTTP transaccional, não uma prova visual de cada clique. A conta QA tem autorizações explicitamente sintéticas; não comprova as designações das contas reais. Não transportar fixtures, configurações QA ou concessões de acesso.
Provas locais: `outputs/content-management-20261022/entrada-final.png`, `build-final.log`, e `tests/Feature/ContentManagementEntryTest.php`. Estado: candidata em branch `codex/content-management-entry-QA`, ainda sem integração ou instalação na homologação. Não declarar encerrada a autonomia operacional de todas as contas/categorias apenas por esta entrada. Não houve migration, publicação remota, alteração de papéis activos ou activação fiscal.
## Entrada única — integração e conferência real, 22/10/2026
A pedido expresso da Tempo, revista e integrada por avanço directo a candidata 97d51db6, seguida de aa2b3d05 (ligação da antiga página de acesso para a entrada autorizada) e 8286d750 (restituição do acesso editorial nominal). Push em main e instalação pelo processo Git automático existente; revisão efectivamente servida 8286d7504d9d368de81b4e8d095398764278bb95, build 22/10/2026 19:04:38 UTC. Nenhuma migration, publicação de conteúdo ou alteração de atribuições activas nesta entrega.
## Recuperação da demarcação territorial — QA, 22/10/2026
A leitura da sessão real de Osmane Nala após login/MFA confirmou a dupla 15/16, Promotor e Validador activos da conta 15, uma atribuição anterior revogada preservada e nenhuma atribuição Publicador na lista actual. Criação abre as seis categorias atribuídas e os promotores reais; a lista recupera os 30 resumos já publicados e a fila Validação e pareceres abre sem casos. Isto não afirma revisão de um caso inexistente nem publica para ensaio. Atribuições futuras de Aurora/Palmira/Mario conservam a decisão da Tempo e não são pré-condição dos acessos de Nala/onala. Não foi repetido login da outra titular; reutiliza-se a prova nominal anterior e a mesma regra editorial delimitada.
Retomada expressa da Tempo como recuperação de funcionalidade anteriormente demonstrada, nos requisitos existentes AUD-GEO-02/03 e na experiência de cadastro. Não é criação de outra cartografia. O incremento de divulgação promocional permanece na sua branch independente.
Falha concreta encontrada no destino: `portal.homologation_only=false` fazia `DocumentManagementAccess::editorial` recusar a designação já aprovada. A reserva do host era escolha técnica, não condição organizacional da edição. 8286d750 remove apenas essa dependência; preserva lista nominal Nala/onala, dupla existente, MFA recente, exclusão de Auditor e âmbito documental. Um teste novo, 24 asserções, exclusivamente em QA isolada com rollback, demonstrou independência da reserva e recusa sem designação/MFA. Não foram repetidos os quatro testes/99 asserções anteriores. TypeScript foi conferido para o delta da antiga página de acesso; build/testes obrigatórios pertencem ao processo automático.
**Causa comprovada:** leitura SSH autenticada, em transacção READ ONLY, da release `8286d750`/base `teste_investidor`: zero linhas em `geo_geometries`, incluindo eliminadas. Cadastro preservado: 11 províncias, 148 distritos, 437 postos e 1324 localidades. Directório dos originais privados ausente; importador desabilitado. Serviço de consulta, controlador e correspondências iguais por SHA256 ao código QA. Hash do cadastro (IDs, nomes, pais, nível, origem/códigos): `9de4181c42055bc6ef11b56333b64dd463d0ebe16bb2d1ea3238fc79e69024f7`, igual no QA e destino. Não se confirmou recusa de acesso nem perda de associação: faltam os próprios dados.
Na mesma sessão real, após instalação, a entrada passou a mostrar Novo documento e Nova legislação e 29 publicados/2 não publicados. A biblioteca abriu com Receber documento em privado, Guardar em quarentena, Registar documento na biblioteca, pesquisa, Editar metadados, Publicar/Retirar e históricos. ClamAV real 1.4.3 disponível, 32 ficheiros limpos no âmbito. Nenhum conteúdo foi alterado ou publicado para repetir prova já aceite em QA.
**Histórico:** as provas de 09–10/10 em `docs/investmoz/v2/auditoria-portal/correspondencias-cartograficas.md` registam 361→393→408 correspondências em bases QA anteriores. Os originais e recibos privados permanecem disponíveis. Os transportes de 19–20/10 deste manual excluíram expressamente geometrias; a disponibilização Git também exclui dados e ficheiros privados (`deploy/homologacao/README.md`). Em 22/10 a leitura de Cabo Delgado já encontrara zero linhas; esta passagem conferiu a tabela inteira. Prova-se uma diferença de composição entre QA cartográfico e homologação. Não foi localizado recibo da instalação anterior destes limites na mesma base; não se atribui data a uma suposta eliminação nem se descarta a observação anterior no mesmo endereço.
**Dependências que permanecem explícitas:** (1) o fluxo normal de oportunidades tem interface, mas a lista actual não tem Publicador activo; falta a disponibilidade da conta/função já designada, não um comando do Codex. Nala não recebe outro papel por inferência. (2) A divulgação promocional de resumos em preparação, usada no lote Inhambane, foi operação por executor privado; ainda não existe acção genérica equivalente na interface. A candidata não encerra essa autonomia específica, nem as variantes de submissão que o editor já identifica como não implementadas. (3) manutenção de indisponibilidade persistente do scanner/worker continua técnica; as operações documentais normais não exigem comandos. Geometrias administrativas permanecem em saldo separado.
**Recuperação executada em QA:** o clone actual também tinha zero geometrias. Reutilizados seis originais INE/UNOCHA de 07/06/2019 (três GeoJSON e três metadados), hashes preservados e correspondências v2 existentes. O serviço `TerritoryGeometryImport` inseriu 11 províncias, 133 distritos e 264 postos, internos, com recibos e auditoria. Todos válidos/SRID4326. Nos exemplos, a consulta pública continua sem devolver limites internos. ClamAV real, assinaturas de 22/10: três originais limpos. ADM3, 26773796 bytes, excedeu o stream de 25 MiB e passou pelo scanner de ficheiro GIS com orçamento de 40 MiB nesse processo; tentativa inconclusiva preservada. Sem alterar limites globais ou configuração do daemon.
O mapa enquadra o limite seleccionado; se não existir, enquadra o nível superior disponível mais próximo e informa que é contexto. A lista distingue selecção de contexto superior. Fonte, edição e actualidade jurídica indeterminada preservadas. Limite administrativo não representa parcela nem autorização de investimento.
**Prova de interface:** oportunidade sintética QA268 criada no portal. Cabo Delgado → ANCUABE → posto ANCUABE → ANCUABE-SEDE; limites e aproximação progressiva nos três primeiros níveis. Recurso de contexto/principal guardado; após recarregar e abrir “Ver / editar / restaurar”, os quatro níveis foram recuperados. A localidade sem limite próprio apresenta aviso dos níveis superiores. A fixture QA255 anterior tinha versão fechada/payload sintético mínimo incompatível com gravação do contrato; não foi usada como prova de persistência nem corrigida silenciosamente. Uma navegação durante a recompilação QA conservava referência a asset removido; recarregar resolveu o carregamento, sem alteração no destino.
**Cobertura:** 408/581 elementos do exemplar aceite: 11/11 províncias, 133/159 distritos, 264/411 postos. Mantêm-se 26+147 correspondências pendentes, com nomes nas prévias e no documento de correspondências existente. O denominador do cadastro é diferente (148 distritos, 437 postos). Este exemplar não contém geometrias próprias de localidades ou parcelas; não atribuir limites superiores às 1324 localidades.
**Reposição preparada, não aplicada na homologação:** `outputs/investmoz-territory-recovery-20261022/demarcation/retained-geometry-restoration.zip`, SHA256 `53a5d8aa2be57603c928279cbd14561741dd2ec4b44b138fbc785380de6f951d`, contém seis originais e manifesto. Não contém dump de substituição, actores QA ou limites sintéticos. Procedimento existente:
1. Rever e integrar pelo Git o ajuste visual; conferir revisão efectivamente servida.
2. Colocar originais no armazenamento privado partilhado, conservando hashes. Executar scanner actual ligado aos originais. Conferir backup/restauro e prova de activação da revisão/alvo, como exige o importador já existente; disponibilizar a configuração do importador.
3. Gestor já autorizado, com MFA, abre `/management/territory-geometry-import`: prévia e aplicação de províncias, depois distritos, depois postos, com motivo/confirmar. Reconciliar prévia fresca no destino; não executar hashes antigos do QA. Recibos e reversão dos lotes novos existentes preservados.
4. Conferir a cadeia territorial no formulário do destino e a recuperação após guardar, mantendo lacunas explícitas.
O staging dos originais, backup/restauro e configuração inicial ainda exigem operação técnica. Depois da reposição, seleccionar, guardar e recuperar a localização/mapa usam a interface. Esta passagem só leu o servidor remoto: sem alterar dados, permissões, camadas ou configuração. Não declarar a reposição no destino concluída.
Origem das restrições: decisões expressas da Tempo e requisitos anteriores do importador para preservação/backup e autenticação. Enquadramento e mensagens são escolhas de implementação, sem novo papel ou aprovador. Fonte oficial aceite reutilizada sem exigir nova validação da credibilidade.
Provas na pasta desta recuperação: inventário dos seis ficheiros, prévias/recibos por nível, `verification.json`, `homologation-readonly.json` e capturas. TypeScript, build QA e sintaxe PHP verificados; provas editoriais anteriores não repetidas.
### Ajuste de acesso encontrado na disponibilização — 22/10/2026
A conta real de Superutilizador encontrou HTTP403 no importador: o middleware não incluía a cartografia no âmbito administrativo já aprovado e o serviço exigia exclusivamente o gate legado `manage-portal`. Corrigidos ambos para reutilizar `ScopedPortalAdministration`, com MFA de sessão e as exclusões existentes de Auditor. Não foram alteradas atribuições, papéis, contas ou o gate global. Origem do bloqueio: escolha antiga de implementação, não decisão organizacional da Tempo. Três testes transaccionais novos/15 asserções em QA: Superutilizador com MFA chega à validação de fonte/aplicação; sem MFA e conta comum são recusados; nenhum grant legado criado. Provas QA cartográficas aceites reutilizadas sem repetição.
## Demarcação territorial reposta na homologação — 22/10/2026
Pedido expresso da Tempo executado. Candidata `15d82611` revista e integrada em `73c046e1`; ajuste de acesso `95d4cf44`, testado em QA, integrado em `30aed7cd`. A revisão `30aed7cd12ef65f797191467232087643c396751` foi instalada pelo processo Git existente e confirmada em `/build/revision.json?demarcation=30aed7cd`. O transporte de dados foi executado separadamente do Git.
### Dados, backup e importação
Seis originais INE/UNOCHA de 07/06/2019 transportados para o armazenamento privado partilhado: hashes iguais ao manifesto aceite, ficheiros 0640 e directório 0750, fora da árvore pública. Análise real dos seis pelo ClamAV 1.4.3, assinaturas de 22/10/2026, resultado limpo. Utilizado o protocolo local FILDES do daemon existente, sem instalar scanner, alargar permissões dos originais ou alterar limites globais: [documentação oficial ClamAV](https://docs.clamav.net/manual/Usage/ClamdProtocol.html).
Backup completo de `teste_investidor`, snapshot exportado consistente, restaurado em `127.0.0.1:55441/demarcation_hml_restore_20261022_complete_test`. As 171 tabelas coincidem integralmente por contagem e checksum canónico; arquivo dos 333 ficheiros verificado por conteúdo/hash. Recibo remoto em `/var/backups/investmoz-demarcation-20261022-complete/backup-receipt.json`, dump SHA256 `f80551de827e954a35b66ee4c8f2fcc559a4c88b48b3dc799c33b74907079c9b`. A comparação inicial revelou diferenças de ordenação Linux/Windows e a visão RLS reduzida da conta da aplicação; a comparação final usou ordenação canónica e a mesma visão completa do backup, preservando também os registos fiscais. Não se desactivou RLS.
A conta real `nala@tempo.co.mz` (ID15), com login e MFA normais renovados pelo titular, abriu as prévias frescas e aplicou os três níveis pela interface `/management/territory-geometry-import`:
| Nível | Criados | Pendentes | Lote auditado |
| --- | ---: | ---: | --- |
| Províncias | 11 | 0 | ec2c7c27-e4a3-466e-91a4-60aba939d3a0 |
| Distritos | 133 | 26 | 142667c7-7309-4461-8d0a-fd00cb421577 |
| Postos administrativos | 264 | 147 | b6d5a7e2-2f44-4bd6-9634-d97ee58ab718 |
Total: **408 limites internos**, válidos, não vazios, SRID4326; três recibos e três eventos `geometry_import_applied` ligados ao actor real. As geometrias foram repostas para consulta autorizada no cadastro; não foram publicadas camadas internas. Reversão existente disponível por lote, preservando originais, histórico e reutilizações e recusando alterações posteriores. Não se executou reversão no destino.
### Delta e acessos conferidos
Na oportunidade real #30, «Centro de Emergência Turística e Medicina de Mergulho de Tofo», a sessão real abriu Recursos → Ver recurso. O mapa desenha o limite da **província de Inhambane**, com fonte/edição e identificação de território seleccionado. Não é um polígono próprio de Tofo: distrito/posto/localidade continuam por indicar nessa ficha, como antes. A oportunidade, o recurso e a publicação não foram gravados nem alterados. Captura: `hml-demarcacao-tofo.png`. A prova QA aceite de guardar/reabrir quatro níveis foi reutilizada, sem repetição.
Consultas de controlo no destino recuperaram 1/2/3 limites na cadeia Cabo Delgado → distrito Ancuabe → posto Ancuabe. A localidade Ancuabe-Sede continua sem limite próprio e com três limites ancestrais de contexto. O cadastro territorial conserva exactamente o hash anterior `9de4181c42055bc6ef11b56333b64dd463d0ebe16bb2d1ea3238fc79e69024f7`.
Conferidos os acessos das contas existentes: IDs15 e16 mantêm a designação aprovada de Superutilizador; ID15 mantém Promotor e Validador. Não foram criadas contas ou atribuições. O endpoint do cadastro aceita os perfis já autorizados; a demonstração visual autenticada foi com ID15. A conferência das atribuições de ID16 foi de política, sem simular outro login. Quinze contas sem o perfil correspondente não satisfazem essa autorização. Pedido HTTP sem sessão ao endpoint privado devolveu 401; API pública devolveu zero limites internos; tentativa de obter o original pelo caminho público devolveu 403. Originais privados e regras de acesso preservados. Contas ainda não criadas não bloquearam a reposição.
O importador tinha um bloqueio legado de implementação: exigia `manage-portal` e não reconhecia a administração já aprovada. Corrigido por reutilização de `ScopedPortalAdministration`, com MFA de sessão e exclusões de Auditor existentes. Três testes novos/15 asserções passaram; não foi criado novo papel, aprovador ou gate global. Não houve repetição das provas QA cartográficas aceites.
Após a importação, **166/171 tabelas integralmente iguais** ao backup. Apenas `geo_geometries` (0→408), `geo_write_receipts` (0→3), `audit_events` (+6), `cache` e `sessions` diferem. Oportunidades, documentos, cadastro territorial, atribuições e par de Superutilizadores preservados integralmente.
### Guia curto e estado final
Entrar em [Gestão de conteúdos e oportunidades](https://teste-investidor.tempo.co.mz/gestao-conteudos) → Gerir oportunidades e histórico → abrir a ficha → Imagens, documentos e localizações → abrir ou preparar a localização. Seleccionar a hierarquia documentada; o mapa enquadra o limite disponível. Se faltar geometria própria, a mensagem distingue o contexto superior. Guardar o recurso e reabrir pela mesma lista recupera a preparação; não é necessário comando ou Codex para a consulta ou cadastro corrente.
**Reposição concluída neste recorte.** Mantidas as 26 correspondências de distritos e 147 de postos pendentes, com nomes nos documentos/prévias existentes. O exemplar não contém polígonos próprios das localidades ou parcelas. Essas lacunas não bloqueiam os 408 limites recuperados. A data de eventual desaparecimento anterior no mesmo endereço continua não determinada. A divulgação promocional mantém o seu incremento separado; este fecho não a declara integrada.
Provas: `homologation-restored-readonly.json`, `staging-receipt.json`, `preservation-receipt.json`, `http-access-verification.json`, captura e recibos locais na pasta desta recuperação; backup/restauro e prova de activação em caminhos privados. Uma interrupção do transporte local foi resolvida por escrita atómica da mensagem, antes de qualquer importação. Não ficaram passos técnicos pendentes para esta reposição; futuras importações usam as salvaguardas de backup/MFA já existentes.
## Concursos e anúncios — implementação em QA, 22/10/2026
Origem: pedido expresso da Tempo no anexo «O InvesteMoz deve ter uma secção pública Concursos e anúncios», com continuação autónoma autorizada. Aplicam-se as decisões permanentes da Tempo de 12/10 e 22/10/2026. Este incremento trata a divulgação de procedimentos; não abre recepção electrónica de propostas nem altera os investimentos associados. A estimativa apresentada antes da implementação foi de 16–24 horas; não representa tempo efectivamente consumido.
Reutilizados: entrada `/gestao-conteudos`, autenticação/MFA, autorização editorial e documental, entidades, oportunidades, projectos, sectores, território, biblioteca, originais privados, análise ClamAV, download verificado e `audit_events`. Acrescentados apenas três cadastros: procedimentos com rascunho, versões/actos imutáveis e acompanhamento individual. Uma oportunidade/projecto pode ter vários procedimentos; cada um admite lotes e actos associados. Não foram criados papéis, designações de funcionários ou aprovadores. Contas ainda não criadas não bloqueiam as contas já autorizadas.
### Fontes, âmbito e escolhas de implementação
- A UFSA identifica o Decreto n.º 79/2022 na [página oficial do regulamento](https://www.ufsa.gov.mz/divnovoreg.php). O [quadro oficial do Banco Mundial](https://www.worldbank.org/ext/en/what-we-do/project-procurement/framework) disponibiliza regulamentos e documentos normalizados, incluindo a edição de Setembro/2025. Cada procedimento regista a sua edição e acordo aplicáveis; a edição mais recente não é imposta a acordos anteriores.
- Inventário deste recorte: instrução anexada, páginas oficiais referidas, pesquisa dos ficheiros acessíveis do repositório e referências da biblioteca existentes. Não foi identificado neste recorte um modelo oficial de concurso já fornecido como original local utilizável. Não se declarou importado ou analisado o articulado integral/modelos que não foram obtidos. Os documentos de demonstração são explicitamente sintéticos, sem classificação de autenticidade oficial. Os modelos disponibilizados pela Tempo usam a biblioteca existente, sem segunda validação genérica da credibilidade de fontes oficiais aceites.
- Decisão expressa da Tempo: separar regimes Estado/externo/privado/outro; não generalizar UGEA, Cadastro Único, garantia ou abertura pública; guardar preparação incompleta; distinguir publicação de origem e publicação do portal; preservar actos, privacidade e auditoria.
- Escolhas técnicas: só a prévia de publicação exige identificação, entidade, objecto, modalidade, instrumento/edição/fonte, calendário coerente, canal e motivo público. Rascunhos permanecem incompletos. Prazos mínimos são opcionais, citados por fonte/edição/modalidade; dias úteis usam exclusivamente o calendário documentado no registo. Não foi parametrizada uma tabela universal de mínimos legais nem presumido um calendário de feriados.
- Escolhas técnicas de preservação: concorrência por versão, prévia assinada pelo servidor, nova verificação dos anexos na publicação, documentos por ID/hash e histórico imutável. Retirar ou substituir um binário na biblioteca torna indisponível o anexo antigo, sem apontar silenciosamente para outros bytes. Contacto sem autorização, notas internas e anexos privados não integram o conteúdo público. Ligações a oportunidades/projectos privados não divulgam os seus títulos ou fichas.
- Autorizações reutilizadas: edição/publicação por contas já elegíveis para gestão documental completa ou edição editorial; auditor e conta simples não obtêm escrita. Acompanhamento exige apenas autenticação, incluindo conta sem email verificado. Estas escolhas não atribuem novos papéis e não dispensam os requisitos existentes de cada autorização.
### Guia curto da equipa
**Entrada QA:** [Gestão de conteúdos e oportunidades](http://127.0.0.1:18580/gestao-conteudos). Abrir **Novo concurso/anúncio**; escolher a entidade já cadastrada e, quando aplicável, oportunidade/projecto, sector e território. Indicar o regime e a edição do instrumento aplicável. Guardar mesmo com preparação incompleta; recuperar em **Gerir concursos e anúncios**. O motivo interno fica no histórico de gestão.
1. Preencher objecto, lotes, participação, financiamento, calendário, fuso horário e canal efectivo de apresentação. A data de origem é a referência do procedimento; o portal regista separadamente a sua publicação.
2. Usar **Carregar / gerir documentos e scan na biblioteca**, que abre outra página sem perder o editor. Carregar o original, acompanhar o scan, editar os metadados e disponibilizar explicitamente os documentos autorizados. Voltar ao concurso, usar **Actualizar op??es da biblioteca** e seleccionar os anexos. Marcar públicos só os destinados à divulgação; os restantes permanecem privados.
3. Guardar, escolher **Anúncio inicial** e **Preparar prévia pública**. Rever contacto, documentos, objecto, entidade, prazo e canal. O motivo público aparece também no histórico público. Usar **Publicar este acto**; alterações posteriores no rascunho não modificam essa publicação.
4. Para esclarecer ou rectificar, guardar a revisão e publicar o acto correspondente. Para prorrogar, indicar o novo prazo, guardar e escolher **Prorrogação**; a prévia mostra o anterior e o novo. Resultados/adjudicação ou cancelamento usam o mesmo percurso, com texto e motivo documentados. O fim do prazo muda a indicação para **Prazo de propostas terminado**, sem adjudicação automática. Actos informativos posteriores não reabrem um cancelamento/resultado.
5. Consultar o [catálogo público QA](http://127.0.0.1:18580/concursos); pesquisar por palavras, entidade, sector, localização, modalidade, financiador, regime, estado ou prazo. Abrir a ficha e **Voltar aos resultados** conserva os filtros. **Relatório imprimível → Imprimir anúncio** permite imprimir/guardar pelo navegador, incluindo o histórico dos actos.
6. Uma conta simples usa **Acompanhar concurso** e **Os concursos que acompanho**; a lista identifica novos actos desde o registo de acompanhamento. **Deixar de acompanhar** remove só a subscrição individual. Não há promessa de alerta por email nem entrega de proposta: apresentar a proposta no canal indicado no anúncio/documentos.
Publicação documental disponibiliza um original da biblioteca; publicação de oportunidade disponibiliza a ficha pelas etapas existentes; divulgação promocional divulga o resumo autorizado de preparação; publicação de concurso divulga um procedimento e os seus actos. Nenhuma dessas operações autoriza execução do investimento, activa cálculo fiscal ou comprova envio à UFSA/financiador.
### Evidência e limites de entrega
Base exclusivamente QA `simulator_fiscal_delta_20261021_test`, porta 55441, com guarda de identidade antes de migração/fixtures/testes. Testes transaccionais preservam a base existente. `ProcurementTest` cobre preparação incompleta, concorrência, três regimes, filtros e retorno, prévia desactualizada, publicação anónima, prorrogação, expiração sem adjudicação, resultados, cancelamento persistente, conta simples, recusas de escrita, scan real, anexo privado, download anónimo e retirada documental. Ver resultado final em `outputs/procurement-20261022/tests.log`. Navegação existente: seis testes aprovados; compilação QA e TypeScript aprovados.
Exemplos persistentes, todos **SINTÉTICO QA**, sem concursos reais: estatal `17f44d8d-d077-4dca-9a63-5eb1c85a6926` (inicial + prorrogação, prazo de 20/11 15h para 16/12 17h, Africa/Maputo); externo `e85861cd-ffbb-4348-9cce-d588a6e09b86` (aberto); privado `fe271b02-0bfd-4fe2-8db2-856567b5111f` (inicial + cancelamento). Os rascunhos foram preparados por fixture identificada; guardar/reabrir, prévias e publicações destes actos foram executados no navegador pela conta sintética existente, não por comando de publicação. Resultado/adjudicação e expiração foram demonstrados pelos testes HTTP, não por adjudicação de um registo real.
Consulta anónima confirmada depois de terminar sessão: três regimes/estados no catálogo, ficha prorrogada, filtros preservados, relatório e download real do anexo 38. Anexo 39 e contacto sem autorização ficam privados. Acompanhamento confirmado pela conta simples já existente, sem MFA ou papel editorial. Evidências locais: `management.png`, `catalogue.png`, `print-notice.png`, `watch.png`, `fixtures.json` e resultados em `outputs/procurement-20261022/`. Estes artefactos QA não contêm credenciais na entrega Git.
Operações correntes deste incremento são feitas pela interface: cadastrar, guardar, recuperar, carregar/editar documentos pela biblioteca, pré-visualizar, publicar, actualizar/prorrogar, publicar resultado/cancelamento, consultar/imprimir e acompanhar. Não requerem executor privado ou Codex por concurso. **Pendente técnico de disponibilização fora de QA:** revisão e integração Git, migração pelo mecanismo de entrega e activação de `PROCUREMENT_ENABLED` no destino autorizado. O código usa flag desligada por defeito. Nenhum anúncio real foi publicado, nenhuma base activa foi migrada e não há integração automática com UFSA/financiadores. Geometrias não foram alteradas.
### Proposta de instalação compatível com deploy automático — candidata `1bcf34c0`
**Estado: proposta para revisão da Tempo, sem execução no destino.** O guia e os links QA da secção anterior foram conferidos pelo executor; a Tempo informou que ainda não os conferiu. A evidência QA aceite não equivale a aceitação pela Tempo nem a disponibilização na homologação. Destino previsto: `https://teste-investidor.tempo.co.mz`; confirmar a configuração instalada antes de executar. Esta passagem não integra em `main`, não altera configuração remota e não publica anúncios.
**Dependência de entrega encontrada.** Em `deploy/homologacao/pipeline.py`, `source_contract()` calcula SHA-256 dos ficheiros de migrations com normalização CRLF→LF; `build()` compara o conjunto completo com `schema_contract` e recusa qualquer diferença antes do build. O pipeline não executa migrations de produção nem importa conteúdos. A promoção troca atomicamente a release, verifica a revisão servida e a página inicial e reinicia a fila; estas verificações gerais não provam o acesso ao módulo. A configuração de exemplo aponta para `/etc/investmoz-deploy/schema-contract.json` e `/etc/investmoz-deploy/delivery.json`. Os ficheiros instalados podem divergir do repositório e devem ser lidos e comparados. Não se deve remover o gate nem converter o deploy em migração global automática.
**Delta exacto de schema.** Uma única migration: `database/migrations/2026_10_22_230000_create_portal_tenders.php`. Não altera tabelas existentes, extensões, utilizadores, papéis, grants, documentos ou dados territoriais; não contém seeds nem publicação de conteúdo.
| Tabela nova | Colunas | Chaves e relações efectivamente declaradas |
|---|---|---|
| `portal_tenders` | `id` UUID; `draft` JSONB obrigatório; `version` integer com default 1; `published_version_id` UUID anulável; `created_by` bigint obrigatório; `created_at`, `updated_at` timestamptz anuláveis | PK `id`; FK `created_by → users.id`, `RESTRICT` na eliminação |
| `portal_tender_versions` | `id` UUID; `tender_id` UUID; `version` integer; `act` varchar(24); `payload` JSONB; `reason` text; `actor_id` bigint; `published_at` timestamptz anulável; `created_at` timestamptz obrigatório com default actual | PK `id`; UNIQUE (`tender_id`,`version`); FK `tender_id → portal_tenders.id` e `actor_id → users.id`, ambas `RESTRICT` na eliminação |
| `portal_tender_watches` | `tender_id` UUID; `user_id` bigint; `seen_version_id` UUID anulável; `created_at`, `updated_at` timestamptz anuláveis | PK (`tender_id`,`user_id`); FK para `portal_tenders.id` e `users.id`, ambas `RESTRICT` na eliminação |
`published_version_id` e `seen_version_id` não têm FK nesta candidata; a associação de publicação é verificada pela aplicação, incluindo pertença da versão ao concurso. O histórico é imutável pelas operações da aplicação; esta migration não acrescenta trigger de imutabilidade. Índices novos: os das três PK e do UNIQUE indicado. O executor Laravel regista também a migration na tabela `migrations` existente. Confirmar tipos e restrições no catálogo PostgreSQL após instalação, não apenas a existência de uma tabela.
Dependências já existentes: PostgreSQL/JSONB, `users`, entidades `organizations`, `opportunities`, `projects`, `sectors`, `geo_locations`, biblioteca `portal_resources`/`documents` e relações documentais, `audit_events`, autenticação/verificação/MFA e autorização documental/editorial conforme a conta. A FK de instalação depende directamente de `users`; as restantes tabelas são dependências de execução do cadastro, prévia, consulta ou publicação. Manter os originais no armazenamento persistente privado e o scanner/fila da biblioteca operacionais; a publicação de anexos exige o scan e os direitos já aprovados. Sem nova dependência Composer/NPM ou serviço externo. `composer.lock` e `package-lock.json` não mudam. As provas locais de `ProcurementTest` usam a base QA nominal e ClamAV real; não adicionar esse teste ao CI remoto sem adaptar a sua guarda de ambiente e disponibilidade do scanner. O pipeline conserva a sua suite isolada existente; não se repete a bateria QA aceite.
**Sequência proposta, com pontos de paragem verificáveis:**
1. **Revisão e identificação.** Rever `1bcf34c0` e este plano. Confirmar SHA integral da fonte, revisão/release actualmente servida, configuração real do pipeline, contrato actual, ligação à base e estado da migration. Conferir as contas reais já existentes contra `DocumentManagementAccess`/`Procurement::access`: gestão completa ou designação editorial existente, email verificado e requisitos MFA aplicáveis; auditor e conta simples sem escrita. Não inferir acesso por nome do papel nem criar designações. Se uma conta ainda não existe, registar só essa pendência e continuar com as já autorizadas.
2. **Coordenar a janela antes do merge.** Pausar o observador `teste-investidor-deploy.path` e impedir novo processamento durante a operação; aguardar o serviço em curso e coordenar com `delivery.lock`. Preservar os pedidos em fila e reconciliar qualquer integração concorrente antes de retomar. Não parar à força um build nem manipular a release servida. Confirmar `PROCUREMENT_ENABLED=false` na configuração efectiva; não colocar esta variável no ficheiro de flags CI, cujo validador só aceita prefixos `PORTAL_`/`INVESTMOZ_`.
3. **Backup recuperável.** Guardar dump consistente da base de destino, cópia/snapshot do armazenamento persistente privado e público e manifesto de hashes, revisão/release anterior, contrato, configuração e recibos. Configuração e segredos ficam em local privado. Ensaiar o restauro desse backup numa instância isolada, sem substituir a base activa nem publicar ficheiros; conferir integridade, tabelas e amostra de binários. A prova de restauro antiga não substitui o backup desta janela. Registar hora/identidade da base e preservar os recibos.
4. **Instalar schema sem activar.** Preparar a fonte exacta revista fora da árvore servida, sem fixtures QA, com dependências do lock e ligação autenticada ao destino conferida. Pela sessão técnica autenticada e com os privilégios de instalação existentes, executar **apenas** `php artisan migrate --path=database/migrations/2026_10_22_230000_create_portal_tenders.php --force` nessa fonte/configuração. Não executar `migrate` global, `migrate:fresh`, seeders ou scripts de demonstração. Se a migration já estiver aplicada, conferir o schema e não duplicar a instalação; tabelas parciais ou divergentes exigem reconciliação concreta, não DROP/recriação. Confirmar registo da migration e as três tabelas vazias, incluindo versões e acompanhamento. A release antiga continua compatível com estas tabelas adicionais.
5. **Actualizar o contrato de migrations.** Guardar o contrato anterior e acrescentar exclusivamente o caminho/hash normalizado desta migration, após a instalação conferida. Comparar o contrato completo com a fonte revista: qualquer outra diferença deve ser explicada antes de prosseguir. Não regenerar/aprovar cegamente um contrato para o HEAD mais recente. Este passo é uma operação técnica explícita e não corre automaticamente por Git.
6. **Integrar e transportar código, ainda desligado.** Integrar pelo processo Git após a revisão, identificar o SHA resultante em `main` e retomar o pipeline/pedidos preservados. Conferir que o contrato corresponde exactamente à fonte resultante; só então o build pode passar. Usar o build isolado e a promoção atómica existentes, sem editar ficheiros da release servida. Confirmar recibo, `/build/revision.json`, página inicial, biblioteca e gestão única. O módulo permanece desligado e as tabelas vazias; a existência do código não constitui activação.
7. **Activar separadamente.** Com código/schema compatíveis conferidos, definir `PROCUREMENT_ENABLED=true` na configuração persistente do destino por acção técnica autenticada. Actualizar a cache efectiva de configuração e recarregar processos persistentes conforme a configuração instalada. O pipeline versionado não faz `config:cache` para a configuração real: não presumir que editar `.env` basta quando houver cache. Se se gerarem caches dentro de uma release sujeita a `tree_hashes`, reconciliar os hashes pelo mecanismo de entrega antes de novo deploy/rollback, sem mascarar outras diferenças. Não executar testes com `RefreshDatabase` no destino.
8. **Conferir só o delta no destino.** Aplicar a lista abaixo, registar revisão, URLs, resultados e actor autenticado sem credenciais. Entregar o link único `https://teste-investidor.tempo.co.mz/gestao-conteudos` e o guia desta secção com os links QA substituídos pelos correspondentes do destino. Não declarar disponibilização enquanto esta passagem não estiver concluída.
**Verificação no destino sem publicar anúncios reais como efeito da instalação:**
- Sem sessão: `/concursos` responde 200, incluindo catálogo vazio quando não houver anúncios; navegação pública mostra a secção; não surge autenticação HTTP adicional. UUID de rascunho/inexistente não permite obter ficha ou relatório públicos; anexos privados continuam inacessíveis.
- Com conta real já autorizada: gestão única mostra **Novo concurso/anúncio** e **Gerir concursos e anúncios**; abrir formulário, guardar um rascunho de verificação claramente identificado, recuperar e pré-visualizar, sem publicar. Registar ID e preservar o rascunho/histórico; não o converter num anúncio real. Conferir scanner/biblioteca existentes por diagnóstico e estado, reutilizando as provas de upload aceites.
- Conta simples: pode abrir a consulta e área de acompanhamento, mas recebe recusa na escrita/gestão; auditor não recebe escrita. Utilizador sem sessão é encaminhado para autenticação nas rotas de gestão. Não alargar grants para passar a prova.
- Se já houver anúncio autorizado no destino, consultar sem sessão ficha, relatório, anexo autorizado e filtros/retorno. Se não houver, a consulta positiva de conteúdo publicado mantém a prova QA aceite e o catálogo vazio é o resultado esperado no destino; não importar exemplos nem publicar um anúncio só para preencher o catálogo. Prorrogação/publicação/resultado já estão cobertos em QA e não são repetidos sobre anúncios reais durante a instalação.
- Conferir que instalação/activação não criou qualquer versão com `published_at` preenchido, não mudou `published_version_id` de anúncios existentes e não alterou documentos/grants. Anúncios que a equipa publicar posteriormente são acções distintas, identificadas pela auditoria.
**Reversão com preservação.** Em falha de instalação antes do merge, manter flag desligada e release antiga; conservar tabelas eventualmente criadas até diagnosticar a falha e repor o contrato anterior se necessário. Em falha após disponibilização, desligar primeiro a flag na configuração efectiva e preservar um novo snapshot/dump dos dados e ficheiros actuais. Preferir correcção progressiva. Se for preciso reverter código, usar o rollback atómico existente do pipeline para a release anterior compatível, com recibo e configuração desligada; conservar as três tabelas, `migrations`, `audit_events`, subscrições e armazenamento partilhado. Esse rollback de código não restaura a base. Conservar o contrato compatível com a linha de código que voltará a ser entregue e documentar qualquer reposição do ficheiro de contrato; a verificação por hashes continua obrigatória.
Não executar `down`, `migrate:rollback` global nem restaurar por cima da base activa o backup anterior à instalação: isso eliminaria anúncios, actos, acompanhamentos, auditoria e ficheiros criados depois. O `down()` da candidata recusa a remoção quando há concursos, mas essa guarda não substitui o plano de preservação. Um restauro extraordinário exige primeiro recuperar numa instância separada e reconciliar os dados posteriores, conservando IDs, versões, relações, hashes e originais; só trocar o destino com um plano próprio revisto. Desligar o módulo torna-o temporariamente indisponível, não elimina nem retira selectivamente anúncios. Ao reactivar a release corrigida, recuperar e conferir os dados existentes.
Origem dos limites: QA/revisão antes de integração e ausência de publicação real na instalação são decisões expressas da Tempo; backup/restauro e autenticação de alterações no destino são requisitos permanentes existentes; pausa coordenada, schema antes de código, flag e contrato são escolhas técnicas impostas pela compatibilidade observada do pipeline. Não constituem nova cadeia organizacional de aprovação. Depois da instalação, as operações correntes de cadastro, prévia, publicação, prorrogação e actualização permanecem na gestão única, sem comandos ou Codex por concurso. As únicas intervenções técnicas deste plano são a instalação/activação e eventual recuperação da plataforma.
### Instalação concluída na homologação — 22/10/2026
Autorização expressa da Tempo nesta conversa: **«pode instalar»**, abrangendo a candidata `1bcf34c0` e o procedimento `e46f9731`. A instalação foi executada por SSH autenticado já disponível; a verificação da interface foi feita pela conta real Osmane Nala, ID 15, após renovação de login/MFA pelo utilizador. Não houve criação de contas, papéis ou aprovadores. A ausência de outras contas não bloqueou esta autorização existente. O guia continua sem declaração de conferência/aceitação pela Tempo.
Sequência efectivamente concluída: pausa coordenada do observador de deploy → backup → restauro isolado conferido → migration selectiva com flag desligada → conferência do schema e contrato → integração/push Git → build/promoção automática → activação separada. Integração funcional `f4d0970917e7e8d141f74c136b66138b929141fc`, confirmada em `/build/revision.json`. Activação às **22h51 de 22/10/2026 (África/Johannesburgo; 20h51 UTC)**. Os commits documentais posteriores conservam o mesmo código funcional. O pipeline está novamente activo e conserva o gate do contrato de migrations; não foi alterado para executar SQL de produção.
Backup privado no servidor: `/var/backups/investmoz-procurement-20261022/backup`. Dump SHA-256 `69de817b288ecb25db4b341375475f2408a47642a8ba69d338b217dcc982854f`; arquivo de ficheiros/configuração `7b75c22e730b5600d6e97e1c6dbb4cd93982bdd47e9dd2a63de2359974132674`. Restauro realizado num PostgreSQL isolado em container sem rede, porta interna 55441: **171 tabelas**, contagens e checksums iguais ao snapshot exportado. Arquivo conferido: **341 ficheiros**, incluindo configuração privada; preservados os **340 ficheiros de conteúdo** no destino. Não foi copiada uma base QA para a homologação.
Schema instalado: **três tabelas, 21 colunas, três PK, cinco FK e um UNIQUE**, correspondentes à migration revista; registo em `migrations` conferido. A conferência inicial do executor tinha uma contagem de colunas incorrecta (22); foi corrigida para as 21 efectivamente declaradas e conferidas antes de actualizar o contrato, sem repetir ou desfazer a migration. Não se alteraram grants. Comparação dos dados preexistentes antes da prova de rascunho: apenas `migrations`, `cache` e `sessions` diferiam do backup; utilizadores, atribuições, biblioteca, oportunidades, cadastro territorial e geometrias permaneciam iguais por checksum. Scanner ClamAV real disponível, assinaturas de 22/10/2026.
Conferência do delta no destino:
- `/concursos` responde 200 sem sessão ou autenticação HTTP adicional; catálogo vazio é esperado, porque não foram publicados anúncios. Gestão sem sessão redirecciona para login. Conta simples existente não tem autorização de escrita; recusas por perfil e operações editoriais conservam as provas QA aceites, sem criar uma conta de teste no destino.
- Gestão única da conta real apresenta **Novo concurso/anúncio**. Rascunho `b970f0f0-9257-42e1-8365-3358237b55db`, referência `INSTALL-CHECK-20261022`, claramente identificado como **VERIFICAÇÃO DE INSTALAÇÃO — NÃO PUBLICAR**: guardado, recuperado pela lista e pré-visualizado na interface. Um acto de preparação auditado (`tender_draft_saved`, actor 15). Preservado como rascunho privado; não é um concurso real.
- Ficha e impressão desse rascunho devolvem 404 sem sessão; download de documento privado devolve 404. Não se alterou a disponibilidade dos documentos existentes. **Uma preparação, uma versão de rascunho, zero versões publicadas e zero acompanhamentos.** Nenhum anúncio real foi publicado pela instalação ou como prova. Não foram transportados exemplos QA.
- Publicação/prorrogação/resultados/cancelamento positivos conservam os 8 testes/285 asserções e a passagem visual QA aceites; não foram repetidos sobre anúncios reais na homologação. O build de entrega executou as suas verificações isoladas normais.
Recibo resumido versionado: [procurement-installation-receipt-20261022.json](procurement-installation-receipt-20261022.json). Recibos técnicos completos, logs e backups permanecem privados; capturas e recibo local em `outputs/procurement-install-20261022/`. A reversão continua a ser desligar a flag e, se necessário, reverter código compatível mantendo tabelas, versões, auditoria e armazenamento; não substituir dados novos pelo backup anterior.
**Links finais e guia de operação:** entrar na [gestão única](https://teste-investidor.tempo.co.mz/gestao-conteudos) → **Novo concurso/anúncio** → preencher regime/edição, entidade, objecto, calendário/fuso e canal → **Guardar rascunho**. Recuperar em **Gerir concursos e anúncios → Recuperar e editar**. Carregar/editar originais pela biblioteca ligada no formulário, acompanhar o scan e autorizar a divulgação dos anexos; voltar ao editor e actualizar as opções. **Preparar prévia pública** → rever conteúdo e motivo público → **Publicar este acto**, quando a equipa pretender publicar um anúncio autorizado. Para actualizar ou prorrogar, guardar a revisão e escolher o acto correspondente; a prorrogação mostra prazo anterior e novo. Resultado ou cancelamento seguem o mesmo percurso. O rascunho de instalação não se destina a publicação.
Consulta: [Concursos e anúncios](https://teste-investidor.tempo.co.mz/concursos). Abrir ficha para documentos e relatório imprimível; uma conta simples pode acompanhar, sem apresentar proposta. Documentos, oportunidades, divulgação promocional e concursos mantêm as distinções do guia anterior. **Não restam comandos ou intervenção do Codex para cada concurso** neste âmbito; a instalação e activação técnica estão concluídas. Geometrias e permissões foram preservadas.
### Legado — correspondência integral e avanço privado QA, 22/10/2026
Fonte do saldo: conferência documental fornecida pela Tempo e [InvesteMoz — entregas, Fintech e classificação](https://chatgpt.com/space/page_d6f090dba9048191a92c9175b3605dee), consultada nesta passagem; originais e reconciliação de 15/10 preservados. O CSV antigo ainda tinha 17 publicados/31 por integrar. Reconciliados os três artigos posteriores, sem os duplicar: **20 publicados, 28 por integrar na homologação, um vazio e um sem título = 50 identidades**. Os 29 recursos da biblioteca e as onze variantes de URL não são contagens de artigos distintos.
Lista única para a Tempo: [título original → endereço original → endereço no novo portal → estado → pendência](../v2/auditoria-portal/legado-correspondencia-integral.md). Actualizado também o [CSV existente dos 50 artigos](../v2/auditoria-portal/legado-conteudos-reconciliados.csv); mantém IDs, títulos, origens, hashes e referências anteriores, com campos explícitos para o estado consolidado e data da conferência. Não se criou nova matriz/backlog. Endereços novos ausentes ficam em branco; não foram fabricadas páginas para os conteúdos ainda não disponibilizados.
**Nova conferência pública, não nova aceitação funcional:** 20/20 páginas na homologação responderam sem login, com componente `portal/legacy`, ID legado, origem e corpo não vazio correspondentes. A identidade não foi deduzida apenas de HTTP 200 nem do título. IDs da biblioteca foram obtidos da resposta real do destino, sem transportar IDs QA. Consulta HTTP em 22/10/2026 às 23h05 (21h05 UTC). Não é revisão visual integral de cada artigo nem confirmação de actualidade de todas as afirmações. Imagens anteriores não foram reimportadas ou reanalisadas; as referências públicas das fichas foram registadas, sem repetir as provas aceites dos binários.
**Cartões educativos:** a branch `codex/educational-content-cards` já é ancestral de `main`, e o componente com imagem maior/resumo/«Ler o guia» está servido. Conferência visual no destino [Explorar Turismo](https://teste-investidor.tempo.co.mz/explorar/turismo): 12 cartões/links «Ler o guia». Corrige a indicação histórica de revisão ainda pendente, sem atribuir à Tempo uma conferência que não fez. Captura `outputs/legacy-correspondence-20261022/guides-homologation.png`.
**28 conteúdos avançados em QA, sem publicar:** dois sectoriais, oito de Trabalho Doméstico e 18 históricos/noticiosos. Preservado o corpo HTML de cada captura, hash do corpo, ID, autor, categoria, datas e origem. Derivadas JSON identificadas pelo formato existente, armazenadas privadamente; imagens não resolvidas não foram substituídas por um fundo genérico nem marcadas como disponíveis. O mecanismo existente `documents:import-batch` foi reutilizado exclusivamente em `simulator_fiscal_delta_20261021_test`, porta 55441, com guarda da identidade real. Não foi alargado o importador activo ou o seu âmbito nominal. Conta sintética QA já existente 239; sem novo grant persistente. **28 rascunhos internos, 28 scans reais limpos e 28 reutilizações por SHA-256 na repetição**, sem duplicações; publicações e atribuições preservadas.
A primeira passagem importou dez e detectou colisões de identidade nos restantes: o manifesto usava emissor/data/versão iguais para artigos distintos. Corrigida a versão documental dos itens restantes para incluir o ID original do artigo; os dez já criados foram reutilizados por bytes. Sem apagar/recriar originais, simular scan ou classificar artigos como diplomas oficiais. Esta era uma escolha de metadados da preparação, não uma decisão organizacional da Tempo nem uma razão para impedir o cadastro. O importador não foi alterado e os títulos originais foram preservados. Preparações, manifesto, logs e recibo completos mantidos em caminhos privados QA; o recibo versionado contém somente metadados de rastreabilidade.
**Lacunas originais conferidas na rede:** [Mercado Financeiro, ID 171994](https://investemoz.tempo.co.mz/mercado-financeiro), HTTP 200, corpo vazio, hash igual à captura. [Post 74364](https://investemoz.tempo.co.mz/74364-2), HTTP 200, título vazio, mesmo corpo capturado (274 caracteres HTML, 21 úteis no inventário). Não se encontrou conteúdo/título novo a recuperar. A resolução editorial destes dois exemplares depende do texto/título da Tempo; não se inventou um título nem se usou Fintech/imagem para preencher o artigo vazio. Não bloqueiam os outros 48.
**Saldo de integração conservado:** os 28 rascunhos QA ainda exigem fechar edição/leitor e entrega/publicação por lotes na homologação. Trabalho Doméstico e notícias mantêm âmbito/data históricos; não foram convertidos em orientação jurídica actual, regras executáveis ou oportunidades vigentes. As dependências de 15/10 estão identificadas como históricas, não como novos requisitos de validação. Nenhum conteúdo novo foi publicado no destino, não houve alteração de schema, mapas, permissões ou integração em `main` nesta passagem. A integração integral continua aberta; não confundir preparação privada QA com publicação dos 28.
Evidência consolidada: [recibo de correspondência, consulta e importação QA](../v2/auditoria-portal/legado-correspondencia-recibo-20261022.json). Ferramenta `tools/legacy-correspondence-audit.py`; `--reuse-http` regenera a lista sem repetir as consultas públicas. Os hashes das capturas/respostas são distintos dos hashes dos corpos/originais; não foram usados para alegar uma nova edição editorial.
### Legado — edição e leitura dos 28 rascunhos em QA, 22/10/2026
Actualiza o saldo anterior: **20 públicos já conferidos, 28 rascunhos privados com editor/leitor disponíveis em QA e dois originais incompletos**. Não houve nova importação, repetição da conferência dos 20, integração em `main`, transporte ou publicação na homologação nesta passagem. A Tempo não declarou ter conferido o guia local ou esta candidata.
**Guia curto da equipa.** Em [gestão única QA](http://127.0.0.1:18580/gestao-conteudos), abrir o acervo e localizar o título. **Editar artigo** recupera o corpo do original, a origem e as datas; corrigir o texto e escolher conservar a imagem de origem, seleccionar uma imagem pública verificada da biblioteca ou não mostrar imagem. **Pré-visualizar** mostra as alterações ainda sem guardar e não publica. **Guardar edição** cria uma revisão, preserva o original e retira eventual publicação até nova decisão expressa. **Ler revisão guardada** recupera a edição persistida. Metadados, classificação/direitos, histórico e publicação continuam no acervo ligado pelo editor; **Publicar** é uma acção distinta, sujeita às permissões e campos já existentes. Para actualizar um artigo publicado, guardar a revisão, rever a prévia e publicar novamente. A consulta pública usa `/artigos/{id-do-destino}` e o acesso pela biblioteca; rascunhos não ficam acessíveis por esse endereço.
O leitor mantém a estrutura HTML sanitizada do original enquanto o corpo não for alterado; uma correcção textual fica como edição separada, sem reescrever o ficheiro capturado. Datas e autor de origem continuam identificados. Conteúdos históricos não se tornam oportunidades actuais, diplomas oficiais ou regras de cálculo. A revisão QA do artigo 62413 contém uma nota de demonstração explicitamente marcada **QA**, guardada pela interface: deve ser revista/corrigida antes de publicação real; não foi removida silenciosamente do pacote.
**Imagens e lacunas.** Preservadas as 16 referências a imagens no corpo e a referência de capa dos 28 originais. Não se descarregam automaticamente imagens externas. Nesta QA não há exemplar público verificado da capa comum: a prévia informa a ausência e conserva a referência. A capa já aceite no destino deve ser reutilizada pelo SHA-256 `28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa`, sem confundir igualdade de URL com igualdade de bytes. Pode seleccionar-se outra imagem autorizada pela interface; nenhuma imagem foi marcada como disponível sem binário verificado. Os dois casos incompletos na origem ficam fora deste lote.
**Permissões e origem das restrições.** Reutilizados os gestores e as designações editoriais existentes, email verificado, MFA aplicável e exclusão de escrita para auditor/conta simples. Nenhum papel ou aprovador novo. A inclusão destes 28 originais no âmbito editorial decorre do pedido expresso da Tempo. A correspondência por hash exacto dos originais é uma escolha técnica: não depende de IDs ou etiquetas de importação QA que mudem no destino. Validação dos bytes, scan e classificação/direitos seguem requisitos anteriores; controlo de versão e prévia privada são escolhas técnicas para evitar sobreposição de edições e publicação acidental.
**Evidência delimitada.** Seis testes específicos, **1.000 asserções**, passaram na base isolada `simulator_fiscal_delta_20261021_test:55441`, com transacções revertidas. Percorrem os 28 editores/prévias, edição/recuperação/histórico, conflito de versão, publicação explícita e retirada, classificação, imagem verificada/retirada, sanitização e permissões nominais/MFA. A prova de publicação dos testes foi revertida; os 28 continuam privados. TypeScript e build QA passaram. Na interface, conta sintética QA existente guardou/recuperou a revisão 2 do artigo 62413; leituras de Alumínio “Verde” e do guia de Trabalho Doméstico demonstradas. Não houve alteração de contas reais. Capturas e logs em `outputs/legacy-editorial-20261022/`; [recibo resumido](../v2/auditoria-portal/legado-editorial-qa-20261022.json).
**Preparação concreta da entrega privada.** `outputs/legacy-editorial-20261022/legacy-editorial-private-v2.zip`, 85 614 bytes, **57 entradas**: 28 originais, 28 snapshots/históricos de proveniência e manifesto. SHA-256 `177c50d1cc3b1610e62123a2f8b532711a15f875aac2ee0e372636c2f747e8a2`. Conferidos os 28 hashes e a integridade do ZIP; zero imagens binárias incluídas e zero escritas de base pelo exportador. Manifesto com `publish=false`, edições actuais e vínculos de imagem por hash; sem credenciais ou cópia da base. `tools/prepare-legacy-editorial-delivery.php` só exporta a QA nominal, não instala/importa no destino. Originais e histórico completo ficam privados; IDs/actores QA são proveniência, não identidades ou autores de auditoria no destino.
**Sequência para homologação, ainda não executada:**
1. Rever e integrar a candidata pelo processo Git existente. Não há migration, alteração de schema ou nova dependência de pacote; o deploy de código não transporta estes conteúdos nem publica artigos.
2. Antes de escrever no destino, conferir revisão servida, identidade da base e backup consistente de base/armazenamento com restauro isolado demonstrado para a janela. Transportar o ZIP para armazenamento privado, fora da árvore pública, e conferir o hash. Preservar o recibo e o manifesto.
3. Com autenticação e permissões existentes, usar o cadastro/upload da biblioteca para cada original ainda ausente, com scan real e classificação privada. Resolver por hash e identidade/versão: reutilizar originais iguais, registar IDs reais e parar apenas o item com conflito, sem sobrescrever. Não repetir a importação QA nem copiar a sua base. Não usar os importadores nominais de Agronegócio/lotes antigos ou um `--actor` para contornar os limites activos; o exportador não alarga esses executores.
4. Recuperar os recursos pelo portal; aplicar metadados/edição actual pelos formulários autenticados, usando a versão do destino e criando histórico atribuído ao actor real. Conservar os snapshots QA privadamente como proveniência, sem inserir actores QA na auditoria activa. Reutilizar a capa aceite por hash; referências sem binário mantêm aviso. Conferir **28 privados, zero publicações**, correspondência original → recurso real e hash, revisão guardada e acessos previstos. Actualizar a lista única com os endereços efectivamente demonstrados.
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.
Link único e guia curto encontram-se no início deste manual: https://teste-investidor.tempo.co.mz/gestao-conteudos. Recibo e imagem da conferência: outputs/content-management-delivery-20261022/. Registo documental mantido na branch QA, sem novo push main/desencadeamento de instalação apenas para o recibo.
@@ -1,51 +1,51 @@
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
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
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
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
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
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,
172258,"Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento",tempo,Turismo,2026-04-14T14:18:28+00:00,2026-04-17T10:42:16+00:00,4c8bdd79212ba98fa347733e2f58aef8796b29cc8cb8b649d200bd37435df1c3,https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento/ | https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento,14,publicado,RecursoQA14; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,20,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-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento,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,
172237,"Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável",tempo,Turismo,2026-04-14T10:55:21+00:00,2026-04-17T08:27:24+00:00,d112d0e535912f4487c2b8d41978e5e663f1db43f1a2cdf170dbbec535f13f27,https://investemoz.tempo.co.mz/provincia-de-maputo-turismo/ | https://investemoz.tempo.co.mz/provincia-de-maputo-turismo,17,publicado,RecursoQA17; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,22,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-maputo-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,
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
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
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
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
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
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,5,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 6, ""sha256"": ""5e3840705cf98226d1f189cf665aaa98cb05da96c645159a1332a1d429d642eb""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/817802064_1_644x461_15-30-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo-maputo.jpg | Referência não recolhida: https://www.olx.co.mz/imoveis-casas/terrenos/terrenos-venda/maputo-maputo/?search%5Bprivate_business%5D=private | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,setorial,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Ausente da biblioteca ativa e QA; falta exemplar versionado no manifesto de um novo lote e extensão nominal do importador. | Slug ausente no mapa do leitor; falta ligação ao percurso/dossier fundamentada para este artigo. | Não há setor mestre Alumínio Verde com correspondência exata; fundamentar o agrupamento sem inventar vínculo a projeto ou criar setor automaticamente.,Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/economia/38-economia/45893-banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Banco-Mundial-classifica-de-proibitivos-juros-praticados-em-Mo%C3%A7ambique.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1460805843956666 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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 no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados",inventariado; cadastro/versão por reconciliar,29,publicado,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz.,"Preservar publicação; restante acervo separado, sem repetir aceitação.",outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json
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.,20,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: https://www.facebook.com/photo.php?fbid=741844132690980&set=gm.1566816196708735&type=3 | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Coloque-o-seu-n%C3%BAmero-para-o-grupo-de-whatsapp-venda-de-acess%C3%B3rios-de-computador.jpg | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/1502293415_298_Coloque-o-seu-n%C3%BAmero-para-o-grupo-de-whatsapp-venda-de-acess%C3%B3rios-de-computador.jpg | Referência não recolhida: https://www.facebook.com/179463555444013/posts/1566816196708735 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,7,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 23, ""sha256"": ""0a2c50d91dad3a6007544634540e0f61b11d3506682a5a19066bae03cdcba490""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,setorial,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Ausente da biblioteca ativa e QA; falta exemplar versionado no manifesto de um novo lote e extensão nominal do importador. | Slug ausente no mapa do leitor; falta ligação ao percurso/dossier fundamentada para este artigo. | Texto distinto de Energia/Mineração já publicado; preservar a ligação declarada /energia-mineracao e delimitar agrupamento, sem fundir os exemplares.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência indisponível na captura (HTTP 404): https://investemoz.tempo.co.mz/images/ANO-2017/JUNHO/21/GOVERNADOR-in.gif | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/a84c6c1e4d1780f63086a86817521b40 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45963-governo-pretende-construir-100-mil-habitacoes-em-dois-anos.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Governo-pretende-construir-100-mil-habita%C3%A7%C3%B5es-em-dois-anos.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1464602060243711 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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 no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados",inventariado; cadastro/versão por reconciliar,28,publicado,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz.,"Preservar publicação; restante acervo separado, sem repetir aceitação.",outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json
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.,22,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 26, ""sha256"": ""8e58544e49e719f9c865c91e07ef1030155a9e3d59260e6dc93e9c9e25674e39""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,16,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,21,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,11,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,18,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,15,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
172258,"Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento",tempo,Turismo,2026-04-14T14:18:28+00:00,2026-04-17T10:42:16+00:00,4c8bdd79212ba98fa347733e2f58aef8796b29cc8cb8b649d200bd37435df1c3,https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento/ | https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento,14,publicado,RecursoQA14; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,14,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
172237,"Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável",tempo,Turismo,2026-04-14T10:55:21+00:00,2026-04-17T08:27:24+00:00,d112d0e535912f4487c2b8d41978e5e663f1db43f1a2cdf170dbbec535f13f27,https://investemoz.tempo.co.mz/provincia-de-maputo-turismo/ | https://investemoz.tempo.co.mz/provincia-de-maputo-turismo,17,publicado,RecursoQA17; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,17,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,19,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,12,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,13,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45870-rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Rofino-Licuco-preso-cinco-meses-depois-de-condenado-por-agress%C3%A3o.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1458270617543522 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/46074-sete-individuos-mortos-a-tiro-na-matola-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Sete-indiv%C3%ADduos-mortos-a-tiro-na-Matola.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1471269102910340 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.verdade.co.mz/internacional/62604-sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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 no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados",inventariado; cadastro/versão por reconciliar,27,publicado,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz.,"Preservar publicação; restante acervo separado, sem repetir aceitação.",outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json
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.,10,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 25, ""sha256"": ""fe9a2e382e385b35f6e61ae320e199a979678677fd327fb7d4b07d8ce0111c11""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/desporto/74-desporto/45358-daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Da%C3%BAde-Razaque-j%C3%A1-n%C3%A3o-%C3%A9-treinador-da-Liga-Desportiva-de-Maputo.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1425759480794636 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/politica/63-politica/45340-daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Daviz-Simango-n%C3%A3o-se-incomoda-com-poss%C3%ADvel-sucess%C3%A3o-na-Beira.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1424683617568889 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,8,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/politica/63-politica/45345-exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/%E2%80%9CExigimos-responsabiliza%C3%A7%C3%A3o-dos-agentes-do-crime%E2%80%9D-Daviz-Simango.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1424873994216518 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45352-governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Governo-e-parceiros-refor%C3%A7am-mecanismos-de-controlo-de-HIVSida.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1425451974158720 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45368-graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Gra%C3%A7a-Machel-diz-que-desnutri%C3%A7%C3%A3o-%C3%A9-um-problema-de-desenvolvimento.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1426040144099903 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/opiniao/182-helder-faife/45364-in-dependencia.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/In-depend%C3%AAncia.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1426022220768362 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.verdade.co.mz/tema-de-fundo/35/62615 | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Kroll-n%C3%A3o-descobriu-como-foram-gastos-2-bili%C3%B5es-de-d%C3%B3lares-Governo-de-Nyusi-n%C3%A3o-apoiou-a-Auditoria-cria%C3%A7%C3%A3o-da-Proindicus-EMATUM-e-MAM-n%C3%A3o-foi-para-prote%C3%A7%C3%A3o-da-Zona-Econ%C3%B3mica-Exclusiva.jpg | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1492451004109920 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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.,9,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.verdade.co.mz/newsflash/62607 | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1491493337539020 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.verdade.co.mz/newsflash/62625 | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1493133914041629 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
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 5 publicados {"scope": "homologação", "href": "/documentos/12/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 6, "sha256": "5e3840705cf98226d1f189cf665aaa98cb05da96c645159a1332a1d429d642eb"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 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. Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/817802064_1_644x461_15-30-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo-maputo.jpg | Referência não recolhida: https://www.olx.co.mz/imoveis-casas/terrenos/terrenos-venda/maputo-maputo/?search%5Bprivate_business%5D=private | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Ausente da biblioteca ativa e QA; falta exemplar versionado no manifesto de um novo lote e extensão nominal do importador. | Slug ausente no mapa do leitor; falta ligação ao percurso/dossier fundamentada para este artigo. | Não há setor mestre Alumínio Verde com correspondência exata; fundamentar o agrupamento sem inventar vínculo a projeto ou criar setor automaticamente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://opais.sapo.mz/index.php/economia/38-economia/45893-banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Banco-Mundial-classifica-de-proibitivos-juros-praticados-em-Mo%C3%A7ambique.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1460805843956666 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 Publicado no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados inventariado; cadastro/versão por reconciliar 29 publicados publicado {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz. Preservar a publicação; gerir edições e versões pela biblioteca existente. Preservar publicação; restante acervo separado, sem repetir aceitação. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json 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 20 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 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. Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: https://www.facebook.com/photo.php?fbid=741844132690980&set=gm.1566816196708735&type=3 | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Coloque-o-seu-n%C3%BAmero-para-o-grupo-de-whatsapp-venda-de-acess%C3%B3rios-de-computador.jpg | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/1502293415_298_Coloque-o-seu-n%C3%BAmero-para-o-grupo-de-whatsapp-venda-de-acess%C3%B3rios-de-computador.jpg | Referência não recolhida: https://www.facebook.com/179463555444013/posts/1566816196708735 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 7 publicados {"scope": "homologação", "href": "/documentos/14/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 23, "sha256": "0a2c50d91dad3a6007544634540e0f61b11d3506682a5a19066bae03cdcba490"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 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. Ausente da biblioteca ativa e QA; falta exemplar versionado no manifesto de um novo lote e extensão nominal do importador. | Slug ausente no mapa do leitor; falta ligação ao percurso/dossier fundamentada para este artigo. | Texto distinto de Energia/Mineração já publicado; preservar a ligação declarada /energia-mineracao e delimitar agrupamento, sem fundir os exemplares. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência indisponível na captura (HTTP 404): https://investemoz.tempo.co.mz/images/ANO-2017/JUNHO/21/GOVERNADOR-in.gif | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/a84c6c1e4d1780f63086a86817521b40 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45963-governo-pretende-construir-100-mil-habitacoes-em-dois-anos.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Governo-pretende-construir-100-mil-habita%C3%A7%C3%B5es-em-dois-anos.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1464602060243711 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 Publicado no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados inventariado; cadastro/versão por reconciliar 7 28 publicados publicado {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz. Preservar a publicação; gerir edições e versões pela biblioteca existente. Preservar publicação; restante acervo separado, sem repetir aceitação. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json 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 22 publicados {"scope": "homologação", "href": "/documentos/16/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 26, "sha256": "8e58544e49e719f9c865c91e07ef1030155a9e3d59260e6dc93e9c9e25674e39"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 16 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 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. Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 21 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 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. Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 11 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 18 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 15 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
27 172258 Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento tempo Turismo 2026-04-14T14:18:28+00:00 2026-04-17T10:42:16+00:00 4c8bdd79212ba98fa347733e2f58aef8796b29cc8cb8b649d200bd37435df1c3 https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento/ | https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento 14 publicado RecursoQA14; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 20 14 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) https://teste-investidor.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento 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
28 172237 Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável tempo Turismo 2026-04-14T10:55:21+00:00 2026-04-17T08:27:24+00:00 d112d0e535912f4487c2b8d41978e5e663f1db43f1a2cdf170dbbec535f13f27 https://investemoz.tempo.co.mz/provincia-de-maputo-turismo/ | https://investemoz.tempo.co.mz/provincia-de-maputo-turismo 17 publicado RecursoQA17; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria. 22 17 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) https://teste-investidor.tempo.co.mz/provincia-de-maputo-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
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 19 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 12 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 13 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 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. Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45870-rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Rofino-Licuco-preso-cinco-meses-depois-de-condenado-por-agress%C3%A3o.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1458270617543522 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/46074-sete-individuos-mortos-a-tiro-na-matola-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Sete-indiv%C3%ADduos-mortos-a-tiro-na-Matola.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1471269102910340 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://www.verdade.co.mz/internacional/62604-sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 Publicado no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados inventariado; cadastro/versão por reconciliar 28 27 publicados publicado {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente. Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz. Preservar a publicação; gerir edições e versões pela biblioteca existente. Preservar publicação; restante acervo separado, sem repetir aceitação. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json 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 10 publicados {"scope": "homologação", "href": "/documentos/15/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 25, "sha256": "fe9a2e382e385b35f6e61ae320e199a979678677fd327fb7d4b07d8ce0111c11"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 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. Referência não recolhida: http://opais.sapo.mz/index.php/desporto/74-desporto/45358-daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Da%C3%BAde-Razaque-j%C3%A1-n%C3%A3o-%C3%A9-treinador-da-Liga-Desportiva-de-Maputo.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1425759480794636 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://opais.sapo.mz/index.php/politica/63-politica/45340-daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Daviz-Simango-n%C3%A3o-se-incomoda-com-poss%C3%ADvel-sucess%C3%A3o-na-Beira.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1424683617568889 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 8 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 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. Referência não recolhida: http://opais.sapo.mz/index.php/politica/63-politica/45345-exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/%E2%80%9CExigimos-responsabiliza%C3%A7%C3%A3o-dos-agentes-do-crime%E2%80%9D-Daviz-Simango.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1424873994216518 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45352-governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Governo-e-parceiros-refor%C3%A7am-mecanismos-de-controlo-de-HIVSida.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1425451974158720 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45368-graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Gra%C3%A7a-Machel-diz-que-desnutri%C3%A7%C3%A3o-%C3%A9-um-problema-de-desenvolvimento.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1426040144099903 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://opais.sapo.mz/index.php/opiniao/182-helder-faife/45364-in-dependencia.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/In-depend%C3%AAncia.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1426022220768362 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://www.verdade.co.mz/tema-de-fundo/35/62615 | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Kroll-n%C3%A3o-descobriu-como-foram-gastos-2-bili%C3%B5es-de-d%C3%B3lares-Governo-de-Nyusi-n%C3%A3o-apoiou-a-Auditoria-cria%C3%A7%C3%A3o-da-Proindicus-EMATUM-e-MAM-n%C3%A3o-foi-para-prote%C3%A7%C3%A3o-da-Zona-Econ%C3%B3mica-Exclusiva.jpg | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1492451004109920 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 9 publicados {"scope": "homologação", "href": "/documentos/27/view", "status": "referência na ficha; binário não reensaiado"} {"status": "imagem já publicada; reutilizar", "resource_id": 24, "sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"} 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. Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente. outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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 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. Referência não recolhida: http://www.verdade.co.mz/newsflash/62607 | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1491493337539020 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Referência não recolhida: http://www.verdade.co.mz/newsflash/62625 | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1493133914041629 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
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 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. Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites. Seguir o guia e a sequência de entrega privada do manual; não repetir importação QA ou provas dos 20 aceites. Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação. legado-editorial-qa-20261022.json; manual: Legado — edição e leitura dos 28 rascunhos em QA; inventário e referências históricas preservados outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY) 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
@@ -1,58 +0,0 @@
# Correspondência integral dos 50 artigos do legado
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`.
| 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. |
| 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. |
| 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. |
| 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. |
| 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. |
| 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. |
| 172258 | Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento | https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento/ \| https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento | https://teste-investidor.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento | Publicado; identidade e conteúdo consultáveis na homologação | Não foi feita aceitação visual ou conferência pela Tempo nesta passagem. |
| 172237 | Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável | https://investemoz.tempo.co.mz/provincia-de-maputo-turismo/ \| https://investemoz.tempo.co.mz/provincia-de-maputo-turismo | https://teste-investidor.tempo.co.mz/provincia-de-maputo-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. |
| 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. |
| 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. |
| 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. |
| 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. |
@@ -1,545 +0,0 @@
{
"checked_utc": "2026-10-22T21:05:03.369388+00:00",
"distinct_articles": 50,
"publications_documented": 20,
"public_pages_identity_verified": 20,
"pending_content": 28,
"private_preparation": {
"historico_noticioso": 18,
"setorial": 2,
"trabalho_domestico": 8
},
"empty": 1,
"untitled": 1,
"database_writes_by_correspondence_script": 0,
"active_database_writes": 0,
"new_publications": 0,
"qa_imports": 28,
"qa_clean_scans": 28,
"remaining_integration_complete": false,
"public_pages": {
"checked_utc": "2026-10-22T21:05:03.369388+00:00",
"method": "Anonymous HTTP GET; Inertia article identity/source/content checked; no visual acceptance or new publication",
"pages": {
"173209": {
"url": "https://teste-investidor.tempo.co.mz/tech-fintech",
"status": 200,
"identity_verified": true,
"resource_id": 28,
"document_sha256": "926f5e4096737c936c9d5002ebdc64be9e63b0c0822023d17ce618111a65c941",
"current_title": "Fintech",
"image_url": "/documentos/27/view",
"response_sha256": "565f86bb5febd5833d5392588551b8e587b2d65898eda06284dcb33228866b63"
},
"173218": {
"url": "https://teste-investidor.tempo.co.mz/imobiliario",
"status": 200,
"identity_verified": true,
"resource_id": 7,
"document_sha256": "43612c358c7573475cea24ef4825c5b7c7925306fa5861051220eed3f4e333b5",
"current_title": "Imobiliário",
"image_url": "/documentos/27/view",
"response_sha256": "684840410238c5a199c581373d5cab233cdf869ccbf7d0da306a3d26181060b4"
},
"173213": {
"url": "https://teste-investidor.tempo.co.mz/bens-de-consumo-franquias",
"status": 200,
"identity_verified": true,
"resource_id": 29,
"document_sha256": "0ba605ae43dec7f685610f828df884bc82cb4da67131fc9783b5cdbe4cc6d9f0",
"current_title": "Bens de Consumo e Franquias",
"image_url": "/documentos/27/view",
"response_sha256": "65145d3b10d494d7e2a8d09736078f9272733c3ae48b5bce501ccffefd63f9bf"
},
"171985": {
"url": "https://teste-investidor.tempo.co.mz/agronegocio",
"status": 200,
"identity_verified": true,
"resource_id": 13,
"document_sha256": "0929184a6d4645b9046512675394ad4f60575273f6dab0955f71cc7474a6a4e2",
"current_title": "Agronegocio",
"image_url": "/documentos/12/view",
"response_sha256": "13c4aeb4307fa5efefa04a9c2cafe0a36b4ab243d93739aa2c1bfe2b0c4ff252"
},
"171981": {
"url": "https://teste-investidor.tempo.co.mz/energia-mineracao",
"status": 200,
"identity_verified": true,
"resource_id": 18,
"document_sha256": "26a70f16cd511c579f08633655ff312db05122f81e44852dd4b163fa6eef85f1",
"current_title": "Energia & Mineração",
"image_url": "/documentos/14/view",
"response_sha256": "10a0e0c00a291929f8923962f9cb31e90bbbb7d2e7eddb856a2ae43e30ca6d1b"
},
"172679": {
"url": "https://teste-investidor.tempo.co.mz/energia",
"status": 200,
"identity_verified": true,
"resource_id": 1,
"document_sha256": "2003755b7dac53b43f4608e707321db6d2f29878926a0e74f4cf27627b70a9cb",
"current_title": "Energia",
"image_url": "/documentos/27/view",
"response_sha256": "41e8ba52174d616cfd81eaa24e4d9135dcfd69a2e6c48e20bfce7b8de5b40166"
},
"172674": {
"url": "https://teste-investidor.tempo.co.mz/mineracao",
"status": 200,
"identity_verified": true,
"resource_id": 2,
"document_sha256": "3ae780f082a8fa7c767635cce98563f5bc027c9656c9f41f8788843a17fa1f54",
"current_title": "Mineração",
"image_url": "/documentos/27/view",
"response_sha256": "b078b87e56f3d68434573aa4d2a2c780845304f44cc65f5f2237732ab32eca7e"
},
"171990": {
"url": "https://teste-investidor.tempo.co.mz/turismo",
"status": 200,
"identity_verified": true,
"resource_id": 19,
"document_sha256": "8cab862be245382dd4c1fd5fcb423c47aed7be3a22e0a7f8d5521510cc36bc72",
"current_title": "Turismo",
"image_url": "/documentos/15/view",
"response_sha256": "471c561e89bf55642ec6aa43b9a27e1dd1f97d0e11e93c8ab95f508b3824da5b"
},
"172263": {
"url": "https://teste-investidor.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel",
"status": 200,
"identity_verified": true,
"resource_id": 3,
"document_sha256": "538495cd5b31047ac1c5993fdaf298ec1303330368248b251c87d201d31ff211",
"current_title": "Província da Zambézia: Onde os Corredores de Moçambique Convergem com a Natureza, a Cultura e o Turismo Sustentável",
"image_url": "/documentos/27/view",
"response_sha256": "8629d5647b8ab3f4752ce7452cc131e5b64c0abc06afd25255231a562e0f534e"
},
"172256": {
"url": "https://teste-investidor.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem",
"status": 200,
"identity_verified": true,
"resource_id": 4,
"document_sha256": "dcc29cbd36cf57e0a5c88dd312c84ee03c32a3d18ae9216d3715dc7b5a6960bf",
"current_title": "Província de Sofala: Onde a Natureza, a História e o Futuro do Turismo Convergem",
"image_url": "/documentos/27/view",
"response_sha256": "16f08eaa50b150d73d85ca0b8dccc17ff2b61179813dd6ad0d78ec4309c599d4"
},
"172261": {
"url": "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",
"status": 200,
"identity_verified": true,
"resource_id": 5,
"document_sha256": "88177fccd78d8516dba670c6f71272af062cc981d52d97adefe5bf77c613b16a",
"current_title": "Província de Tete: Onde o Rio Zambeze, a Cultura Viva e a Conservação Comunitária Criam o Futuro do Turismo",
"image_url": "/documentos/27/view",
"response_sha256": "7c24f3bfddf8c5bee5ef1312e6d55f46e3ca48c7e48e3f363eac4c95979e6aca"
},
"172258": {
"url": "https://teste-investidor.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento",
"status": 200,
"identity_verified": true,
"resource_id": 20,
"document_sha256": "48314a576dea2f2dadf47d8f1eadd7ab58030606b02eebe17aa9bd6badffb7e9",
"current_title": "Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento",
"image_url": "/documentos/27/view",
"response_sha256": "bac797abb94d97ffdc11f8b8cfe9b7782f2c8a9d2311c96e83f71f4ba86bffcb"
},
"172253": {
"url": "https://teste-investidor.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico",
"status": 200,
"identity_verified": true,
"resource_id": 6,
"document_sha256": "e90e39e49ba65bbbcbbc303c6eca456e445238daf9acc935ab03690819281678",
"current_title": "Província de Inhambane: Um Destino Estratégico para Investimento Turístico",
"image_url": "/documentos/27/view",
"response_sha256": "a6fbbccb7f9499c5aa0034a3d10810a033c6140f1269bd0074e81f1a5bb8da0c"
},
"172240": {
"url": "https://teste-investidor.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel",
"status": 200,
"identity_verified": true,
"resource_id": 21,
"document_sha256": "8c5e91c937032680883793a12844f1128f7ac99e97c63b68c23d1396e009ba9d",
"current_title": "Maputo Cidade – Plataforma Estratégica de Turismo, Negócios e Investimento Sustentável",
"image_url": "/documentos/27/view",
"response_sha256": "265afdbc2b8997daa69cb519c7409a74d3dd590f7c57b144723786a3c167034d"
},
"172237": {
"url": "https://teste-investidor.tempo.co.mz/provincia-de-maputo-turismo",
"status": 200,
"identity_verified": true,
"resource_id": 22,
"document_sha256": "a62a43e31da32795a7286f4c152a93d5dc829233e72023b00ea61fd8e2fcb58c",
"current_title": "Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável",
"image_url": "/documentos/27/view",
"response_sha256": "7827fa353f9fc126938732d42fa57353b48c58f448e25f8466665086779860dc"
},
"172233": {
"url": "https://teste-investidor.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique",
"status": 200,
"identity_verified": true,
"resource_id": 23,
"document_sha256": "345dfd72d8ebf459eae8eb025d699afddbae751df55ffa8d053568cd08096c97",
"current_title": "Província de Gaza: Oportunidades mais sólidas e estratégicas de investimento no turismo no sul de Moçambique.",
"image_url": "/documentos/27/view",
"response_sha256": "bfb80dff52964448b4bbd03995706020b9bccaa14d8abc1d944123e6b1240a6f"
},
"172230": {
"url": "https://teste-investidor.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo",
"status": 200,
"identity_verified": true,
"resource_id": 24,
"document_sha256": "4f4570f7bbd5599cb925ed996c1734a23582362fe485736931a53b9266565d4e",
"current_title": "Província de Nampula - Perfil de investimento no setor do turismo",
"image_url": "/documentos/27/view",
"response_sha256": "6d42e0a347c938d201b8c8780fcdf0da83e6dab9fc031ea0ac73b14464f4f696"
},
"172223": {
"url": "https://teste-investidor.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique",
"status": 200,
"identity_verified": true,
"resource_id": 25,
"document_sha256": "514a9d88c097d234038fa6341f5a5b01e8938cb6a9535a807145c84c37010a4d",
"current_title": "Cabo Delgado - Pemba, A capital do turismo costeiro do norte de Moçambique",
"image_url": "/documentos/27/view",
"response_sha256": "a579796f41716bb43444295dce91b19d0346828e7b3cbfc994efbdc5058ec69b"
},
"172219": {
"url": "https://teste-investidor.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano",
"status": 200,
"identity_verified": true,
"resource_id": 26,
"document_sha256": "0d468ae0de9a76d2b140bc8cb5c555f29626fb6422287c917762bec3e615a70c",
"current_title": "Niassa - O último grande destino virgem do turismo africano",
"image_url": "/documentos/27/view",
"response_sha256": "cffb6ea36fa8273112edaa31432f9c5093ea8e0303fee83c3cdb396e83aac816"
},
"171992": {
"url": "https://teste-investidor.tempo.co.mz/infraestruturas",
"status": 200,
"identity_verified": true,
"resource_id": 17,
"document_sha256": "05eb492dd6cfca6a7f305b633658a16723c315168f4b2c75103f22d1fac84032",
"current_title": "Infraestruturas",
"image_url": "/documentos/16/view",
"response_sha256": "0afd5c42dc0a187a22cb3f8ef8af1b10348d31899ce3b1befbc2c38b379d475b"
}
}
},
"qa_import": {
"port": 55441,
"actor": 239,
"resources": [
{
"id": 43,
"title": "15/30 costa do sol com dua na zona de mupulene muito lindo",
"published": false,
"external_id": "legacy-tempo-post-62413-20170626",
"sha256": "b471c1afd7235f359acdcc16a93088f77e1f988706c8d3c4d4f11c5d560aea47",
"malware_scan_status": "clean",
"malware_scanned_sha256": "b471c1afd7235f359acdcc16a93088f77e1f988706c8d3c4d4f11c5d560aea47",
"data_classification": "internal"
},
{
"id": 44,
"title": "Banco Mundial classifica de proibitivos juros praticados em Moçambique",
"published": false,
"external_id": "legacy-tempo-post-73945-20170731",
"sha256": "2aa0ce0eb305bfdf93e390a978d3694d0fbc0129034077b68cebce418f878415",
"malware_scan_status": "clean",
"malware_scanned_sha256": "2aa0ce0eb305bfdf93e390a978d3694d0fbc0129034077b68cebce418f878415",
"data_classification": "internal"
},
{
"id": 45,
"title": "Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador",
"published": false,
"external_id": "legacy-tempo-post-76474-20170808",
"sha256": "8f769aec4715449d056c8c25294060b2ff290ec0893c28e9bdcc4e8092fc75f5",
"malware_scan_status": "clean",
"malware_scanned_sha256": "8f769aec4715449d056c8c25294060b2ff290ec0893c28e9bdcc4e8092fc75f5",
"data_classification": "internal"
},
{
"id": 46,
"title": "Governo pretende construir 100 mil habitações em dois anos",
"published": false,
"external_id": "legacy-tempo-post-75002-20170804",
"sha256": "7b6fbd998be2b47b96e9a4724560c192c502709fa308d6590c0797ddcdb10544",
"malware_scan_status": "clean",
"malware_scanned_sha256": "7b6fbd998be2b47b96e9a4724560c192c502709fa308d6590c0797ddcdb10544",
"data_classification": "internal"
},
{
"id": 47,
"title": "Rofino Licuco preso cinco meses depois de condenado por agressão",
"published": false,
"external_id": "legacy-tempo-post-73246-20170728",
"sha256": "430ee8674c71104fc126bed2911d676f150ac623857a1ada75662987fd9ac390",
"malware_scan_status": "clean",
"malware_scanned_sha256": "430ee8674c71104fc126bed2911d676f150ac623857a1ada75662987fd9ac390",
"data_classification": "internal"
},
{
"id": 48,
"title": "Sete indivíduos mortos a tiro na Matola",
"published": false,
"external_id": "legacy-tempo-post-77232-20170811",
"sha256": "27544d3127803b7495bef9fd633147d0225d8c31816c4d59ed05a2edd59de070",
"malware_scan_status": "clean",
"malware_scanned_sha256": "27544d3127803b7495bef9fd633147d0225d8c31816c4d59ed05a2edd59de070",
"data_classification": "internal"
},
{
"id": 49,
"title": "Daúde Razaque já não é treinador da Liga Desportiva de Maputo",
"published": false,
"external_id": "legacy-tempo-post-62929-20170627",
"sha256": "488017b062c6760659d9147b7f12aea4afd8d824121adb9462e2c7a2ae58437b",
"malware_scan_status": "clean",
"malware_scanned_sha256": "488017b062c6760659d9147b7f12aea4afd8d824121adb9462e2c7a2ae58437b",
"data_classification": "internal"
},
{
"id": 50,
"title": "Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (...",
"published": false,
"external_id": "legacy-tempo-post-63248-20170628",
"sha256": "6c30e61197b8568332af6d9b19bbba7ad8665b3873bb031a8c8aedd41536b060",
"malware_scan_status": "clean",
"malware_scanned_sha256": "6c30e61197b8568332af6d9b19bbba7ad8665b3873bb031a8c8aedd41536b060",
"data_classification": "internal"
},
{
"id": 51,
"title": "Alumínio “Verde”",
"published": false,
"external_id": "legacy-tempo-post-173220-20260616",
"sha256": "5b76c3d84dcf7f9a489686d90e3857ae6536705c918e841310bb42b354e80976",
"malware_scan_status": "clean",
"malware_scanned_sha256": "5b76c3d84dcf7f9a489686d90e3857ae6536705c918e841310bb42b354e80976",
"data_classification": "internal"
},
{
"id": 52,
"title": "Checklist para Contratação e Direitos do Trabalho Doméstico",
"published": false,
"external_id": "legacy-tempo-post-173482-20260915",
"sha256": "6f888e133a779c719073246f89bcae150198e5897c0e7d9b7ba75f54c54a7830",
"malware_scan_status": "clean",
"malware_scanned_sha256": "6f888e133a779c719073246f89bcae150198e5897c0e7d9b7ba75f54c54a7830",
"data_classification": "internal"
},
{
"id": 53,
"title": "Frelimo e Zanu-PF: Evocados laços de irmandade",
"published": false,
"external_id": "legacy-tempo-post-62414-20170626",
"sha256": "a040c0b7cb95dd7f053f4d13662dd58b2b06453b6fa61a2d531d0257a8db8c17",
"malware_scan_status": "clean",
"malware_scanned_sha256": "a040c0b7cb95dd7f053f4d13662dd58b2b06453b6fa61a2d531d0257a8db8c17",
"data_classification": "internal"
},
{
"id": 54,
"title": "Governo dará todo O apoio à PGR no seguimento da auditoria",
"published": false,
"external_id": "legacy-tempo-post-62418-20170626",
"sha256": "e8ccafa68f0d1aa80f2e41d9e09f7b13e7c653a8472a731798cfd5e04ce2963e",
"malware_scan_status": "clean",
"malware_scanned_sha256": "e8ccafa68f0d1aa80f2e41d9e09f7b13e7c653a8472a731798cfd5e04ce2963e",
"data_classification": "internal"
},
{
"id": 55,
"title": "Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia",
"published": false,
"external_id": "legacy-tempo-post-62416-20170626",
"sha256": "ac575ce340571192552c89b63f0bd62a84dbc47828e6930133af5ff70e249319",
"malware_scan_status": "clean",
"malware_scanned_sha256": "ac575ce340571192552c89b63f0bd62a84dbc47828e6930133af5ff70e249319",
"data_classification": "internal"
},
{
"id": 56,
"title": "Daviz Simango não se incomoda com possível sucessão na Beira",
"published": false,
"external_id": "legacy-tempo-post-62649-20170626",
"sha256": "38a858713472759a2d20a308bdd9d8afa9cfb76dcaf8d11ca709e89261573e42",
"malware_scan_status": "clean",
"malware_scanned_sha256": "38a858713472759a2d20a308bdd9d8afa9cfb76dcaf8d11ca709e89261573e42",
"data_classification": "internal"
},
{
"id": 57,
"title": "“Exigimos responsabilização dos agentes do crime”, Daviz Simango",
"published": false,
"external_id": "legacy-tempo-post-62739-20170626",
"sha256": "5870fc0fad9bb7af537b7b1468151cde138b1b886ce846c7be25647b630245dd",
"malware_scan_status": "clean",
"malware_scanned_sha256": "5870fc0fad9bb7af537b7b1468151cde138b1b886ce846c7be25647b630245dd",
"data_classification": "internal"
},
{
"id": 58,
"title": "Governo e parceiros reforçam mecanismos de controlo de HIV/Sida",
"published": false,
"external_id": "legacy-tempo-post-62854-20170627",
"sha256": "44b1ba9d593bb625cf53de8909e78eb0b3129742c3ec9d58ec68c984e8930bce",
"malware_scan_status": "clean",
"malware_scanned_sha256": "44b1ba9d593bb625cf53de8909e78eb0b3129742c3ec9d58ec68c984e8930bce",
"data_classification": "internal"
},
{
"id": 59,
"title": "Graça Machel diz que desnutrição é um problema de desenvolvimento",
"published": false,
"external_id": "legacy-tempo-post-63128-20170627",
"sha256": "74be8f29e5053f53ab1a39a2f63208145c30f23357ca6d78b637dd02bf9c1fb4",
"malware_scan_status": "clean",
"malware_scanned_sha256": "74be8f29e5053f53ab1a39a2f63208145c30f23357ca6d78b637dd02bf9c1fb4",
"data_classification": "internal"
},
{
"id": 60,
"title": "In dependência",
"published": false,
"external_id": "legacy-tempo-post-63181-20170627",
"sha256": "3d0f9ac14d36156d8178e33f8616d6406f31ea4cd69c8308cbf4227586d7ccb3",
"malware_scan_status": "clean",
"malware_scanned_sha256": "3d0f9ac14d36156d8178e33f8616d6406f31ea4cd69c8308cbf4227586d7ccb3",
"data_classification": "internal"
},
{
"id": 61,
"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",
"published": false,
"external_id": "legacy-tempo-post-63146-20170627",
"sha256": "542353466cc6d82b651619c495f138b0576a4be41d21aad194ae2005050cb1bc",
"malware_scan_status": "clean",
"malware_scanned_sha256": "542353466cc6d82b651619c495f138b0576a4be41d21aad194ae2005050cb1bc",
"data_classification": "internal"
},
{
"id": 62,
"title": "O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ...",
"published": false,
"external_id": "legacy-tempo-post-62688-20170626",
"sha256": "a210a789b06d425822f4124f74226a2b27246c086c5ec5f041f1b2237d7c2b65",
"malware_scan_status": "clean",
"malware_scanned_sha256": "a210a789b06d425822f4124f74226a2b27246c086c5ec5f041f1b2237d7c2b65",
"data_classification": "internal"
},
{
"id": 63,
"title": "Energia e Recursos Naturais",
"published": false,
"external_id": "legacy-tempo-post-173222-20260616",
"sha256": "e64d7063d1ac4dda028c97e1ba64938d2a9e426a0b630c57ee5df52a41312cc7",
"malware_scan_status": "clean",
"malware_scanned_sha256": "e64d7063d1ac4dda028c97e1ba64938d2a9e426a0b630c57ee5df52a41312cc7",
"data_classification": "internal"
},
{
"id": 64,
"title": "Direitos Especiais da Trabalhadora Doméstica no Regulamento",
"published": false,
"external_id": "legacy-tempo-post-173484-20260915",
"sha256": "297df455a9c6fd1f0ab7ca7bbe124ce483c86fe55be26baa695f03089b3ac049",
"malware_scan_status": "clean",
"malware_scanned_sha256": "297df455a9c6fd1f0ab7ca7bbe124ce483c86fe55be26baa695f03089b3ac049",
"data_classification": "internal"
},
{
"id": 65,
"title": "Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico",
"published": false,
"external_id": "legacy-tempo-post-173478-20260915",
"sha256": "d4e320ed99dd9d53d205e47932f73651976d43081d5d39f2bfc2996901408644",
"malware_scan_status": "clean",
"malware_scanned_sha256": "d4e320ed99dd9d53d205e47932f73651976d43081d5d39f2bfc2996901408644",
"data_classification": "internal"
},
{
"id": 66,
"title": "Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias",
"published": false,
"external_id": "legacy-tempo-post-173480-20260915",
"sha256": "c3ee6401eda5b582c61969b5e3b74fdf26ef34ca481b1aca8c4c309d845147ae",
"malware_scan_status": "clean",
"malware_scanned_sha256": "c3ee6401eda5b582c61969b5e3b74fdf26ef34ca481b1aca8c4c309d845147ae",
"data_classification": "internal"
},
{
"id": 67,
"title": "Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique",
"published": false,
"external_id": "legacy-tempo-post-173476-20260915",
"sha256": "72fbf28391db4804e0637b64e7f59e9fa597812a2681b4562dc3d6dfb4093a30",
"malware_scan_status": "clean",
"malware_scanned_sha256": "72fbf28391db4804e0637b64e7f59e9fa597812a2681b4562dc3d6dfb4093a30",
"data_classification": "internal"
},
{
"id": 68,
"title": "Direitos e Deveres do Trabalhador Doméstico",
"published": false,
"external_id": "legacy-tempo-post-173470-20260915",
"sha256": "26feeae6b8d04972c7a64ee360583cccdcaeb4b0d8795fd7bc2fd3c38866cc19",
"malware_scan_status": "clean",
"malware_scanned_sha256": "26feeae6b8d04972c7a64ee360583cccdcaeb4b0d8795fd7bc2fd3c38866cc19",
"data_classification": "internal"
},
{
"id": 69,
"title": "Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique",
"published": false,
"external_id": "legacy-tempo-post-173474-20260915",
"sha256": "9fa741a17b746bfa2f3ce7b6ce1d2bb34d3a35d3b58330b0554f9e0a6844f049",
"malware_scan_status": "clean",
"malware_scanned_sha256": "9fa741a17b746bfa2f3ce7b6ce1d2bb34d3a35d3b58330b0554f9e0a6844f049",
"data_classification": "internal"
},
{
"id": 70,
"title": "Regulamento do Trabalho Doméstico",
"published": false,
"external_id": "legacy-tempo-post-173463-20260915",
"sha256": "4f34b7bac4b3030c0614844d379f6e3cfad1b7f6ea3db575a58c33ae033b0e73",
"malware_scan_status": "clean",
"malware_scanned_sha256": "4f34b7bac4b3030c0614844d379f6e3cfad1b7f6ea3db575a58c33ae033b0e73",
"data_classification": "internal"
}
],
"imported_private": 28,
"clean_actual_scans": 28,
"idempotent_replay_reused": 28,
"existing_resources_preserved": true,
"roles_unchanged": true,
"new_publications": 0,
"active_writes": 0
},
"original_gaps": [
{
"legacy_id": 171994,
"url": "https://investemoz.tempo.co.mz/mercado-financeiro",
"status": 200,
"title": "Mercado Financeiro",
"body_characters": 0,
"body_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"same_body_as_capture": true
},
{
"legacy_id": 74364,
"url": "https://investemoz.tempo.co.mz/74364-2",
"status": 200,
"title": "",
"body_characters": 274,
"body_sha256": "2a7f0a5b09e0136fec9eae357ac8a88a159ead23b25ed7bb735c75997b10ec5e",
"same_body_as_capture": true
}
],
"educational_cards": {
"in_main": true,
"observed_url": "https://teste-investidor.tempo.co.mz/explorar/turismo",
"read_guide_links": 12,
"visual_acceptance_by_tempo": false
}
}
@@ -1,339 +0,0 @@
{
"qa_only": true,
"originals": 28,
"rows": [
{
"external_id": "legacy-tempo-post-62413-20170626",
"qa_resource_id": 43,
"version": 2,
"original_sha256": "b471c1afd7235f359acdcc16a93088f77e1f988706c8d3c4d4f11c5d560aea47",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 2
},
{
"external_id": "legacy-tempo-post-73945-20170731",
"qa_resource_id": 44,
"version": 1,
"original_sha256": "2aa0ce0eb305bfdf93e390a978d3694d0fbc0129034077b68cebce418f878415",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-76474-20170808",
"qa_resource_id": 45,
"version": 1,
"original_sha256": "8f769aec4715449d056c8c25294060b2ff290ec0893c28e9bdcc4e8092fc75f5",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 2,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-62414-20170626",
"qa_resource_id": 53,
"version": 1,
"original_sha256": "a040c0b7cb95dd7f053f4d13662dd58b2b06453b6fa61a2d531d0257a8db8c17",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-62418-20170626",
"qa_resource_id": 54,
"version": 1,
"original_sha256": "e8ccafa68f0d1aa80f2e41d9e09f7b13e7c653a8472a731798cfd5e04ce2963e",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-75002-20170804",
"qa_resource_id": 46,
"version": 1,
"original_sha256": "7b6fbd998be2b47b96e9a4724560c192c502709fa308d6590c0797ddcdb10544",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-73246-20170728",
"qa_resource_id": 47,
"version": 1,
"original_sha256": "430ee8674c71104fc126bed2911d676f150ac623857a1ada75662987fd9ac390",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-77232-20170811",
"qa_resource_id": 48,
"version": 1,
"original_sha256": "27544d3127803b7495bef9fd633147d0225d8c31816c4d59ed05a2edd59de070",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-62416-20170626",
"qa_resource_id": 55,
"version": 1,
"original_sha256": "ac575ce340571192552c89b63f0bd62a84dbc47828e6930133af5ff70e249319",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-62929-20170627",
"qa_resource_id": 49,
"version": 1,
"original_sha256": "488017b062c6760659d9147b7f12aea4afd8d824121adb9462e2c7a2ae58437b",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-62649-20170626",
"qa_resource_id": 56,
"version": 1,
"original_sha256": "38a858713472759a2d20a308bdd9d8afa9cfb76dcaf8d11ca709e89261573e42",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-62739-20170626",
"qa_resource_id": 57,
"version": 1,
"original_sha256": "5870fc0fad9bb7af537b7b1468151cde138b1b886ce846c7be25647b630245dd",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-62854-20170627",
"qa_resource_id": 58,
"version": 1,
"original_sha256": "44b1ba9d593bb625cf53de8909e78eb0b3129742c3ec9d58ec68c984e8930bce",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-63128-20170627",
"qa_resource_id": 59,
"version": 1,
"original_sha256": "74be8f29e5053f53ab1a39a2f63208145c30f23357ca6d78b637dd02bf9c1fb4",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-63181-20170627",
"qa_resource_id": 60,
"version": 1,
"original_sha256": "3d0f9ac14d36156d8178e33f8616d6406f31ea4cd69c8308cbf4227586d7ccb3",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-63146-20170627",
"qa_resource_id": 61,
"version": 1,
"original_sha256": "542353466cc6d82b651619c495f138b0576a4be41d21aad194ae2005050cb1bc",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 1,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-62688-20170626",
"qa_resource_id": 62,
"version": 1,
"original_sha256": "a210a789b06d425822f4124f74226a2b27246c086c5ec5f041f1b2237d7c2b65",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-63248-20170628",
"qa_resource_id": 50,
"version": 1,
"original_sha256": "6c30e61197b8568332af6d9b19bbba7ad8665b3873bb031a8c8aedd41536b060",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-173220-20260616",
"qa_resource_id": 51,
"version": 1,
"original_sha256": "5b76c3d84dcf7f9a489686d90e3857ae6536705c918e841310bb42b354e80976",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-173222-20260616",
"qa_resource_id": 63,
"version": 1,
"original_sha256": "e64d7063d1ac4dda028c97e1ba64938d2a9e426a0b630c57ee5df52a41312cc7",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-173482-20260915",
"qa_resource_id": 52,
"version": 1,
"original_sha256": "6f888e133a779c719073246f89bcae150198e5897c0e7d9b7ba75f54c54a7830",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-173484-20260915",
"qa_resource_id": 64,
"version": 1,
"original_sha256": "297df455a9c6fd1f0ab7ca7bbe124ce483c86fe55be26baa695f03089b3ac049",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-173478-20260915",
"qa_resource_id": 65,
"version": 1,
"original_sha256": "d4e320ed99dd9d53d205e47932f73651976d43081d5d39f2bfc2996901408644",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-173480-20260915",
"qa_resource_id": 66,
"version": 1,
"original_sha256": "c3ee6401eda5b582c61969b5e3b74fdf26ef34ca481b1aca8c4c309d845147ae",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-173476-20260915",
"qa_resource_id": 67,
"version": 1,
"original_sha256": "72fbf28391db4804e0637b64e7f59e9fa597812a2681b4562dc3d6dfb4093a30",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-173470-20260915",
"qa_resource_id": 68,
"version": 1,
"original_sha256": "26feeae6b8d04972c7a64ee360583cccdcaeb4b0d8795fd7bc2fd3c38866cc19",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-173474-20260915",
"qa_resource_id": 69,
"version": 1,
"original_sha256": "9fa741a17b746bfa2f3ce7b6ce1d2bb34d3a35d3b58330b0554f9e0a6844f049",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
},
{
"external_id": "legacy-tempo-post-173463-20260915",
"qa_resource_id": 70,
"version": 1,
"original_sha256": "4f34b7bac4b3030c0614844d379f6e3cfad1b7f6ea3db575a58c33ae033b0e73",
"private": true,
"image_available": false,
"image_reference": "https://investemoz.tempo.co.mz/images/tempo-background.png",
"body_image_references": 0,
"history_revisions": 1
}
],
"archive_entries": 57,
"archive_sha256": "177c50d1cc3b1610e62123a2f8b532711a15f875aac2ee0e372636c2f747e8a2",
"archive_bytes": 85614,
"verified_original_hashes": 28,
"included_image_originals": 0,
"destination_imported": false,
"destination_published": false,
"database_writes": 0,
"tests": {
"passed": 6,
"assertions": 1000,
"database": "simulator_fiscal_delta_20261021_test",
"port": 55441,
"publication_transactions_rolled_back": true,
"all_28_sanitized_original_text_preserved": true
},
"typescript": "passed",
"qa_build": "passed",
"public20_rechecked": false,
"reimported": false,
"main_integrated": false,
"user_review_claimed": false,
"ui_saved_resource": 43,
"ui_saved_version": 2,
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
}
@@ -1,127 +0,0 @@
export type EditorialArticle = {
id: number;
title: string;
description: string | null;
author: string | null;
body: string;
html?: string | null;
image_url: string | null;
original_url: string;
source_url?: string | null;
published_at?: string | null;
modified_at?: string | null;
legacy_id?: number | null;
image_source_url?: string | null;
image_notice?: string | null;
image_references?: string[];
metadata_version?: number;
private_preview?: boolean;
};
export default function EditorialReading({
article,
}: {
article: EditorialArticle;
}) {
return (
<div className="space-y-5">
{article.private_preview && (
<p
role="status"
className="rounded border border-amber-500 bg-amber-50 p-3 text-slate-900"
>
Prévia privada — não publica o artigo nem altera os direitos
do original.
</p>
)}
<h1 className="text-3xl font-bold">{article.title}</h1>
{article.description && <p>{article.description}</p>}
{article.author && <p>Autor / entidade: {article.author}</p>}
{article.legacy_id && (
<p>
Arquivo do portal antigo · artigo {article.legacy_id}.
Conteúdo editorial preservado; não corresponde por si a
oportunidade concreta ou regra executável.
</p>
)}
{(article.published_at || article.modified_at) && (
<p>
Origem: publicado em{' '}
{article.published_at ?? 'data não indicada'} · modificado
em {article.modified_at ?? 'data não indicada'}. A edição no
portal conserva estas datas de origem.
</p>
)}
{article.image_url && (
<img
className="max-h-96 w-full object-contain"
src={article.image_url}
alt={`Imagem do artigo ${article.title}`}
/>
)}
{article.image_notice && (
<p role="note" className="rounded border p-3">
{article.image_notice}
</p>
)}
{article.html ? (
<article
className="prose dark:prose-invert max-w-none overflow-x-auto"
dangerouslySetInnerHTML={{ __html: article.html }}
/>
) : (
<article className="space-y-5">
{article.body.split(/\n\s*\n/).map((p, i) => (
<p className="whitespace-pre-wrap" key={i}>
{p}
</p>
))}
</article>
)}
{!!article.image_references?.length && (
<section aria-label="Imagens referenciadas no corpo original">
<h2>Imagens referenciadas no corpo original</h2>
<p>
Referências preservadas; não confirmam um ficheiro
disponível na biblioteca.
</p>
<ul>
{article.image_references.map((url, i) => (
<li key={url}>
<a
className="underline"
href={url}
rel="noopener noreferrer"
>
Referência da imagem {i + 1}
</a>
</li>
))}
</ul>
</section>
)}
<nav aria-label="Origem do artigo" className="flex flex-wrap gap-4">
{article.source_url && (
<a
className="underline"
href={article.source_url}
rel="noopener noreferrer"
>
Consultar página de origem
</a>
)}
{article.image_source_url && (
<a
className="underline"
href={article.image_source_url}
rel="noopener noreferrer"
>
Referência da imagem de origem
</a>
)}
<a href={article.original_url} className="underline">
Consultar documento original
</a>
</nav>
</div>
);
}
@@ -19,8 +19,6 @@ export type InvestmentMapFeature = {
};
};
export type InvestmentMapArea = {
selected_territory?: boolean;
location_type?: string;
purpose?: string;
geometry: GeoJsonObject;
title: string;
@@ -76,13 +74,6 @@ export default function InteractiveInvestmentMap({
.addTo(instance);
L.control.scale({ imperial: false }).addTo(instance);
const bounds: [number, number][] = [];
const hasSelectedBoundary = areas.some((area) => area.selected_territory);
const administrativeLevel: Record<string, number> = {
province: 1, district: 2, admin_post: 3, locality: 4,
};
const closestContextLevel = contextOnly
? Math.max(0, ...areas.map((area) => administrativeLevel[area.location_type ?? ''] ?? 0))
: 0;
for (const area of areas) {
const label = document.createElement('p');
label.textContent = `${area.title} · ${area.purpose === 'administrative_boundary' ? 'Limite administrativo da edição indicada; não representa um local de investimento' : 'Polígono cadastrado, limites oficiais por verificar'} · Fonte: ${area.source_reference ?? 'Não indicada'} · Data: ${area.source_date ?? 'Não documentada'}`;
@@ -101,10 +92,7 @@ export default function InteractiveInvestmentMap({
.bindPopup(label)
.addTo(instance);
const extent = layer.getBounds();
const focusBoundary = hasSelectedBoundary
? area.selected_territory
: !closestContextLevel || administrativeLevel[area.location_type ?? ''] === closestContextLevel;
if (extent.isValid() && focusBoundary)
if (extent.isValid())
bounds.push(
[extent.getSouth(), extent.getWest()],
[extent.getNorth(), extent.getEast()],
@@ -48,7 +48,6 @@ export function PortalGroupedMenu() {
existingBusinessEnabled?: boolean;
businessReviewUrl?: string | null;
educationEnabled?: boolean;
procurementEnabled?: boolean;
aiEnabled?: boolean;
legacyContentEnabled?: boolean;
profileAccess?: ProfileAccess | null;
@@ -67,7 +66,6 @@ export function PortalGroupedMenu() {
businesses: props.existingBusinessEnabled,
businessReviewUrl: props.businessReviewUrl,
education: props.educationEnabled,
procurement: props.procurementEnabled,
ai: props.aiEnabled,
legacyContent: props.legacyContentEnabled,
opportunityManagement: props.opportunityManagement,
@@ -71,12 +71,6 @@ export default function TerritoryGeometryPreview({
? 'Limite administrativo disponível para este território.'
: 'Sem limite administrativo acessível para este território neste perfil.'}
</p>
{!context.selected_geometry_available && context.areas.length > 0 && (
<p role="note">
O mapa mostra apenas limites dos níveis superiores como contexto.
Estes limites não representam o território seleccionado.
</p>
)}
<p>
{context.context_geometry_count} limites disponíveis na
hierarquia selecionada. São contexto administrativo, não
@@ -99,7 +93,7 @@ export default function TerritoryGeometryPreview({
<ul>
{context.areas.map((area, index) => (
<li key={index}>
{area.title} · {area.selected_territory ? 'Território seleccionado' : 'Contexto de nível superior'} · Fonte:{' '}
{area.title} · Fonte:{' '}
{area.source_reference ?? 'Não indicada'} ·
Edição: {area.source_date ?? 'Não indicada'}
</li>
-2
View File
@@ -8,7 +8,6 @@ export type PortalNavItem = {
children?: PortalNavItem[];
};
export type PortalNavAccess = {
procurement?: boolean;
authenticated: boolean;
manager: boolean;
businesses?: boolean;
@@ -462,7 +461,6 @@ export function portalNavigation(access: PortalNavAccess): PortalNavItem[] {
),
link('sectors', 'Sectores de investimento', '/sectores'),
link('locations', 'Localizações', '/oportunidades?view=map'),
...(access.procurement ? [link('procurement','Concursos e anúncios','/concursos')] : []),
{
id: 'related-catalogues',
label: 'Catálogos relacionados',
@@ -3,7 +3,6 @@ import { Frame, card, button } from '@/pages/investment/shared';
import { states } from './shared';
type Access = {
procurement?: {index:string;create:string};
opportunities?: {index: string; create: string | null; profileWorkflow: boolean};
documents?: {index: string; edit: boolean};
};
@@ -11,7 +10,6 @@ export default function ContentHub({access, counts}: {access: Access; counts: Re
return <Frame title="Gestão de conteúdos e oportunidades">
<p>Use os cadastros e a biblioteca existentes. Guardar um rascunho, analisar um ficheiro e publicar são operações distintas. Cada acção respeita a sua autorização actual.</p>
<div className="grid gap-4 md:grid-cols-2">
{access.procurement && <section className={card}><h2 className="text-xl font-semibold">Concursos e anúncios</h2><p>Cadastre o procedimento e os lotes, guarde e recupere a preparação, reveja a prévia e publique os actos autorizados. Esclarecimentos, prorrogações, resultados e cancelamentos conservam versões e histórico. Divulgação de oportunidade e abertura de concurso são operações distintas.</p><Link className={button} href={access.procurement.create}>Novo concurso/anúncio</Link><Link className="block underline" href={access.procurement.index}>Gerir concursos e anúncios</Link><Link className="block underline" href="/concursos">Catálogo público</Link></section>}
{access.opportunities && <section className={card}>
<h2 className="text-xl font-semibold">Oportunidades</h2>
<p>Escolha a modalidade, o sector e a localização; preencha, guarde o rascunho e siga as acções de submissão, revisão e publicação disponíveis no seu perfil.</p>
+25 -184
View File
@@ -1,35 +1,14 @@
import { Link, useForm } from '@inertiajs/react';
import { useEffect, useState } from 'react';
import { Management, Field, button, control } from '../management/shared';
import EditorialReading, {
type EditorialArticle,
} from '@/components/editorial-reading';
type Content = {
body: string;
image_resource_id: number | null;
image_mode?: string;
};
type Content = { body: string; image_resource_id: number | null };
export default function ArticleEditor({
resource,
content,
source,
images,
revisions,
}: {
resource: {
id: number;
title: string;
metadata_version: number;
published: boolean;
};
resource: { id: number; title: string; metadata_version: number };
content: Content | null;
source?: {
source_url?: string;
image_source_url?: string;
published_at?: string;
modified_at?: string;
legacy_id?: number;
} | null;
images: { id: number; title: string }[];
revisions: {
revision_no: number;
@@ -37,107 +16,28 @@ export default function ArticleEditor({
created_at: string;
}[];
}) {
const initial = () => ({
const form = useForm({
body: content?.body ?? '',
image_resource_id: content?.image_resource_id
? String(content.image_resource_id)
: '',
image_mode:
content?.image_mode ??
(content?.image_resource_id ? 'selected' : 'none'),
metadata_version: resource.metadata_version,
});
const form = useForm(initial());
const [preview, setPreview] = useState<EditorialArticle | null>(null);
const [error, setError] = useState('');
const [busy, setBusy] = useState(false);
useEffect(() => {
form.setData(initial());
setPreview(null);
setError('');
}, [resource.id, resource.metadata_version]);
useEffect(() => {
setPreview(null);
}, [form.data.body, form.data.image_mode, form.data.image_resource_id]);
const showPreview = async () => {
setBusy(true);
setError('');
try {
const token = document.cookie
.split('; ')
.find((v) => v.startsWith('XSRF-TOKEN='))
?.slice(11);
const response = await fetch(
`/management/portal-services/resources/${resource.id}/article/preview`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'X-XSRF-TOKEN': decodeURIComponent(token ?? ''),
},
body: JSON.stringify(form.data),
},
);
const data = await response
.json()
.catch(() => ({
message:
'Não foi possível abrir a prévia. Recupere o editor e confirme a sessão e o MFA existentes.',
}));
if (!response.ok)
throw new Error(
Object.values(data.errors ?? {})
.flat()
.join(' ') ||
data.message ||
'Não foi possível preparar a prévia.',
);
setPreview(data.article);
} catch (e) {
setError(
e instanceof Error
? e.message
: 'Não foi possível preparar a prévia.',
);
} finally {
setBusy(false);
}
};
return (
<Management title={`Editar artigo — ${resource.title}`}>
<p>
O original, a origem e as versões permanecem na biblioteca.
Guardar cria uma revisão editorial e retira a publicação até à
sua acção expressa no acervo.
O original permanece intacto na biblioteca. Guardar o corpo
retira a publicação até à sua ação expressa no acervo.
</p>
<p role="status">
Revisão guardada {resource.metadata_version} ·{' '}
{resource.published ? 'Publicado' : 'Rascunho privado'}
</p>
{source && (
<p>
Original {source.legacy_id} · publicado em{' '}
{source.published_at} · modificado em {source.modified_at}.
A imagem de origem mantém a sua referência mesmo quando não
existe exemplar disponível.
</p>
)}
<form
className="max-w-3xl space-y-5"
onSubmit={(e) => {
e.preventDefault();
setError('');
form.put(
`/management/portal-services/resources/${resource.id}/article`,
);
}}
>
{!!Object.keys(form.errors).length && (
<div role="alert">
{Object.values(form.errors).join(' ')}
</div>
)}
<Field label="Corpo do artigo" error={form.errors.body}>
<textarea
className={control}
@@ -146,93 +46,36 @@ export default function ArticleEditor({
onChange={(e) => form.setData('body', e.target.value)}
/>
<p>
Texto simples, com uma linha em branco entre parágrafos.
Se mantiver o texto original, a leitura conserva também
a sua formatação; as correcções ficam numa edição
separada.
Texto simples. Separe os parágrafos com uma linha em
branco.
</p>
</Field>
<Field
label="Tratamento da imagem"
error={form.errors.image_mode}
label="Imagem da biblioteca"
error={form.errors.image_resource_id}
>
<select
className={control}
value={form.data.image_mode}
value={form.data.image_resource_id}
onChange={(e) =>
form.setData('image_mode', e.target.value)
form.setData('image_resource_id', e.target.value)
}
>
<option value="original">
Manter referência e imagem de origem disponível
</option>
<option value="selected">
Escolher imagem pública da biblioteca
</option>
<option value="none">
Não mostrar imagem nesta edição
</option>
<option value="">Sem imagem</option>
{images.map((i) => (
<option key={i.id} value={i.id}>
{i.title}
</option>
))}
</select>
</Field>
{form.data.image_mode === 'selected' && (
<Field
label="Imagem da biblioteca"
error={form.errors.image_resource_id}
>
<select
className={control}
value={form.data.image_resource_id}
onChange={(e) =>
form.setData(
'image_resource_id',
e.target.value,
)
}
>
<option value="">Seleccione uma imagem</option>
{images.map((i) => (
<option key={i.id} value={i.id}>
{i.title}
</option>
))}
</select>
</Field>
)}
<div className="flex flex-wrap gap-4">
<button className={button} disabled={form.processing}>
Guardar artigo como rascunho
</button>
<button
className={button}
type="button"
disabled={busy}
onClick={() => void showPreview()}
>
Pré-visualizar alterações
</button>
<Link
className="underline"
href={`/management/portal-services/resources/${resource.id}/article/preview`}
>
Ler revisão guardada
</Link>
<Link
className="underline"
href="/management/portal-services"
>
Voltar ao acervo para metadados e publicação
</Link>
</div>
<button className={button} disabled={form.processing}>
Guardar artigo como rascunho
</button>{' '}
<Link className="underline" href="/management/portal-services">
Voltar ao acervo
</Link>
</form>
{error && <p role="alert">{error}</p>}
{preview && (
<section
aria-label="Prévia das alterações"
className="my-6 max-w-3xl rounded border p-5"
>
<EditorialReading article={preview} />
</section>
)}
<h2>Histórico</h2>
<ul>
{revisions.map((r) => (
@@ -243,10 +86,8 @@ export default function ArticleEditor({
))}
</ul>
<p>
Título, descrição, autor, fonte, direitos e acesso são
corrigidos em Editar metadados no acervo. Carregue e analise
imagens na biblioteca antes de as seleccionar. Publicar continua
a ser uma acção separada.
Título, descrição, autor e fonte são editados em Editar
metadados no acervo.
</p>
</Management>
);
+31 -16
View File
@@ -1,27 +1,42 @@
import { Head, Link } from '@inertiajs/react';
import { PortalMenu } from '@/layouts/portal-navigation';
import EditorialReading, {
type EditorialArticle,
} from '@/components/editorial-reading';
export default function Article({ article }: { article: EditorialArticle }) {
export default function Article({
article,
}: {
article: {
id: number;
title: string;
description: string | null;
author: string | null;
body: string;
image_url: string | null;
original_url: string;
};
}) {
return (
<>
<Head title={article.title} />
<PortalMenu />
<main className="mx-auto max-w-3xl space-y-6 p-6">
<EditorialReading article={article} />
<h1 className="text-3xl font-bold">{article.title}</h1>
{article.description && <p>{article.description}</p>}
{article.author && <p>Autor / entidade: {article.author}</p>}
{article.image_url && (
<img src={article.image_url} alt="Imagem do artigo" />
)}
<article className="space-y-5">
{article.body.split(/\n\s*\n/).map((p, i) => (
<p className="whitespace-pre-wrap" key={i}>
{p}
</p>
))}
</article>
<Link href={article.original_url} className="underline">
Consultar documento original
</Link>
<p>
<Link
href={
article.private_preview
? `/management/portal-services/resources/${article.id}/article`
: '/documentos'
}
className="underline"
>
{article.private_preview
? 'Voltar ao editor'
: 'Voltar à biblioteca'}
<Link href="/documentos" className="underline">
Voltar à biblioteca
</Link>
</p>
</main>
-1
View File
@@ -1385,7 +1385,6 @@ export default function Manage({
>
Editar artigo
</a>
<a className={button} href={`/management/portal-services/resources/${r.id}/article/preview`}>Ler / pré-visualizar artigo</a>
<button
type="button"
className={button}
-832
View File
@@ -1,832 +0,0 @@
import { Link, router, useForm } from '@inertiajs/react';
import { useEffect, useState } from 'react';
import { Frame, card, button } from '@/pages/investment/shared';
import {
Field,
control,
labels,
acts,
NoticeContent,
type Draft,
type Lot,
type Attachment,
type Payload,
} from './shared';
type Choice = {
id: string | number;
name?: string;
title?: string;
location_type?: string;
published?: boolean;
malware_scan_status?: string;
};
type References = {
regimes: Record<string, string>;
acts: Record<string, string>;
organizations: Choice[];
sectors: Choice[];
territories: Choice[];
opportunities: Choice[];
projects: Choice[];
documents: Choice[];
};
type RecordData = {
id: string;
version: number;
draft: Draft;
published: boolean;
};
type Plan = {
id: string;
version: number;
act: string;
payload: Payload;
hash: string;
};
const dates = [
'origin_published_at',
'clarifications_at',
'deadline',
'opening_at',
];
const groups: [string, string[]][] = [
[
'Identificação e objecto',
['title', 'reference', 'modality', 'object', 'quantities'],
],
[
'Regime e financiamento',
[
'financier',
'instrument',
'edition',
'rule_source',
'financing_agreement',
],
],
['Participação', ['eligibility', 'requirements', 'proposal_validity']],
[
'Calendário e entrega',
[
'origin_published_at',
'clarifications_at',
'deadline',
'opening_at',
'delivery_channel',
'delivery_address',
'delivery_url',
],
],
['Divulgação e contacto', ['origin_url', 'dissemination']],
];
export default function Edit({
record,
references,
history,
}: {
record: RecordData | null;
references: References;
history: {
version: number;
act: string;
reason: string;
actor_id: number;
published_at: string | null;
created_at: string;
}[];
}) {
const empty: Draft = {
timezone: 'Africa/Maputo',
lots: [],
attachments: [],
contact_authorized: false,
};
const form = useForm({
version: record?.version ?? 0,
reason: '',
draft: record?.draft ?? empty,
});
const [act, setAct] = useState(
record?.published ? 'clarification' : 'initial',
);
const [preview, setPreview] = useState<Plan | null>(null);
const [message, setMessage] = useState('');
const [busy, setBusy] = useState(false);
const [saved, setSaved] = useState(true);
useEffect(() => {
form.setData({
version: record?.version ?? 0,
reason: '',
draft: record?.draft ?? empty,
});
setPreview(null);
setSaved(true);
}, [record?.id, record?.version]); // A server version is the recovery boundary.
const change = (key: string, value: Draft[string]) => {
form.setData('draft', { ...form.data.draft, [key]: value });
setPreview(null);
setSaved(false);
};
const value = (key: string) => String(form.data.draft[key] ?? '');
const select = (key: string, label: string, choices: Choice[]) => (
<Field label={label}>
<select
className={control}
value={value(key)}
onChange={(e) =>
change(
key,
e.target.value
? key === 'sector_id' || key === 'opportunity_id'
? Number(e.target.value)
: e.target.value
: null,
)
}
>
<option value="">Por indicar</option>
{choices.map((o) => (
<option key={o.id} value={o.id}>
{o.name ?? o.title}
{o.location_type ? ` · ${o.location_type}` : ''}
</option>
))}
</select>
</Field>
);
const input = (key: string, label?: string) => (
<Field key={key} label={label ?? labels[key] ?? key}>
{dates.includes(key) ? (
<input
type="datetime-local"
className={control}
value={value(key)}
onChange={(e) => change(key, e.target.value)}
/>
) : (
<textarea
className={control}
rows={key === 'object' ? 4 : 2}
value={value(key)}
onChange={(e) => change(key, e.target.value)}
/>
)}
</Field>
);
const lots = (form.data.draft.lots ?? []) as Lot[];
const attachments = (form.data.draft.attachments ?? []) as Attachment[];
const makePreview = async () => {
setBusy(true);
setMessage('');
try {
const token = document.cookie
.split('; ')
.find((v) => v.startsWith('XSRF-TOKEN='))
?.slice(11);
const response = await fetch(
`/management/concursos/${record!.id}/previa`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'X-XSRF-TOKEN': decodeURIComponent(token ?? ''),
},
body: JSON.stringify({ act }),
},
);
const body = await response.json();
if (!response.ok)
throw new Error(
Object.values(body.errors ?? {})
.flat()
.join(' ') ||
body.message ||
'Não foi possível preparar a prévia.',
);
setPreview(body);
} catch (error) {
setMessage(
error instanceof Error ? error.message : 'Erro de ligação.',
);
} finally {
setBusy(false);
}
};
return (
<Frame
title={record ? 'Editar concurso/anúncio' : 'Novo concurso/anúncio'}
>
<div className="flex flex-wrap gap-3">
<Link className="underline" href="/management/concursos">
Recuperar concursos
</Link>
<Link className="underline" href="/gestao-conteudos">
Entrada única de gestão
</Link>
<a
className="underline"
href="/management/portal-services?intent=document#receber"
target="_blank"
rel="noopener noreferrer"
>
Carregar / gerir documentos e scan na biblioteca (outra
página)
</a>
<button
className="underline"
type="button"
onClick={() => router.reload({ only: ['references'] })}
>
Actualizar opções da biblioteca
</button>
</div>
<p>
Os campos destinam-se à divulgação após revisão da prévia,
excepto as notas internas, os anexos não públicos e o contacto
sem autorização. O vínculo a um cadastro privado não publica os
seus dados.
</p>
<p>
O rascunho pode ficar incompleto. Alterações guardadas não
substituem o acto público; reveja a prévia e publique
explicitamente. Publicar concurso não publica a oportunidade nem
recebe propostas.
</p>
<p role="status">
{record
? `Versão guardada ${record.version}. ${saved ? 'Preparação recuperada do servidor.' : 'Há alterações por guardar.'}`
: 'Preparação ainda não guardada.'}
</p>
{!!Object.keys(form.errors).length && (
<div role="alert">
{Object.values(form.errors).map((error, i) => (
<p key={i}>{error}</p>
))}
</div>
)}
<form
className="space-y-5"
onSubmit={(e) => {
e.preventDefault();
setPreview(null);
record
? form.put(`/management/concursos/${record.id}`)
: form.post('/management/concursos');
}}
>
<section className={`${card} grid gap-3 md:grid-cols-2`}>
{select(
'organization_id',
'Entidade contratante existente',
references.organizations,
)}
{select(
'opportunity_id',
'Oportunidade relacionada existente',
references.opportunities,
)}
{select(
'project_id',
'Projecto existente',
references.projects,
)}
{select('sector_id', 'Sector', references.sectors)}
{select(
'territory_id',
'Localização existente',
references.territories,
)}
<p>
Os vínculos reutilizam os cadastros; não criam nova
entidade, oportunidade, projecto ou limite. Referências
privadas não são transformadas em conteúdo público.
</p>
</section>
<section className={card}>
<h2 className="text-xl font-semibold">
Regime do procedimento
</h2>
<Field label="Regime">
<select
className={control}
value={value('regime')}
onChange={(e) => change('regime', e.target.value)}
>
<option value="">Por indicar</option>
{Object.entries(references.regimes).map(
([v, l]) => (
<option key={v} value={v}>
{l}
</option>
),
)}
</select>
</Field>
{value('regime') === 'state' ? (
<>
<p>
Contratação do Estado: identifique a modalidade,
o instrumento e a edição aplicáveis.{' '}
<a
className="underline"
href="https://www.ufsa.gov.mz/divnovoreg.php"
rel="noopener noreferrer"
>
UFSA — Decreto n.º 79/2022
</a>
. A referência não atribui automaticamente
requisitos ou prazos a todos os procedimentos.
</p>
{input(
'responsible_unit',
'UGEA / unidade responsável quando aplicável',
)}
</>
) : (
<>
<p>
{value('regime') === 'external' ? (
<>
<a
className="underline"
href="https://www.worldbank.org/ext/en/what-we-do/project-procurement/framework"
>
Quadro e documentos normalizados do
Banco Mundial
</a>{' '}
são referências; indique a edição e o
acordo efectivamente aplicáveis.
</>
) : (
'Use as regras documentadas da entidade e deste procedimento.'
)}{' '}
UGEA, Cadastro Único, garantias e abertura
pública não são impostos a este regime.
</p>
{input(
'responsible_unit',
'Unidade responsável (quando aplicável)',
)}
</>
)}
<Field label="Obras, bens ou serviços">
<select
className={control}
value={value('object_kind')}
onChange={(e) =>
change('object_kind', e.target.value)
}
>
<option value="">Por indicar</option>
{Object.entries({
works: 'Obras',
goods: 'Bens',
services: 'Serviços',
mixed: 'Misto',
other: 'Outro',
}).map(([v, l]) => (
<option key={v} value={v}>
{l}
</option>
))}
</select>
</Field>
</section>
{groups.map(([title, fields]) => (
<section className={card} key={title}>
<h2 className="mb-3 text-xl font-semibold">{title}</h2>
<div className="grid gap-3 md:grid-cols-2">
{fields.map((key) =>
input(
key,
key === 'title'
? 'Título do concurso/anúncio'
: undefined,
),
)}
</div>
</section>
))}
<section className={`${card} space-y-3`}>
<h2 className="text-xl font-semibold">
Garantias e prazo mínimo documentado
</h2>
<Field label="Garantias exigidas neste procedimento">
<select
className={control}
value={value('guarantee_status')}
onChange={(e) =>
change('guarantee_status', e.target.value)
}
>
<option value="unknown">
Por determinar nos documentos
</option>
<option value="required">
Exigidas nos documentos
</option>
<option value="not_required">Não exigidas</option>
</select>
</Field>
{value('guarantee_status') === 'required' &&
input('guarantees')}
<Field label="Fuso horário IANA do procedimento">
<input
className={control}
value={value('timezone')}
onChange={(e) => change('timezone', e.target.value)}
placeholder="Africa/Maputo"
/>
</Field>
<p>
As datas e horas introduzidas pertencem a este fuso.
Publicação no InvesteMoz é registada separadamente pelo
servidor; não reinicia o prazo.
</p>
<Field label="Prazo mínimo documentado em dias (opcional)">
<input
className={control}
type="number"
min="0"
value={value('minimum_days')}
onChange={(e) =>
change(
'minimum_days',
e.target.value === ''
? null
: Number(e.target.value),
)
}
/>
</Field>
{form.data.draft.minimum_days !== null &&
form.data.draft.minimum_days !== undefined && (
<div className="grid gap-3 md:grid-cols-2">
{input('minimum_source')}
{input('minimum_edition')}
{input('minimum_modality')}
<Field label="Contagem documentada">
<select
className={control}
value={value('minimum_day_basis')}
onChange={(e) =>
change(
'minimum_day_basis',
e.target.value,
)
}
>
<option value="">Por indicar</option>
<option value="calendar">
Dias corridos
</option>
<option value="business">
Dias úteis — calendário documentado
</option>
</select>
</Field>
{value('minimum_day_basis') === 'business' && (
<>
{input(
'minimum_calendar_source',
'Fonte do calendário aplicável e abrangência de feriados',
)}
{input(
'minimum_working_days',
'Dias de trabalho documentados: 1=segunda a 7=domingo, separados por vírgula',
)}
{input(
'minimum_holidays',
'Feriados / exclusões documentados (AAAA-MM-DD, separados por espaço ou vírgula)',
)}
</>
)}
</div>
)}
<p>
Sem prazo parametrizado não é presumido um mínimo geral.
A contagem em dias úteis usa exclusivamente os dias de
trabalho e exclusões do calendário documentado neste
registo; não adopta um calendário nacional por
suposição.
</p>
</section>
<section className={`${card} space-y-3`}>
<h2 className="text-xl font-semibold">Lotes</h2>
{lots.map((lot, i) => (
<fieldset
className="grid gap-3 rounded border p-3 md:grid-cols-3"
key={i}
>
<legend>Lote {i + 1}</legend>
{(
['code', 'description', 'quantities'] as const
).map((key) => (
<Field
key={key}
label={
{
code: 'Referência do lote',
description: 'Objecto do lote',
quantities: 'Quantidades do lote',
}[key]
}
>
<textarea
className={control}
value={lot[key]}
onChange={(e) =>
change(
'lots',
lots.map((r, n) =>
n === i
? {
...r,
[key]: e.target
.value,
}
: r,
),
)
}
/>
</Field>
))}
<button
type="button"
className="underline"
onClick={() =>
change(
'lots',
lots.filter((_, n) => n !== i),
)
}
>
Retirar lote do rascunho
</button>
</fieldset>
))}
<button
type="button"
className={button}
onClick={() =>
change('lots', [
...lots,
{ code: '', description: '', quantities: '' },
])
}
>
Acrescentar lote
</button>
</section>
<section className={`${card} space-y-3`}>
<h2 className="text-xl font-semibold">
Documentos e anexos
</h2>
<p>
Carregue e classifique os originais na biblioteca
existente pelo link acima. Reutilize-os aqui: anúncio,
caderno, termos de referência, formulários, anexos ou
comprovativos. Publicar exige que cada anexo marcado
público já esteja autorizado, publicado e com scan limpo
na biblioteca. Os restantes ficam privados no cadastro.
</p>
{attachments.map((item, i) => (
<fieldset
key={i}
className="space-y-2 rounded border p-3"
>
<legend>Anexo {i + 1}</legend>
<Field label={`Documento do anexo ${i + 1}`}>
<select
className={control}
value={item.resource_id || ''}
onChange={(e) =>
change(
'attachments',
attachments.map((r, n) =>
n === i
? {
...r,
resource_id: Number(
e.target.value,
),
}
: r,
),
)
}
>
<option value="">
Seleccione da biblioteca
</option>
{references.documents.map((d) => (
<option key={d.id} value={d.id}>
{d.title} · {d.malware_scan_status}{' '}
·{' '}
{d.published
? 'publicado'
: 'privado / rascunho'}
</option>
))}
</select>
</Field>
<Field label={`Finalidade do anexo ${i + 1}`}>
<input
className={control}
value={item.purpose}
onChange={(e) =>
change(
'attachments',
attachments.map((r, n) =>
n === i
? {
...r,
purpose:
e.target.value,
}
: r,
),
)
}
/>
</Field>
<label>
<input
type="checkbox"
checked={item.public}
onChange={(e) =>
change(
'attachments',
attachments.map((r, n) =>
n === i
? {
...r,
public: e.target
.checked,
}
: r,
),
)
}
/>{' '}
Incluir este anexo na divulgação pública
</label>
<button
type="button"
className="ml-3 underline"
onClick={() =>
change(
'attachments',
attachments.filter((_, n) => n !== i),
)
}
>
Retirar anexo do rascunho
</button>
</fieldset>
))}
<button
type="button"
className={button}
onClick={() =>
change('attachments', [
...attachments,
{ resource_id: 0, purpose: '', public: false },
])
}
>
Reutilizar documento
</button>
</section>
<section className={`${card} space-y-3`}>
<h2 className="text-xl font-semibold">
Contacto e acto a divulgar
</h2>
{input('public_contact')}
<label className="block">
<input
type="checkbox"
checked={Boolean(
form.data.draft.contact_authorized,
)}
onChange={(e) =>
change('contact_authorized', e.target.checked)
}
/>{' '}
Contacto autorizado para divulgação pública
</label>
{input('result')}
{input(
'public_reason',
'Motivo público do acto — aparece na prévia e no histórico público',
)}
{input(
'internal_notes',
'Notas internas — nunca incluídas na divulgação',
)}
<Field label="Motivo interno da gravação (20–1000 caracteres)">
<textarea
className={control}
value={form.data.reason}
onChange={(e) =>
form.setData('reason', e.target.value)
}
/>
</Field>
<button className={button} disabled={form.processing}>
Guardar rascunho
</button>
</section>
</form>
{record && (
<section className={`${card} my-5 space-y-3`}>
<h2 className="text-xl font-semibold">
Pré-visualizar e publicar
</h2>
<Field label="Acto a publicar">
<select
className={control}
value={act}
onChange={(e) => {
setAct(e.target.value);
setPreview(null);
}}
>
{Object.entries(references.acts).map(([v, l]) => (
<option key={v} value={v}>
{l}
</option>
))}
</select>
</Field>
<button
className={button}
disabled={!saved || busy}
onClick={makePreview}
>
Preparar prévia pública
</button>
<p>
Guarde antes da prévia. Uma prorrogação identifica o
prazo anterior e o novo; o fim do prazo não é
adjudicação.
</p>
{message && <p role="alert">{message}</p>}
{preview && (
<div className="space-y-3 rounded border p-4">
<h3 className="text-xl font-semibold">
Prévia do conteúdo público — {acts[preview.act]}
</h3>
<p>
Motivo público:{' '}
{String(preview.payload.public_reason)}
</p>
<NoticeContent p={preview.payload} />
<button
className={button}
onClick={() =>
router.post(
`/management/concursos/${record.id}/publicar`,
{
act: preview.act,
hash: preview.hash,
reason: String(
preview.payload.public_reason,
),
},
{ onSuccess: () => setPreview(null) },
)
}
>
Publicar este acto
</button>
</div>
)}
{record.published && (
<Link
className="block underline"
href={`/concursos/${record.id}`}
>
Consultar anúncio público
</Link>
)}
</section>
)}
<section className={card}>
<h2 className="text-xl font-semibold">
Histórico de preparação e publicação
</h2>
{history.map((v) => (
<p key={v.version}>
Versão {v.version} ·{' '}
{v.act === 'draft' ? 'Rascunho' : acts[v.act]} ·
responsável {v.actor_id} ·{' '}
{v.published_at ?? v.created_at} · {v.reason}
</p>
))}
</section>
</Frame>
);
}
-196
View File
@@ -1,196 +0,0 @@
import { Link, useForm } from '@inertiajs/react';
import { Frame, card, button } from '@/pages/investment/shared';
import { Field, control, states, type Publication } from './shared';
type Choice = { id: string; name: string };
export default function Index({
items,
filters,
options,
regimes,
management,
}: {
items: {
data: { id: string; publication: Publication; state: string }[];
current_page: number;
links: { url: string | null; label: string; active: boolean }[];
};
filters: Record<string, string>;
options: Record<string, Choice[]>;
regimes: Record<string, string>;
management: boolean;
}) {
const form = useForm({
q: filters.q ?? '',
entity: filters.entity ?? '',
sector: filters.sector ?? '',
territory: filters.territory ?? '',
modality: filters.modality ?? '',
financier: filters.financier ?? '',
state: filters.state ?? '',
deadline_before: filters.deadline_before ?? '',
regime: filters.regime ?? '',
});
const query = new URLSearchParams(
Object.entries({ ...filters, page: String(items.current_page) }).filter(
([, v]) => v != null && v !== '',
),
).toString();
return (
<Frame title="Concursos e anúncios">
<p>
Procedimentos e actos divulgados pelas entidades responsáveis.
Uma oportunidade divulgada não é, por si, um concurso aberto.
</p>
<div className="flex flex-wrap gap-3">
<Link className="underline" href="/concursos/acompanhar">
Os concursos que acompanho
</Link>
{management && (
<Link className={button} href="/management/concursos">
Gerir concursos e anúncios
</Link>
)}
</div>
<form
className={`${card} grid gap-3 md:grid-cols-3`}
onSubmit={(e) => {
e.preventDefault();
form.get('/concursos', { preserveState: true });
}}
>
<Field label="Palavras-chave">
<input
className={control}
value={form.data.q}
onChange={(e) => form.setData('q', e.target.value)}
/>
</Field>
{(
[
'entity',
'sector',
'territory',
'modality',
'financier',
] as const
).map((key) => (
<Field
key={key}
label={
{
entity: 'Entidade',
sector: 'Sector',
territory: 'Localização',
modality: 'Modalidade',
financier: 'Financiador',
}[key]
}
>
<select
className={control}
value={form.data[key]}
onChange={(e) => form.setData(key, e.target.value)}
>
<option value="">Todos</option>
{(options[key] ?? []).map((o) => (
<option key={o.id} value={o.id}>
{o.name}
</option>
))}
</select>
</Field>
))}
<Field label="Regime">
<select
className={control}
value={form.data.regime}
onChange={(e) => form.setData('regime', e.target.value)}
>
<option value="">Todos</option>
{Object.entries(regimes).map(([v, l]) => (
<option key={v} value={v}>
{l}
</option>
))}
</select>
</Field>
<Field label="Estado">
<select
className={control}
value={form.data.state}
onChange={(e) => form.setData('state', e.target.value)}
>
<option value="">Todos</option>
{Object.entries(states).map(([v, l]) => (
<option key={v} value={v}>
{l}
</option>
))}
</select>
</Field>
<Field label="Prazo até (data local do procedimento)">
<input
className={control}
type="date"
value={form.data.deadline_before}
onChange={(e) =>
form.setData('deadline_before', e.target.value)
}
/>
</Field>
<button className={button}>Pesquisar</button>
</form>
{!items.data.length && (
<p role="status">Nenhum anúncio corresponde aos filtros.</p>
)}
<div className="grid gap-4 md:grid-cols-2">
{items.data.map((item) => (
<article key={item.id} className={card}>
<h2 className="text-xl font-semibold">
<Link
className="underline"
href={`/concursos/${item.id}${query ? '?' + query : ''}`}
>
{String(item.publication.payload.title)}
</Link>
</h2>
<p>
{String(item.publication.payload.organization_name)}{' '}
· {states[item.state]}
</p>
<p>
Entrega:{' '}
{String(item.publication.payload.deadline).replace(
'T',
' ',
)}{' '}
· {String(item.publication.payload.timezone)}
</p>
<p>{String(item.publication.payload.object)}</p>
</article>
))}
</div>
<nav aria-label="Paginação">
{items.links.map((link, i) =>
link.url ? (
<Link
key={i}
className={`mx-2 underline ${link.active ? 'font-bold' : ''}`}
href={link.url}
>
{link.label
.replace('&laquo;', '«')
.replace('&raquo;', '»')}
</Link>
) : (
<span key={i} className="mx-2">
{link.label
.replace('&laquo;', '«')
.replace('&raquo;', '»')}
</span>
),
)}
</nav>
</Frame>
);
}
-106
View File
@@ -1,106 +0,0 @@
import { Link } from '@inertiajs/react';
import { Frame, card, button } from '@/pages/investment/shared';
import { states, type Publication } from './shared';
export default function Manage({
items,
watched = false,
}: {
items: {
id: string;
title?: string;
version?: number;
published?: boolean;
publication?: Publication;
state?: string;
changed?: boolean;
}[];
watched?: boolean;
}) {
return (
<Frame
title={
watched
? 'Concursos que acompanho'
: 'Gestão de concursos e anúncios'
}
>
<Link className="underline" href="/concursos">
Catálogo público
</Link>
{!watched && (
<>
<Link className={button} href="/management/concursos/novo">
Novo concurso/anúncio
</Link>
<Link className="ml-3 underline" href="/gestao-conteudos">
Entrada única de gestão
</Link>
<p>
Guardar → recuperar → pré-visualizar → publicar →
actualizar/prorrogar → publicar resultado ou
cancelamento. Carregue documentos na biblioteca
existente, acompanhe o scan e autorize separadamente os
anexos públicos. O rascunho pode ficar incompleto.
</p>
<p>
Para actualizar, reabra o concurso, guarde as
alterações, escolha o acto e confira a prévia. A data de
publicação no portal não substitui a data de origem.
Acompanhar não apresenta proposta.
</p>
</>
)}
{!items.length && <p>Sem registos.</p>}
{items.map((item) => (
<article key={item.id} className={`${card} my-3`}>
<h2 className="font-semibold">
{item.title ?? String(item.publication?.payload.title)}
</h2>
{watched ? (
<>
<p>
{states[item.state ?? '']} ·{' '}
{item.changed
? 'Há novos actos desde que começou a acompanhar'
: 'Sem novos actos desde o registo de acompanhamento'}
</p>
<p>
O acompanhamento é consultado nesta área; não
afirma envio de alertas por email.
</p>
<Link
className="underline"
href={`/concursos/${item.id}`}
>
Consultar concurso
</Link>
</>
) : (
<>
<p>
Versão {item.version} ·{' '}
{item.published
? 'Com acto publicado; alterações em preparação são separadas'
: 'Rascunho privado'}
</p>
<Link
className="underline"
href={`/management/concursos/${item.id}`}
>
Recuperar e editar
</Link>
{item.published && (
<Link
className="ml-3 underline"
href={`/concursos/${item.id}`}
>
Consultar publicação
</Link>
)}
</>
)}
</article>
))}
</Frame>
);
}
-253
View File
@@ -1,253 +0,0 @@
import type { ReactNode } from 'react';
export type Lot = { code: string; description: string; quantities: string };
export type Attachment = {
resource_id: number;
public: boolean;
purpose: string;
title?: string;
available?: boolean;
};
export type Draft = {
[key: string]: string | number | boolean | null | Lot[] | Attachment[];
};
export type Payload = Draft & {
opportunity?: { title: string; url: string } | null;
};
export type Publication = {
id: string;
version: number;
act: string;
payload: Payload;
published_at: string;
reason: string;
};
export const states: Record<string, string> = {
open: 'Aberto',
extended: 'Prorrogado',
deadline_ended: 'Prazo de propostas terminado',
cancelled: 'Cancelado',
results: 'Resultados publicados',
};
export const acts: Record<string, string> = {
initial: 'Anúncio inicial',
clarification: 'Esclarecimento',
correction: 'Rectificação',
extension: 'Prorrogação',
award: 'Resultado / adjudicação',
cancellation: 'Cancelamento',
other: 'Outro acto',
};
export const labels: Record<string, string> = {
reference: 'Referência',
object: 'Objecto',
responsible_unit: 'Unidade responsável / UGEA quando aplicável',
modality: 'Modalidade',
object_kind: 'Natureza do objecto',
quantities: 'Quantidades essenciais',
financier: 'Financiador',
instrument: 'Instrumento aplicável',
edition: 'Edição aplicável',
rule_source: 'Fonte das regras',
financing_agreement: 'Acordo de financiamento',
eligibility: 'Elegibilidade',
requirements: 'Requisitos de participação',
proposal_validity: 'Validade da proposta',
guarantee_status: 'Aplicabilidade de garantias',
guarantees: 'Garantias documentadas',
delivery_channel: 'Canal de entrega',
delivery_address: 'Endereço / instruções para apresentar proposta',
delivery_url: 'Plataforma de entrega',
public_contact: 'Contacto público autorizado',
dissemination: 'Meios de divulgação exigidos / adoptados e comprovativos',
origin_url: 'Anúncio de origem',
origin_published_at: 'Publicação de origem — referência do prazo',
clarifications_at: 'Limite para esclarecimentos',
deadline: 'Entrega de propostas',
opening_at: 'Abertura (quando aplicável)',
timezone: 'Fuso horário do procedimento',
minimum_days: 'Prazo mínimo documentado (dias)',
minimum_source: 'Fonte / citação do prazo mínimo',
minimum_edition: 'Edição da regra de prazo',
minimum_modality: 'Modalidade da regra de prazo',
minimum_day_basis: 'Base de contagem do prazo',
minimum_calendar_source: 'Fonte do calendário de dias úteis',
minimum_working_days: 'Dias de trabalho (1=segunda, 7=domingo)',
minimum_holidays: 'Feriados e exclusões documentados',
result: 'Acto ou resultado documentado',
};
export const control =
'w-full rounded border border-slate-400 bg-background p-2 text-foreground';
export function Field({
label,
children,
}: {
label: string;
children: ReactNode;
}) {
return (
<label className="block space-y-1">
<span className="font-medium">{label}</span>
{children}
</label>
);
}
export function NoticeContent({ p }: { p: Payload }) {
const links = ['rule_source', 'origin_url', 'delivery_url'];
const names: Record<string, string> = {
works: 'Obras',
goods: 'Bens',
services: 'Serviços',
mixed: 'Misto',
other: 'Outro',
required: 'Exigidas',
not_required: 'Não exigidas',
unknown: 'Por determinar',
calendar: 'Dias corridos',
business: 'Dias úteis',
};
return (
<div className="space-y-5">
<h2 className="text-2xl font-semibold">{String(p.title ?? '')}</h2>
<p>
<strong>Entidade:</strong>{' '}
{String(p.organization_name ?? 'Por indicar')}
</p>
<p>
Regime:{' '}
{(
{
state: 'Contratação pública do Estado',
external: 'Financiamento externo',
private: 'Concurso privado',
other: 'Outro regime documentado',
} as Record<string, string>
)[String(p.regime)] ?? 'Por indicar'}
</p>
<section>
<h3 className="text-lg font-semibold">
Objecto e como participar
</h3>
<p className="whitespace-pre-wrap">{String(p.object ?? '')}</p>
<p className="my-2 rounded border p-3">
<strong>Entrega:</strong>{' '}
{String(p.deadline ?? 'Por indicar').replace('T', ' ')} ·{' '}
{String(p.timezone ?? '')}
<br />
{String(p.delivery_channel ?? '')} ·{' '}
{String(p.delivery_address ?? '')}
</p>
<p>
Sector: {String(p.sector_name ?? 'Por indicar')} ·
Localização: {String(p.territory_name ?? 'Por indicar')}
</p>
{p.project_name && (
<p>
Projecto relacionado: {String(p.project_name)}. Esta
relação não confirma execução ou contratação.
</p>
)}
{p.opportunity && (
<a className="underline" href={p.opportunity.url}>
Oportunidade relacionada: {p.opportunity.title}
</a>
)}
</section>
{p.deadline_previous && (
<p className="rounded border p-3">
<strong>Prorrogação:</strong> prazo anterior{' '}
{String(p.deadline_previous).replace('T', ' ')} (
{String(p.timezone_previous)}) → novo prazo{' '}
{String(p.deadline).replace('T', ' ')} ({String(p.timezone)}
).
</p>
)}
<dl className="grid gap-3 md:grid-cols-2">
{Object.entries(labels)
.filter(
([key]) =>
p[key] !== null &&
p[key] !== undefined &&
p[key] !== '',
)
.map(([key, label]) => (
<div
key={key}
className="rounded border p-3 break-words"
>
<dt className="font-semibold">{label}</dt>
<dd className="whitespace-pre-wrap">
{links.includes(key) ? (
<a
className="underline"
href={String(p[key])}
rel="noopener noreferrer"
>
{String(p[key])}
</a>
) : (
(
names[String(p[key])] ?? String(p[key])
).replace(/^(\d{4}-\d{2}-\d{2})T/, '$1 ')
)}
</dd>
</div>
))}
</dl>
<section>
<h3 className="text-lg font-semibold">Lotes</h3>
{((p.lots ?? []) as Lot[]).length ? (
<ul>
{(p.lots as Lot[]).map((lot, i) => (
<li key={i}>
{lot.code} — {lot.description} ·{' '}
{lot.quantities}
</li>
))}
</ul>
) : (
<p>Sem lotes indicados.</p>
)}
</section>
<section>
<h3 className="text-lg font-semibold">
Documentos do concurso
</h3>
<ul>
{((p.attachments ?? []) as Attachment[]).map((item, i) => (
<li key={i}>
{item.available === false ? (
<span>
{item.title} — documento actualmente
indisponível
</span>
) : (
<a
className="underline"
href={`/documentos/${item.resource_id}/download`}
>
{item.title ??
`Documento ${item.resource_id}`}{' '}
— {item.purpose}
</a>
)}
</li>
))}
</ul>
{!((p.attachments as Attachment[]) ?? []).length && (
<p>
Sem anexos públicos neste acto. Consulte o canal e o
anúncio de origem.
</p>
)}
</section>
<p className="rounded border p-3">
O InvesteMoz divulga este acto e não recebe propostas nesta
secção. Apresente a proposta no canal indicado nos documentos.
Esta divulgação não substitui os meios oficiais exigidos,
não comprova envio à UFSA ou ao financiador e não equivale à
execução do investimento.
</p>
</div>
);
}
-89
View File
@@ -1,89 +0,0 @@
import { Head, Link, router, usePage } from '@inertiajs/react';
import { Frame, card, button } from '@/pages/investment/shared';
import { NoticeContent, states, acts, type Publication } from './shared';
export default function Show({
id,
publication,
state,
history,
watching,
backUrl,
printMode,
}: {
id: string;
publication: Publication;
state: string;
history: Publication[];
watching: boolean;
backUrl: string;
printMode: boolean;
}) {
const { auth } = usePage<{ auth: { user: unknown | null } }>().props;
return (
<Frame title="Concurso e anúncio">
<Head title={String(publication.payload.title)} />
<style>
{
'@media print { nav, header, aside, footer, [data-slot="sidebar"], .no-print {display:none!important} main {margin:0!important; width:100%!important} details {display:block} }'
}
</style>
<div className="no-print flex flex-wrap gap-4">
<Link className="underline" href={backUrl}>
Voltar aos resultados
</Link>
<Link className="underline" href={`/concursos/${id}/imprimir`}>
Relatório imprimível
</Link>
{printMode && (
<button className={button} onClick={() => window.print()}>
Imprimir anúncio
</button>
)}
{auth?.user ? (
<button
className={button}
onClick={() =>
watching
? router.delete(`/concursos/${id}/acompanhar`)
: router.put(`/concursos/${id}/acompanhar`)
}
>
{watching
? 'Deixar de acompanhar'
: 'Acompanhar concurso'}
</button>
) : (
<Link className="underline" href="/login">
Entrar para acompanhar — conta simples
</Link>
)}
</div>
<p className="rounded border p-3">
<strong>{states[state]}</strong> · {acts[publication.act]} ·
Versão {publication.version}
</p>
<p>
Publicação deste acto no InvesteMoz: {publication.published_at}{' '}
(UTC). Esta data não reinicia o prazo de origem.
</p>
<article className={card}>
<NoticeContent p={publication.payload} />
</article>
<section className={card}>
<h2 className="text-xl font-semibold">
Actos publicados e histórico
</h2>
{history.map((v) => (
<details key={v.id} open={printMode}>
<summary>
{acts[v.act]} · versão {v.version} ·{' '}
{v.published_at} (UTC)
</summary>
<p className="my-2">Motivo público: {v.reason}</p>
<NoticeContent p={v.payload} />
</details>
))}
</section>
</Frame>
);
}
-20
View File
@@ -1,20 +0,0 @@
<?php
use App\Http\Controllers\ProcurementController as Procurement;
use Illuminate\Support\Facades\Route;
Route::get('/concursos', [Procurement::class, 'index'])->name('procurement.index');
Route::get('/concursos/acompanhar', [Procurement::class, 'watched'])->middleware('auth');
Route::get('/concursos/{id}', [Procurement::class, 'show'])->whereUuid('id')->name('procurement.show');
Route::get('/concursos/{id}/imprimir', [Procurement::class, 'print'])->whereUuid('id');
Route::put('/concursos/{id}/acompanhar', [Procurement::class, 'watch'])->whereUuid('id')->middleware(['auth', 'throttle:30,1']);
Route::delete('/concursos/{id}/acompanhar', [Procurement::class, 'unwatch'])->whereUuid('id')->middleware(['auth', 'throttle:30,1']);
Route::middleware(['auth', 'verified'])->prefix('management/concursos')->group(function () {
Route::get('/', [Procurement::class, 'manage']);
Route::get('/novo', [Procurement::class, 'edit']);
Route::post('/', [Procurement::class, 'save']);
Route::get('/{id}', [Procurement::class, 'edit'])->whereUuid('id');
Route::put('/{id}', [Procurement::class, 'save'])->whereUuid('id');
Route::post('/{id}/previa', [Procurement::class, 'preview'])->whereUuid('id');
Route::post('/{id}/publicar', [Procurement::class, 'publish'])->whereUuid('id');
});
-4
View File
@@ -1,7 +1,5 @@
<?php
require __DIR__.'/procurement.php';
require __DIR__.'/existing-business.php';
require __DIR__.'/territorial-registry.php';
require __DIR__.'/partnerships.php';
@@ -71,8 +69,6 @@ Route::middleware(['auth', 'verified'])->group(function () {
Route::middleware(['auth', 'verified', \App\Http\Middleware\EnsureScopedEditorial::class])->group(function () {
Route::get('/management/portal-services/resources/{id}/article', [\App\Http\Controllers\EditorialArticleController::class, 'edit'])->whereNumber('id')->name('editorial.edit');
Route::put('/management/portal-services/resources/{id}/article', [\App\Http\Controllers\EditorialArticleController::class, 'save'])->whereNumber('id')->name('editorial.save');
Route::get('/management/portal-services/resources/{id}/article/preview', [\App\Http\Controllers\EditorialArticleController::class, 'preview'])->whereNumber('id')->name('editorial.preview');
Route::post('/management/portal-services/resources/{id}/article/preview', [\App\Http\Controllers\EditorialArticleController::class, 'previewContent'])->whereNumber('id')->name('editorial.preview-content');
Route::get('/management/editorial-installation', [\App\Http\Controllers\EditorialArticleController::class, 'installation'])->name('editorial.installation');
Route::get('/management/editorial-installation/mfa', [\App\Http\Controllers\EditorialArticleController::class, 'showMfa'])->name('editorial.mfa');
Route::post('/management/editorial-installation/mfa', [\App\Http\Controllers\EditorialArticleController::class, 'confirmMfa'])->middleware('throttle:5,1');
@@ -1,173 +0,0 @@
<?php
namespace Tests\Feature;
use App\Models\User;
use App\Services\EditorialReading;
use App\Services\LegacyContent;
use App\Services\Malware\MalwareScanner;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Inertia\Testing\AssertableInertia as Assert;
use Tests\TestCase;
class LegacyEditorialWorkflowTest extends TestCase
{
use DatabaseTransactions;
private User $editor;
private $resources;
protected function setUp(): void
{
parent::setUp();
$db = DB::selectOne('select current_database() as name,inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test', $db->name);
$this->assertSame(55441, (int) $db->port);
$this->withoutVite();
$identities = json_decode(file_get_contents(config_path('legacy_editorial_resources.json')), true);
$this->resources = DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->whereIn('d.external_id', array_column($identities, 'external_id'))->orderBy('r.id')->get(['r.*']);
$this->assertCount(28, $this->resources);
$this->editor = User::factory()->create();
config(['portal.managers' => [$this->editor->email]]);
$this->actingAs($this->editor);
}
private function payload(object $r, string $body): array
{
return ['metadata_version' => (int) $r->metadata_version, 'body' => $body, 'image_mode' => 'original', 'image_resource_id' => null];
}
public function test_all_28_open_from_existing_originals_and_private_previews_without_reimport_or_save(): void
{
$before = DB::table('portal_resource_revisions')->count();
$service = app(EditorialReading::class);
foreach ($this->resources as $r) {
$original = $service->original($r);
$this->assertNotEmpty($original['content_html']);
$text = fn (string $html) => preg_replace('/\s+/u', '', html_entity_decode(strip_tags($html), ENT_QUOTES | ENT_HTML5, 'UTF-8'));
$this->assertSame($text($original['content_html']), $text(app(LegacyContent::class)->sanitize($original['content_html'], true)), 'Reader must preserve the original text, including inline spans and table cells.');
$this->assertStringStartsWith('https://investemoz.tempo.co.mz/', $service->reading($r, null, true)['image_source_url']);
$this->get('/management/portal-services/resources/'.$r->id.'/article')->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertInertia(fn (Assert $p) => $p->where('source.legacy_id', $original['legacy_id'])->where('content.body', $service->content($r, $original)['body']));
$this->get('/management/portal-services/resources/'.$r->id.'/article/preview')->assertOk()->assertHeader('X-Robots-Tag', 'noindex, nofollow')->assertInertia(fn (Assert $p) => $p->where('article.private_preview', true)->where('article.source_url', $original['source_url'])->where('article.legacy_id', $original['legacy_id']));
$this->get('/artigos/'.$r->id)->assertNotFound();
}
$this->assertSame($before, DB::table('portal_resource_revisions')->count());
}
public function test_review_changes_save_recover_versions_and_stale_previews_preserve_original(): void
{
$r = $this->resources->first(fn ($item) => ! $item->editorial_content);
$original = app(EditorialReading::class)->original($r);
$sha = DB::table('documents')->where('id', $r->document_id)->value('sha256');
$payload = $this->payload($r, 'Correcção editorial sintética QA; preservar o original e não publicar.');
$this->postJson('/management/portal-services/resources/'.$r->id.'/article/preview', $payload)->assertOk()->assertJsonPath('article.body', $payload['body']);
$this->assertNull(DB::table('portal_resources')->where('id', $r->id)->value('editorial_content'));
$this->put('/management/portal-services/resources/'.$r->id.'/article', $payload)->assertSessionHasNoErrors()->assertRedirect();
$this->get('/management/portal-services/resources/'.$r->id.'/article')->assertInertia(fn (Assert $p) => $p->where('resource.metadata_version', (int) $r->metadata_version + 1)->where('content.body', $payload['body']));
$this->postJson('/management/portal-services/resources/'.$r->id.'/article/preview', $payload)->assertConflict();
$this->put('/management/portal-services/resources/'.$r->id.'/article', $payload)->assertConflict();
$payload['metadata_version']++;
$payload['body'] .= ' Segunda revisão.';
$this->put('/management/portal-services/resources/'.$r->id.'/article', $payload)->assertSessionHasNoErrors()->assertRedirect();
$this->get('/management/portal-services/resources/'.$r->id.'/article/preview')->assertInertia(fn (Assert $p) => $p->where('article.body', $payload['body'])->where('article.source_url', $original['source_url']));
$this->assertSame($sha, DB::table('documents')->where('id', $r->document_id)->value('sha256'));
$this->assertSame($original, app(EditorialReading::class)->original($r));
$this->assertFalse((bool) DB::table('portal_resources')->where('id', $r->id)->value('published'));
$this->assertGreaterThanOrEqual(2, DB::table('portal_resource_revisions')->where('resource_id', $r->id)->count());
}
public function test_publication_remains_explicit_and_reader_works_before_first_editorial_save(): void
{
$r = $this->resources->first(fn ($item) => ! $item->editorial_content);
$original = app(EditorialReading::class)->original($r);
$this->post('/management/portal-services/resources/'.$r->id, ['published' => true])->assertSessionHasErrors();
$document = DB::table('documents')->find($r->document_id);
$metadata = ['document_id' => $r->document_id, 'title' => $r->title, 'category' => $r->category, 'topic' => $r->topic, 'issuer' => $document->issuer,
'document_type' => $r->document_type, 'language' => 'pt', 'description' => 'Arquivo editorial QA. Sem oportunidade concreta ou regra activa.',
'source_url' => $r->source_url, 'source_reference' => $r->source_reference, 'source_confirmation' => 'identified', 'legal_status' => 'historical', 'rights_status' => 'authorized', 'data_classification' => 'public', 'metadata_version' => $r->metadata_version, 'associations' => [],
'territorial_scope' => 'unknown', 'independent_review' => false, 'legislation' => false, 'essential' => false];
$this->put('/management/portal-services/resources/'.$r->id, $metadata)->assertSessionHasNoErrors()->assertRedirect();
$this->get('/artigos/'.$r->id)->assertNotFound();
$this->post('/management/portal-services/resources/'.$r->id, ['published' => true])->assertSessionHasNoErrors()->assertRedirect();
Auth::logout();
$this->app['auth']->forgetGuards();
$this->get('/artigos/'.$r->id)->assertOk()->assertInertia(fn (Assert $p) => $p->where('article.legacy_id', $original['legacy_id'])->where('article.private_preview', false));
$this->get('/documentos/'.$r->id)->assertOk()->assertInertia(fn (Assert $p) => $p->where('articleUrl', '/artigos/'.$r->id));
$this->actingAs($this->editor);
$current = DB::table('portal_resources')->find($r->id);
$this->put('/management/portal-services/resources/'.$r->id.'/article', $this->payload($current, 'Edição sintética depois da publicação; revisão expressa necessária.'))->assertRedirect();
$this->get('/artigos/'.$r->id)->assertNotFound();
}
public function test_named_editorial_scope_reuses_28_exact_original_identities_and_mfa_without_global_grant(): void
{
$actor = $this->editor;
$other = User::factory()->create();
$actor->forceFill(['two_factor_secret' => Crypt::encryptString('JBSWY3DPEHPK3PXP'), 'two_factor_confirmed_at' => now()])->save();
config(['portal.profile_access_enabled' => true, 'portal.managers' => [], 'homologation_editorial.accounts' => [$actor->email]]);
DB::table('portal_superuser_pair')->updateOrInsert(['id' => 1], ['first_user_id' => $actor->id, 'second_user_id' => $other->id, 'approved_by' => $other->id]);
$this->withSession(['portal.mfa_actor' => $actor->id, 'portal.mfa_at' => time(), 'portal.access_revision' => (int) $actor->portal_access_revision]);
$this->get('/management/portal-services/resources/'.$this->resources->first()->id.'/article/preview')->assertOk();
$this->assertFalse($actor->can('manage-portal'));
DB::table('documents')->where('id', $this->resources->first()->document_id)->update(['external_id' => 'destination-upload-qa-identity', 'source_system' => 'portal-services']);
$this->get('/management/portal-services/resources/'.$this->resources->first()->id.'/article/preview')->assertOk();
$this->get('/management/portal-services/resources/38/article/preview')->assertForbidden();
$this->withSession(['portal.mfa_at' => time() - 901])->get('/management/portal-services/resources/'.$this->resources->first()->id.'/article/preview')->assertForbidden();
$this->actingAs($other)->get('/management/portal-services/resources/'.$this->resources->first()->id.'/article/preview')->assertForbidden();
}
public function test_structured_original_is_sanitized_and_unavailable_images_are_explicit(): void
{
$html = app(LegacyContent::class)->sanitize('<div onclick="evil()"><table><tr><td>Conteúdo</td></tr></table><script>evil()</script><a href="javascript:evil()">Ligação</a></div>', true);
$this->assertStringContainsString('<table>', $html);
$this->assertStringContainsString('Conteúdo', $html);
$this->assertStringNotContainsString('evil', $html);
$this->assertStringNotContainsString('onclick', $html);
$r = $this->resources->first(fn ($item) => ! $item->editorial_content);
$data = app(EditorialReading::class)->reading($r, null, true);
if (! $data['image_url']) {
$this->assertNotEmpty($data['image_notice']);
}
$payload = $this->payload($r, app(EditorialReading::class)->content($r, app(EditorialReading::class)->original($r))['body']);
$payload['image_mode'] = 'selected';
$payload['image_resource_id'] = 999999;
$this->postJson('/management/portal-services/resources/'.$r->id.'/article/preview', $payload)->assertUnprocessable();
}
public function test_team_selects_a_real_scanned_image_and_withdrawal_never_exposes_private_bytes(): void
{
config(['queue.default' => 'sync', 'services.malware.scanner' => 'clamd', 'services.malware.socket' => null, 'services.malware.host' => '127.0.0.1', 'services.malware.port' => 3310]);
$this->assertTrue(app(MalwareScanner::class)->health()['available']);
$name = 'synthetic-editorial-'.Str::uuid().'.png';
$bytes = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+jVmkAAAAASUVORK5CYII=');
$this->post('/management/portal-services/upload', ['file' => UploadedFile::fake()->createWithContent($name, $bytes)])->assertSessionHasNoErrors();
$doc = DB::table('documents')->where('file_name', $name)->first();
$this->assertNotNull($doc);
try {
$this->assertSame('clean', $doc->malware_scan_status);
$metadata = ['document_id' => $doc->id, 'title' => 'Imagem sintética QA', 'issuer' => 'Synthetic QA', 'category' => 'education', 'topic' => 'legacy-archive', 'document_type' => 'unknown', 'language' => 'pt', 'source_url' => 'https://example.invalid/qa-image.png', 'source_reference' => 'Imagem sintética para ensaio transaccional, não é original do legado.', 'source_confirmation' => 'identified', 'legal_status' => 'not_applicable', 'rights_status' => 'authorized', 'data_classification' => 'public', 'territorial_scope' => 'unknown', 'independent_review' => false, 'legislation' => false, 'essential' => false, 'associations' => []];
$this->post('/management/portal-services/resources', $metadata)->assertSessionHasNoErrors();
$image = DB::table('portal_resources')->where('document_id', $doc->id)->first();
$this->post('/management/portal-services/resources/'.$image->id, ['published' => true])->assertSessionHasNoErrors();
$r = $this->resources->first();
$payload = $this->payload($r, 'Texto sintético de prévia com selecção de imagem.');
$payload['image_mode'] = 'selected';
$payload['image_resource_id'] = $image->id;
$this->postJson('/management/portal-services/resources/'.$r->id.'/article/preview', $payload)->assertOk()->assertJsonPath('article.image_url', '/documentos/'.$image->id.'/view');
$this->post('/management/portal-services/resources/'.$image->id, ['published' => false])->assertSessionHasNoErrors();
$this->postJson('/management/portal-services/resources/'.$r->id.'/article/preview', $payload)->assertUnprocessable();
Auth::logout();
$this->app['auth']->forgetGuards();
$this->get('/documentos/'.$image->id.'/view')->assertNotFound();
} finally {
Storage::disk('local')->delete($doc->storage_key);
}
}
}
-217
View File
@@ -1,217 +0,0 @@
<?php
namespace Tests\Feature;
use App\Models\User;
use App\Services\Malware\MalwareScanner;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Inertia\Testing\AssertableInertia as Assert;
use Tests\TestCase;
class ProcurementTest extends TestCase
{
use DatabaseTransactions;
private User $editor;
private string $organization;
protected function setUp(): void
{
parent::setUp();
$identity = DB::selectOne('select current_database() as database,inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test', $identity->database);
$this->assertSame(55441, (int) $identity->port);
$this->withoutVite();
$this->editor = User::factory()->create();
config(['procurement.enabled' => true, 'portal.managers' => [$this->editor->email]]);
$this->organization = (string) Str::uuid();
DB::table('organizations')->insert(['id' => $this->organization, 'name' => 'SINTÉTICO QA — Entidade de ensaio', 'organization_type' => 'private']);
$this->actingAs($this->editor);
}
private function payload(string $regime = 'state'): array
{
return ['title' => 'SINTÉTICO QA — '.$regime, 'reference' => 'QA-'.Str::uuid(), 'organization_id' => $this->organization,
'regime' => $regime, 'modality' => 'Modalidade documentada de ensaio', 'object' => 'Objecto sintético de concurso para ensaio QA; não corresponde a contratação real.',
'instrument' => $regime === 'state' ? 'Decreto n.º 79/2022 — referência do âmbito estatal' : 'Regras documentadas do procedimento sintético',
'edition' => $regime === 'external' ? 'Banco Mundial, Setembro/2025 — exemplar de referência' : 'QA-2026',
'rule_source' => $regime === 'state' ? 'https://www.ufsa.gov.mz/divnovoreg.php' : 'https://example.invalid/qa-rules',
'origin_published_at' => '2026-10-20T09:00', 'deadline' => '2026-11-20T15:00', 'timezone' => 'Africa/Maputo',
'delivery_channel' => 'Canal externo documentado', 'delivery_address' => 'Endereço sintético para ensaio; não enviar propostas.',
'public_contact' => 'contacto-interno-que-nao-deve-sair@example.test', 'contact_authorized' => false, 'internal_notes' => 'SEGREDO-INTERNO-QA',
'public_reason' => 'Divulgação de anúncio sintético para ensaio QA, sem contratação real.',
'lots' => [['code' => 'L1', 'description' => 'Lote de bens sintéticos', 'quantities' => '10 unidades de ensaio']], 'attachments' => []];
}
private function create(array $payload): string
{
$response = $this->post('/management/concursos', ['version' => 0, 'reason' => 'Preparação sintética documentada para ensaio QA.', 'draft' => $payload])->assertSessionHasNoErrors()->assertRedirect();
return basename(parse_url($response->headers->get('Location'), PHP_URL_PATH));
}
private function save(string $id, array $payload): void
{
$this->put('/management/concursos/'.$id, ['version' => DB::table('portal_tenders')->where('id', $id)->value('version'), 'reason' => 'Actualização sintética de ensaio com histórico conservado.', 'draft' => $payload])->assertRedirect()->assertSessionHasNoErrors();
}
private function publish(string $id, string $act = 'initial'): array
{
$plan = $this->postJson('/management/concursos/'.$id.'/previa', ['act' => $act])->assertOk()->json();
$this->post('/management/concursos/'.$id.'/publicar', ['act' => $act, 'hash' => $plan['hash'], 'reason' => $plan['payload']['public_reason']])->assertRedirect()->assertSessionHasNoErrors();
return $plan;
}
public function test_incomplete_draft_recovers_without_becoming_public_and_rejects_stale_save(): void
{
$id = $this->create(['title' => 'Preparação incompleta']);
$this->get('/management/concursos/'.$id)->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertInertia(fn (Assert $p) => $p->component('procurement/edit')->where('record.draft.title', 'Preparação incompleta'));
$this->get('/concursos/'.$id)->assertNotFound();
$this->postJson('/management/concursos/'.$id.'/previa', ['act' => 'initial'])->assertUnprocessable()->assertJsonValidationErrors(['organization_id', 'deadline', 'regime']);
$this->putJson('/management/concursos/'.$id, ['version' => 0, 'reason' => 'Pedido concorrente obsoleto, sem sobrescrever o rascunho.', 'draft' => ['title' => 'Não guardar']])->assertConflict();
$this->assertSame(1, DB::table('portal_tender_versions')->where('tender_id', $id)->count());
}
public function test_state_external_private_regimes_and_filters_are_public_without_ug_ea_or_guarantee_defaults(): void
{
$ids = [];
foreach (['state', 'external', 'private'] as $regime) {
$p = $this->payload($regime);
$ids[$regime] = $this->create($p);
$plan = $this->publish($ids[$regime]);
$this->assertArrayNotHasKey('responsible_unit', $plan['payload']);
$this->assertArrayNotHasKey('internal_notes', $plan['payload']);
$this->assertArrayNotHasKey('public_contact', $plan['payload']);
}
Auth::logout();
$this->get('/concursos?regime=external&entity='.$this->organization.'&q=SINT')->assertOk()->assertInertia(fn (Assert $p) => $p->component('procurement/index')->where('filters.regime', 'external')->has('items.data', 1)->where('items.data.0.id', $ids['external']));
$this->get('/concursos?q=&entity=&sector=&state=open')->assertOk()->assertInertia(fn (Assert $p) => $p->where('filters', ['state' => 'open']));
$this->get('/concursos/'.$ids['private'].'?regime=private&q=SINT&page=2')->assertOk()->assertInertia(fn (Assert $p) => $p->component('procurement/show')->where('backUrl', '/concursos?q=SINT&regime=private&page=2')->where('publication.payload.regime', 'private')->missing('publication.payload.internal_notes')->missing('publication.payload.public_contact')->has('history', 1));
$this->get('/concursos/'.$ids['state'].'/imprimir')->assertOk()->assertInertia(fn (Assert $p) => $p->where('printMode', true));
}
public function test_extension_preserves_publication_origin_and_history_and_expiry_is_not_an_award(): void
{
$p = $this->payload();
$id = $this->create($p);
$this->publish($id);
$first = DB::table('portal_tender_versions')->where('tender_id', $id)->where('act', 'initial')->first();
$p['deadline'] = '2026-11-25T16:00';
$this->save($id, $p);
$this->postJson('/management/concursos/'.$id.'/previa', ['act' => 'correction'])->assertUnprocessable()->assertJsonValidationErrors('act');
$plan = $this->publish($id, 'extension');
$this->assertSame('2026-11-20T15:00', $plan['payload']['deadline_previous']);
$this->assertSame('2026-10-20T09:00', $plan['payload']['origin_published_at']);
$this->assertSame($first->payload, DB::table('portal_tender_versions')->where('id', $first->id)->value('payload'));
$this->travelTo(now()->setDate(2026, 11, 26));
$this->get('/concursos/'.$id)->assertInertia(fn (Assert $p) => $p->where('state', 'deadline_ended')->where('publication.act', 'extension')->has('history', 2));
$this->travelBack();
$p['result'] = 'Resultado sintético de ensaio, não adjudicação real.';
$this->save($id, $p);
$this->publish($id, 'award');
$this->get('/concursos/'.$id)->assertInertia(fn (Assert $p) => $p->where('state', 'results')->has('history', 3));
}
public function test_cancellation_and_later_clarification_do_not_reopen_the_procedure(): void
{
$p = $this->payload('private');
$id = $this->create($p);
$this->publish($id);
$p['result'] = 'Cancelamento sintético fundamentado para ensaio.';
$this->save($id, $p);
$this->publish($id, 'cancellation');
$p['object'] .= ' Esclarecimento posterior ao cancelamento.';
$this->save($id, $p);
$this->publish($id, 'clarification');
$this->get('/concursos/'.$id)->assertInertia(fn (Assert $p) => $p->where('state', 'cancelled')->has('history', 3));
}
public function test_stale_preview_cannot_publish_new_draft_and_public_snapshot_stays_unchanged_until_explicit_publication(): void
{
$p = $this->payload();
$id = $this->create($p);
$plan = $this->postJson('/management/concursos/'.$id.'/previa', ['act' => 'initial'])->assertOk()->json();
$p['title'] = 'Nova edição ainda privada';
$this->save($id, $p);
$this->postJson('/management/concursos/'.$id.'/publicar', ['act' => 'initial', 'hash' => $plan['hash'], 'reason' => $p['public_reason']])->assertConflict();
$this->publish($id);
$p['title'] = 'Rascunho futuro privado';
$this->save($id, $p);
$this->get('/concursos/'.$id)->assertInertia(fn (Assert $p) => $p->where('publication.payload.title', 'Nova edição ainda privada'));
}
public function test_documented_minimum_dates_and_business_calendar_are_specific_to_the_procedure(): void
{
$p = $this->payload();
$p['deadline'] = '2026-10-19T15:00';
$id = $this->create($p);
$this->postJson('/management/concursos/'.$id.'/previa', ['act' => 'initial'])->assertUnprocessable()->assertJsonValidationErrors('deadline');
$p['origin_published_at'] = '2026-10-23T09:00';
$p['deadline'] = '2026-10-27T09:00';
$p += ['minimum_days' => 2, 'minimum_source' => 'Regra sintética de contagem, cláusula QA-1', 'minimum_edition' => 'QA-2026', 'minimum_modality' => $p['modality'], 'minimum_day_basis' => 'business', 'minimum_working_days' => '1,2,3,4,5', 'minimum_holidays' => '2026-10-26', 'minimum_calendar_source' => 'Calendário sintético QA: segunda a sexta, exclui 26/10. Não é calendário oficial.'];
$this->save($id, $p);
$this->postJson('/management/concursos/'.$id.'/previa', ['act' => 'initial'])->assertUnprocessable()->assertJsonValidationErrors('deadline');
$p['deadline'] = '2026-10-28T09:00';
$this->save($id, $p);
$this->postJson('/management/concursos/'.$id.'/previa', ['act' => 'initial'])->assertOk();
$p['minimum_modality'] = 'Outra modalidade';
$this->save($id, $p);
$this->postJson('/management/concursos/'.$id.'/previa', ['act' => 'initial'])->assertUnprocessable()->assertJsonValidationErrors('minimum_modality');
}
public function test_simple_account_can_follow_but_cannot_edit_or_publish_and_tracking_is_not_a_bid(): void
{
$id = $this->create($this->payload());
$this->publish($id);
$reader = User::factory()->unverified()->create();
$before = DB::table('portal_role_assignments')->count();
$this->actingAs($reader)->put('/concursos/'.$id.'/acompanhar')->assertRedirect();
$this->get('/concursos/acompanhar')->assertOk()->assertInertia(fn (Assert $p) => $p->where('watched', true)->has('items', 1)->where('items.0.changed', false));
$this->actingAs($this->editor);
$p = $this->payload();
$this->save($id, $p);
$this->publish($id, 'clarification');
$reader->forceFill(['email_verified_at' => now()])->save();
$this->actingAs($reader);
$this->get('/concursos/acompanhar')->assertInertia(fn (Assert $p) => $p->where('items.0.changed', true));
$this->get('/management/concursos')->assertForbidden();
$this->postJson('/management/concursos/'.$id.'/publicar', [])->assertForbidden();
$this->delete('/concursos/'.$id.'/acompanhar')->assertRedirect();
$this->assertSame($before, DB::table('portal_role_assignments')->count());
}
public function test_real_scanned_library_attachment_private_redaction_and_withdrawal_are_reused(): void
{
Storage::fake('local');
config(['queue.default' => 'sync', 'services.malware.scanner' => 'clamd', 'services.malware.socket' => null, 'services.malware.host' => '127.0.0.1', 'services.malware.port' => 3310]);
$this->assertTrue(app(MalwareScanner::class)->health()['available'], 'Current real scanner required');
$name = 'synthetic-tender-'.Str::uuid().'.txt';
$this->post('/management/portal-services/upload', ['file' => UploadedFile::fake()->createWithContent($name, 'Exemplo sintético de anúncio QA, sem valor jurídico.')])->assertSessionHasNoErrors();
$doc = DB::table('documents')->where('file_name', $name)->first();
$this->assertSame('clean', $doc->malware_scan_status);
$metadata = ['document_id' => $doc->id, 'title' => $name, 'category' => 'Synthetic QA', 'topic' => 'Tender QA', 'document_type' => 'unknown', 'issuer' => 'Synthetic QA only', 'source_url' => 'https://example.invalid/qa', 'language' => 'pt', 'version_label' => 'QA-1', 'territorial_scope' => 'national', 'source_confirmation' => 'identified', 'legal_status' => 'unknown', 'rights_status' => 'authorized', 'data_classification' => 'public', 'source_reference' => 'Synthetic QA only, not an official notice.', 'legislation' => false, 'essential' => false, 'independent_review' => false, 'associations' => []];
$this->post('/management/portal-services/resources', $metadata)->assertSessionHasNoErrors();
$resource = DB::table('portal_resources')->where('document_id', $doc->id)->first();
$this->assertNotNull($resource);
$p = $this->payload('external');
$p['attachments'] = [['resource_id' => $resource->id, 'public' => true, 'purpose' => 'Anúncio de ensaio']];
$id = $this->create($p);
$this->postJson('/management/concursos/'.$id.'/previa', ['act' => 'initial'])->assertUnprocessable()->assertJsonValidationErrors('attachments');
$this->post('/management/portal-services/resources/'.$resource->id, ['published' => true])->assertSessionHasNoErrors();
$this->publish($id);
Auth::logout();
$this->get('/documentos/'.$resource->id.'/download')->assertOk()->assertDownload($name);
$this->get('/concursos/'.$id)->assertInertia(fn (Assert $p) => $p->where('publication.payload.attachments.0.available', true));
$this->actingAs($this->editor)->post('/management/portal-services/resources/'.$resource->id, ['published' => false])->assertSessionHasNoErrors();
Auth::logout();
$this->get('/documentos/'.$resource->id.'/download')->assertNotFound();
$this->get('/concursos/'.$id)->assertInertia(fn (Assert $p) => $p->where('publication.payload.attachments.0.available', false));
}
}
@@ -1,61 +0,0 @@
<?php
namespace Tests\Feature;
use App\Models\User;
use App\Services\TerritoryGeometryImport;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Tests\TestCase;
class TerritoryGeometryApprovedAdministrationTest extends TestCase
{
use DatabaseTransactions;
public function test_existing_superuser_with_completed_mfa_reaches_importer_without_legacy_manager_grant(): void
{
$actor = $this->holder();
$this->actingAs($actor)->withSession(['portal.mfa_actor' => $actor->id, 'portal.mfa_at' => time(), 'portal.access_revision' => (int) $actor->portal_access_revision]);
$this->assertFalse($actor->can('manage-portal'));
// A missing exemplar must produce the source error, not deny the approved actor.
try {
app(TerritoryGeometryImport::class)->preview($actor, 1);
$this->fail('The deliberately absent source must be reported.');
} catch (HttpException $exception) {
$this->assertSame(422, $exception->getStatusCode());
}
$this->getJson('/management/territory-geometry-import')->assertStatus(422);
$this->postJson('/management/territory-geometry-import', [])->assertStatus(422);
$this->assertFalse($actor->can('manage-portal'));
}
public function test_superuser_without_mfa_session_cannot_import(): void
{
$actor = $this->holder();
$this->actingAs($actor)->getJson('/management/territory-geometry-import')->assertForbidden();
$this->postJson('/management/territory-geometry-import', [])->assertForbidden();
}
public function test_ordinary_account_does_not_gain_cartographic_administration(): void
{
$this->holder();
$actor = User::factory()->create();
$this->actingAs($actor)->getJson('/management/territory-geometry-import')->assertForbidden();
$this->postJson('/management/territory-geometry-import', [])->assertForbidden();
}
private function holder(): User
{
$identity = DB::selectOne('select current_database() as name,inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test', $identity->name);
$this->assertSame(55441, (int) $identity->port);
config(['portal.profile_access_enabled' => true, 'portal.managers' => [], 'geometry-import.enabled' => true,
'geometry-import.directory' => storage_path('app/private/nonexistent-demarcation-source')]);
$actor = User::factory()->create(['two_factor_secret' => Crypt::encryptString('JBSWY3DPEHPK3PXP'), 'two_factor_confirmed_at' => now()]);
$other = User::factory()->create();
DB::table('portal_superuser_pair')->updateOrInsert(['id' => 1], ['first_user_id' => $actor->id, 'second_user_id' => $other->id, 'approved_by' => $other->id]);
return $actor;
}
}
-177
View File
@@ -1,177 +0,0 @@
"""Reconcile the 50 captured identities; public GETs only, no DB/publication writes."""
from pathlib import Path
from html.parser import HTMLParser
from concurrent.futures import ThreadPoolExecutor
import collections, csv, datetime, hashlib, json, re, subprocess, sys, urllib.request
ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / 'outputs/legacy-correspondence-20261022'
OUT.mkdir(parents=True, exist_ok=True)
AUDIT = ROOT / 'docs/investmoz/v2/auditoria-portal'
reconciliation = json.loads((ROOT / 'outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json').read_text(encoding='utf-8'))
inventory = json.loads((ROOT / 'storage/app/private/investmoz-v2/portal-audit/legacy-discovery/inventory.json').read_text(encoding='utf-8'))
config = json.loads(subprocess.check_output(['php', '-r', "$c=require 'config/legacy_content.php';echo json_encode($c);"], cwd=ROOT))
mapped = {int(re.search(r'post-(\d+)-', item['external_id'])[1]): (slug, item) for slug, item in config['articles'].items() if item['publishable']}
assert len(mapped) == 20 and len(reconciliation['articles']) == 50
class Page(HTMLParser):
data = None
reading = False
chunks = None
def handle_starttag(self, tag, attrs):
attrs = dict(attrs)
if tag == 'script' and attrs.get('type') == 'application/json' and 'data-page' in attrs:
self.reading = True; self.chunks = []
elif 'data-page' in attrs and attrs['data-page'].startswith('{'):
self.data = json.loads(attrs['data-page'])
def handle_data(self, value):
if self.reading: self.chunks.append(value)
def handle_endtag(self, tag):
if tag == 'script' and self.reading:
self.data = json.loads(''.join(self.chunks)); self.reading = False
def fetch(pair):
legacy_id, (slug, identity) = pair
url = 'https://teste-investidor.tempo.co.mz/' + slug
try:
request = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0 InvesteMoz-Legacy-Correspondence', 'Cache-Control': 'no-cache'})
with urllib.request.urlopen(request, timeout=35) as response:
raw = response.read(); status = response.status
page = Page(); page.feed(raw.decode('utf-8'))
article = page.data['props']['article']
assert page.data['component'] == 'portal/legacy' and article['legacy_id'] == legacy_id
assert article['source_url'] == identity['source_url'] and article['html'].strip()
return legacy_id, {'url': url, 'status': status, 'identity_verified': True,
'resource_id': article['id'], 'document_sha256': article['sha256'],
'current_title': article['title'], 'image_url': article['image']['href'] if article.get('image') else None,
'response_sha256': hashlib.sha256(raw).hexdigest()}
except Exception as error:
return legacy_id, {'url': url, 'identity_verified': False, 'error': type(error).__name__, 'status': getattr(error, 'code', None)}
if '--reuse-http' in sys.argv:
cached = json.loads((OUT / 'public-pages.json').read_text(encoding='utf-8'))
checks = {int(k): v for k, v in cached['pages'].items()}; stamp = cached['checked_utc']
assert set(checks) == set(mapped)
else:
with ThreadPoolExecutor(max_workers=4) as pool:
checks = dict(pool.map(fetch, mapped.items()))
stamp = datetime.datetime.now(datetime.timezone.utc).isoformat()
(OUT / 'public-pages.json').write_text(json.dumps({'checked_utc': stamp, 'method': 'Anonymous HTTP GET; Inertia article identity/source/content checked; no visual acceptance or new publication', 'pages': checks}, ensure_ascii=False, indent=2), encoding='utf-8')
captures = {}
for record in inventory['records']:
post = record.get('public_props', {}).get('post')
if post:
captures.setdefault(int(post['id']), []).append(record)
staged = collections.defaultdict(list)
prepared = {}
for article in reconciliation['articles']:
legacy_id = article['legacy_id']
if legacy_id in mapped or article['group'] in ['mercado_financeiro', 'identidade_incompleta']:
continue
record = next(r for r in captures[legacy_id] if hashlib.sha256(r['public_props']['post']['content'].encode()).hexdigest() == article['body_sha256'])
original = ROOT / record['private_file']
assert original.is_file() and hashlib.sha256(original.read_bytes()).hexdigest() == record['sha256']
post = record['public_props']['post']; seo = record['public_props']['seo']
group = article['group']; directory = OUT / 'private-preparation' / group; directory.mkdir(parents=True, exist_ok=True)
payload = {'format': 'investmoz-legacy-article-v1', 'legacy_id': legacy_id, 'title': article['title'],
'author': seo.get('author', 'tempo'), 'legacy_category': article['category'],
'source_url': record['url'], 'published_at': seo.get('publishedTime', ''),
'modified_at': article['modified_at'], 'content_html': post['content'],
'image_source_url': post.get('thumbnail'), 'image_sha256': None,
'references': article['references']}
data = (json.dumps(payload, ensure_ascii=False, indent=2) + '\n').encode()
filename = f"post-{legacy_id}-{article['modified_at'][:10].replace('-', '')}.txt"
path = directory / filename
if path.exists():
assert path.read_bytes() == data, 'Prepared version changed; preserve prior bytes'
else:
path.write_bytes(data)
item = {'legacy_id': legacy_id, 'title': article['title'], 'source_url': record['url'],
'external_id': f"legacy-tempo-post-{legacy_id}-{article['modified_at'][:10].replace('-', '')}",
'file_name': filename, 'relative_path': f'{group}/{filename}',
'sha256': hashlib.sha256(data).hexdigest(), 'source_capture_sha256': record['sha256'],
'original_body_sha256': article['body_sha256'], 'bytes': len(data), 'published': False,
'scan': 'not_run_on_prepared_derivative', 'dependencies': article['dependencies'],
'note': 'Private preparation only. Not imported, scanned, published or assigned to a current opportunity. Image unresolved, never substituted by generic image.'}
staged[group].append(item); prepared[legacy_id] = item
assert len(prepared) == 28
qa_receipt_path = OUT / 'qa-import-receipt.json'
qa_rows = {}
if qa_receipt_path.exists():
proof = json.loads(qa_receipt_path.read_text(encoding='utf-8'))
assert proof['qa_database'] == 'simulator_fiscal_delta_20261021_test' and proof['port'] == 55441
assert proof['imported_private'] == proof['clean_actual_scans'] == proof['idempotent_replay_reused'] == 28
qa_rows = {int(re.search(r'post-(\d+)-', r['external_id'])[1]): r for r in proof['resources']}
assert set(qa_rows) == set(prepared)
assert all(not r['published'] and r['malware_scan_status'] == 'clean' and r['sha256'] == prepared[i]['sha256'] for i, r in qa_rows.items())
for group, items in staged.items():
(OUT / 'private-preparation' / group / 'preparation.json').write_text(json.dumps({'importable_manifest': False, 'group': group, 'items': items}, ensure_ascii=False, indent=2), encoding='utf-8')
path = AUDIT / 'legado-conteudos-reconciliados.csv'
with path.open(encoding='utf-8-sig', newline='') as f:
reader = csv.DictReader(f); columns = reader.fieldnames; rows = list(reader)
editorial_receipt = AUDIT / 'legado-editorial-qa-20261022.json'
editorial_rows = {}
if editorial_receipt.exists():
editorial = json.loads(editorial_receipt.read_text(encoding='utf-8'))
assert editorial['qa_only'] and not editorial['destination_imported'] and not editorial['destination_published']
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']
for col in extra:
if col not in columns: columns.append(col)
articles = {a['legacy_id']: a for a in reconciliation['articles']}
for row in rows:
legacy_id = int(row['ID legado']); article = articles[legacy_id]; check = checks.get(legacy_id)
row['Endereço no novo portal'] = check['url'] if check else ''
row['Conferência HTTP UTC'] = stamp if check else ''
row['Grupo de preparação QA'] = article['group'] if legacy_id in prepared else ''
if check:
row['Estado actual consolidado'] = 'Publicado; identidade e conteúdo consultáveis na homologação' if check['identity_verified'] else 'Publicação documentada; consulta actual não confirmada'
row['Pendência actual'] = 'Não foi feita aceitação visual ou conferência pela Tempo nesta passagem.' if check['identity_verified'] else str(check)
if check['identity_verified']:
row['Situação'] = 'publicado'; row['Recurso ativo'] = str(check['resource_id'])
row['Grupo restante'] = 'publicados'
row['Dependência concreta'] = 'Sem pendência de integração desta identidade; mantém-se a revisão editorial corrente.'
row['Próxima ação'] = 'Preservar a publicação; gerir edições e versões pela biblioteca existente.'
row['Imagem atual'] = json.dumps({'scope': 'homologação', 'href': check['image_url'], 'status': 'referência na ficha; binário não reensaiado'}, ensure_ascii=False)
elif legacy_id in prepared:
row['Estado actual consolidado'] = 'Importado privado em QA; scan real limpo; por integrar na homologação' if legacy_id in qa_rows else 'Por integrar; exemplar derivado preparado privadamente, sem importação'
if legacy_id in qa_rows: row['Recurso QA'] = str(qa_rows[legacy_id]['id'])
row['Pendência actual'] = 'Fechar edição/destino de leitura e publicação por lote na homologação. Dependências históricas de 15/10, por confrontar com o estado actual (não são novos bloqueios): ' + ' | '.join(article['dependencies'])
if legacy_id in qa_rows:
row['Dependência concreta'] = 'Rascunho QA analisado; falta fechar leitor/edição e entrega/publicação na homologação. Referências externas e imagens não recolhidas continuam discriminadas no inventário.'
row['Próxima ação'] = 'Continuar por lote, preservando o carácter histórico/editorial; não converter em oportunidade vigente nem em regra fiscal.'
elif article['group'] == 'mercado_financeiro':
row['Estado actual consolidado'] = 'Original vazio'; row['Pendência actual'] = 'Fornecer corpo editorial pela Tempo; imagem e Fintech não substituem o original. Sem novo endereço público.'
else:
row['Estado actual consolidado'] = 'Original sem título'; row['Pendência actual'] = 'Identificação editorial pela Tempo para o post 74364; corpo com 21 caracteres úteis preservado. Sem título ou endereço novo inventado.'
row['Evidência atual'] = 'outputs/legacy-correspondence-20261022/public-pages.json; qa-import-receipt.json; editorial-gaps-current.json; inventário histórico de 15/10 preservado'
if legacy_id in editorial_rows:
assert editorial_rows[legacy_id]['original_sha256'] == prepared[legacy_id]['sha256']
row['Estado actual consolidado'] = 'Privado em QA; edição, leitura e prévia disponíveis; entrega privada preparada'
row['Pendência actual'] = '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.'
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'] = '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'
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)
def esc(value): return str(value).replace('|', '\\|').replace('\n', ' ')
table = ['# Correspondência integral dos 50 artigos do legado', '',
'Conferência HTTP individual em ' + stamp + '. 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.', '',
'| ID | Título original | Endereço original | Endereço no novo portal | Estado | Pendência |', '| --- | --- | --- | --- | --- | --- |']
for row in rows:
table.append('| ' + ' | '.join(esc(row[k]) for k in ['ID legado', 'Título', 'URLs observadas', 'Endereço no novo portal', 'Estado actual consolidado', 'Pendência actual']) + ' |')
(AUDIT / 'legado-correspondencia-integral.md').write_text('\n'.join(table) + '\n', encoding='utf-8')
summary = {'checked_utc': stamp, 'distinct_articles': 50, 'publications_documented': 20,
'public_pages_identity_verified': sum(p['identity_verified'] for p in checks.values()),
'pending_content': 28, 'private_preparation': {k: len(v) for k, v in staged.items()},
'empty': 1, 'untitled': 1, 'database_writes_by_correspondence_script': 0, 'active_database_writes': 0, 'new_publications': 0,
'qa_imports': len(qa_rows), 'qa_clean_scans': len(qa_rows), 'remaining_integration_complete': False}
(OUT / 'receipt.json').write_text(json.dumps(summary, indent=2), encoding='utf-8')
print(json.dumps(summary))
-117
View File
@@ -1,117 +0,0 @@
<?php
// Read-only export from the named QA; this does not import or publish in a destination.
require dirname(__DIR__).'/vendor/autoload.php';
$app = require dirname(__DIR__).'/bootstrap/app.php';
$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
use App\Services\EditorialReading;
use App\Services\VerifiedDocumentBinary;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
$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('Named isolated QA only');
}
$directory = base_path('outputs/legacy-editorial-20261022');
if (! is_dir($directory)) {
mkdir($directory, 0700, true);
}
$identities = json_decode(file_get_contents(config_path('legacy_editorial_resources.json')), true, 512, JSON_THROW_ON_ERROR);
if (count($identities) !== 28) {
throw new RuntimeException('Exact 28-original scope required');
}
$label = $argv[1] ?? 'v1';
if (! preg_match('/^[a-z0-9-]{1,32}$/D', $label)) {
throw new RuntimeException('Invalid package label');
}
$zip = new ZipArchive;
$archive = $directory.'/legacy-editorial-private-'.$label.'.zip';
if (is_file($archive)) {
throw new RuntimeException('Preserve existing package; choose a reviewed subsequent version rather than overwrite');
}
if ($zip->open($archive, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Cannot create private package');
}
$manifest = ['format' => 'investmoz-legacy-editorial-private-delivery-v1', 'prepared_at' => gmdate(DATE_ATOM), 'destination' => 'teste-investidor.tempo.co.mz', 'publish' => false, 'documents' => [], 'images' => [],
'rules' => ['Transport/import is private and distinct from publication.', 'Resolve target IDs by original SHA256/external identity; no QA user/document/resource IDs are authoritative in the destination.', 'Keep source QA revisions as provenance, never impersonate their actors as destination audit authors.', 'Recheck target scan and existing identity/version; reuse matching originals, never overwrite conflicts.', 'Apply current metadata/edition through authenticated management, creating destination history. No automatic publication.']];
$reading = app(EditorialReading::class);
$rows = [];
$imageHashes = [];
DB::beginTransaction();
DB::statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY');
try {
foreach ($identities as $identity) {
$doc = DB::table('documents')->where('external_id', $identity['external_id'])->where('sha256', $identity['sha256'])->whereNull('deleted_at')->first();
if (! $doc) {
throw new RuntimeException('Missing original identity');
}
$resource = DB::table('portal_resources')->where('document_id', $doc->id)->first();
if (! $resource || $resource->published || $doc->data_classification !== 'internal') {
throw new RuntimeException('Expected private QA draft');
}
$binary = app(VerifiedDocumentBinary::class)->respond($doc);
$bytes = $binary instanceof BinaryFileResponse ? file_get_contents($binary->getFile()->getPathname()) : $binary->getContent();
if (hash('sha256', $bytes) !== $identity['sha256']) {
throw new RuntimeException('Original changed');
}
$file = 'originals/'.$identity['external_id'].'.txt';
$zip->addFromString($file, $bytes);
$display = $reading->reading($resource, null, true);
$edition = $resource->editorial_content ? json_decode($resource->editorial_content, true, 512, JSON_THROW_ON_ERROR) : null;
$imageBinding = null;
if ($edition && ! empty($edition['image_resource_id'])) {
$imageDoc = DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->where('r.id', $edition['image_resource_id'])->first(['d.*']);
if (! $imageDoc) {
throw new RuntimeException('Selected image missing');
}
$imageBinding = ['sha256' => $imageDoc->sha256, 'source_url' => $imageDoc->original_source];
unset($edition['image_resource_id']);
}
if ($display['image_url']) {
preg_match('~/documentos/(\d+)/view~', $display['image_url'], $match);
$imageDoc = $reading->publicResources()->where('r.id', (int) $match[1])->first(['d.*']);
$imageBinary = app(VerifiedDocumentBinary::class)->respond($imageDoc);
$imageBytes = $imageBinary instanceof BinaryFileResponse ? file_get_contents($imageBinary->getFile()->getPathname()) : $imageBinary->getContent();
if (! isset($imageHashes[$imageDoc->sha256])) {
$imageFile = 'images/'.$imageDoc->sha256;
$zip->addFromString($imageFile, $imageBytes);
$imageHashes[$imageDoc->sha256] = true;
$manifest['images'][] = ['file' => $imageFile, 'sha256' => $imageDoc->sha256, 'source_url' => $imageDoc->original_source, 'mode' => 'reuse target matching hash first; import only if absent and authorized'];
}
}
$revisions = DB::table('portal_resource_revisions')->where('resource_id', $resource->id)->orderBy('revision_no')->get();
$historyFile = 'provenance/'.$identity['external_id'].'.json';
$zip->addFromString($historyFile, json_encode(['scope' => 'QA provenance only; IDs and actors are not destination identities', 'resource_snapshot' => $resource, 'revisions' => $revisions], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$metadata = (array) $resource;
foreach (['id', 'document_id', 'created_by', 'approved_by', 'last_reviewed_by', 'last_reviewed_at', 'metadata_version', 'document_group_id', 'duplicate_of_resource_id', 'document_identity_key', 'editorial_content', 'created_at', 'updated_at'] as $key) {
unset($metadata[$key]);
}
$manifest['documents'][] = ['external_id' => $identity['external_id'], 'file' => $file, 'sha256' => $identity['sha256'], 'kind' => $identity['kind'], 'metadata' => $metadata, 'qa_metadata_version' => $resource->metadata_version, 'edition' => $edition, 'selected_image' => $imageBinding, 'original_image_reference' => $display['image_source_url'], 'original_image_sha256' => $display['image_expected_sha256'], 'body_image_references' => $display['image_references'], 'history_file' => $historyFile, 'publish' => false, 'version_identity' => 'Legado '.$identity['external_id']];
$rows[] = ['external_id' => $identity['external_id'], 'qa_resource_id' => $resource->id, 'version' => $resource->metadata_version, 'original_sha256' => $doc->sha256, 'private' => ! $resource->published, 'image_available' => (bool) $display['image_url'], 'image_reference' => $display['image_source_url'], 'body_image_references' => count($display['image_references']), 'history_revisions' => $revisions->count()];
}
} finally {
DB::rollBack();
}
$manifest['notice'] = 'The QA proof edition of original post 62413 contains an explicitly marked QA note. Review/correct it in the portal before any publication; no editorial text is silently removed from this package.';
$zip->addFromString('manifest.json', json_encode($manifest, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$zip->close();
$verify = new ZipArchive;
if ($verify->open($archive, ZipArchive::CHECKCONS) !== true) {
throw new RuntimeException('Archive invalid');
}
foreach ($manifest['documents'] as $item) {
if (hash('sha256', $verify->getFromName($item['file'])) !== $item['sha256']) {
throw new RuntimeException('Archive original mismatch');
}
}
foreach ($manifest['images'] as $item) {
if (hash('sha256', $verify->getFromName($item['file'])) !== $item['sha256']) {
throw new RuntimeException('Archive image mismatch');
}
}
$entries = $verify->numFiles;
$verify->close();
$receipt = ['qa_only' => true, 'originals' => count($rows), 'rows' => $rows, 'archive_entries' => $entries, 'archive_sha256' => hash_file('sha256', $archive), 'archive_bytes' => filesize($archive), 'verified_original_hashes' => 28, 'included_image_originals' => count($manifest['images']), 'destination_imported' => false, 'destination_published' => false, 'database_writes' => 0];
file_put_contents($directory.'/private-delivery-'.$label.'-receipt.json', json_encode($receipt, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
echo json_encode(['originals' => count($rows), 'archive_entries' => $entries, 'sha256' => $receipt['archive_sha256'], 'included_images' => count($manifest['images']), 'destination_imported' => false, 'destination_published' => false]);
@@ -1,64 +0,0 @@
<?php
// Rehearse recovery with the existing importer. Never accepts an active database.
require dirname(__DIR__).'/vendor/autoload.php';
$app = require dirname(__DIR__).'/bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$target = Illuminate\Support\Facades\DB::selectOne('select current_database() as database,inet_server_port() as port');
throw_unless($target->database === 'simulator_fiscal_delta_20261021_test' && (int) $target->port === 55441
&& config('database.connections.pgsql.host') === '127.0.0.1', RuntimeException::class, 'Isolated QA only.');
$app->detectEnvironment(fn () => 'testing');
config(['geometry-import.enabled' => true, 'portal.managers' => ['qa-content-promoter@example.test'],
'services.malware.scanner' => 'clamd', 'services.malware.socket' => null,
'services.malware.host' => '127.0.0.1', 'services.malware.port' => 3310]);
$actor = App\Models\User::where('email', 'qa-content-promoter@example.test')->firstOrFail();
$directory = config('geometry-import.directory');
$out = storage_path('app/private/territory-demarcation-recovery');
Illuminate\Support\Facades\File::ensureDirectoryExists($out, 0700);
$manifest = [];
foreach (glob($directory.'/moz-adm*-ine-*') as $file) {
$manifest[] = ['file' => basename($file), 'bytes' => filesize($file), 'sha256' => hash_file('sha256', $file)];
}
file_put_contents($out.'/source-inventory.json', json_encode($manifest, JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
$scanner = app(App\Services\Malware\MalwareScanner::class);
$health = $scanner->health();
throw_unless($health['available'], RuntimeException::class, 'Current scanner unavailable.');
$scans = [];
foreach ([1, 2, 3] as $level) {
$file = $directory.'/moz-adm'.$level.'-ine-20190607.geojson';
// Scope the stream budget to this retained GIS original in this process only.
config(['services.malware.max_file_bytes' => filesize($file), 'services.malware.max_stream_bytes' => filesize($file)]);
$scan = $scanner->scan($file, filesize($file), storage_path('app/private'));
$scan['signatures_at'] = $scan['signatures_at']?->format(DATE_ATOM);
if ($level === 3 && $scan['reason_code'] === 'scanner_decompression_limit') {
$binary = getenv('GIS_CLAMSCAN_BINARY');
$database = getenv('GIS_CLAMSCAN_DATABASE');
throw_unless(is_file($binary ?: '') && is_dir($database ?: ''), RuntimeException::class, 'GIS scanner paths required.');
$process = new Symfony\Component\Process\Process([$binary, '--database='.$database, '--max-filesize=40M', '--max-scansize=100M', '--no-summary', $file]);
$process->setTimeout(120)->mustRun();
throw_unless(str_ends_with(trim($process->getOutput()), ': OK'), RuntimeException::class, 'GIS original scan incomplete.');
$version = new Symfony\Component\Process\Process([$binary, '--database='.$database, '--version']);
$version->mustRun();
$parts = explode('/', trim($version->getOutput()));
$signatureTime = strtotime(end($parts));
throw_unless($signatureTime && time() - $signatureTime < 48 * 3600, RuntimeException::class, 'Current GIS signatures required.');
$scan = ['result' => 'clean', 'engine' => 'ClamAV', 'engine_version' => trim($version->getOutput()),
'signatures_at' => gmdate(DATE_ATOM, $signatureTime), 'scope' => 'retained GIS original only',
'original_sha256' => hash_file('sha256', $file), 'stream_attempt' => $scan, 'exit_code' => $process->getExitCode()];
}
$scans[] = ['file' => basename($file), 'sha256' => hash_file('sha256', $file), 'scan' => $scan];
echo json_encode(['level' => $level, 'scan' => $scan]).PHP_EOL;
throw_unless($scan['result'] === 'clean', RuntimeException::class, 'Original scan incomplete.');
}
file_put_contents($directory.'/geometry-source-scans.json', json_encode(['captured_at' => gmdate('c'), 'files' => $scans], JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
$service = app(App\Services\TerritoryGeometryImport::class);
foreach ([1, 2, 3] as $level) {
$plan = $service->preview($actor, $level);
file_put_contents($out.'/preview-'.$level.'.json', json_encode($plan, JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
echo json_encode(['level' => $level, 'resolved' => $plan['resolved'], 'pending' => $plan['pending']]).PHP_EOL;
if (! in_array('--apply', $argv, true)) break; // Lower levels require imported parent correspondences.
$result = $service->apply($actor, ['level' => $level, 'hash' => $plan['hash'], 'idempotency_key' => (string) Illuminate\Support\Str::uuid(),
'reason' => 'Recuperação QA da demarcação anteriormente demonstrada, com originais e correspondências aceites.', 'confirm' => true]);
file_put_contents($out.'/result-'.$level.'.json', json_encode($result, JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
echo json_encode(['level' => $level, 'inserted' => $result['inserted'], 'reused' => $result['reused']]).PHP_EOL;
}