# 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.

```mermaid
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:

```prisma
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`)

```typescript
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

```mermaid
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`)

```mermaid
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

```mermaid
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_xxx` e criado/atualizado em `app.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

```typescript
// 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`):

```json
[
  {
    "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

1. Navegue para `/fastapp/tutorials` → **"Novo Tutorial"**
2. Preencha **Nome**, **App**, **Publico-alvo**, **Descricao**
3. Ative **"Gerar Workflow"** se quiser criar um workflow visual automatico
4. Adicione **Passos**: titulo, seletor CSS (dropdown ou livre), descricao
5. Use o botao de validacao para testar se o seletor existe na pagina
6. Clique **"Preview"** para testar no Driver.js
7. 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_workflow` desativado
- 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_id` na query garante isolamento

### Regras de Rule
- `rule: null` → tutorial para **todos** os usuarios da App
- `rule: "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
