73 lines
15 KiB
Markdown
73 lines
15 KiB
Markdown
# Formulário por etapas — entrega local, 29/09/2026
|
||
|
||
**Disponível em `/investidor/negocios`: criar rascunho e abrir a ficha. O prompt A–C completo ainda não está entregue.** Este incremento implementa a preparação privada por etapas, autosave, retoma, sector e confirmação. Não implementa ainda publicação, uploads seguros, manifestações MNE ou operação integral.
|
||
|
||
1. **Diagnóstico tecnológico:** Laravel 13.30.1, PHP de validação 8.5.11, React 19.2.8, TypeScript 5.9.3, Inertia, Vite Plus, Leaflet e PostgreSQL 17.11/PostGIS. Mantidos componentes e autenticação por sessão/email verificado. Filas database/Redis e disco S3 são configuráveis; conectividade Redis/S3/ClamAV e CRM não ensaiada neste incremento. Sem novas dependências.
|
||
2. **Pressupostos:** formulário autenticado, classificação reservada e `public.existing_businesses` como autoridade. Identidade e titularidade são declarações pendentes. Referências documentais não são uploads, mandatos validados ou autorizações de transmissão. O preenchimento permite rascunhos incompletos; a submissão aplica validações adicionais. Clientes anteriores sem wizard_version conservam o contrato legado; converter todos os clientes exige uma migração de contrato posterior.
|
||
3. **Mapa A–C:** ver matriz abaixo. Não há equivalência entre oito etapas visíveis e implementação de todos os requisitos dessas etapas.
|
||
4. **Plano por fase:** responsável técnico da implementação: Codex. Incremento A1 executado: schema/validação, FK sectorial, wizard e testes. A2 pendente: localização normalizada/cartografia, contexto económico, anexos/scanner, consentimentos separados e acessibilidade integral. B pendente: manifestação MNE ligada a anúncio publicado, perfil e CRM idempotente. C pendente: aprovações, tarefas, SLA, alertas e dashboard. Dependências e gates mantidos em `implementation-status.md`; autorizações de desenvolvimento existentes preservadas.
|
||
5. **Modelo PostgreSQL:** coluna nullable bigint `existing_businesses.sector_id`, FK RESTRICT para a taxonomia existente e índice B-tree completo. Dados declarativos privados ficam no payload cifrado já existente; activos/direitos continuam nas entidades tipadas existentes. Não foram criadas pessoas, sectores ou negócios no schema mne. Localização deste formulário é ainda descritiva, não georreferenciada.
|
||
6. **Migration/modelos:** `2026_09_29_200000_existing_business_form_sector.php` aplicada localmente. DOWN remove a coluna somente se não houver associações sectoriais. Modelo ExistingBusiness existente preservado; `BusinessFormSchema` centraliza campos, rótulos PT/EN e validação. Snapshot/auditoria cifrados existentes conservados.
|
||
7. **API:** mesmos nove endpoints privados `/api/v1/existing-business`. `sector_id` é adicional no draft; `confirmation_code` exigido na submissão de wizard_version=1. GET da ficha fornece formSchema e sectores activos. Erros 403/409/422 e ausência de publicação preservados. OpenAPI actualizado para 1.2.0; schema exportável por `tools/export-business-form-schema.php`.
|
||
8. **Permissões:** proprietário verificado cria/edita rascunho ou pedido de informação; revisor designado, independente e com MFA consulta submissões. Terceiros recusados. Revisores recebem os novos campos apenas após a policy de consulta. Autosave usa as mesmas autorizações e versões da gravação manual.
|
||
9. **Estados:** rascunho → submetido; revisão/pedido de informação/retirada existentes. Confirmação explícita por código e consentimento de análise interna no servidor. Repetir submissão com versão anterior dá 409 sem duplicar histórico; ainda não há comprovativo idempotente por chave de pedido. As duas aprovações e os demais estados de A–C continuam pendentes.
|
||
10. **Serviços/eventos/Jobs:** reutilizados ExistingBusinessDrafts, ExistingBusinessIntake, objectos, snapshots e ponte legada. Nenhum Job externo, tarefa de triagem, notificação ou envio CRM novo. O consentimento actual é de revisão interna; não é o catálogo completo de consentimentos versionados do anexo.
|
||
11. **React:** `business-wizard.tsx` oferece oito etapas, progresso, PT/EN nos controlos principais, autosave após três segundos, retoma no servidor, resumo e confirmação. Navegação/fecho avisam sobre alterações não gravadas; conflitos não substituem silenciosamente dados. Representante revela campos de mandato. Activos/direitos reutilizam BusinessObjects; estes componentes existentes ainda não estão integralmente traduzidos. Criação/consulta administrativa por representação de terceiros permanece pendente.
|
||
12. **Código por ficheiro:** novos `app/Services/BusinessFormSchema.php`, migration sectorial, `resources/js/pages/investment/business-wizard.tsx`, `tests/Feature/ExistingBusinessWizardTest.php`, exportador de schema e ferramentas de navegador. Alterados controlador, Drafts, Intake, business.tsx, businesses.tsx, business-types.ts e gerador OpenAPI. Código completo nesses ficheiros; sem ficheiros removidos nem commit Git.
|
||
13. **Testes:** suite completa executada: 180 testes / 1845 verificações. Depois do controlo adicional por modalidade e do teste de rollback, suite específica do wizard: 2 testes / 30 verificações aprovados. Cobertura inclui cifragem, terceiro recusado, retoma, sector, dados inválidos, conflito de versão, mandato, activo obrigatório, confirmação, submissão duplicada e rollback. Navegador: autosave/recarga, resumo em 390/1440 px e submissão, sem excepções JS. Isto não é uma auditoria WCAG completa.
|
||
14. **Comandos:** abaixo. Não foi necessário instalar pacotes Composer/npm. Backend requer PHP com pgsql. Migration local aplicada após backup/restauro, usando `--path` específico. Os scripts de navegador e fixtures só usam QA em 55441/18027, nunca a base local operacional.
|
||
15. **Resultados:** PHPStan, Pint, TypeScript, lint do wizard e build aprovados. Backup com restauro de 210 tabelas: `storage/app/private/mne-integrity-backup-20260929-200103/`. Evidência do navegador: `wizard-browser-validation.json`. Auditoria de dependências e ensaios de serviços externos não executados neste incremento.
|
||
16. **Riscos residuais:** restantes campos e relações A; identidade normalizada; coordenadas/geometria; CRM MNE; scanner/upload; redis em operação; consentimentos separados; comprovativo/notificações; SLA; aprovações/publicação; tradução integral; testes de acessibilidade, carga e serviços externos. A conta de BD local ainda é superuser. Nenhuma alegação de prontidão para produção.
|
||
17. **Go/No-Go:** Go para testar preparação privada local; **No-Go para entrega integral A–C ou Go-Live**. Os fluxos incompletos não foram expostos como funcionais.
|
||
|
||
| Requisito | Implementação actual | Estado |
|
||
| --------------------------- | ----------------------------------------------------------------- | ------------------------------------------------- |
|
||
| A: proponente/representação | Campos cifrados, mandato condicional, declaração e validação | Parcial; sem verificação de identidade/documentos |
|
||
| A: modalidade/sector/valor | Taxonomia existente, FK, limites, moeda e natureza na submissão | Parcial; faltam intervalos e estruturas completas |
|
||
| A: localização/contexto | Descrição privada | Geografia estruturada e ligações pendentes |
|
||
| A: activos/direitos | Editor tipado existente; objecto aplicável exigido por modalidade | Parcial |
|
||
| A: fontes/documentos | Referências declaradas | Upload/scanner pendentes |
|
||
| A: rascunho/retoma/resumo | Autosave, versão, oito etapas, confirmação no servidor | Testado |
|
||
| B: interesse/CRM | Serviço geral existente preservado | Integração MNE pendente |
|
||
| C: revisão | Revisão privada e histórico existentes | Tarefas/SLA/dupla aprovação pendentes |
|
||
|
||
```powershell
|
||
php artisan migrate --path=database/migrations/2026_09_29_200000_existing_business_form_sector.php
|
||
php tools/export-business-form-schema.php
|
||
node tools/existing-business-openapi.mjs
|
||
php vendor/bin/phpunit --filter ExistingBusinessWizard --do-not-cache-result
|
||
npm.cmd run types:check
|
||
npm.cmd run build
|
||
```
|
||
|
||
Em ambiente QA isolado (`APP_ENV=testing`, base `portal_services_test`, porta 55441): `php tools/business-wizard-browser-seed.php`, seguido de `node tools/business-wizard-browser.mjs`, com servidor QA 18027 e navegador CDP 9224. As fixtures sintéticas ficam apenas nessa base de teste.
|
||
|
||
## Revisão da especificação do formulário de oportunidades — 02/10/2026
|
||
|
||
- O cadastro continua em sessão autenticada em `/investidor/negocios`, com classificação reservada. Não é uma submissão pública anónima e não publica automaticamente.
|
||
- O wizard `wizard_version=2` apresenta os sete tipos pedidos, recolhe proponente/representação e fonte, mostra dados de negócio por tipo, disponibilidade, estado de valor e três confirmações separadas. Rascunho/retoma permanecem no armazenamento cifrado já existente. O contrato legado v1 continua com validação própria; não se reescrevem rascunhos históricos.
|
||
- A nova migration aditiva `2026_10_02_160000_extend_existing_business_opportunity_types.php` estende o CHECK de modalidades sem editar migration anterior. Recusa migrar se não localizar exactamente uma constraint da modalidade. A reversão recusa remover os valores quando existirem registos que os usam. **Migration não executada nesta continuação.**
|
||
- Localização específica/múltipla usa dropdowns territoriais em cascata da referência pública existente e valida a hierarquia na submissão. Os IDs ficam no payload cifrado; ainda não criam relação espacial canónica para a oportunidade, não há marcador de mapa nem múltiplas localizações estruturadas. Subsector/actividade é texto pesquisável por designação, sem código obrigatório.
|
||
- Recursos tipados aceitam estado (disponível, contratado, previsto ou por confirmar) e data da fonte. Referências documentais continuam referências, não upload. Anexos classificados, scanner, classificação individual de conteúdo público/interno/confidencial, parque/cluster/corredor/ZEE/ZFI e projecto âncora continuam pendentes.
|
||
- Proponente existente pode ser declarado por nome, mas não há selector de CRM/cadastro sem duplicação. A escolha de contacto empresarial aprovado é uma preferência declarada; não é autorização automática de publicação. A projecção pública mantém contactos pessoais fora da allowlist.
|
||
- Não foi implementado pedido pós-publicação para suspensão/encerramento, alerta periódico de disponibilidade, nem fluxo MNE completo de consulta e resposta. Alterações materiais continuam limitadas a draft/pedido de informação e precisam de nova submissão/revisão.
|
||
- `docs/investmoz/existing-business/form-schema.json` e `docs/investmoz/existing-business/openapi.json` foram regenerados pelos exportadores existentes. `npm.cmd run types:check`, `php -l` nos seis ficheiros PHP alterados e `git diff --check` passaram. Não executei testes PHPUnit nem a migration.
|
||
- Gate proposto: **parcial, apenas teste privado após aplicar e validar a migration num banco isolado**. Sem uploads/revisão de anexos e consentimentos de divulgação por item, não avançar para publicação de oportunidades reais.
|
||
|
||
## Verificação do formulário recebido — 03/10/2026
|
||
|
||
- A proposta foi comparada com o wizard v2. Já existem as oito etapas, sete tipos de oportunidade, campos por modalidade, declaração de proponente/representação, contacto por email ou telefone, hierarquia territorial dependente, resumo editável e submissão reservada para revisão. O marketplace público usa uma allowlist e não recebe contactos pessoais nem o payload cifrado.
|
||
- Corrigida a submissão com `valid_until` vencido em payloads sem `wizard_version`: o prazo continua opcional, mas qualquer prazo fornecido passa a ser validado como não vencido. A versão 1 continua a exigir prazo conforme o contrato legado; as versões seguintes aceitam prazo omitido.
|
||
- Permanecem por implementar: selector de proponente/cadastro sem duplicação; múltiplas localizações estruturadas, coordenadas e precisão no mapa; relações económicas; upload com antivírus e classificação individual de anexos; selecção granular dos campos publicáveis; e fluxo para actualizar disponibilidade, suspender/encerrar e confirmar disponibilidade periodicamente. Referências documentais continuam a não ser anexos validados.
|
||
- Evidência executada nesta verificação: `php -l app/Services/ExistingBusinessIntake.php`, `php vendor/bin/pint --test app/Services/ExistingBusinessIntake.php` e o teste dirigido `ExistingBusinessIntakeTest::test_arbitrary_states_and_incomplete_or_expired_submission_are_rejected` passaram (1 teste, 5 asserções) no PostgreSQL isolado em 55441. O cluster de QA foi parado e a porta confirmou-se fechada; não usei a base da aplicação. Restantes testes do wizard permanecem por executar nesta verificação.
|
||
|
||
- **Pesquisa de sector:** o campo do passo 3 agora filtra a taxonomia activa por designação, sem perder a selecção actual do rascunho. Esta melhoria não altera a API nem o armazenamento. Continuam pendentes o proponente associado a cadastro existente sem duplicação, localizações múltiplas/georreferenciadas, relações económicas estruturadas, anexos com scanner e consentimento individual de divulgação, e ciclo de vida pós-publicação.
|
||
|
||
### Localizações administrativas múltiplas — 2026-10-03
|
||
|
||
- O rascunho privado agora admite 2–20 percursos administrativos, guardados em `payload.locations_json` dentro do payload já cifrado. O cliente limpa selecções descendentes ao mudar um nível; o servidor valida UUID, hierarquia na referência pública, mínimo/máximo e percursos repetidos ou sobrepostos. Não são recolhidas nem inventadas coordenadas.
|
||
- A resposta de leitura/gravação resolve os nomes dos percursos exclusivamente a partir da referência territorial pública. O resumo mostra os nomes depois de guardar. `wizard_version=2` consta do contrato OpenAPI; a rota legada conserva validação própria.
|
||
- Ficheiros desta tranche: `BusinessFormSchema.php`, `InvestmentGeography.php`, `ExistingBusinessController.php`, `business-locations.ts`, `business-wizard.tsx`, `business-types.ts`, `existing-business-openapi.mjs`, `ExistingBusinessWizardTest.php` e `business-locations.test.mjs`.
|
||
- Evidência: PHP 8.5.11 e PostgreSQL 17 descartável na porta 55441, migrations aplicadas apenas na base temporária; `ExistingBusinessWizardTest` 3/3, 49 assertions; testes frontend da localização 3/3; TypeScript, Pint dirigido, PHP lint e `git diff --check` passaram. O listener preexistente em 5432 não foi utilizado. Cluster parado; os ficheiros de dados QA permanecem no directório temporário `%TEMP%\investmoz-stage-multiloc` porque a limpeza automática foi bloqueada pelo executor.
|
||
- Sem migration nem alteração de esquema persistente. Rollback: reverter os trechos acima e remover os dois testes/helpers novos; não há dados existentes a migrar. Permanecem pendentes mapa/coordenadas, relação territorial canónica e associação a parques/zonas; esta entrega não autoriza publicação de oportunidade.
|