6.3 KiB
Feature Specification: Pré-preenchimento Self-Service → Wizard (016)
Criado: 2026-06-16
Solicitado por: Roger
Status: Implementação
Prioridade: P0 (regressão UX onboarding)
Sistema: Portal VM112 (ibytera-mail-portal) — wizard /onboard
Relacionado: Spec 012 (ticket no onboarding.started), chat bruto CHAT_BRUTO_ONBOARD_INFRA_SUPORTE_20260603
Resumo
Quando o utilizador preenche o card Self-Service na landing (hero) ou chega via «Criar Meu Servidor Agora», os dados declarados devem propagar automaticamente para o wizard de onboarding, em especial no passo «Conta admin» (criação da conta do administrador no Carbonio).
Regra de ouro: dados do Self-Service têm prioridade sobre estado antigo do wizard guardado em sessionStorage (domínio/localPart de sessão anterior não pode apagar o que o utilizador acabou de declarar na landing).
Origem dos dados (landing)
| Campo Self-Service | Label UI | Chave persistência |
|---|---|---|
| E-mail corporativo do administrador | admin@suaempresa.com.br |
localStorage.ligbox_planned_email |
| Senha | campo Senha | sessionStorage.ibytera_onboard_admin_password |
| Login portal | telefone/nickname | sessionStorage (portal login id — fora do escopo conta admin) |
Botões equivalentes: card Self-Service (hero) e CTA «Criar Meu Servidor Agora» (scroll para o mesmo card).
Fluxos que disparam pré-preenchimento:
- Registo → 2FA TOTP →
finishOnboarding()→ redirect/onboard - Login (ou login + 2FA) → redirect
/onboard
Destino no wizard (passo Conta admin — step 2)
Ao abrir ou regressar a este passo, três valores devem estar preenchidos:
| # | Origem Self-Service | Campo wizard | Exemplo |
|---|---|---|---|
| 1 | E-mail corporativo completo | localPart + domain (parte local + domínio) |
admin + suaempresa.com.br |
| 2 | Domínio extraído do e-mail | domain (passo 0 também) |
suaempresa.com.br |
| 3 | Senha | password (mascarada, reutilização) |
via AdminPasswordField |
Passo 0 (Domínio): se ligbox_planned_email existir, o campo domínio deve iniciar com o domínio do e-mail e mostrar banner informativo.
Passo 3 (Rever e criar): senha em modo confirm — mascarada, reutilizada; revelar com olho exige re-autenticação portal (2FA).
Comportamento funcional
FR-001 — Persistência imediata no registo
Após registo portal com sucesso (antes do TOTP), gravar:
setAdminPassword(password)localStorage.ligbox_planned_email= e-mail corporativo normalizado (lowercase, trim)
FR-002 — Prioridade Self-Service sobre wizard state
Se ligbox_planned_email ou senha em sessionStorage existirem ao montar /onboard:
- Ignorar
domain/localPart/notifyEmailantigos deibytera_onboard_wizard_statepara pré-preenchimento - Aplicar valores derivados do Self-Service
FR-003 — Sincronização no mount
useEffect no wizard reaplica pré-preenchimento se o utilizador navegou landing → onboard na mesma aba.
FR-004 — Senha não vai para wizard state JSON
Senha permanece apenas em sessionStorage (onboardPassword.js) — nunca em saveWizardState().
FR-005 — Revelação de senha
Ícone olho → modal re-autenticação portal (PasswordRevealAuth); visível 30s; opção «Definir senha diferente».
FR-006 — Sem Self-Service
Utilizador entra directo em /onboard sem landing: campos vazios ou defaults (admin, domínio manual) — sem regressão.
Critérios de aceitação
- Given registo com
admin@empresa.com+ senhaMinhaSenh@8+ TOTP concluído, When abre/onboardpasso Conta admin, Then vêadmin@empresa.com, domínioempresa.com, senha reutilizada (mascarada). - Given wizard state antigo com domínio
outro.comem sessionStorage, When novo registo comadmin@novo.com, Then domínio no wizard énovo.com(nãooutro.com). - Given login com
planned_corporate_emailda API, When redirect/onboard, Then campos pré-preenchidos. - Given F5 na mesma aba após Self-Service, When wizard recarrega, Then e-mail/domínio/senha mantêm-se (localStorage + sessionStorage).
- Given nova aba sem storage, When
/onboarddirecto, Then sem pré-preenchimento (comportamento legítimo).
Implementação (referência código VM112 — /opt/ligbox-wizard)
| Ficheiro | Função |
|---|---|
frontend/src/sessionPersist.js |
beginOnboardingForEmail(), syncWizardWithPlannedEmail(), applyPlannedEmailPrefill(), loadWizardStateForOnboard() |
frontend/src/portalAuth.js |
setPortalOnboardCredentials() → sessionStorage.ligbox_onboard_password |
frontend/src/onboardPassword.js |
alias leitura/escrita na mesma chave ligbox_onboard_password (wizard) |
frontend/src/ligbox/components/SelfServiceCard.jsx |
registo/login/TOTP → beginOnboardingForEmail + credenciais |
frontend/src/App.jsx |
loadWizardStateForOnboard() no init + useEffect de sync |
frontend/src/AdminPasswordField.jsx |
senha mascarada + reveal com verifyStepUp (2FA) |
Fora de escopo
- Enviar senha para VM122 / webhooks / Desk (nunca)
- Pré-preencher a partir de cookies cross-domain
- Sincronizar com Carbonio antes de
POST /account/create
Regressão conhecida (corrigida nesta spec)
Causas identificadas (2026-06-16):
- Wizard state antigo em
sessionStorage(ligbox_onboard_wizard_state) mantinhadomain/localPartde sessão anterior e bloqueava o e-mail novo do Self-Service. - Senha gravada em chave errada (
ibytera_onboard_admin_passwordem código de dev) enquanto o portal em produção lialigbox_onboard_password. - E-mail só ia para
localStorageapós TOTP completo — registo sembeginOnboardingForEmail()deixava o wizard sem âncora.
Fix aplicado:
syncWizardWithPlannedEmail()+ligbox_wizard_planned_emailcomo âncora — descarta wizard stale quando o e-mail muda.loadWizardStateForOnboard()aplica sempre domínio/localPart/notify a partir deligbox_planned_email.SelfServiceCardchamabeginOnboardingForEmail()+setPortalOnboardCredentials()no registo, login e fim do TOTP.