Public Markdown Document
Sistema de Tutoriais Interativos — Manual Tecnico
Documento vivo. Sistema de onboarding guiado integrado ao Fastapp Engine com Driver.js. Tutoriais vivem como JSON dentro da entidade App (Estrategia A — Cidadao Pleno do App).
Sistema de Tutoriais Interativos — Manual Tecnico
Documento vivo. Sistema de onboarding guiado integrado ao Fastapp Engine com Driver.js.
Tutoriais vivem como JSON dentro da entidade App (Estrategia A — Cidadao Pleno do App).
Visao Geral
O Sistema de Tutoriais permite criar e gerenciar tutoriais interativos que guiam usuarios pela interface, destacando elementos da UI passo a passo. O sistema e multi-tenant (por App), respeita o modelo de Rules/Permissoes do RBAC, e pode gerar Workflows automaticamente a partir dos passos do tutorial.
graph LR
subgraph "Admin (Builder)"
EDITOR["Tutorial Editor<br/>Visual Step Builder"]
LIST["Lista de Tutoriais<br/>Filtros por App/Rule"]
ANALYTICS["Analytics<br/>Metricas de engajamento"]
end
subgraph "Runtime (Usuario)"
CHECK["Plugin Check<br/>Verifica disponiveis"]
PROMPT["Prompt<br/>Popup de convite"]
RUNNER["Runner<br/>Driver.js execucao"]
end
subgraph "Backend"
API["Tutorial API<br/>CRUD + Status"]
APPJSON["App JSON<br/>app.tutorials[]"]
WFJSON["App JSON<br/>app.workflows[]"]
DB["PostgreSQL<br/>tutorial_user_status"]
end
EDITOR -->|"salva"| API
LIST -->|"lista"| API
ANALYTICS -->|"consulta"| API
API --> APPJSON
API -->|"gera workflow"| WFJSON
API --> DB
CHECK -->|"GET available"| API
CHECK -->|"tutoriais encontrados"| PROMPT
PROMPT -->|"Iniciar"| RUNNER
RUNNER -->|"POST status"| DB
style EDITOR fill:#6366f1,color:#fff
style RUNNER fill:#059669,color:#fff
style API fill:#7c3aed,color:#fff
style APPJSON fill:#0891b2,color:#fff
style WFJSON fill:#0891b2,color:#fff
Stack & Dependencias
| Camada | Tecnologia | Funcao |
|---|---|---|
| Highlight Engine | Driver.js 1.x | Overlay, steps, navegacao passo-a-passo |
| UI Components | PrimeVue (AutoComplete, Select, Checkbox, RadioButton) | Formularios do editor |
| Drag & Drop | vuedraggable | Reordenacao de passos no editor |
| State | Pinia (tutorial.ts) |
Estado global de tutoriais |
| Composable | useTutorials.ts |
Integracao Driver.js + logica de negocio |
| API | Nitro (server/api/tutorial/) | CRUD + status + analytics |
| Storage | App JSON (app.tutorials) |
Definicoes de tutorial dentro da entidade App |
| Workflow Link | server/utils/tutorial-workflow.ts |
Conversao tutorial → workflow |
| User Tracking | Prisma (tutorial_user_status) |
Status por usuario (progress/dismiss) |
| DB | PostgreSQL | Persistencia |
1. Modelo de Dados (DNA)
Arquitetura: Tutorial como JSON da App
Tutoriais nao possuem tabela propria. Sao armazenados como JSON dentro da coluna app.tutorials:
App (tabela) → tutorials: Json (TutorialDefinition[])
A unica tabela relacional e tutorial_user_status, que rastreia progresso por usuario:
model tutorial_user_status {
id Int @id @default(autoincrement())
user_id Int
app_id Int
tutorial_id String // ID string do tutorial no JSON
rule String?
status String @default("not_started") // not_started | in_progress | completed
dismissed Boolean @default(false) // "Nao mostrar novamente"
dismissed_at DateTime? @db.Timestamptz(6)
completed_at DateTime? @db.Timestamptz(6)
created_at DateTime @default(now()) @db.Timestamptz(6)
updated_at DateTime? @default(now()) @db.Timestamptz(6)
@@unique([user_id, tutorial_id])
@@index([user_id])
@@index([app_id])
@@index([tutorial_id])
}
Interface: TutorialDefinition (JSON dentro de app.tutorials)
interface TutorialStepDefinition {
id: string; // step_<timestamp>_<random>
order: number; // Ordem de execucao (1-based)
elementSelector: string; // Seletor CSS do elemento
title: string; // Titulo do popover
description: string; // Instrucao do passo
highlightType: 'element' | 'region';
}
interface TutorialDefinition {
id: string; // tut_<timestamp>_<random>
name: string;
description?: string;
rule?: string | null; // null = todos os usuarios
is_active: boolean;
steps: TutorialStepDefinition[];
generate_workflow?: boolean; // Gerar workflow automaticamente
workflow_id?: string; // ID do workflow vinculado
}
Relacionamento entre Entidades
erDiagram
APP ||--o{ TUTORIAL_JSON : "tutorials JSON[]"
APP ||--o{ WORKFLOW_JSON : "workflows JSON[]"
TUTORIAL_JSON ||--o| WORKFLOW_JSON : "generate_workflow"
TUTORIAL_JSON ||--o{ TUTORIAL_USER_STATUS : "tracks"
USER ||--o{ TUTORIAL_USER_STATUS : "has status"
APP {
int id PK
string slug
json tutorials "TutorialDefinition[]"
json workflows "WorkflowDefinition[]"
}
TUTORIAL_JSON {
string id "tut_xxx"
string name
string rule "nullable"
boolean is_active
json steps "TutorialStepDefinition[]"
boolean generate_workflow
string workflow_id "nullable"
}
WORKFLOW_JSON {
string id "wf_from_tut_xxx"
string label
string source_type "manual | tutorial"
string source_id "tutorial ID"
json steps "WorkflowStep[]"
}
TUTORIAL_USER_STATUS {
int id PK
int user_id
string tutorial_id "string FK"
string status "not_started|in_progress|completed"
boolean dismissed
}
2. Integracao Tutorial x Workflow
Conceito
Quando generate_workflow = true, o sistema converte automaticamente os passos do tutorial em steps de um Workflow visual. A relacao e bidirecional via IDs:
TutorialDefinition.workflow_id ←→ WorkflowDefinition.source_id
Conversao de Steps
TutorialStep → WorkflowStep
───────────────────────────────────────────────────
id: "step_1" → id: "wf_tut_xxx_step_0"
title: "Preencha o formulario" → label: "Preencha o formulario"
elementSelector: "#form-lead" → object: "lead" (extraido do selector)
order: 0 → position: { x: 0*290, y: 180 }
(proximo step) → next_step: "wf_tut_xxx_step_1"
highlightType: "element" → icon: "pi pi-compass"
Ciclo de Vida
| Acao no Tutorial | Efeito no Workflow |
|---|---|
Criar com generate_workflow: true |
Cria workflow wf_from_tut_xxx |
| Editar steps/nome | Atualiza o workflow vinculado |
Desativar generate_workflow |
Remove o workflow vinculado |
| Deletar tutorial | Remove o workflow vinculado |
Utilitario: server/utils/tutorial-workflow.ts
| Funcao | Descricao |
|---|---|
tutorialStepsToWorkflowSteps() |
Converte TutorialStep[] em WorkflowStep[] |
generateWorkflowFromTutorial() |
Gera WorkflowDefinition completa |
upsertTutorialWorkflow() |
Insere ou atualiza workflow no array |
removeTutorialWorkflow() |
Remove workflow gerado do array |
3. API Endpoints
Todos os endpoints estao em server/api/tutorial/.
CRUD
| Rota | Metodo | Descricao |
|---|---|---|
/api/tutorial |
GET | Lista tutoriais (filtros: app_id, rule, active) |
/api/tutorial |
POST | Cria tutorial + workflow opcional (generate_workflow) |
/api/tutorial/:id |
GET | Busca tutorial por ID (requer app_id query) |
/api/tutorial/:id |
PATCH | Atualiza tutorial + sincroniza workflow |
/api/tutorial/:id |
DELETE | Exclui tutorial + workflow vinculado + statuses |
Status & Disponibilidade
| Rota | Metodo | Descricao |
|---|---|---|
/api/tutorial/available |
GET | Tutoriais disponiveis para o usuario (exclui dismissed) |
/api/tutorial/status |
POST | Atualiza status: start, complete, dismiss |
/api/tutorial/analytics |
GET | Metricas: iniciaram, completaram, dispensaram |
Suporte ao Editor
| Rota | Metodo | Descricao |
|---|---|---|
/api/tutorial/roles |
GET | Roles disponiveis (padrao + existentes nos tutoriais) |
/api/tutorial/selectors |
GET | Seletores CSS predefinidos da plataforma |
Logica de Disponibilidade (available.get.ts)
graph TD
REQ["GET /api/tutorial/available<br/>?user_id=X&app_id=Y&rules=a,b"]
APPJSON["Ler app.tutorials JSON<br/>filtrar por is_active + rule"]
STATUS["Buscar statuses do user<br/>na tabela tutorial_user_status"]
FILTER["Filtrar: remover apenas<br/>dismissed = true"]
RESULT["Retornar tutoriais disponiveis"]
REQ --> APPJSON --> STATUS --> FILTER --> RESULT
style REQ fill:#2563eb,color:#fff
style APPJSON fill:#0891b2,color:#fff
style FILTER fill:#f59e0b,color:#000
style RESULT fill:#059669,color:#fff
Regra importante: Tutoriais completados continuam aparecendo. Apenas dismissed = true (checkbox "Nao mostrar novamente") impede que o tutorial reapareca.
4. Arquitetura de Componentes
Estrutura de Diretorios
app/
├── components/
│ └── tutorial/
│ ├── TutorialEditor.vue # Visual Step Builder (admin)
│ ├── TutorialInitialPrompt.vue # Popup de convite (runtime)
│ └── TutorialRunner.vue # Watcher que dispara Driver.js
├── composables/
│ └── useTutorials.ts # Integracao Driver.js + logica
├── stores/
│ └── tutorial.ts # Pinia store (status + estado UI)
├── plugins/
│ └── tutorial-check.client.ts # Verifica tutoriais apos login
├── pages/
│ └── fastapp/
│ └── tutorials/
│ ├── index.vue # Lista de tutoriais (admin)
│ ├── new.vue # Criar novo tutorial
│ └── [id].vue # Editar tutorial
server/
├── api/
│ └── tutorial/
│ ├── index.get.ts # Lista (filtros)
│ ├── index.post.ts # Criar + gerar workflow
│ ├── [id].get.ts # Buscar por ID
│ ├── [id].patch.ts # Atualizar + sync workflow
│ ├── [id].delete.ts # Excluir + cleanup workflow
│ ├── available.get.ts # Disponiveis para o usuario
│ ├── status.post.ts # Atualizar status
│ ├── analytics.get.ts # Metricas
│ ├── roles.get.ts # Roles para autocomplete
│ └── selectors.get.ts # Seletores CSS predefinidos
└── utils/
└── tutorial-workflow.ts # Conversao tutorial → workflow
5. Fluxo de Runtime
Fluxo Completo
sequenceDiagram
participant User as Usuario
participant Plugin as tutorial-check.client.ts
participant Store as TutorialStore
participant API as /api/tutorial
participant Prompt as TutorialInitialPrompt
participant Composable as useTutorials
participant Driver as Driver.js
Note over User: Login → navega para /app-slug/...
Plugin->>API: GET /api/tutorial/available?user_id&app_id&rules
API-->>Plugin: Tutorial[] (nao-dismissed, lidos do App JSON)
Plugin->>Store: availableTutorials = [T1, T2]
Store->>Prompt: showPrompt = true, currentTutorial = T1
Note over Prompt: Popup aparece (bottom-right)
Prompt-->>User: "Tutorial 1 de 2: Tour pelo Dashboard"
alt Clica "Iniciar"
User->>Prompt: click Iniciar
Prompt->>Composable: runTutorial(T1)
Composable->>API: POST /api/tutorial/status {action: "start"}
Composable->>Driver: driver.drive()
Driver-->>User: Overlay + Steps
alt Completa todos os passos
Driver->>Composable: onDestroyStarted (hasNextStep = false)
Composable->>API: POST /api/tutorial/status {action: "complete"}
Composable->>Store: remove T1 de availableTutorials
Store->>Prompt: showNextAvailable() → T2
else Pula o tutorial
Driver->>Composable: onDestroyStarted (hasNextStep = true)
Composable->>Store: stopRunning → showNextAvailable
end
else Marca "Nao mostrar novamente"
User->>Prompt: checkbox + fecha
Prompt->>Composable: dismissTutorial(T1)
Composable->>API: POST /api/tutorial/status {action: "dismiss"}
Note over API: dismissed=true → tutorial nunca mais aparece
end
6. Painel Administrativo
Acessivel em
/fastapp/tutorials — Registrado como Page no JSON da App fastapp.
Lista (/fastapp/tutorials)
- Filtros por App (Select) e Rule (InputText)
- Toggle de Ativo/Inativo por tutorial
- Exclusao com confirmacao (ConfirmDialog)
- Badge "Workflow" clicavel nos tutoriais que possuem workflow vinculado
- Painel de Analytics expansivel com metricas por tutorial
Editor (/fastapp/tutorials/new e /fastapp/tutorials/:id)
| Campo | Tipo | Descricao |
|---|---|---|
| Nome | InputText | Nome do tutorial (obrigatorio) |
| App | Select | Aplicacao destino (obrigatorio) |
| Publico-alvo | RadioButton | "Todos os usuarios" ou "Rule especifica" |
| Rule | AutoComplete (dropdown) | Roles disponiveis |
| Ativo | ToggleSwitch | Liga/desliga exibicao |
| Gerar Workflow | ToggleSwitch | Gera workflow automaticamente no Workflow Studio |
| Descricao | Textarea | Descricao do tutorial |
Quando Gerar Workflow esta ativo e o tutorial tem steps:
- Um workflow
wf_from_tut_xxxe criado/atualizado emapp.workflows - Botao "Ver Workflow" aparece no header do editor
- Na lista, um badge cyan clicavel leva ao Workflow Studio
7. Integracao com Driver.js
Configuracao
// useTutorials.ts → createDriver()
driver({
showProgress: true,
animate: true,
overlayOpacity: 0.4,
allowClose: true,
stagePadding: 8,
stageRadius: 8,
popoverClass: 'tutorial-popover',
nextBtnText: 'Proximo',
prevBtnText: 'Anterior',
doneBtnText: 'Concluir',
progressText: '{{current}} de {{total}}',
onDestroyStarted: () => { /* salvar progresso */ }
});
8. Analytics
Endpoint: GET /api/tutorial/analytics
Retorna metricas agregadas por tutorial (lidas do App JSON + cruzadas com tutorial_user_status):
[
{
"id": "tut_1711234567_abc",
"name": "Tour pelo Dashboard",
"app_id": 5,
"is_active": true,
"total_users": 45,
"started": 12,
"completed": 30,
"dismissed": 3
}
]
9. Como Criar um Tutorial
- Navegue para
/fastapp/tutorials→ "Novo Tutorial" - Preencha Nome, App, Publico-alvo, Descricao
- Ative "Gerar Workflow" se quiser criar um workflow visual automatico
- Adicione Passos: titulo, seletor CSS (dropdown ou livre), descricao
- Use o botao de validacao para testar se o seletor existe na pagina
- Clique "Preview" para testar no Driver.js
- Clique "Criar" — tutorial fica ativo imediatamente
Se "Gerar Workflow" estiver ativo, o workflow aparece no Workflow Studio (/fastapp/workflows).
10. Pontos Importantes
Armazenamento
- Tutoriais vivem dentro do JSON da App (
app.tutorials) - Nao possuem tabela propria — seguem o mesmo padrao de
objects,modules,pages - Mutacoes via PATCH
/api/app/:id(FADAP protocol)
Tutorial x Workflow
- Vinculo via
tutorial.workflow_id↔workflow.source_id - Workflow gerado e atualizado automaticamente quando tutorial e editado
- Workflow gerado e removido quando tutorial e deletado ou
generate_workflowdesativado - Workflows manuais (criados no Studio) nao sao afetados
Multi-Tenancy
- Cada tutorial pertence a uma App (dentro do JSON)
- Status e por usuario x tutorial (unique constraint na tabela)
- Filtro de
app_idna query garante isolamento
Regras de Rule
rule: null→ tutorial para todos os usuarios da Apprule: "admin"→ apenas usuarios com essa ability/role- Um usuario pode ter multiplos tutoriais (genericos + especificos)
Persistencia de Preferencia
- "Nao mostrar novamente" seta
dismissed = true— irreversivel via UI - Completar um tutorial nao impede reexibicao — apenas registra analytics
- "Nao agora" apenas fecha o popup — tutorial reaparece na proxima sessao
Data: 13/04/2026
Branch: feat/panel-tutorial
Status: Implementado — CRUD + Runtime + Analytics + Admin Panel + Workflow Integration