Skip to content

feat(treinamento-interno): aba de cursos internos com sync Drive, comentários e likes#139

Merged
Warleypablo merged 20 commits intomainfrom
feature/treinamento-interno
Apr 29, 2026
Merged

feat(treinamento-interno): aba de cursos internos com sync Drive, comentários e likes#139
Warleypablo merged 20 commits intomainfrom
feature/treinamento-interno

Conversation

@Warleypablo
Copy link
Copy Markdown
Owner

Summary

Nova aba Treinamento Interno na página /conhecimentos. Sincroniza automaticamente vídeos da pasta TREINAMENTOS no Google Drive, com player embed, marcação manual de conclusão por usuário, likes e comentários.

  • Sync Drive: cron a cada 1h + botão manual. Subpastas viram trilhas (Performance, IA, Tech, CX/CS, Designer, Comercial, Pré-vendas, Social media, Creators). Suporte a Shared Drive.
  • 5 tabelas novas em cortex_core: internal_video_tracks, internal_videos, internal_video_completions, internal_video_likes, internal_video_comments. Soft-delete preserva engajamento se vídeo for retirado do Drive.
  • API REST sob /api/treinamentos-internos/* com 8 endpoints (3 GET, 4 POST toggle/comment/sync, 1 DELETE comment com 403/404).
  • Frontend: 3ª aba em Conhecimentos.tsx, página dedicada /conhecimentos/treinamentos/:videoId com player iframe + thread de comentários + ações.

Validação

Smoke test E2E feito local: 9 trilhas, 22 vídeos puxados do Drive (Performance: 14, Social media: 8). Player embed funciona, conclusão/like/comentários e DELETE com autorização verificados.

Test plan

  • 134 testes unitários passando (22 novos em sync + routes)
  • Migration aplicada em local e produção (cortex_core.internal_video_*)
  • Service account report-job-sa@auto-report-turbo.iam.gserviceaccount.com com acesso à pasta TREINAMENTOS
  • INTERNAL_TRAININGS_DRIVE_FOLDER_ID configurada no .env local
  • Pré-deploy: adicionar INTERNAL_TRAININGS_DRIVE_FOLDER_ID=126AbwLea-me3aeQRKxl3Y9pIYnztY438 no env de produção
  • Pré-deploy: garantir permissão "Qualquer pessoa com o link → Leitor" nos vídeos do Drive (necessário para o iframe carregar)
  • Após deploy: clicar em "Sincronizar agora" na aba uma vez para popular o banco de prod

Docs

  • Spec: docs/superpowers/specs/2026-04-29-treinamento-interno-design.md
  • Plano: docs/superpowers/plans/2026-04-29-treinamento-interno.md

Warleypablo and others added 20 commits April 29, 2026 12:49
… interno

Spec completo da nova aba "Treinamento Interno" na página Conhecimentos.
Sync automático com pasta TREINAMENTOS no Drive (subpastas viram trilhas),
player embed, comentários e likes, marcação manual de conclusão.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Plano com 12 tasks numeradas, cada uma com TDD passo-a-passo, código
completo e comandos verificáveis. Cobre schema/migration, sync com
Drive, endpoints REST (leitura, toggle, comentários, sync), cron de
1h, frontend (themes, player, comentários, cards, aba, página do
vídeo) e checklist operacional final com smoke E2E.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Worktrees locais nunca devem ser commitadas; previne git add . acidental.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Schema cortex_core ganha tabelas para sync com Drive (tracks, videos),
progresso (completions), likes e comentários. Migration aplicada local
(prod fica para etapa operacional).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…keys

Insert<Name> types via $inferInsert (alinha com convenção do projeto, evita
fricção em Tasks 2-5 que farão upserts). Renomeia
uniqueUserVideo → uniqueCompletionUserVideo / uniqueLikeUserVideo para
desambiguar entre completions e likes.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Sync lê pasta raiz TREINAMENTOS, percorre subpastas (trilhas) e seus
vídeos, faz upsert nas tabelas. Reconciliação por soft-delete preserva
comentários/likes. Lock em memória previne sync paralelo. Erros por
trilha não interrompem outras trilhas.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…s transientes

- Paginação no listing de subpastas (evita perder trilhas em folders >1000)
- erroredFolderIds não deixa reconciliação desativar trilhas que falharam
- try/catch em torno de cada etapa de reconciliação (DB blip não invalida sync)
- Defensive mimeType check no per-video loop

Endereça issues important do code review da Task 2.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
GET /trilhas com agregação de progresso do usuário, GET /videos por
trilha (lazy load), GET /videos/:id com comentários e flags
isOwner/userConcluiu/userCurtiu. Soft-deleted retorna 404.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Substitui error.message por strings genéricas em handlers de leitura
para evitar leak de detalhes internos (Postgres errors, constraint
names, fragments de SQL) no payload de 500. Logs ainda capturam o
error completo para debug.

Endereça issue important do code review da Task 3.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
POST /videos/:id/concluir e POST /videos/:id/like com semântica de
toggle (cria registro na primeira chamada, deleta na segunda).
Endpoint de like também retorna o totalLikes atualizado.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…LICT DO NOTHING)

Insere com ON CONFLICT DO NOTHING nos toggles de concluir/like.
Sem isso, dois cliques rápidos do mesmo usuário podiam disparar 2
INSERTs concorrentes — o segundo violaria a unique constraint
(video_id, user_email) e devolveria 500 ao usuário, mesmo o primeiro
tendo sucedido. Agora o segundo INSERT é silently no-op.

Endereça issue important do code review da Task 4.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
POST /videos/:id/comentarios cria comentário (validação inline para
conteúdo vazio ou >5000 chars). DELETE /comentarios/:id valida que
userEmail bate com o dono — 403 para outros, 404 se não existe.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
POST /api/treinamentos-internos/sync dispara sync sob demanda. Cron em
server/index.ts roda a cada 1 hora (primeira execução 60s após boot).
Status do último sync exposto em globalThis.__internalTrainingsSyncStatus.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
trackThemes.ts mapeia cor/ícone das 9 trilhas com fallback default.
VideoPlayer wrappa iframe Drive embed e expõe link "Abrir no Drive"
como fallback se permissão do iframe falhar.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
ComentarioItem renderiza um comentário com avatar (inicial), tempo
relativo em pt-BR, linkifica URLs, e expõe botão de excluir só para o
dono (com AlertDialog). ComentariosThread tem form com Enter para
enviar (Shift+Enter quebra linha), contador de caracteres e lista.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
VideoCard mostra thumbnail, duração formatada (mm:ss) e badge ✓ se
concluído. Click navega para a página do vídeo. TrilhaCard é
expansível com progresso visual, lazy-load dos vídeos ao expandir e
suporte a filtro de busca recebido via prop.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
TreinamentoInternoTab combina busca, botão de sync manual e listagem
de trilhas. Conhecimentos.tsx agora tem 3 abas (Cursos, Benefícios,
Treinamento Interno) com ícones na TabsList.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…ários

Rota /conhecimentos/treinamentos/:videoId. Mostra breadcrumb da
trilha, player embed, botões de Concluído (toggle) e Like (toggle com
contador) e thread de comentários abaixo. 404 vira tela amigável de
"vídeo não disponível".

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…utations

Mutations (concluir, like, criar/excluir comentário) usavam chave
['videos', videoId] que só invalidava a query do detalhe. As listas
por trilha (chave ['videos', { trackId }]) ficavam stale, e o ✓ no
VideoCard saía de sincronia com o contador da trilha.

Agora invalidam o prefixo ['videos'], cobrindo detalhe e listas.

Endereça issue important do code review do frontend.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
A pasta TREINAMENTOS vive num Shared Drive (Drive de Equipe). Sem
supportsAllDrives + includeItemsFromAllDrives nas queries do Drive,
a API retorna "File not found" / lista vazia mesmo com a service
account autorizada.

Sync validado E2E: 9 trilhas, 22 vídeos puxados sem erros.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@Warleypablo Warleypablo merged commit c334d80 into main Apr 29, 2026
1 check passed
@Warleypablo Warleypablo deleted the feature/treinamento-interno branch April 29, 2026 18:38
@Warleypablo Warleypablo restored the feature/treinamento-interno branch April 30, 2026 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant