Frontend: Páginas¶
Visão Geral¶
Páginas do portal em Ciba.Web/Pages/. Organizadas por recurso.
Estrutura:
Pages/
├── Dashboard.razor → Pagina inicial com checklist/welcome
├── Login.razor → Autenticacao
├── Profile.razor → Minha conta (alterar senha)
├── Agents/ → Gestao de agentes
├── Instances/ → Instancias WhatsApp
├── Conversations/ → Chat e conversas
├── AiModels/ → Modelos de IA
├── Onboarding/ → Wizard de configuracao inicial
├── Help/ → Ajuda in-app
└── Admin/ → Tenants e configuracoes
Padrão de organização:
- Página: {Nome}.razor (markup)
- Code-behind: {Nome}.razor.cs (lógica)
- Componentes locais: Components/ dentro da pasta do recurso
Dashboard (/)¶
Arquivo: Pages/Dashboard.razor + Pages/Dashboard.razor.cs
Dashboard com relatórios visuais, KPIs e listagem de instâncias/agentes.
Layout¶
[SetupChecklist (admin, onboarding incompleto) OU WelcomeCard (usuario comum)]
[DashboardDateFilter — filtro de período + agente]
[KpiCards — 6 cards com métricas principais]
[ConversationsOverTimeChart — gráfico de área full width]
[StepFunnelChart | PeakHoursHeatmap — 50/50 grid]
[FollowUpEffectivenessCard — 4 cards full width]
--- divider ---
[Instâncias WhatsApp — cards com status]
[Agentes — cards com métricas do dia]
Componentes de Dashboard (Components/Dashboard/)¶
| Componente | Tipo | Descrição |
|---|---|---|
SetupChecklist |
MudBlazor | Checklist de configuracao inicial (admin) com 3 criterios |
WelcomeCard |
MudBlazor | Card de boas-vindas para usuarios comuns com dismiss |
DashboardDateFilter |
MudBlazor | DateRangePicker + botões rápidos (7d/30d/90d) + seletor de agente |
KpiCards |
MudBlazor | 6 MudCards: Total, Ativas, IA, Escaladas, Tempo Médio, Taxa IA |
ConversationsOverTimeChart |
ApexCharts | Gráfico de área com 3 séries (Total, IA, Escalado) |
StepFunnelChart |
ApexCharts | Gráfico de barras horizontal (funil de steps) |
PeakHoursHeatmap |
ApexCharts | Heatmap 7 dias × 24 horas |
FollowUpEffectivenessCard |
MudBlazor | 4 cards com métricas de follow-up |
Filtros¶
- Período: DateRangePicker com botões rápidos (7 dias, 30 dias, 90 dias)
- Agente: Select opcional para filtrar por agente específico
- Default: últimos 30 dias, todos os agentes
Carregamento¶
- Instâncias e agentes carregados no
OnInitializedAsync - 5 endpoints de relatório carregados em paralelo via
Task.WhenAllquando filtro muda DashboardDateFilterdisparaOnFilterChangedautomaticamente noOnInitializedAsync
Chart Library¶
- Blazor-ApexCharts v3.* —
@using ApexChartsadicionado por componente (não global, conflita com MudBlazor nos tiposSize,Color,Mode) - Scripts JS carregados em
wwwroot/index.html
Dados Exibidos¶
KPIs: - Total de conversas no período - Conversas ativas - Resolvidas por IA - Escaladas para humano - Tempo médio de resolução (horas) - Taxa de resolução por IA (%)
Por Instância: - Nome - Status de conexão (Connected, Disconnected, etc.) - Agente vinculado - Conversas do dia
Por Agente: - Nome - Status (Ativo/Inativo) - Conversas do dia
Login (/login)¶
Arquivo: Pages/Login.razor
Página de autenticação com layout próprio (EmptyLayout).
Estrutura¶
- Lado esquerdo: Branding CIBA + lista de features
- Lado direito: Form de login
Form¶
<FluentForm TModel="LoginRequest" Model="_model" OnValidSubmit="HandleLogin">
<MudTextField @bind-Value="_model.Email" Label="Email" />
<MudTextField @bind-Value="_model.Password" InputType="InputType.Password" />
<FormButtonGroup SaveText="Entrar" HideCancel="true" />
</FluentForm>
Comportamento¶
- Valida credenciais via
AuthService - Armazena JWT no
LocalStorage - Se
mustChangePassword=true, redireciona para/profile - Caso contrário, redireciona para Dashboard
Minha Conta (/profile)¶
Arquivo: Pages/Profile.razor
Página para alteração de senha do próprio usuário.
Campos: - Senha atual - Nova senha (mínimo 8 caracteres, 1 maiúscula, 1 minúscula, 1 número)
Comportamento:
- Se mustChangePassword=true, exibe alerta e exige alteração
- Após sucesso, limpa a flag e redireciona para /
Agentes¶
Lista (/agents)¶
Arquivo: Pages/Agents/AgentList.razor
| Coluna | Descrição |
|---|---|
| Nome | Link para detalhe |
| Status | StatusChip (Ativo/Inativo) |
| Conversas Hoje | Contador |
Componentes: StateView, EmptyState, StatusChip
Criar (/agents/create)¶
Arquivo: Pages/Agents/AgentCreate.razor
Form com campos: - Nome (obrigatório) - Descrição - System Prompt (textarea) - Status (toggle)
Editar (/agents/{id}/edit)¶
Arquivo: Pages/Agents/AgentEdit.razor
Mesmo form do criar, preenchido com dados existentes.
Detalhe (/agents/{id})¶
Arquivo: Pages/Agents/AgentDetail.razor
Layout com abas:
| Aba | Componente | Descrição |
|---|---|---|
| Geral | AgentGeneralTab |
Informações básicas |
| Prompt | AgentPromptTab |
Edição do system prompt |
| Conhecimento | AgentKnowledgeTab |
Knowledge blocks com drag-drop |
| FAQ | AgentFaqTab |
Perguntas frequentes com drag-drop |
| Comportamento IA | AgentAiSettingsTab |
Tom, idioma e emojis |
Header: DetailPageHeader com estatísticas (StatisticCard)
Ações no Header:
- Playground (abre AgentPlaygroundDialog via DialogHelper)
- Editar
- Arquivar
Playground (AgentPlaygroundTab / AgentPlaygroundDialog)¶
Ambiente de teste para conversar diretamente com o agente. Usa os mesmos componentes visuais do Chat (Components/Chat/) com Mode=ChatMode.Playground.
Funcionalidades: - Envio de texto, imagens (Claude Vision) e áudio (Whisper transcrição) - Múltiplas conversas com persistência em localStorage - Exportação de chat em JSON - Contador de tokens (input/output)
Armazenamento: localStorage via PlaygroundStorageService (sem persistência em banco)
Dialog: AgentPlaygroundDialog encapsula AgentPlaygroundTab em um MudDialog
Instâncias WhatsApp¶
Lista (/instances)¶
Arquivo: Pages/Instances/InstanceList.razor
| Coluna | Descrição |
|---|---|
| Nome | Link para detalhe |
| Status | Chip colorido |
| Agente | Link ou "Não vinculado" |
Criar (dialog)¶
Arquivo: Pages/Instances/Components/InstanceCreateDialog.razor
Dialog com campos: - Nome (obrigatório) - Agente (select opcional)
Detalhe (/instances/{id})¶
Arquivo: Pages/Instances/InstanceDetail.razor
Abas:
| Aba | Componente | Descrição |
|---|---|---|
| Geral | InstanceGeneralTab |
Info da instância |
| Configurações | InstanceConfigTab |
Agente, modelo, assinatura, typing, delay |
| Whitelist | InstanceWhitelistTab |
Números permitidos |
| Blacklist | InstanceBlacklistTab |
Números bloqueados |
Ações no Header:
- Conectar/Desconectar WhatsApp (abre QrCodeDialog)
- Arquivar
Diálogos¶
- InstanceCreateDialog: Criação de instância
- QrCodeDialog: Exibe QR code para conexão
- InstanceWhitelistEntryDialog: Adicionar/editar whitelist
- InstanceBlacklistEntryDialog: Adicionar/editar blacklist
Conversas¶
Layout (/conversations)¶
Arquivo: Pages/Conversations/ConversationsLayout.razor
Layout split-pane responsivo: - Desktop: Sidebar (350px) + Chat - Mobile: Uma view por vez
Rotas suportadas:
- /conversations — Lista de conversas
- /conversations/{conversationId} — Conversa específica
- /conversations/instance/{instanceId} — Filtro por instância
Sidebar¶
Arquivo: Pages/Conversations/ConversationSidebar.razor
- Filtro por instância
- Busca por nome/telefone
- Lista de conversas com:
- Avatar do contato
- Nome/telefone
- Preview da última mensagem
- Badge de não lidas
- Timestamp
Chat¶
Arquivo: Pages/Conversations/ConversationChat.razor
Componentes locais:
- ChatHeader — Info do contato + ações
Componentes compartilhados (Components/Chat/):
- MessageBubble — Bolha de mensagem (com Mode=ChatMode.Conversation)
- MessageInput — Campo de envio com texto, anexos e gravação
- AudioPlayer — Player de áudio
- DocumentPreview — Preview de documento
Funcionalidades: - Scroll infinito (paginação) - Real-time via SignalR - Envio de texto e mídia - Reações com emoji - Status de mensagem (sent, delivered, read)
Diálogos¶
- StartConversationDialog: Iniciar nova conversa
- ResolveConversationDialog: Resolver/fechar conversa
- MediaLightboxDialog: Visualizar mídia em tela cheia
Modelos de IA¶
Lista (/ai-models)¶
Arquivo: Pages/AiModels/AiModelList.razor
| Coluna | Descrição |
|---|---|
| Nome | Nome do modelo |
| Provider | OpenAI, Anthropic, etc. |
| Model ID | ID da API |
Criar (/ai-models/create)¶
Arquivo: Pages/AiModels/AiModelCreate.razor
Editar (/ai-models/{id}/edit)¶
Arquivo: Pages/AiModels/AiModelEdit.razor
Admin (SuperAdmin)¶
Usuarios (/admin/users)¶
Arquivo: Pages/Admin/UsersList.razor
Gerenciamento de usuários (Admin e SuperAdmin).
Tabela: - Nome - Email - Role - Status - Último acesso - Tenant (apenas SuperAdmin)
Ações: - Criar usuário - Editar usuário - Resetar senha - Ativar/Desativar
Tenants¶
Lista: /admin/tenants
Criar: /admin/tenants/create
Editar: /admin/tenants/{id}/edit
Gerenciamento de tenants para multi-tenancy.
LLM Usage (/admin/llm-usage)¶
Arquivo: Pages/Admin/LlmUsage/Index.razor
Dashboard de monitoramento de uso de LLM (tokens e custos).
Componentes:
| Componente | Descrição |
|---|---|
LlmUsageSummaryCards |
Cards com totais (tokens, custo, requests) |
LlmUsageFilterBar |
Filtros por período, provider, modelo |
LlmUsageByModelTable |
Tabela de uso agrupado por modelo |
LlmUsageByOperationTable |
Tabela de uso agrupado por tipo de operação |
LlmUsageByTenantTable |
Tabela de uso agrupado por tenant (SuperAdmin) |
Funcionalidades: - Filtro por período (data inicial/final) - Filtro por provider (Anthropic, OpenAI) - Filtro por modelo específico - Visualização de custo estimado em USD - Agregação por modelo, operação e tenant
System Settings (/admin/settings)¶
Arquivo: Pages/Admin/SystemSettings.razor
Configurações globais do sistema: - Mensagem de erro padrão - Mensagem de boas-vindas padrão - Mensagem de rate limit - Mensagem fora do horário
Onboarding (/onboarding)¶
Arquivo: Pages/Onboarding/OnboardingWizard.razor + .razor.cs
Wizard de configuracao inicial para administradores na primeira utilizacao. Usa EmptyLayout (sem menu lateral).
Layout¶
[MudContainer MaxWidth.Small, centralizado, altura total do viewport]
[MudPaper com elevacao]
Indicador de passo: "Passo X de 3"
Conteudo do passo ativo
Botoes de navegacao (Anterior / Proximo / Pular)
Passos¶
| Passo | Indice | Descricao |
|---|---|---|
| Boas-vindas | 0 | Apresentacao do sistema com lista de features e botoes "Comecar" / "Pular" |
| Criar Agente | 1 | Formulario com nome e system prompt do agente |
| Criar Instancia | 2 | Formulario com nome da instancia (pre-vinculada ao agente criado) |
| QR Code | 3 | Exibicao do QR code com polling automatico de status (5s) |
| Sucesso | 4 | Tela de conclusao com links rapidos para agente e dashboard |
Comportamento¶
- Pular: Chama
POST /api/onboarding/completee redireciona para Dashboard - Finalizar: Mesmo fluxo do pular, apos completar todos os passos
- Polling QR: Timer a cada 5s verifica status de conexao; auto-avanca quando conectado
- Disposal: Timer limpo via
IDisposable - Erros:
Snackbar.ShowIfError(result)para feedback de erros
Dependencias¶
ApiClient(criar agente, instancia, conectar, status)NavigationManager(redirecionamentos)ISnackbar(feedback)
Help (/help)¶
Arquivo: Pages/Help/HelpIndex.razor + .razor.cs
Pagina de ajuda in-app com documentacao das funcionalidades do sistema.
Layout¶
[MudGrid]
[Sidebar xs=12 md=3]
MudNavMenu com links para secoes
[Conteudo xs=12 md=9]
Secao ativa renderizada via switch
Secoes¶
| # | Secao | Componente | Visibilidade |
|---|---|---|---|
| 0 | Primeiros Passos | GettingStartedSection.razor |
Todos |
| 1 | Agentes | AgentsSection.razor |
Admin |
| 2 | Canais WhatsApp | InstancesSection.razor |
Admin |
| 3 | Conversas | ConversationsSection.razor |
Todos |
| 4 | Dashboard | DashboardSection.razor |
Todos |
| 5 | Follow-Up | FollowUpSection.razor |
Admin |
Comportamento¶
- Navegacao client-side (sem mudanca de rota, troca de secao via estado)
- Filtro por role: secoes admin-only ocultadas para usuarios comuns
- Secoes sao componentes estaticos (sem chamadas a API)
- Todo conteudo em portugues
Secoes em Pages/Help/Sections/¶
Cada secao e um componente Razor puro (sem code-behind) envolto em MudPaper:
| Componente | Conteudo |
|---|---|
GettingStartedSection |
O que e Ciba, 3 cards conceituais (Agente, Instancia, Conversa), timeline de setup |
AgentsSection |
Guia de criacao, abas detalhadas (MudExpansionPanels), boas praticas de prompt |
InstancesSection |
Timeline de criacao, tabela de configuracoes, whitelist/blacklist |
ConversationsSection |
Tabela de status, modos IA/Manual, acoes disponiveis |
DashboardSection |
Filtros, metricas (KPIs, graficos, heatmap, follow-up) |
FollowUpSection |
Timeline de fluxo, tabela de configuracoes, dicas |
Padroes de Pagina¶
Página de Lista¶
@page "/recurso"
<MudText Typo="Typo.h4">Título</MudText>
<MudButton Href="/recurso/create">Novo</MudButton>
<StateView TItem="List<ItemResponse>" Result="_result" Loading="_loading" OnRetry="Load">
<EmptyContent>
<EmptyState Message="Nenhum item" ActionText="Criar" OnAction="Create" />
</EmptyContent>
<ChildContent Context="items">
<MudTable Items="items">
@* colunas *@
</MudTable>
</ChildContent>
</StateView>
Página de Detalhe¶
@page "/recurso/{Id:guid}"
<StateView TItem="ItemResponse" Result="_result" Loading="_loading" OnRetry="Load">
<ChildContent Context="item">
<DetailPageHeader Title="@item.Name" EditHref="..." OnDelete="Delete" />
<MudTabs>
@* abas de conteúdo *@
</MudTabs>
</ChildContent>
</StateView>
Página de Form (Create/Edit)¶
@page "/recurso/create"
<MudText Typo="Typo.h4">Novo Item</MudText>
<FluentForm TModel="CreateRequest" Model="_model" OnValidSubmit="Save">
<MudTextField @bind-Value="_model.Name" Label="Nome" />
@* campos *@
<FormButtonGroup CancelHref="/recurso" SaveText="Criar" />
</FluentForm>
Code-Behind Padrão¶
public partial class RecursoList
{
[Inject] private ApiClient ApiClient { get; set; } = null!;
[Inject] private ISnackbar Snackbar { get; set; } = null!;
[Inject] private NavigationManager Navigation { get; set; } = null!;
private bool _loading = true;
private Result<List<ItemResponse>>? _result;
protected override async Task OnInitializedAsync() => await Load();
private async Task Load()
{
_loading = true;
_result = await ApiClient.GetItemsAsync();
_loading = false;
}
private async Task Delete(ItemResponse item)
{
var result = await ApiClient.DeleteItemAsync(item.Id);
if (Snackbar.ShowIfError(result)) return;
Snackbar.Add("Item excluído", Severity.Success);
await Load();
}
}
Navegação¶
Menu lateral (NavMenu):
Dashboard
Canais
Agentes
Usuarios (Admin+)
Conversas
Ajuda
Minha Conta
───────────
Tenants (SuperAdmin)
Uso de LLM (SuperAdmin)
Configuracoes (SuperAdmin)
Breadcrumbs: Implícitos via estrutura de URLs
Responsividade¶
- Mobile (<960px): Layout single-column
- Tablet (960-1264px): Sidebar reduzida
- Desktop (>1264px): Layout completo
Conversas tem comportamento especial: - Mobile: alterna entre lista e chat - Desktop: split-pane permanente