1// catalog-journeys.js â dados de jornadas/conceitos/telas/patterns 2// (extraÃdo de app.js em 2026-09-02, Fase 2 do split). 3// Só é carregado nas páginas que renderizam catálogo/jornada. 4// Consts globais (script clássico), como antes do split. 5 6const patternExamples = [ 7 { 8 slug: 'landing-page', 9 label: 'Landing page', 10 title: 'Hero + CTA', 11 accent: '#1D3557', 12 summary: 'Header, Hero, Button, Card', 13 description: 'Boa para apresentar uma oferta, explicar valor e conduzir a pessoa para uma ação principal.', 14 components: ['Header', 'Hero', 'CTA', 'Card'], 15 prompt: 'Crie uma landing page com Header, Hero com promessa clara, CTA principal e cards de benefÃcios abaixo.', 16 visual: () => `<div class="pattern-example pattern-landing"><header><strong>Como Pedir</strong><nav>Recursos · Planos · Entrar</nav></header><section><p>Treinamento prático</p><h3>Aprenda a pedir interfaces melhores.</h3><button>Começar agora</button></section><div><article>Clareza</article><article>Exemplos</article><article>Prática</article></div></div>` 17 }, 18 { 19 slug: 'dashboard', 20 label: 'Dashboard', 21 title: 'Sidebar + Cards + Chart', 22 accent: '#E63946', 23 summary: 'Sidebar, Badge, Chart, Filter', 24 description: 'Serve para acompanhar métricas, navegar por áreas internas e comparar indicadores com rapidez.', 25 components: ['Sidebar', 'Filter', 'Chart'], 26 prompt: 'Crie um dashboard com sidebar lateral, filtros no topo, três cards de KPI e um gráfico principal de desempenho.', 27 visual: () => `<div class="pattern-example pattern-dashboard"><aside><span>Home</span><span>Vendas</span><span>Alunos</span></aside><main><header><strong>Visão geral</strong><button>Filtrar</button></header><section><article><span>Alunos</span><b>248</b></article><article><span>Receita</span><b>R$ 12k</b></article><article><span>Ativos</span><b>91%</b></article></section><div class="fake-chart"><span></span><span></span><span></span><span></span></div></main></div>` 28 }, 29 { 30 slug: 'formulario', 31 label: 'Formulário', 32 title: 'Form + Input + Button', 33 accent: '#1D3557', 34 summary: 'Label, Input, Select, Alert', 35 description: 'Ideal quando o usuário precisa informar dados, escolher opções e receber feedback antes de avançar.', 36 components: ['Label', 'Input', 'Alert'], 37 prompt: 'Crie um formulário com labels claros, campos de nome e e-mail, select de interesse, mensagem de ajuda e botão de envio.', 38 visual: () => `<div class="pattern-example pattern-form"><form><label>Nome<input placeholder="Maria Souza"></label><label>E-mail<input placeholder="[email protected]"></label><label>Interesse<select><option>Primeiros Passos</option></select></label><p>Revise os dados antes de continuar.</p><button>Enviar cadastro</button></form></div>` 39 }, 40 { 41 slug: 'onboarding', 42 label: 'Onboarding', 43 title: 'Progress + Form + Tooltip', 44 accent: '#E17BB8', 45 summary: 'Progress, Tooltip, Button', 46 description: 'Ajuda uma pessoa nova a passar por etapas curtas sem se perder no começo do produto.', 47 components: ['Progress', 'Tooltip', 'Button'], 48 prompt: 'Crie um onboarding em três passos com barra de progresso, card de orientação, tooltip contextual e botões de avançar/voltar.', 49 visual: () => `<div class="pattern-example pattern-onboarding"><div class="progress"><span></span><span></span><span></span></div><article><small>Passo 02 de 03</small><h3>Configure seu primeiro pedido</h3><p>Use uma frase simples e escolha o tipo de tela.</p><em>Dica: comece pelo objetivo.</em></article><footer><button>Voltar</button><button>Avançar</button></footer></div>` 50 }, 51 { 52 slug: 'galeria-midia', 53 label: 'Galeria de mÃdia', 54 title: 'Gallery + Modal + Image', 55 accent: '#6A58E8', 56 summary: 'Gallery, Modal, Aspect Ratio', 57 description: 'Boa para mostrar imagens, produtos, aulas, portfólio ou materiais visuais em uma grade organizada.', 58 components: ['Gallery', 'Modal', 'Aspect Ratio'],
59 prompt: 'Crie uma galeria com imagem principal grande, miniaturas laterais, tÃtulo da mÃdia e botão para abrir preview em modal.', 60 visual: () => `<div class="pattern-example pattern-gallery"><div class="hero-image">Preview</div><div class="thumbs"><span></span><span></span><span></span></div><article><h3>Aula visual</h3><p>Abra a imagem para ver detalhes.</p><button>Ver preview</button></article></div>` 61 }, 62 { 63 slug: 'busca-avancada', 64 label: 'Busca avançada', 65 title: 'Search + Filter + Pagination', 66 accent: '#26896E', 67 summary: 'Search, Filter, Pagination', 68 description: 'Ajuda a explorar listas grandes com busca, filtros, resultados escaneáveis e paginação.', 69 components: ['Search', 'Filter', 'Pagination'], 70 prompt: 'Crie uma busca avançada com campo de pesquisa, filtros por categoria e status, lista de resultados e paginação.', 71 visual: () => `<div class="pattern-example pattern-search"><header><input placeholder="Buscar componente"><button>
71Buscar</button></header><div class="filters"><span>Categoria</span><span>Status</span><span>NÃvel</span></div><section><article>Modal</article><article>Tabs</article><article>Dropdown</article></section><footer><button>1</button><button>2</button><button>3</button></footer></div>` 72 } 73]; 74 75const fullScreens = [ 76 { 77 slug: 'login', 78 name: 'Login', 79 label: 'Acesso', 80 audience: 'Entrada rápida e segura para produtos SaaS, áreas de membros e painéis internos.', 81 description: 'Uma tela curta, objetiva e focada em reduzir fricção. Ideal para destacar credenciais, recuperação de senha e caminhos alternativos como SSO.', 82 components: ['Header', 'Card', 'Form', 'Input', 'Button', 'Alert'], 83 contexts: ['SaaS', 'Ãrea logada', 'Mobile first'], 84 steps: [ 85 'Apresente marca, valor e contexto em um bloco simples acima do formulário.', 86 'Agrupe email, senha e ação principal em um card com hierarquia clara.', 87 'Reserve espaço para erro, loading e recuperação de acesso sem quebrar a composição.' 88 ], 89 blueprint: loginBlueprint 90 }, 91 { 92 slug: 'dashboard', 93 name: 'Dashboard', 94 label: 'Operação', 95 audience: 'Painéis com dados, métricas e ações frequentes para times de produto, vendas ou operações.', 96 description: 'Combina navegação lateral, filtros, cards de KPI e área analÃtica. A meta é permitir leitura rápida e decisões sem sobrecarga visual.', 97 components: ['Sidebar', 'Header', 'Filter', 'Card', 'Chart', 'Badge'], 98 contexts: ['Analytics', 'Admin', 'B2B'], 99 steps: [ 100 'Separe navegação, contexto da página e conteúdo analÃtico em zonas visuais distintas.', 101 'Use cards-resumo para leitura imediata antes de gráficos e tabelas mais densas.', 102 'Mantenha filtros próximos das métricas para reforçar causa e efeito na exploração.' 103 ], 104 blueprint: dashboardBlueprint 105 }, 106 { 107 slug: 'checkout', 108 name: 'Checkout', 109 label: 'Conversão', 110 audience: 'Fluxos de compra que precisam gerar confiança, mostrar resumo e evitar abandono.', 111 description: 'Organiza entrega, pagamento e revisão em uma progressão clara. A tela precisa equilibrar informação, confiança e foco na ação principal.', 112 components: ['Progress Bar', 'Form', 'Input', 'Select', 'Radio Button', 'Button'], 113 contexts: ['E-commerce', 'Pagamento', 'Fluxo guiado'], 114 steps: [ 115 'Mostre progresso, etapa atual e resumo do pedido desde o inÃcio.', 116 'Divida o formulário em blocos curtos para reduzir sensação de esforço.', 117 'Deixe total, polÃtica e CTA final sempre visÃveis na coluna de apoio ou no rodapé fixo.' 118 ], 119 blueprint: checkoutBlueprint 120 }, 121 { 122 slug: 'profile', 123 name: 'Perfil', 124 label: 'Conta', 125 audience: 'Ãreas de conta com dados pessoais, preferências e histórico de uso.', 126 description: 'Mistura leitura e edição com segurança. Boa para planos, avatar, configurações e dados persistentes do usuário.', 127 components: ['Avatar', 'Tabs', 'Form', 'Input', 'Switch', 'Button'], 128 contexts: ['Configurações', 'Conta', 'Preferências'], 129 steps: [ 130 'Crie um resumo superior com identidade, cargo, plano ou status atual.', 131 'Separe dados pessoais, segurança e notificações em abas ou seções independentes.', 132 'Confirme mudanças com feedback persistente, não apenas toast passageiro.' 133 ], 134 blueprint: profileBlueprint 135 }, 136 { 137 slug: 'product', 138 name: 'Página de produto', 139 label: 'Catálogo', 140 audience: 'Páginas de detalhe para e-commerce, cursos, templates e produtos digitais.', 141 description: 'Precisa vender o item e responder dúvidas ao mesmo tempo. Imagem, preço, variações, prova social e CTA trabalham em conjunto.', 142 components: ['Gallery', 'Aspect Ratio', 'Badge', 'Accordion', 'Button', 'Tabs'], 143 contexts: ['E-commerce', 'Marketplace', 'Landing transacional'], 144 steps: [ 145 'Destaque mÃdia e preço logo no primeiro bloco da dobra.', 146 'Use badges e microtextos para confiança, estoque e benefÃcio principal.', 147 'Empilhe detalhes técnicos, polÃticas e perguntas frequentes abaixo da decisão de compra.' 148 ], 149 blueprint: productBlueprint 150 }, 151 { 152 slug: 'notifications', 153 name: 'Central de notificações', 154 label: 'Engajamento', 155 audience: 'Feeds de avisos, atividades e atualizações em produtos com colaboração ou automação.', 156 description: 'Organiza volume e prioridade. Deve permitir leitura escaneável, filtros rápidos e estados de lido/não lido sem virar ruÃdo.', 157 components: ['Header', 'Search Bar', 'Filter', 'Badge', 'Tabs', 'Scroll Area'], 158 contexts: ['Colaboração', 'Sistema', 'Activity feed'], 159 steps: [ 160 'Mostre filtros por tipo, prioridade e status de leitura logo no topo.', 161 'Use badges e tipografia para diferenciar novidade, urgência e agrupamentos.', 162 'Combine lista densa com detalhes progressivos para não interromper o fluxo de leitura.' 163 ], 164 blueprint: notificationsBlueprint 165 } 166]; 167 168const learningJourney = [ 169 { 170 stage: 'Etapa 01', 171 title: 'Entenda blocos básicos', 172 goal: 'Comece por peças fáceis de reconhecer em quase toda interface: estrutura, ação e leitura rápida.', 173 components: ['Header', 'Section', 'Card', 'Button'], 174 markers: ['Header', 'Section', 'Card', 'Card', 'Button'], 175 focus: 'Comece lendo a tela de cima para baixo: topo, destaque, conteúdo e ação.', 176 practice: 'Nomeie quatro blocos de qualquer página e transforme isso em uma frase de pedido.', 177 lessons: [ 178 'Aprenda a diferença entre estrutura da página e conteúdo dentro dela.', 179 'Observe como tÃtulos, textos curtos e ações principais se organizam em um mesmo bloco.', 180 'Compare componentes que aparecem em marketing, dashboards e páginas institucionais.' 181 ], 182 visual: () => `<div class="training-wireframe grid grid-cols-1 gap-3"><div class="training-target" data-marker="1" data-label="Header"><div class="h-10 border-2 border-mondrian-black bg-white"></div></div><div class="training-target" data-marker="2" data-label="Section"><div class="h-24 border-2 border-mondrian-black bg-forge-blue"></div></div><div class="grid grid-cols-2 gap-3"><div class="training-target" data-marker="3" data-label="Card"><div class="h-20 border-2 border-mondrian-black bg-white"></div></div><div class="training-target" data-marker="4" data-label="Card"><div class="h-20 border-2 border-mondrian-black bg-white"></div></div></div><div class="training-target training-target-inline" data-marker="5" data-label="Button"><div class="h-10 w-32 bg-mondrian-black"></div></div></div>` 183 }, 184 { 185 stage: 'Etapa 02', 186 title: 'Domine entrada e decisão', 187 goal: 'Depois dos blocos, foque em como o usuário informa dados, confirma ações e recebe orientação.',
188 components: ['Form', 'Input', 'Select', 'Checkbox', 'Label'], 189 markers: ['Label', 'Input', 'Mensagem', 'Select', 'Opção', 'CTA'], 190 focus: 'Procure primeiro o label, depois o campo e por último a ação de confirmação.', 191 practice: 'Pegue um formulário real e escreva quais dados entram, quais escolhas existem e qual botão finaliza.', 192 lessons: [ 193 'Veja como labels, campos e mensagens de ajuda formam um conjunto.', 194 'Pratique a diferença entre selecionar uma opção, marcar várias ou apenas digitar.', 195 'Leia os estados e erros esperados antes de copiar qualquer snippet.' 196 ], 197 visual: () => `<div class="training-wireframe space-y-3"><div class="training-target training-target-inline" data-marker="1" data-label="Label"><div class="h-9 w-24 bg-mondrian-black"></div></div><div class="training-target" data-marker="2" data-label="Input"><div class="h-11 border-2 border-mondrian-black bg-white"></div></div><div class="training-target" data-marker="3" data-label="Mensagem"><div class="h-11 border-2 border-mondrian-black bg-white"></div></div><div class="grid grid-cols-2 gap-3"><div class="training-target" data-marker="4" data-label="Select"><div class="h-11 border-2 border-mondrian-black bg-white"></div></div><div class="training-target" data-marker="5" data-label="Opção"><div class="h-11 border-2 border-mondrian-black bg-white"></div></div></div><div class="training-target" data-marker="6" data-label="CTA"><div class="h-10 bg-forge-lime border-2 border-mondrian-black"></div></div></div>` 198 }, 199 { 200 stage: 'Etapa 03', 201 title: 'Navegue sem confusão', 202 goal: 'Agora que os componentes básicos fazem sentido, avance para orientação, menus e descoberta de conteúdo.', 203 components: ['Navbar/Navigation', 'Tabs', 'Dropdown', 'Breadcrumb', 'Pagination'], 204 markers: ['Navbar', 'Menu', 'Tab', 'Aba ativa', 'Conteúdo', 'Página'], 205 focus: 'Identifique o que orienta localização, o que troca conteúdo e o que abre novas escolhas.', 206 practice: 'Descreva uma navegação usando nomes reais: Navbar, Tabs, Dropdown, Breadcrumb e Pagination.', 207 lessons: [ 208 'Entenda quando cada padrão organiza escolhas, contexto ou caminhos.', 209 'Observe o que fica sempre visÃvel e o que aparece apenas sob demanda.', 210 'Teste no catálogo quais padrões servem para poucas opções e quais lidam com listas maiores.' 211 ], 212 visual: () => `<div class="training-wireframe space-y-3"><div class="grid grid-cols-[minmax(0,1fr)_72px] gap-3"><div class="training-target" data-marker="1" data-label="Navbar"><div class="h-10 bg-mondrian-black"></div></div><div class="training-target" data-marker="2" data-label="Menu"><div class="h-10 border-2 border-mondrian-black bg-white"></div></div></div><div class="grid grid-cols-3 gap-2"><div class="training-target" data-marker="3" data-label="Tab"><div class="h-9 bg-white border-2 border-mondrian-black"></div></div><div class="training-target" data-marker="4" data-label="Ativa"><div class="h-9 bg-forge-pink border-2 border-mondrian-black"></div></div><div class="h-9 bg-white border-2 border-mondrian-black"></div></div><div class="training-target" data-marker="5" data-label="Conteúdo"><div class="h-20 border-2 border-mondrian-black bg-white"></div></div><div class="grid grid-cols-[42px_72px_42px] gap-3"><div class="h-8 border-2 border-mondrian-black bg-white"></div><div class="training-target" data-marker="6" data-label="Página"><div class="h-8 bg-mondrian-black"></div></div><div class="h-8 border-2 border-mondrian-black bg-white"></div></div></div>` 213 }, 214 { 215 stage: 'Etapa 04', 216 title: 'Monte fluxos reais', 217 goal: 'Feche a trilha conectando componentes em telas completas, estados e interações mais avançadas.', 218 components: ['Modal', 'Drawer', 'Toast', 'Chart', 'Dashboard'], 219 markers: ['Sidebar', 'Header', 'Chart', 'Card', 'Feedback'], 220 focus: 'Veja a tela como fluxo: navegação, conteúdo, dado importante e feedback de ação.', 221 practice: 'Escolha uma tela completa e escreva quais componentes aparecem, em que ordem e por quê.', 222 lessons: [ 223 'Abra uma tela completa e tente reconhecer cada bloco do fluxo.', 224 'Estude feedback, overlays e componentes ricos como parte da experiência, não como itens soltos.', 225 'Volte ao catálogo com uma pergunta prática: âo que preciso para montar minha próxima tela?â' 226 ], 227 visual: () => `<div class="training-wireframe grid grid-cols-[70px_1fr] gap-3"><div class="training-target" data-marker="1" data-label="Sidebar"><div class="bg-mondrian-black min-h-[150px]"></div></div><div class="grid gap-3"><div class="training-target" data-marker="2" data-label="Header"><div class="h-10 border-2 border-mondrian-black bg-white"></div></div><div class="grid grid-cols-2 gap-3"><div class="training-target" data-marker="3" data-label="Chart"><div class="h-24 border-2 border-mondrian-black bg-forge-blue"></div></div><div class="training-target" data-marker="4" data-label="Card"><div class="h-24 border-2 border-mondrian-black bg-forge-pink"></div></div></div><div class="training-target" data-marker="5" data-label="Feedback"><div class="h-12 border-2 border-mondrian-black bg-white"></div></div></div></div>` 228 } 229]; 230 231const primeirosPassosCodigos = { 232 '01': [ 233 { codigo: '/anatomy' }, 234 { codigo: '/layout' }, 235 { codigo: '/component' } 236 ], 237 '02': [ 238 { codigo: '/form' }, 239 { codigo: '/feedback' } 240 ], 241 '03': [ 242 { codigo: '/navigation' } 243 ], 244 '04': [ 245 { codigo: '/flow' }, 246 { codigo: '/empty' }, 247 { codigo: '/loading' }, 248 { codigo: '/error' } 249 ], 250 '05': [ 251 { codigo: '/pattern' }, 252 { codigo: '/composition' } 253 ], 254 '06': [ 255 { codigo: '/screen' }, 256 { codigo: '/responsive' } 257 ], 258 '07': [ 259 { codigo: '/prompt' }, 260 { codigo: '/context' } 261 ] 262}; 263 264 265// Slug do plano/curso "Regras e Funcionamento" â precisa bater exatamente 266// com o slug real criado no painel gestor (Cursos -> Novo curso), gerado 267// automaticamente a partir do nome do curso na criação (ver 268// slugifyPlanName em functions/_shared/plans.js) e que não muda depois. 269const REGRAS_FUNCIONAMENTO_PLAN_SLUG = 'regras_e_funcionamentos'; 270 271const conceitoJourney = [ 272 { 273 stage: 'Aula 01', 274 estimatedMinutes: 35, 275 layout: 'grid', 276 title: 'Estado e decisão', 277 goal: 'Aprenda a reconhecer as regras que definem quando algo pode acontecer, em que situação um item está e até onde ele pode ir â a base de qualquer pedido de funcionamento, não só de visual.', 278 focus: 'Antes de pedir uma tela ou uma funcionalidade, pergunte: isso depende de alguma condição? Em qual status esse item está? Precisa de aprovação? Pode ser cancelado? O que acontece se der errado? Existe um limite?', 279 practice: 'Escolha um fluxo que você já usa (um app de delivery, um sistema de tarefas) e escreva a condição, o status, quem aprova, se cancela, o que é exceção e qual é o limite dele.', 280 exerciseFeedback: 'Não existe resposta única aqui â o que importa é cada frase estar especÃfica: a condição diz exatamente quando algo acontece, o status tem nomes claros, fica definido quem aprova, até quando dá pra cancelar, o que conta como exceção e qual é o limite numérico. Releia sua resposta e veja se um dev ou uma IA entenderiam sem precisar perguntar nada de volta.', 281 lessons: [ 282 'Aprenda a diferença entre uma condição (regra de decisão) e um status (estado atual do item).', 283 'Veja como aprovação e cancelamento definem quem controla cada etapa de um fluxo.', 284 'Pratique como descrever exceções e limites sem deixar brechas no pedido.' 285 ], 286 conceitos: [ 287 { 288 nome: 'Condição', 289 oQueE: 'Uma regra que diz o que precisa ser verdade pra alguma coisa acontecer. à o "se isso, então aquilo" por trás de qualquer comportamento condicional na tela ou no sistema.', 290 quandoUsar: 'Use quando o comportamento depende de um valor, escolha ou situação especÃfica â por exemplo, um botão que só aparece se o carrinho tiver itens, ou um desconto que só vale acima de certo valor.', 291 pedidoConfuso: 'O botão de finalizar deveria sumir à s vezes.', 292 pedidoClaro: 'O botão "Finalizar compra" só deve aparecer quando o carrinho tiver pelo menos 1 item. Se estiver vazio, mostrar o botão desabilitado com a mensagem "Adicione um item para continuar".', 293 termoTecnico: 'Condição (if/condition)', 294 termosRelacionados: ['regra condicional', 'if/else', 'critério', 'requisito'] 295 }, 296 { 297 nome: 'Status', 298 oQueE: 'O estado atual de um registro dentro de um fluxo â mostra em qual etapa ou situação aquele item está agora (pendente, ativo, concluÃdo, etc.).', 299 quandoUsar: 'Use sempre que um item passa por fases diferentes ao longo do tempo â um pedido, um cadastro, uma tarefa â e você precisa deixar claro em qual fase ele está.', 300 pedidoConfuso: 'Mostra lá se o pedido já foi ou não.', 301 pedidoClaro: 'Cada pedido deve ter um status visÃvel: "Pendente", "Em preparo", "Enviado" ou "Entregue". O status muda automaticamente conforme o pedido avança no fluxo.', 302 termoTecnico: 'Status (state)', 303 termosRelacionados: ['estado', 'etapa do fluxo', 'situação atual'] 304 }, 305 { 306 nome: 'Aprovação', 307 oQueE: 'Uma etapa em que alguém (ou algum critério automático) precisa confirmar que uma ação pode seguir em frente antes dela valer de fato.', 308 quandoUsar: 'Use quando uma ação tem impacto sério o suficiente pra exigir confirmação de outra pessoa antes de ser executada â reembolsos, publicações, mudanças de permissão.', 309 pedidoConfuso: 'Alguém precisa dar OK antes de liberar.', 310 pedidoClaro: 'Toda solicitação de reembolso acima de R$ 500 precisa de aprovação de um gestor antes de ser processada. Enquanto isso, o status fica "Aguardando aprovação".', 311 termoTecnico: 'Aprovação (approval workflow)', 312 termosRelacionados: ['fluxo de aprovação', 'confirmação', 'revisão'] 313 }, 314 { 315 nome: 'Cancelamento', 316 oQueE: 'A ação de interromper algo que já estava em andamento ou programado, antes que ele se complete.', 317 quandoUsar: 'Use quando o usuário precisa poder desistir de uma ação já iniciada â um pedido, um agendamento, uma assinatura â e você precisa definir até quando isso é permitido e o que acontece depois.', 318 pedidoConfuso: 'Precisa ter como cancelar.', 319 pedidoClaro: 'O usuário pode cancelar o pedido enquanto o status for "Pendente" ou "Em preparo". Depois que o status virar "Enviado", o cancelamento fica bloqueado e mostra a mensagem "Este pedido já está a caminho".', 320 termoTecnico: 'Cancelamento (cancel action)', 321 termosRelacionados: ['desistência', 'estorno', 'revogação'] 322 }, 323 { 324 nome: 'Exceção', 325 oQueE: 'Uma situação fora do caminho normal esperado â um erro, uma falha ou um caso especial que o fluxo principal não previu.', 326 quandoUsar: 'Use quando você precisa descrever o que acontece quando algo dá errado ou foge da regra geral â falha de pagamento, dado inválido, item fora de estoque.', 327 pedidoConfuso: 'Trata os erros direitinho.', 328 pedidoClaro: 'Se o pagamento falhar, mostrar a mensagem "Não conseguimos processar seu pagamento" e manter os dados do carrinho salvos para nova tentativa, sem cancelar o pedido automaticamente.', 329 termoTecnico: 'Exceção (exception/edge case)', 330 termosRelacionados: ['caso extremo', 'erro', 'falha', 'cenário fora do padrão'] 331 }, 332 { 333 nome: 'Limite', 334 oQueE: 'Um teto ou piso definido pra quantidade, valor, tempo ou tentativas permitidas antes que o sistema bloqueie ou avise.', 335 quandoUsar: 'Use quando existe um número máximo (ou mÃnimo) que não pode ser ultrapassado â tentativas de login, itens no carrinho, caracteres num campo, tempo de sessão.', 336 pedidoConfuso: 'Não deixa exagerar na quantidade.', 337 pedidoClaro: 'O campo "Quantidade" aceita no máximo 10 unidades por pedido. Ao tentar digitar mais, mostrar a mensagem "Limite de 10 unidades por pedido" e travar o valor em 10.', 338 termoTecnico: 'Limite (limit/threshold)', 339 termosRelacionados: ['teto', 'máximo', 'mÃnimo', 'quota'] 340 } 341 ], 342 codigos: [ 343 { codigo: '/conditions' }, 344 { codigo: '/status' }, 345 { codigo: '/decision' }, 346 { codigo: '/exceptions' } 347 ] 348 }, 349 { 350 stage: 'Aula 02', 351 estimatedMinutes: 35, 352 layout: 'timeline', 353 sequenceCount: 3, 354 connectors: ['dispara', 'avisa'], 355 title: 'Automação e tempo: o que o sistema faz sozinho', 356 goal: 'Aprenda a descrever o que acontece sozinho no sistema â prazos que vencem, ações que disparam automaticamente, avisos que chegam sem pedir e telas que se atualizam na hora.', 357 focus: 'Antes de pedir uma tela ou funcionalidade, pergunte: isso tem prazo? O sistema precisa fazer algo sozinho quando esse prazo bate? Alguém precisa ser avisado automaticamente? à um fluxo com etapas obrigatórias? A tela precisa se atualizar sozinha?', 358 practice: 'Pegue o mesmo fluxo que você usou na Aula 01 e acrescente: um prazo, uma ação automática ligada a esse prazo, uma notificação automática, se esse fluxo tem etapas obrigatórias e o que precisa atualizar em tempo real.', 359 exerciseFeedback: 'Não existe resposta única aqui â o que importa é a cadeia ficar especÃfica: qual é o prazo exato, o que dispara quando ele bate, quem é avisado e como, se existem etapas que não podem ser puladas, e o que na tela precisa mudar sozinho sem o usuário atualizar a página. Releia e veja se cada peça da cadeia está clara, não genérica.', 360 lessons: [ 361 'Aprenda a diferença entre um prazo (limite de tempo) e uma ação automática (o que acontece quando o prazo bate).', 362 'Veja como notificações automáticas mantêm o usuário informado sem ele precisar ficar checando a tela.', 363 'Pratique como descrever fluxos por etapas e telas que se atualizam em tempo real sem ambiguidade.' 364 ], 365 conceitos: [ 366 { 367 nome: 'Prazo', 368 when: 'Ponto de partida', 369 icon: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 3"/>', 370 oQueE: 'Uma data ou horário limite até quando algo precisa acontecer, depois do qual o comportamento muda (expira, atrasa, bloqueia).', 371 quandoUsar: 'Use quando uma ação só é válida até um certo momento â pagamento, cupom, convite, resposta a uma solicitação.', 372 pedidoConfuso: 'Bota um prazo pro cupom.', 373 pedidoClaro: 'O cupom "BEMVINDO10" fica válido por 7 dias a partir do cadastro. Depois de expirar, o campo mostra "Cupom expirado" e não aplica mais o desconto.', 374 termoTecnico: 'Prazo (deadline)', 375 termosRelacionados: ['contagem regressiva', 'expiração', 'vencimento', 'data limite'] 376 }, 377 { 378 nome: 'Ação automática', 379 when: 'Quando o prazo bate',
380 icon: '<path d="M13 2 3 14h7l-1 8 10-12h-7l1-8z"/>', 381 oQueE: 'Algo que o sistema faz sozinho, sem o usuário clicar em nada, quando uma condição ou um tempo é atingido.', 382 quandoUsar: 'Use quando o comportamento deve acontecer sem depender de um clique â cancelamento automático, renovação, arquivamento.', 383 pedidoConfuso: 'Faz isso sozinho depois de um tempo.', 384 pedidoClaro: 'Se o pedido ficar "Aguardando pagamento" por mais de 24 horas, o sistema cancela automaticamente e muda o status pra "Cancelado por falta de pagamento" â sem o usuário precisar fazer nada.', 385 termoTecnico: 'Ação automática (automated trigger)', 386 termosRelacionados: ['gatilho', 'trigger', 'job agendado', 'tarefa em segundo plano'] 387 }, 388 { 389 nome: 'Notificação automática', 390 when: 'Logo depois da ação', 391 icon: '<path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/>', 392 oQueE: 'Um aviso (e-mail, push, mensagem na tela) que o sistema dispara sozinho quando algo relevante acontece, sem precisar que alguém peça.', 393 quandoUsar: 'Use quando o usuário precisa saber de uma mudança sem estar olhando a tela naquele momento â pedido enviado, prazo próximo do fim, aprovação concluÃda.', 394 pedidoConfuso: 'Manda um aviso pro usuário.', 395 pedidoClaro: 'Quando o pedido mudar pra "Enviado", mandar um e-mail automático com o código de rastreio, e também mostrar um sininho de notificação no Ãcone do perfil.', 396 termoTecnico: 'Notificação automática (automated notification)', 397 termosRelacionados: ['alerta', 'push', 'e-mail transacional', 'aviso em tempo real'] 398 }, 399 { 400 nome: 'Fluxo por etapas', 401 when: 'Durante todo o processo', 402 icon: '<path d="M4 7l8-4 8 4-8 4-8-4z"/><path d="M4 12l8 4 8-4"/><path d="M4 17l8 4 8-4"/>', 403 oQueE: 'Um processo dividido em passos numerados que precisam acontecer em ordem, um depois do outro, sem pular etapas.', 404 quandoUsar: 'Use quando uma ação só pode avançar depois que a anterior foi concluÃda â checkout, onboarding, aprovação em cadeia.', 405 pedidoConfuso: 'Faz um passo a passo.', 406 pedidoClaro: 'O cadastro tem 3 etapas obrigatórias em ordem: dados pessoais, endereço e pagamento. O usuário só acessa a etapa 2 depois de preencher a etapa 1 corretamente â não dá pra pular direto pro pagamento.', 407 termoTecnico: 'Fluxo por etapas (step flow / wizard)', 408 termosRelacionados: ['wizard', 'etapas sequenciais', 'checklist de progresso', 'passo a passo'] 409 }, 410 { 411 nome: 'Atualização em tempo real', 412 when: 'A qualquer momento', 413 icon: '<path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/>', 414 oQueE: 'Quando a tela muda sozinha, na hora, refletindo uma mudança que aconteceu no sistema, sem o usuário precisar atualizar a página.', 415 quandoUsar: 'Use quando a informação muda com frequência e o usuário precisa ver isso instantaneamente â status de entrega, chat, painel de acompanhamento.', 416 pedidoConfuso: 'Atualiza sozinho.', 417 pedidoClaro: 'O status do pedido na tela de acompanhamento muda de "Em preparo" pra "Saiu para entrega" automaticamente, sem o usuário precisar apertar F5 ou sair e voltar na página.', 418 termoTecnico: 'Atualização em tempo real (real-time update)', 419 termosRelacionados: ['live update', 'polling', 'websocket', 'sincronização automática'] 420 } 421 ], 422 codigos: [ 423 { codigo: '/deadline' }, 424 { codigo: '/automation' }, 425 { codigo: '/notifications' }, 426 { codigo: '/workflow' } 427 ] 428 }, 429 { 430 stage: 'Aula 03', 431 estimatedMinutes: 45, 432 layout: 'diagram', 433 diagramCount: 3, 434 title: 'Integração entre sistemas: quando dois sistemas precisam se falar', 435 goal: 'Aprenda a descrever como o seu sistema troca dados com sistemas externos, e as regras internas que controlam a ordem e as condições dessas trocas.', 436 focus: 'Antes de pedir uma integração, pergunte: com qual sistema externo isso conversa? Quem avisa quem quando algo muda? Os dados precisam ficar sincronizados? Existe uma ordem obrigatória entre as ações? Alguma regra deveria bloquear isso em certos casos?', 437 practice: 'Pegue um fluxo que envolva um sistema externo que você conhece (pagamento, e-mail, login social) e descreva: como os dois sistemas se conectam, quem avisa quem, o que precisa ficar sincronizado, e quais regras internas dependem disso.', 438 exerciseFeedback: 'Não existe resposta única â o que importa é distinguir os papéis: qual sistema manda o webhook e qual recebe, o que exatamente precisa ficar sincronizado (e com que frequência), qual ação depende da outra pra acontecer, e qual regra bloquearia isso se uma condição não fosse atendida. Releia e veja se cada peça está especÃfica, não genérica.', 439 lessons: [ 440 'Aprenda a diferença entre integração (a conexão em si), webhook (o aviso automático) e sincronização (manter os dados iguais).', 441 'Veja como dependência entre ações define a ordem obrigatória de um processo.', 442 'Pratique como descrever um bloqueio por regra de negócio sem confundir com erro técnico.' 443 ], 444 conceitos: [ 445 { 446 nome: 'Integração com sistema externo', 447 icon: '<path d="M4 12h4M16 12h4M9 6l-2 6 2 6M15 6l2 6-2 6"/>', 448 oQueE: 'A conexão entre o seu sistema e outro sistema de fora (de outra empresa ou outro serviço), pra trocar dados ou disparar ações automaticamente.', 449 quandoUsar: 'Use quando o sistema precisa conversar com uma ferramenta externa â gateway de pagamento, serviço de e-mail, CRM, transportadora.', 450 comoFunciona: [ 451 'Você identifica qual sistema externo precisa participar do fluxo (ex.: gateway de pagamento).',
452 'O sistema externo disponibiliza uma forma de conexão (geralmente uma API ou um webhook).', 453 'Seu sistema se conecta usando uma credencial de acesso fornecida por esse sistema externo.', 454 'A partir daÃ, os dois sistemas trocam informações conforme o fluxo definido.' 455 ], 456 pedidoConfuso: 'Conecta com o sistema deles.', 457 pedidoClaro: 'Quando o pagamento for aprovado no Asaas (sistema externo), nosso sistema recebe essa confirmação automaticamente e libera o acesso do aluno.', 458 segundoExemplo: 'Em vez de cadastrar o endereço manualmente, o checkout usa a integração com o serviço dos Correios (ViaCEP) pra preencher rua, bairro e cidade automaticamente assim que o CEP é digitado.', 459 errosComuns: [ 460 'Não prever o que acontece se o sistema externo estiver fora do ar.', 461 'Guardar a credencial de acesso em local inseguro ou visÃvel no código.', 462 'Achar que a integração funciona pra sempre sem monitorar se ela continua ativa.' 463 ], 464 termoTecnico: 'Integração (external integration)', 465 termosRelacionados: ['API', 'sistema terceiro', 'conector', 'integração nativa'] 466 }, 467 { 468 nome: 'Webhook', 469 icon: '<path d="M12 3v7"/><path d="m8 7 4 3 4-3"/><rect x="4" y="13" width="16" height="7" rx="1"/>', 470 oQueE: 'Um aviso automático que um sistema externo manda pro seu sistema assim que algo acontece do lado dele, sem você precisar ficar perguntando.', 471 quandoUsar: 'Use quando você precisa reagir a um evento que acontece em outro sistema â pagamento confirmado, e-mail entregue, formulário externo enviado.', 472 comoFunciona: [ 473 'Algo acontece no sistema externo (ex.: um pagamento é confirmado).', 474 'O sistema externo monta um pacote de dados descrevendo esse evento.', 475 'Ele envia esse pacote pro endereço (endpoint) que você configurou com antecedência.', 476 'Seu sistema recebe, confere se é confiável, e reage (ex.: libera o acesso do aluno).' 477 ], 478 pedidoConfuso: 'Recebe o aviso deles.', 479 pedidoClaro: 'O Asaas manda um webhook pro nosso sistema assim que um Pix é pago. Assim que recebemos esse aviso, o sistema libera o acesso do aluno automaticamente, sem esperar alguém verificar manualmente.', 480 segundoExemplo: 'Quando um cliente responde "PARE" num SMS, o provedor de SMS manda um webhook avisando, e o sistema remove esse número da lista de envios automaticamente.', 481 errosComuns: [ 482 'Não validar se o webhook realmente veio do sistema externo (brecha de segurança).', 483 'Não tratar o caso do mesmo webhook chegar duas vezes (duplicidade).', 484 'Deixar o endpoint lento, fazendo o sistema externo desistir de entregar o aviso.' 485 ], 486 termoTecnico: 'Webhook (callback event)', 487 termosRelacionados: ['callback', 'evento externo', 'notificação de sistema', 'endpoint receptor'] 488 }, 489 { 490 nome: 'Sincronização', 491 icon: '<path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/>', 492 oQueE: 'Manter os mesmos dados atualizados e iguais em dois lugares diferentes, sem um ficar desatualizado em relação ao outro.', 493 quandoUsar: 'Use quando a mesma informação existe em dois sistemas e precisa estar sempre igual nos dois â estoque, cadastro de cliente, status de pedido.', 494 comoFunciona: [ 495 'Você define qual sistema é a fonte da verdade (quem manda no dado).', 496 'Toda vez que esse dado muda na fonte, o outro sistema é avisado ou consultado.', 497 'O outro sistema atualiza sua cópia pra ficar igual.', 498 'Em caso de conflito (os dois mudam ao mesmo tempo), uma regra decide quem vence.' 499 ], 500 pedidoConfuso: 'Deixa tudo igual nos dois sistemas.', 501 pedidoClaro: 'Quando o estoque muda no sistema de vendas, o número de unidades disponÃveis no site precisa atualizar em até 1 minuto, pra não vender um produto que já acabou.', 502 segundoExemplo: 'O nome do aluno cadastrado no sistema de pagamento sincroniza com o cadastro do curs
502o, então se ele corrige o nome no pagamento, o certificado já sai com o nome certo.', 503 errosComuns: [ 504 'Não definir qual sistema é a fonte da verdade, gerando dados conflitantes.', 505 'Sincronizar com atraso maior do que o negócio realmente precisa.', 506 'Não ter um jeito de perceber quando a sincronização parou de funcionar.' 507 ], 508 termoTecnico: 'Sincronização (data sync)', 509 termosRelacionados: ['fonte da verdade', 'dessincronização', 'atualização bidirecional', 'replicação'] 510 }, 511 { 512 nome: 'Dependência entre ações', 513 icon: '<circle cx="6" cy="6" r="2"/><circle cx="6" cy="18" r="2"/><path d="M6 8v8"/><path d="M6 8a6 6 0 0 0 6 6h4"/>', 514 oQueE: 'Quando uma ação só pode acontecer depois que outra ação especÃfica já foi concluÃda â existe uma ordem obrigatória entre elas.', 515 quandoUsar: 'Use quando uma etapa depende do resultado de outra pra fazer sentido â emitir nota fiscal depois do pagamento, enviar certificado depois da conclusão do curso.', 516 comoFunciona: [ 517 'Você mapeia a ordem natural das ações (o que precisa vir antes).', 518 'O sistema verifica se a ação anterior já foi concluÃda antes de liberar a próxima.', 519 'Se não foi, a ação seguinte fica bloqueada ou escondida.', 520 'Assim que a condição é atendida, a próxima ação libera automaticamente.' 521 ], 522 pedidoConfuso: 'Isso só pode acontecer depois daquilo.', 523 pedidoClaro: 'O certificado só pode ser emitido depois que todas as 7 aulas estiverem marcadas como concluÃdas. Se faltar alguma, o botão "Emitir certificado" fica desabilitado com a mensagem "Termine todas as aulas primeiro".', 524 segundoExemplo: 'Só é possÃvel avaliar um produto depois que o pedido está marcado como "Entregue" â antes disso, o botão "Avaliar" nem aparece na tela.', 525 errosComuns: [ 526 'Bloquear a ação sem explicar pro usuário por que ela está bloqueada.', 527 'Criar dependências circulares (A depende de B que depende de A).', 528 'Esquecer de liberar a ação automaticamente, exigindo recarregar a página.' 529 ], 530 termoTecnico: 'Dependência entre ações (action dependency)', 531 termosRelacionados: ['pré-requisito', 'ordem de execução', 'bloqueio condicional', 'encadeamento'] 532 }, 533 { 534 nome: 'Bloqueio por regra', 535 icon: '<rect x="3" y="11" width="18" height="10" rx="1"/><path d="M7 11V8a5 5 0 0 1 10 0v3"/>', 536 oQueE: 'Quando o sistema impede uma ação de acontecer porque uma regra de negócio não foi atendida â não é erro técnico, é uma decisão deliberada.', 537 quandoUsar: 'Use quando existe uma regra de negócio que precisa impedir uma ação especÃfica em vez de deixar ela acontecer e dar errado depois.', 538 comoFunciona: [ 539 'Você define a regra de negócio que precisa ser respeitada.', 540 'Antes de executar a ação, o sistema checa se a regra está sendo cumprida.', 541 'Se não estiver, a ação é impedida e o motivo é explicado.', 542 'Se estiver, a ação segue normalmente.' 543 ], 544 pedidoConfuso: 'Não deixa fazer se não puder.', 545 pedidoClaro: 'Um aluno não pode se matricular num curso avançado sem ter concluÃdo o curso básico primeiro. Se tentar, o sistema mostra a mensagem "Conclua o curso Primeiros Passos antes de acessar este curso" em vez de permitir a matrÃcula.', 546 segundoExemplo: 'Um cupom de primeira compra é bloqueado automaticamente se o CPF já tiver um pedido anterior no sistema, mesmo com e-mail diferente.', 547 errosComuns: [ 548 'Bloquear sem dizer o motivo, deixando o usuário sem saber o que fazer.', 549 'Confundir bloqueio por regra com erro técnico â um é intencional, o outro é falha.', 550 'Regra de bloqueio desatualizada que passa a impedir casos que deveriam ser permitidos.' 551 ], 552 termoTecnico: 'Bloqueio por regra (business rule block)', 553 termosRelacionados: ['regra de negócio', 'validação de acesso', 'restrição', 'pré-condição'] 554 } 555 ], 556 codigos: [ 557 { codigo: '/integration' }, 558 { codigo: '/dependencies' }, 559 { codigo: '/rules' } 560 ] 561 }, 562 { 563 stage: 'Aula 04', 564 estimatedMinutes: 45, 565 layout: 'groups', 566 title: 'Concorrência e resiliência: o que fazer quando algo repete ou trava', 567 goal: 'Aprenda a descrever como o sistema se protege de ações repetidas, se recupera de falhas temporárias, e lida com tarefas demoradas ou disputadas por mais de uma pessoa ao mesmo tempo.', 568 focus: 'Antes de pedir uma tela ou funcionalidade, pergunte: essa ação pode ser disparada duas vezes por acidente? Se falhar, deveria tentar de novo sozinha? Ela demora tempo suficiente pra não travar a tela? Duas pessoas podem disputar a mesma coisa ao mesmo tempo?', 569 practice: 'Pegue uma ação importante de um sistema que você usa (finalizar uma compra, reservar um horário) e descreva: como ela evita duplicidade, o que acontece se falhar, se ela roda em segundo plano, e como o sistema decide quando duas pessoas disputam a mesma coisa.', 570 exerciseFeedback: 'Não existe resposta única â o que importa é cada peça estar concreta: qual identificador evita a duplicidade, quantas vezes e com que intervalo o sistema tenta de novo, o que o usuário vê enquanto o processo roda em segundo plano, e qual mensagem especÃfica aparece pra quem "perde" a disputa por um recurso concorrido. Releia e veja se um dev entenderia sem perguntar nada de volta.', 571 lessons: [ 572 'Aprenda a diferença entre evitar uma ação duplicada e simplesmente impedir o usuário de tentar de novo.', 573 'Veja como timeout, novas tentativas e interruptor de circuito trabalham juntos quando algo falha.', 574 'Entenda quando um processo deveria rodar em segundo plano em vez de travar a tela.', 575 'Pratique como descrever o que acontece quando duas ações disputam o mesmo recurso ao mesmo tempo.' 576 ], 577 groups: [ 578 { title: 'Lidando com falhas', desc: 'O que fazer quando uma ação falha, demora demais, ou pode ser disparada mais de uma vez.' }, 579 { 580 title: 'Simultaneidade', 581 desc: 'O que fazer quando mais de uma coisa acontece â ou é disputada â ao mesmo tempo.', 582 note: 'Os dois trabalham juntos com frequência: uma tarefa demorada rodando em segundo plano ainda pode ser disputada por duas pessoas ao mesmo tempo â por isso o cenário completo abaixo usa os dois no mesmo passo.' 583 } 584 ], 585 scenario: { 586 title: 'Cenário completo: comprando o último ingresso de um evento', 587 intro: 'Um único fluxo real, mostrando onde cada conceito desta aula aparece.', 588 steps: [ 589 { text: 'Você clica em "Comprar" â o pedido usa uma chave de idempotência, então clicar duas vezes não gera duas cobranças.', tag: 'Evitar ação duplicada' }, 590 { text: 'O sistema chama o gateway de pagamento com um limite de 8 segundos de espera â se não responder a tempo, desiste e avisa.', tag: 'Timeout' }, 591 { text: 'Se a chamada falhar por instabilidade, o sistema tenta de novo automaticamente até 3 vezes, com intervalo crescente.', tag: 'Tentar novamente após erro' }, 592 { text: 'Se o gateway falhar repetidamente em pouco tempo, o circuito abre e o sistema para de tentar por 2 minutos, mostrando "pagamento temporariamente indisponÃvel" direto.', tag: 'Interruptor de circuito' }, 593 { text: 'Enquanto isso, o envio do ingresso por e-mail e a geração do PDF rodam em segundo plano, sem travar a tela de confirmação.', tag: 'Processo em segundo plano' }, 594 { text: 'Se outra pessoa tentar comprar o mesmo último ingresso no mesmo segundo, só uma das duas compras é confirmada â a outra recebe "esse ingresso acabou de ser vendido".', tag: 'Operações simultâneas' } 595 ] 596 }, 597 conceitos: [ 598 { 599 nome: 'Evitar ação duplicada', 600 grupo: 0, 601 icon: '<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/>', 602 oQueE: 'Garantir que uma mesma ação, mesmo se disparada mais de uma vez sem querer (duplo clique, conexão instável, nova tentativa automática), só produza um resultado â não repete o efeito.', 603 quandoUsar: 'Use quando uma ação tem consequência real que não pode acontecer duas vezes â cobrar um pagamento, enviar um e-mail, criar um pedido.', 604 quandoNaoUsar: 'Não é necessário quando a ação já é naturalmente segura de repetir, como marcar uma notificação como lida â idempotência importa mais quanto maior a consequência de repetir.', 605 comparacao: 'Diferente de "tentar novamente", que é sobre reagir a falhas â idempotência é o que torna seguro tentar de novo sem duplicar o efeito.', 606 comoFunciona: [ 607 'Cada ação recebe um identificador único no momento em que é disparada.', 608 'Antes de executar, o sistema confere se já existe um resultado registrado pra esse identificador.', 609 'Se já existe, o sistema devolve o resultado anterior em vez de repetir a ação.', 610 'Se não existe, executa normalmente e guarda o resultado vinculado a esse identificador.' 611 ], 612 pedidoConfuso: 'Não deixa cobrar duas vezes.', 613 pedidoClaro: 'Se o usuário clicar em "Finalizar compra" duas vezes seguidas (ou a internet cair e o app tentar de novo), o sistema usa o mesmo identificador de pedido e cobra só uma vez â a segunda tentativa devolve o mesmo pedido já criado, sem duplicar.', 614 segundoExemplo: 'Um formulário de cadastro usa o e-mail como identificador â se o usuário reenviar o mesmo formulário, o sistema não cria uma segunda conta, atualiza a existente.', 615 errosComuns: [ 616 'Usar só o botão desabilitado como proteção â não impede duplicidade se a nova tentativa vier de outro lugar.',
617 'Não guardar o identificador de forma que sobreviva a uma queda do sistema no meio da ação.', 618 'Confundir "evitar duplicado" com "impedir o usuário de tentar de novo" â a ideia é permitir a tentativa, só não duplicar o efeito.' 619 ], 620 termoTecnico: 'Idempotência (idempotency)', 621 termosRelacionados: ['chave de idempotência', 'ação repetÃvel', 'deduplicação', 'identificador único de operação'] 622 }, 623 { 624 nome: 'Tentar novamente após erro', 625 grupo: 0, 626 icon: '<path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/>', 627 oQueE: 'Quando uma ação falha por um motivo temporário, o sistema tenta executá-la de novo automaticamente, em vez de desistir na primeira falha.', 628 quandoUsar: 'Use quando a falha pode ser passageira â uma conexão instável, um sistema externo temporariamente fora do ar, um tempo limite excedido.', 629 quandoNaoUsar: 'Não use quando o erro é definitivo, como um cartão recusado por saldo insuficiente â tentar de novo nesses casos só atrasa mostrar o problema real pro usuário.', 630 comparacao: 'Só é seguro fazer isso se a ação for idempotente â senão, tentar de novo pode duplicar o efeito da primeira tentativa.', 631 comoFunciona: [ 632 'A ação falha por um motivo que pode ser temporário.', 633 'O sistema espera um tempo antes de tentar de novo, em vez de tentar imediatamente sem parar.', 634 'Tenta executar a ação novamente.', 635 'Se continuar falhando, aumenta o tempo de espera a cada tentativa, até desistir depois de um número máximo.' 636 ], 637 pedidoConfuso: 'Tenta de novo se der erro.', 638 pedidoClaro: 'Se o envio do webhook de pagamento falhar, o sistema tenta de novo em 1 minuto, depois em 5 minutos, depois em 15 minutos â até 3 tentativas. Se todas falharem, marca o pedido como "Pendente de confirmação" e avisa o suporte.', 639 segundoExemplo: 'Ao fazer upload de uma foto de perfil e a conexão cair no meio, o app tenta reenviar automaticamente até 2 vezes antes de mostrar a mensagem "Não foi possÃvel enviar a foto".', 640 errosComuns: [ 641 'Tentar de novo infinitamente sem limite, deixando o problema mascarado.', 642 'Tentar de novo imediatamente e sem intervalo crescente, sobrecarregando um sistema que já está com problema.', 643 'Repetir uma ação sem garantir também que ela não duplique o efeito (por isso anda junto com idempotência).' 644 ], 645 termoTecnico: 'Nova tentativa (retry / backoff)', 646 termosRelacionados: ['backoff exponencial', 'número máximo de tentativas', 'falha temporária', 'fila de reprocessamento'] 647 }, 648 { 649 nome: 'Timeout', 650 grupo: 0, 651 icon: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 3"/>', 652 oQueE: 'Um limite de tempo que o sistema espera por uma resposta antes de desistir e tratar como falha, em vez de ficar esperando indefinidamente.', 653 quandoUsar: 'Use quando uma ação depende de uma resposta externa que pode nunca chegar â uma chamada pra outro sistema, uma consulta ao banco, um upload.', 654 quandoNaoUsar: 'Não faz sentido quando a ação é instantânea por natureza, como validar um campo localmente na tela â timeout é pra esperas que dependem de algo externo.', 655 comparacao: 'Trabalha junto com "tentar novamente": o timeout decide QUANDO desistir de esperar; o retry decide o que fazer depois disso.', 656 comoFunciona: [ 657 'Antes de disparar a ação, você define quanto tempo é razoável esperar.', 658 'O sistema inicia a ação e começa a contar esse tempo.', 659 'Se a resposta chegar dentro do prazo, segue normalmente.', 660 'Se o tempo esgotar sem resposta, o sistema desiste, trata como erro e libera pra seguir.' 661 ], 662 pedidoConfuso: 'Não deixa travar esperando pra sempre.', 663 pedidoClaro: 'Se a consulta de frete não responder em 5 segundos, o sistema desiste, mostra "Não foi possÃvel calcular o frete agora" e libera o checkout com frete a combinar, em vez de travar a tela esperando indefinidamente.', 664 segundoExemplo: 'Uma chamada de vÃdeo desliga sozinha se a outra pessoa não atender em 45 segundos, em vez de ficar chamando pra sempre.', 665 errosComuns: [
666 'Não definir timeout nenhum, deixando o sistema vulnerável a travar esperando um sistema externo lento.', 667 'Definir um timeout curto demais, cancelando ações que só estavam um pouco lentas.', 668 'Tratar o timeout só como "deu erro" sem considerar que a ação pode ter sido concluÃda do outro lado mesmo sem resposta a tempo.' 669 ], 670 termoTecnico: 'Timeout (tempo limite de espera)', 671 termosRelacionados: ['tempo limite', 'cancelamento por inatividade', 'resposta lenta', 'prazo de resposta'] 672 }, 673 { 674 nome: 'Interruptor de circuito', 675 grupo: 0, 676 icon: '<path d="M12 2v6"/><path d="M18.4 6.6a9 9 0 1 1-12.8 0"/>', 677 oQueE: 'Um mecanismo que percebe quando um sistema externo está falhando repetidamente e para de chamá-lo por um tempo, em vez de continuar tentando e piorando o problema.', 678 quandoUsar: 'Use quando repetidas falhas de um sistema externo podem sobrecarregar ainda mais esse sistema ou travar o seu próprio sistema esperando por ele.', 679 quandoNaoUsar: 'Não vale a pena pra chamadas muito raras ou de baixÃssimo risco â o custo de implementar e manter o circuito não compensa nesses casos.', 680 comparacao: 'Enquanto o timeout limita UMA chamada, o interruptor de circuito olha o HISTÃRICO de várias chamadas pra decidir se vale a pena nem tentar.', 681 comoFunciona: [ 682 'O sistema monitora quantas vezes seguidas uma chamada a um serviço externo falhou.', 683 'Se as falhas passarem de um limite, o circuito "abre" â o sistema para de tentar chamar esse serviço por um tempo.', 684 'Enquanto o circuito está aberto, o sistema responde imediatamente com uma alternativa, sem nem tentar.', 685 'Depois de um tempo, o sistema tenta de novo com cautela; se funcionar, volta ao normal.' 686 ], 687 pedidoConfuso: 'Para de tentar se tiver dando muito erro.', 688 pedidoClaro: 'Se o serviço de recomendação de produtos falhar 5 vezes seguidas, o sistema para de chamá-lo por 2 minutos e mostra uma lista padrão de produtos populares nesse perÃodo, em vez de deixar a página inteira lenta esperando um serviço que já está com problema.', 689 segundoExemplo: 'Um app de transporte para de tentar buscar a localização em tempo real de um motorista se o serviço de mapas falhar repetidamente, e mostra a última localização conhecida com um aviso, em vez de travar o app tentando de novo sem parar.', 690 errosComuns: [ 691 'Não ter um plano B pra quando o circuito está aberto, deixando a experiência tão ruim quanto o erro original.', 692 'Deixar o circuito aberto pra sempre, sem nunca testar se o sistema externo já voltou a funcionar.', 693 'Confundir com retry â um evita insistir, o outro insiste com intervalo; geralmente os dois trabalham juntos.' 694 ], 695 termoTecnico: 'Interruptor de circuito (circuit breaker)', 696 termosRelacionados: ['circuito aberto', 'plano B', 'degradação graciosa', 'disjuntor'] 697 }, 698 { 699 nome: 'Processo em segundo plano', 700 grupo: 1, 701 icon: '<path d="M12 2 2 7l10 5 10-5-10-5Z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/>', 702 oQueE: 'Uma tarefa que roda por conta própria, sem travar a tela nem exigir que o usuário fique esperando ela terminar.', 703 quandoUsar: 'Use quando a tarefa demora mais do que o usuário deveria esperar olhando pra tela parada â gerar um relatório grande, processar um vÃdeo, enviar um lote de e-mails.', 704 quandoNaoUsar: 'Não use quando o usuário precisa da confirmação imediata pra continuar, como saber se o pagamento passou antes de fechar a tela â nesses casos, a espera é necessária.', 705 comparacao: 'Diferente de operações simultâneas, que é sobre DISPUTA por um recurso â processo em segundo plano é sobre NÃO travar a tela enquanto algo demorado roda.', 706 comoFunciona: [ 707 'O usuário dispara a ação, e o sistema confirma que recebeu o pedido na hora.',
708 'A tarefa pesada é colocada numa fila separada, fora do caminho principal da tela.', 709 'O sistema processa essa fila no seu próprio ritmo, sem travar mais nada.', 710 'Quando termina, o usuário é avisado (notificação, e-mail, ou a tela atualiza sozinha).' 711 ], 712 pedidoConfuso: 'Processa isso sem travar a tela.', 713 pedidoClaro: 'Ao clicar em "Exportar relatório completo", a tela mostra "Preparando seu relatório..." na hora e libera o usuário pra continuar usando o sistema. Quando o relatório fica pronto, chega uma notificação com o link pra baixar.', 714 segundoExemplo: 'Depois que um vÃdeo é enviado pra plataforma, ele aparece como "Processando" na lista â o usuário já pode sair da tela, e o vÃdeo fica disponÃvel assim que o processamento em segundo plano termina.', 715 errosComuns: [ 716 'Deixar o usuário sem nenhum feedback de que a tarefa está rodando (parece que travou).', 717 'Não avisar quando o processo termina, obrigando o usuário a ficar checando manualmente.', 718 'Rodar em segundo plano uma ação que na verdade precisa de confirmação imediata do usuário.' 719 ], 720 termoTecnico: 'Processamento assÃncrono (background job)', 721 termosRelacionados: ['fila de tarefas', 'job assÃncrono', 'processamento em lote', 'worker'] 722 }, 723 { 724 nome: 'Operações simultâneas', 725 grupo: 1, 726 icon: '<circle cx="8" cy="8" r="3"/><circle cx="16" cy="16" r="3"/><path d="M11 8h5M8 11v5"/>', 727 oQueE: 'Quando mais de uma ação tenta acontecer ao mesmo tempo sobre o mesmo dado, e o sistema precisa decidir como lidar com isso sem gerar inconsistência.', 728 quandoUsar: 'Use quando existe risco real de duas pessoas (ou dois processos) mexerem na mesma coisa ao mesmo tempo â a última vaga de um evento, o mesmo cupom, o mesmo horário sendo agendado.', 729 quandoNaoUsar: 'Não é preciso se o recurso nunca é disputado por mais de uma pessoa ao mesmo tempo â a complexidade de travar só vale a pena quando existe risco real de conflito.', 730 comparacao: 'Diferente de processo em segundo plano, que é sobre demora â aqui o problema é DISPUTA, mesmo que a ação seja rápida.', 731 comoFunciona: [ 732 'Duas ações chegam quase ao mesmo tempo, mirando no mesmo recurso (ex.: a última vaga de um curso).', 733 'O sistema trava esse recurso brevemente pra processar uma ação de cada vez, nunca as duas juntas.', 734 'A primeira ação a chegar é processada e o recurso é atualizado (ex.: vaga ocupada).', 735 'A segunda ação, ao ser processada, já encontra o recurso indisponÃvel e recebe uma resposta clara.' 736 ], 737 pedidoConfuso: 'Não deixa dar erro se dois mexerem ao mesmo tempo.', 738 pedidoClaro: 'Se dois alunos tentarem comprar a última vaga de uma turma no mesmo segundo, o sistema processa um pedido primeiro, marca a vaga como ocupada, e mostra pro segundo aluno "Essa vaga acabou de ser preenchida" em vez de deixar os dois pagarem pela mesma vaga.', 739 segundoExemplo: 'Dois atendentes tentam responder o mesmo chamado de suporte ao mesmo tempo â o sistema atribui o chamado a quem clicou primeiro e avisa o segundo que o chamado já foi assumido.', 740 errosComuns: [ 741 'Não travar o recurso durante o processamento, permitindo as duas ações passarem (overselling).', 742 'Travar por tempo demais, fazendo outras ações legÃtimas esperarem sem necessidade.', 743 'Mostrar um erro técnico genérico em vez de explicar que outra pessoa já pegou aquilo primeiro.' 744 ], 745 termoTecnico: 'Concorrência (concurrency / race condition)', 746 termosRelacionados: ['condição de corrida', 'travamento otimista', 'travamento pessimista', 'conflito de escrita'] 747 } 748 ], 749 codigos: [ 750 { codigo: '/idempotency' }, 751 { codigo: '/retry' }, 752 { codigo: '/edgecases' } 753 ] 754 }, 755 { 756 stage: 'Aula 05', 757 estimatedMinutes: 50, 758 layout: 'groups', 759 title: 'Permissões e controle de acesso: quem pode fazer o quê', 760 goal: 'Aprenda a descrever quem tem autorização pra ver ou fazer algo no sistema, e até onde esse acesso se espalha.', 761 focus: 'Antes de pedir uma tela ou funcionalidade, pergunte: quem pode fazer essa ação? Existe um responsável especÃfico por esse item? Quem consegue nem ver que ele existe? Se der acesso a um grupo, isso libera tudo dentro dele automaticamente?', 762 practice: 'Pegue uma área do seu sistema que envolve mais de uma pessoa (um documento, uma pasta, um projeto) e descreva: quais papéis existem, quais permissões cada um tem, quem é o dono, quem consegue ver e o que a herança de acesso libera automaticamente.', 763 exerciseFeedback: 'Não existe resposta única â o que importa é distinguir claramente: o papel (o pacote de permissões), a permissão especÃfica (a ação isolada), quem é o responsável pelo item, quem consegue nem ver que ele existe, e o que se prop
763aga automaticamente pros itens de dentro. Releia e veja se um dev entenderia sem perguntar nada de volta.', 764 lessons: [ 765 'Aprenda a diferença entre papel (um pacote de permissões) e permissão (uma autorização isolada).', 766 'Veja como o dono de um recurso se diferencia de quem só tem acesso a ele.', 767 'Pratique como descrever visibilidade e herança de permissão sem misturar os dois conceitos.' 768 ], 769 groups: [ 770 { title: 'Quem decide o que pode ser feito', desc: 'Como o sistema determina se alguém tem autorização pra uma ação especÃfica.' }, 771 { 772 title: 'Até onde o acesso alcança', 773 desc: 'Quando uma autorização vale só pra um item, ou se estende pros itens dentro dele.', 774 note: 'Os dois grupos andam juntos: decidir quem pode fazer algo não resolve sozinho até onde esse alguém enxerga â por isso o cenário completo abaixo usa os dois no mesmo fluxo.' 775 } 776 ], 777 scenario: { 778 title: 'Cenário completo: compartilhando uma pasta de projeto com o time', 779 intro: 'Um único fluxo real, mostrando onde cada conceito desta aula aparece.', 780 steps: [ 781 { text: 'Maria cria a pasta "Contratos 2026" â ela vira automaticamente a dona do recurso.', tag: 'Dono do recurso' }, 782 { text: 'Ela convida João como "Editor", um papel que já vem com um pacote pronto de permissões (ver, editar, comentar â não excluir).', tag: 'Papel' }, 783 { text: 'Internamente, o sistema checa a permissão "pode_editar" antes de deixar João salvar qualquer alteração.', tag: 'Permissão' }, 784 { text: 'A pasta está marcada como "Restrita ao time JurÃdico" â quem está fora desse grupo nem encontra a pasta na busca.', tag: 'Visibilidade' }, 785 { text: 'Como a pasta tem 12 arquivos dentro, ninguém precisa configurar acesso arquivo por arquivo â o acesso à pasta já libera os 12 automaticamente.', tag: 'Herança de permissão' }, 786 { text: 'Quando Maria sai da empresa, seu acesso some, mas a pasta continua existindo â uma regra decide quem vira o novo dono, pra ela não ficar órfã.', tag: 'Dono do recurso' } 787 ] 788 }, 789 conceitos: [ 790 { 791 nome: 'Papel', 792 grupo: 0, 793 icon: '<circle cx="12" cy="8" r="4"/><path d="M4 21v-2a6 6 0 0 1 12 0v2"/><path d="M17 10a3 3 0 1 0 0-6"/><path d="M20 21v-2a4 4 0 0 0-3-3.87"/>', 794 oQueE: 'Um perfil predefinido que já vem com um conjunto fixo de permissões â em vez de configurar autorização pessoa por pessoa, você atribui um papel e todas as permissões dele valem de uma vez.', 795 quandoUsar: 'Use quando várias pessoas exercem a mesma função e devem ter exatamente as mesmas autorizações â editor, revisor, administrador, convidado.', 796 quandoNaoUsar: 'Não crie um papel novo pra uma autorização que só uma pessoa especÃfica vai ter â nesse caso, dê a permissão direto pra ela, sem inventar um papel exclusivo.', 797 comparacao: 'Diferente de permissão, que é uma autorização isolada â papel é um pacote pronto de várias permissões, pensado pra não repetir a mesma configuração pra cada pessoa.', 798 comoFunciona: [ 799 'Você define os papéis que existem no sistema (ex.: Admin, Editor, Visitante).', 800 'Cada papel recebe um conjunto fixo de permissões vinculadas a ele.', 801 'Uma pessoa é associada a um ou mais papéis.', 802 'O sistema soma as permissões de todos os papéis dela pra decidir o que ela pode fazer.' 803 ], 804 pedidoConfuso: 'Cria um nÃvel de acesso pra cada pessoa.', 805 pedidoClaro: 'Crie três papéis: "Admin" (acesso total), "Editor" (pode criar e editar, não pode excluir nem convidar gente) e "Visitante" (só visualiza). Cada membro do time recebe um desses três papéis.', 806 segundoExemplo: 'Num fórum, o papel "Moderador" já vem com permissão de apagar comentários e banir usuários, sem precisar marcar essas duas permissões manualmente pra cada moderador novo.', 807 errosComuns: [ 808 'Criar um papel novo pra cada exceção, até virar impossÃvel saber quem pode o quê.', 809 'Dar poderes de mais a um papel só porque "vai ser mais prático", sem revisar se é realmente necessário.', 810 'Esquecer de remover o papel de alguém que trocou de função dentro do time.' 811 ], 812 termoTecnico: 'Papel (role)', 813 termosRelacionados: ['role-based access', 'perfil de acesso', 'grupo de permissões', 'nÃvel de acesso'] 814 }, 815 { 816 nome: 'Permissão', 817 grupo: 0, 818 icon: '<rect x="3" y="11" width="18" height="10" rx="1"/><path d="M7 11V8a5 5 0 0 1 10 0v3"/><circle cx="12" cy="16" r="1.5"/>', 819 oQueE: 'Uma autorização especÃfica pra executar uma ação sobre um recurso â não é "o que a pessoa é", é "o que ela pode fazer" (editar, excluir, aprovar, ver).', 820 quandoUsar: 'Use quando uma ação precisa de checagem individual antes de ser liberada, independentemente de papel â inclusive pra dar uma exceção pontual a alguém.', 821 quandoNaoUsar: 'Não use permissão avulsa pra algo que várias pessoas do mesmo grupo sempre vão precisar â nesse caso, agrupe num papel em vez de repetir a mesma configuração pessoa por pessoa.', 822 comparacao: 'Permissão é o item individual; papel é o pacote. Um papel "Editor" é, por baixo dos panos, só uma lista de permissões marcadas como concedidas.', 823 comoFunciona: [ 824 'Cada ação sensÃvel do sistema é identificada por um nome de permissão (ex.: "excluir_pedido").', 825 'Antes de executar essa ação, o sistema verifica se a pessoa tem essa permissão â direto ou via um papel.', 826 'Se tiver, a ação roda normalmente.', 827 'Se não tiver, a ação é bloqueada e a interface nem mostra o botão, ou mostra desabilitado.' 828 ], 829 pedidoConfuso: 'Só quem pode, faz.', 830 pedidoClaro: 'A ação "Excluir pedido" só fica disponÃvel pra quem tem a permissão "excluir_pedido". Sem essa permissão, o botão nem aparece na tela â não é só desabilitado, é removido.', 831 segundoExemplo: 'Um estagiário pode ter a permissão "ver_relatorio_financeiro" liberada como exceção pontual, sem ganhar o papel completo de "Gestor financeiro".', 832 errosComuns: [ 833 'Checar a permissão só no frontend (esconder o botão) sem validar de novo no backend â qualquer um pode chamar a API direto.',
834 'Nomear permissões de forma vaga ("acesso especial") em vez de descrever a ação exata que ela libera.', 835 'Deixar uma permissão perigosa (ex.: excluir dados) sem exigir confirmação extra antes de executar.' 836 ], 837 termoTecnico: 'Permissão (permission)', 838 termosRelacionados: ['autorização', 'ação permitida', 'controle de acesso granular', 'permission grant'] 839 }, 840 { 841 nome: 'Dono do recurso', 842 grupo: 0, 843 icon: '<path d="M12 15a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z"/><path d="M12 15v6"/><path d="m9 18 3 3 3-3"/>', 844 oQueE: 'A pessoa (ou conta) responsável por um item especÃfico â geralmente quem criou, mas pode ser transferido â e que costuma ganhar automaticamente permissões totais sobre aquele item.', 845 quandoUsar: 'Use quando um item precisa de um responsável claro, mesmo que outras pessoas tenham acesso a ele â quem decide excluir, transferir ou mudar a visibilidade.', 846 quandoNaoUsar: 'Não force um "dono" em recursos que são genuinamente coletivos desde o inÃcio (ex.: um documento criado em conjunto por um time) â nesse caso, o time inteiro pode ser o responsável, sem um dono individual.', 847 comoFunciona: [ 848 'Quando um item é criado, quem criou vira automaticamente o dono.', 849 'O dono recebe todas as permissões sobre aquele item, mesmo sem estar em nenhum papel especial.', 850 'O dono pode transferir a titularidade pra outra pessoa, se o sistema permitir.', 851 'Se o dono deixa de existir no sistema (conta removida), uma regra decide o que acontece â ficar órfão não é uma opção segura.' 852 ], 853 pedidoConfuso: 'Quem criou pode mexer em tudo.', 854 pedidoClaro: 'Quem cria uma pasta de projeto vira o dono dela automaticamente, com permissão total (editar, excluir, convidar, mudar visibilidade). Se o dono sair da empresa, o gestor direto assume automaticamente a titularidade.', 855 segundoExemplo: 'Num app de notas, cada nota tem um único dono, mesmo que ela seja compartilhada com permissão de edição pra outras pessoas.', 856 errosComuns: [ 857 'Não definir o que acontece quando o dono é removido do sistema, deixando o item sem responsável.', 858 'Confundir "quem criou" com "quem pode decidir sobre o item" â à s vezes a titularidade precisa ser transferÃvel.', 859 'Dar ao dono permissões implÃcitas demais, sem deixar claro na interface o que exatamente isso inclui.' 860 ], 861 termoTecnico: 'Dono do recurso (resource owner)', 862 termosRelacionados: ['titularidade', 'responsável pelo item', 'ownership', 'transferência de posse'] 863 }, 864 { 865 nome: 'Visibilidade', 866 grupo: 1, 867 icon: '<path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>', 868 oQueE: 'A regra que define quem consegue enxergar (não necessariamente editar) um item â público, privado, ou restrito a um grupo especÃfico.', 869 quandoUsar: 'Use quando existe diferença entre "poder editar" e "poder simplesmente ver que aquilo existe" â nem tudo que é editável deveria ser visÃvel a qualquer um, e vice-versa.', 870 quandoNaoUsar: 'Não confunda visibilidade com permissão de edição â um item pode ser visÃvel a todo mundo (público) e ainda assim só o dono poder editá-lo.', 871 comparacao: 'Visibilidade decide quem enxerga; permissão decide o que quem enxerga pode fazer. Um item pode ser visÃvel e ainda assim só permitir leitura.', 872 comoFunciona: [ 873 'Cada item recebe um nÃvel de visibilidade: público, privado ou restrito a um grupo.', 874 'Ao montar uma busca ou listagem, o sistema filtra o que aparece de acordo com quem está pedindo.', 875 'Itens fora da visibilidade da pessoa nem aparecem â não é só bloqueado ao clicar, é omitido da lista.', 876 'O dono (ou um administrador) pode mudar o nÃvel de visibilidade a qualquer momento.' 877 ], 878 pedidoConfuso: 'Deixa privado quem não pode ver.', 879 pedidoClaro: 'A pasta "Contratos 2026" tem visibilidade "Restrita ao time JurÃdico" â pessoas fora desse grupo não veem a pasta nem na busca, e não só recebem "acesso negado" ao tentar abrir.', 880 segundoExemplo: 'Um post de rascunho num blog tem visibilidade "Privada" (só o autor vê) até ser publicado, quando passa a "Pública".', 881 errosComuns: [ 882 'Confiar só na interface pra esconder algo, sem bloquear de verdade a consulta no backend.',
883 'Deixar um item "privado por padrão" trocar sem querer pra "público" numa edição, sem confirmação extra.', 884 'Misturar visibilidade com status de publicação (rascunho/publicado), quando são regras diferentes.' 885 ], 886 termoTecnico: 'Visibilidade (visibility scope)', 887 termosRelacionados: ['escopo de acesso', 'público/privado', 'acesso restrito', 'nÃvel de exposição'] 888 }, 889 { 890 nome: 'Herança de permissão', 891 grupo: 1, 892 icon: '<circle cx="6" cy="6" r="2"/><circle cx="6" cy="14" r="2"/><circle cx="6" cy="18" r="2"/><path d="M6 8v4"/><path d="M6 10h6"/>', 893 oQueE: 'Quando o acesso concedido a um item "pai" se aplica automaticamente aos itens "filhos" dentro dele, sem precisar configurar cada um separadamente.', 894 quandoUsar: 'Use quando os itens filhos fazem parte naturalmente do item pai e não faz sentido configurar acesso peça por peça â arquivos dentro de uma pasta, aulas dentro de um curso.', 895 quandoNaoUsar: 'Não use quando um item filho especÃfico precisa de uma regra diferente do resto â nesses casos, uma exceção pontual deve poder sobrescrever a herança, não ser impedida por ela.', 896 comparacao: 'Enquanto visibilidade decide o alcance de um item isolado, herança decide se esse alcance se prop
896aga pros itens dentro dele.', 897 comoFunciona: [ 898 'Um item pai (ex.: pasta) recebe uma permissão ou visibilidade.', 899 'Todo item criado dentro dele herda essa mesma configuração automaticamente.', 900 'Se alguém muda a configuração do pai, os filhos sem exceção própria acompanham a mudança.', 901 'Um filho pode receber uma exceção especÃfica, que passa a valer só pra ele, sobrescrevendo a herança.' 902 ], 903 pedidoConfuso: 'O acesso da pasta vale pra tudo dentro.', 904 pedidoClaro: 'Dar acesso de leitura a uma pasta libera automaticamente a leitura de todos os arquivos dentro dela â exceto o arquivo "Confidencial.pdf", que tem uma exceção própria de acesso restrito só ao gestor.', 905 segundoExemplo: 'Num curso com módulos e aulas, liberar acesso ao módulo "Fundamentos" já libera automaticamente as 5 aulas dentro dele, sem precisar marcar aula por aula.', 906 errosComuns: [ 907 'Herdar permissão em cadeias longas demais sem visibilidade clara de onde a regra "nasceu".', 908 'Não permitir nenhuma exceção pontual, forçando tudo a seguir exatamente a regra do pai.', 909 'Mudar a permissão do pai sem avisar que isso vai afetar dezenas de itens filhos de uma vez.' 910 ], 911 termoTecnico: 'Herança de permissão (permission inheritance)', 912 termosRelacionados: ['acesso em cascata', 'propagação de permissão', 'exceção pontual', 'permissão sobrescrita'] 913 } 914 ], 915 codigos: [ 916 { codigo: '/roles' }, 917 { codigo: '/permissions' }, 918 { codigo: '/visibility' } 919 ] 920 }, 921 { 922 stage: 'Aula 06', 923 estimatedMinutes: 45, 924 layout: 'timeline', 925 sequenceCount: 3, 926 connectors: ['fica registrada em', 'pode ser desfeita com'], 927 title: 'Histórico, auditoria e reversão: o que aconteceu e como desfazer', 928 goal: 'Aprenda a descrever como o sistema guarda o que mudou ao longo do tempo, quando isso é obrigatório, e como permitir desfazer algo com segurança.', 929 focus: 'Antes de pedir uma tela ou funcionalidade, pergunte: essa mudança precisa ficar registrada por obrigação? Alguém vai precisar consultar o que já foi diferente antes? Dá pra desfazer um erro sem refazer tudo na mão? Faz sentido ter uma versão em edição separada da versão que está valendo?', 930 practice: 'Pegue uma ação importante de um sistema que você usa (mudar um preço, editar um cadastro) e descreva: o que precisa ficar registrado por obrigação, onde esse histórico fica visÃvel, como alguém desfaria um erro, e se existe uma etapa de rascunho antes de valer de verdade.', 931 exerciseFeedback: 'Não existe resposta única â o que importa é cada peça estar concreta: o que exatamente vira registro obrigatório (e por quê), onde e como o histórico fica consultável, o que acontece quando alguém reverte uma mudança, e se o conteúdo passa por um estágio de rascunho antes de valer publicamente. Releia e veja se um dev entenderia sem perguntar nada de volta.', 932 lessons: [ 933 'Aprenda a diferença entre trilha de auditoria (obrigação de registrar) e histórico de alterações (o registro em si, consultável).', 934 'Veja como a reversão depende do histórico existir pra ter o que restaurar.', 935 'Entenda quando vale separar uma versão em edição (rascunho) da versão que está valendo (publicada).', 936 'Pratique a diferença entre guardar mudança por mudança e guardar uma foto completa do estado (snapsh
936ot).' 937 ], 938 conceitos: [ 939 { 940 nome: 'Trilha de auditoria em ações sensÃveis', 941 when: 'Quando a ação acontece', 942 icon: '<path d="M12 2 3 6v6c0 5 3.8 9.4 9 11 5.2-1.6 9-6 9-11V6l-9-4Z"/>', 943 oQueE: 'A obrigação de registrar quem fez o quê, e quando, sempre que a ação envolve dados sensÃveis (financeiros, pessoais, de acesso) â não é opcional, é rastreabilidade exigida.', 944 quandoUsar: 'Use em ações com consequência real ou exigência legal â mudar um valor cobrado, alterar dado de outra pessoa, conceder ou revogar acesso.', 945 quandoNaoUsar: 'Não é necessário auditar toda ação trivial do sistema (ex.: abrir uma página) â isso só gera ruÃdo; reserve pra ações que alguém pode legitimamente perguntar "quem fez isso e por quê".', 946 comparacao: 'Trilha de auditoria decide o QUE precisa virar registro obrigatório; histórico de alterações é ONDE e COMO esse registro fica guardado e consultável.', 947 comoFunciona: [ 948 'Você identifica quais ações são sensÃveis o bastante pra exigir registro obrigatório.', 949 'Toda vez que uma dessas ações roda, o sistema captura quem fez, o quê, e quando, antes de considerar a ação concluÃda.', 950 'Esse registro não pode ser editado nem apagado depois â inclusive por quem tem acesso de administrador.', 951 'Em caso de dúvida ou investigação, esse registro é a fonte confiável do que realmente aconteceu.' 952 ], 953 pedidoConfuso: 'Guarda um log disso.', 954 pedidoClaro: 'Toda mudança no valor cobrado de um plano precisa registrar quem alterou, o valor antigo, o valor novo e a data/hora â esse registro não pode ser editado nem apagado depois, nem por admin.', 955 segundoExemplo: 'Alterar o e-mail de contato de outro usuário (ação feita por um admin do sistema) gera automaticamente um registro de auditoria, mesmo que o admin tenha autorização total pra fazer isso.', 956 errosComuns: [ 957 'Registrar só "usuário X editou algo", sem guardar o valor antes/depois â isso não serve de nada numa investigação.', 958 'Deixar o próprio registro de auditoria editável, o que anula a confiança nele.', 959 'Auditar tudo indiscriminadamente, gerando tanto volume de log que ninguém consegue achar o que importa.' 960 ], 961 termoTecnico: 'Trilha de auditoria (audit trail)', 962 termosRelacionados: ['log de auditoria', 'rastreabilidade', 'compliance', 'registro imutável'] 963 }, 964 { 965 nome: 'Histórico de alterações', 966 when: 'Logo depois, já registrado', 967 icon: '<path d="M3 3v18h18"/><path d="m7 14 4-4 3 3 5-6"/>', 968 oQueE: 'O registro consultável de tudo que mudou num item ao longo do tempo â quem mudou, o que era antes, o que passou a ser, e quando.', 969 quandoUsar: 'Use quando alguém pode legitimamente perguntar "isso sempre foi assim?" ou "quem mudou esse valor?" â dados que evoluem e cuja evolução importa.', 970 comoFunciona: [ 971 'Toda alteração relevante num item gera uma entrada no histórico, em vez de simplesmente sobrescrever o valor antigo.', 972 'Cada entrada guarda o valor anterior, o valor novo, quem fez e quando.', 973 'O histórico fica disponÃvel pra consulta, geralmente numa aba ou seção separada do item.', 974 'Diferente da trilha de auditoria (que é sobre obrigação legal), o histórico pode existir só por utilidade â entender a evolução de um dado.' 975 ], 976 pedidoConfuso: 'Mostra o que mudou.', 977 pedidoClaro: 'A tela de detalhe do aluno tem uma aba "Histórico" listando cada mudança de plano ou status: data, quem mudou (gestor ou automação), valor antigo e valor novo.', 978 segundoExemplo: 'Um documento colaborativo mostra "Editado por Maria há 2 horas, por João há 1 dia" â um resumo do histórico sem precisar abrir o log completo.', 979 errosComuns: [ 980 'Guardar histórico só de alguns campos e não de outros, sem critério claro de por que uns importam e outros não.',
981 'Não indicar quem fez a mudança quando ela foi automática (cron, webhook) â "sistema" também é uma origem válida a registrar.', 982 'Deixar o histórico crescer sem paginação, travando a tela quando o item tem muitas mudanças acumuladas.' 983 ], 984 termoTecnico: 'Histórico de alterações (change log)', 985 termosRelacionados: ['log de mudanças', 'linha do tempo do item', 'change history', 'registro de edição'] 986 }, 987 { 988 nome: 'Reversão', 989 when: 'Quando alguém precisa desfazer', 990 icon: '<path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v6h6"/>', 991 oQueE: 'A capacidade de voltar um item pro estado anterior a uma mudança especÃfica, usando o histórico como base â sem precisar refazer tudo manualmente.', 992 quandoUsar: 'Use quando um erro (humano ou automático) precisa ser desfeito rapidamente, ou quando alguém quer comparar/restaurar uma versão anterior de algo.', 993 quandoNaoUsar: 'Não ofereça reversão em ações que já dis
993pararam efeito colateral externo irreversÃvel (ex.: um pagamento já processado no banco) â nesses casos, a correção precisa de um fluxo próprio, não um simples "desfazer".', 994 comparacao: 'Reversão depende do histórico existir â sem um registro do estado anterior, não tem o que restaurar.', 995 comoFunciona: [ 996 'O sistema identifica qual versão anterior (do histórico) deve ser restaurada.', 997 'Confirma que restaurar aquele estado não quebra nenhuma outra regra vigente hoje (ex.: um preço antigo que já não é permitido).', 998 'Aplica os valores da versão anterior sobre o item atual.', 999 'Registra a própria reversão como uma nova entrada no histórico â desfazer também é uma mudança, e também fica registrado.' 1000 ], 1001 pedidoConfuso: 'Deixa voltar atrás se errar.', 1002 pedidoClaro: 'No editor de curso, o botão "Reverter" ao lado de cada entrada do histórico restaura o conteúdo daquele momento especÃfico, e essa reversão vira uma nova entrada no histórico (não apaga as anteriores).', 1003 segundoExemplo: 'Um gestor que mudou o preço de um plano por engano usa "Reverter última alteração" pra voltar ao valor correto, sem precisar digitar o valor de novo manualmente.', 1004 errosComuns: [ 1005 'Permitir reversão sem registrar que ela aconteceu, apagando o rastro do que foi desfeito.', 1006 'Reverter sem checar se o estado antigo ainda é válido pelas regras atuais do sistema.', 1007 'Confundir reversão com exclusão â desfazer uma mudança não deveria apagar a existência do item inteiro.' 1008 ], 1009 termoTecnico: 'Reversão (undo / rollback)', 1010 termosRelacionados: ['desfazer', 'restaurar versão anterior', 'rollback', 'correção retroativa'] 1011 }, 1012 { 1013 nome: 'Rascunho vs. publicado', 1014 icon: '<rect x="4" y="4" width="16" height="16" rx="2"/><path d="M8 10h8M8 14h5"/>', 1015 oQueE: 'Dois estados paralelos de um mesmo conteúdo: uma versão em edição (rascunho), que ninguém de fora vê, e uma ver
1015são que está valendo de fato (publicado).', 1016 quandoUsar: 'Use quando alguém precisa editar algo com calma, errar, revisar, sem que isso afete quem já está vendo a versão atual â posts, cursos, páginas, textos legais.', 1017 quandoNaoUsar: 'Não force esse modelo em dados que sempre precisam refletir a realidade imediatamente (ex.: status de um pedido) â lá, a mudança precisa valer na hora, não esperar uma "publicação".', 1018 comoFunciona: [ 1019 'O conteúdo existe em duas versões: a publicada (visÃvel a todos) e o rascunho (visÃvel só a quem edita).', 1020 'Mudanças no rascunho não afetam a versão publicada até uma ação explÃcita de "publicar".', 1021 'Ao publicar, o conteúdo do rascunho substitui o publicado, e um novo rascunho pode começar a partir dali.', 1022 'Enquanto o rascunho existe sem publicar, ele pode ser descartado sem deixar rastro na versão pública.' 1023 ], 1024 pedidoConfuso: 'Deixa editar sem mudar o que já está no ar.', 1025 pedidoClaro: 'O artigo do blog tem um botão "Salvar rascunho" (só o autor vê essa versão) e um botão separado "Publicar" (só aà a mudança aparece pros leitores).', 1026 segundoExemplo: 'Um certificado com erro de digitação pode ser corrigido em rascunho e revisado antes de "republicar" a versão oficial, sem que o aluno veja a versão errada durante a correção.', 1027 errosComuns: [ 1028 'Publicar automaticamente sem uma ação explÃcita de confirmação, perdendo a proteção que o rascunho deveria dar.', 1029 'Não deixar claro na interface qual versão (rascunho ou publicada) a pessoa está vendo no momento.', 1030 'Perder o rascunho ao sair da tela sem salvar, sem nenhum aviso antes.' 1031 ], 1032 termoTecnico: 'Rascunho vs. publicado (draft / published state)', 1033 termosRelacionados: ['estado de publicação', 'versão de trabalho', 'conteúdo ao vivo', 'preview antes de publicar'] 1034 }, 1035 { 1036 nome: 'Versão/snapshot', 1037 icon: '<circle cx="12" cy="12" r="3"/><path d="M12 2v4M12 18v4M4.9 4.9l2.8 2.8M16.3 16.3l2.8 2.8M2 12h4M18 12h4M4.9 19.1l2.8-2.8M16.3 7.7l2.8-2.8"/>', 1038 oQueE: 'Uma cópia completa do estado de algo num momento especÃfico, guardada pra permitir comparação ou restauração depois, independente do histórico de campo a campo.', 1039 quandoUsar: 'Use quando faz sentido guardar o item inteiro de uma vez (não só o que mudou) â antes de uma operação arriscada, ou em marcos importantes (ex.: versão enviada pro cliente).', 1040 quandoNaoUsar: 'Não crie um snapshot pra toda mudança pequena â isso pesa em armazenamento; reserve pra momentos que realmente merecem uma foto completa do estado.', 1041 comparacao: 'Diferente de histórico de alterações (que registra mudanças campo a campo), snapshot guarda o item inteiro de uma vez, como uma foto â mais pesado, mas mais simples de restaurar de uma vez só.', 1042 comoFunciona: [ 1043 'Em um momento definido (manual ou automático), o sistema copia o estado completo do item.', 1044 'Essa cópia fica guardada com uma identificação (data, versão, motivo).', 1045 'A pessoa pode comparar duas versões lado a lado, ou restaurar o item inteiro pra aquele estado.', 1046 'Snapshots antigos e sem uso podem ser descartados depois de um tempo, pra não acumular indefinidamente.' 1047 ], 1048 pedidoConfuso: 'Guarda uma cópia de segurança.', 1049 pedidoClaro: 'Antes de rodar a migração que reorganiza os dados dos alunos, o sistema tira um snapshot completo da tabela, identificado com data e motivo, guardado por 30 dias.', 1050 segundoExemplo: 'Um editor de design salva "Versão 3 â aprovada pelo cliente" como snapshot, podendo comparar com a "Versão 5 â em revisão" atual a qualquer momento.', 1051 errosComuns: [ 1052 'Tirar snapshot de tudo o tempo todo, sem critério, lotando o armazenamento sem necessidade real.',
1053 'Não guardar o motivo/contexto do snapshot, deixando uma lista de versões sem significado nenhum meses depois.', 1054 'Confundir snapshot com backup de segurança do sistema inteiro â são propósitos diferentes, mesmo que pareçam parecidos.' 1055 ], 1056 termoTecnico: 'Versão/snapshot (state snapshot)', 1057 termosRelacionados: ['ponto de restauração', 'cópia de estado', 'versionamento', 'comparação de versões'] 1058 } 1059 ], 1060 codigos: [ 1061 { codigo: '/audit' }, 1062 { codigo: '/history' }, 1063 { codigo: '/revert' }, 1064 { codigo: '/draft' } 1065 ], 1066 scenario: { 1067 title: 'Cenário completo: corrigindo um erro no plano de um aluno', 1068 intro: 'Um único fluxo real, mostrando onde cada conceito desta aula aparece.', 1069 steps: [ 1070 { text: 'O gestor muda por engano o preço do plano "Equipe" de R$ 199 pra R$ 19 â como é uma ação sensÃvel (valor cobrado), o sistema registra automaticamente quem fez e quando.', tag: 'Trilha de auditoria' }, 1071 { text: 'Essa mudança aparece na aba "Histórico" do plano, mostrando o valor antigo (R$ 199) e o novo (R$ 19).', tag: 'Histórico de alterações' }, 1072 { text: 'Um segundo gestor percebe o erro e clica em "Reverter última alteração" â o preço volta pra R$ 199, e essa correção também vira uma nova entrada no histórico.', tag: 'Reversão' }, 1073 { text: 'Antes de qualquer uma dessas mudanças valer pros alunos, ela passa por um estágio de rascunho revisável, evitando que um erro de digitação chegue direto ao público.', tag: 'Rascunho vs. publicado' }, 1074 { text: 'Como essa era uma mudança importante de polÃtica de preço, o sistema também guardou um snapshot completo do plano antes da alteração, pra restaurar tudo de uma vez se precisasse.', tag: 'Versão/snapshot' } 1075 ] 1076 } 1077 }, 1078 { 1079 stage: 'Aula 07', 1080 estimatedMinutes: 30, 1081 layout: 'grid', 1082 title: 'Códigos Secretos: a régua do curso inteiro', 1083 goal: 'Aula bônus. Aqui a gente recapitula, aula por aula, o que o curso ensinou â e logo abaixo de cada recap traz os Códigos Secretos daquela aula: os comandos curtos que transformam o conteúdo em pedido.', 1084 focus: 'Antes de mandar um pedido de sistema pra IA ou pro dev, passe a régua da aula certa: o comportamento tem condição? tem status? algo dispara sozinho? depende de outro sistema? o que acontece se repetir ou travar? quem pode fazer? fica registrado?', 1085 practice: 'Pegue um pedido de funcionalidade que você precisa fazer esta semana. Rode pelo menos 4 códigos desta lista sobre ele â copie os prompts, preencha os [colchetes] com o seu caso, e junte tudo num pedido só.', 1086 exerciseFeedback: 'Não existe resposta única. O que importa: o pedido final não deixa buraco. Cada código que você aplicou virou uma frase especÃfica â condição exata, status nomeados, gatilho de automação claro, o que acontece no erro, quem tem permissão. Releia: um dev ou uma IA conseguiria implementar sem te perguntar nada de volta?', 1087 lessons: [ 1088 'Reconheça, num pedido pronto, quais códigos já foram respondidos e quais ficaram de fora.', 1089 'Monte a régua de revisão que você vai usar em todo pedido de sistema daqui pra frente.', 1090 'Combine vários códigos num pedido único, sem repetir nem se contradizer.' 1091 ], 1092 conceitos: [], 1093 bonus: true 1094 } 1095 1096]; 1097 1098// Curso "Do Pedido ao Sistema" (Primeiros Passos + Regras e Funcionamento 1099// combinados). Só as 2 aulas de ponte moram aqui â as outras 13 aulas do 1100// curso já existem em `aprender.html`/`combinacoes.html`/`telas.html`/ 1101// `prompt-ia.html` (curso 1) e `regras-e-funcionamento.html` (curso 2), e 1102// continuam sendo servidas por lá; o painel do aluno já sabe listar aulas 1103// de páginas diferentes dentro do mesmo curso. 1104const pedidoCompletoJourney = [ 1105 { 1106 stage: 'Aula 01', 1107 estimatedMinutes: 35, 1108 layout: 'grid', 1109 title: 'Onde interface e regra se encontram', 1110 goal: 'Aprenda a descrever, num pedido só, o comportamento de tela e a regra do sistema que c
1110ausa esse comportamento â a ponte entre os dois vocabulários que você já aprendeu separados.', 1111 focus: 'Antes de pedir uma tela com comportamento dinâmico, pergunte: o que faz esse botão/campo/selo mudar? Existe uma condição, uma automação, uma permissão ou um histórico por trás? Se a tela muda, alguma coisa no sistema decidiu isso.', 1112 practice: 'Escolha uma tela que você usa com frequência e ache 2 comportamentos de interface (botão que some, campo bloqueado, selo que aparece) e descreva a regra do sistema que causa cada um.', 1113 exerciseFeedback: 'Não existe resposta única â o que importa é conseguir apontar exatamente qual regra (condição, automação, permissão, histórico) explica o comportamento visual, em vez de descrever só o que aparece na tela.', 1114 lessons: [ 1115 'Aprenda a reconhecer quando um comportamento "só visual" na verdade é uma regra de sistema se manifestando.', 1116 'Veja 5 pares comuns de interfaceâregra, prontos pra reconhecer no seu próprio trabalho.', 1117 'Pratique escrever um pedido que já nasce cobrindo os dois lados de uma vez.' 1118 ], 1119 conceitos: [ 1120 { 1121 nome: 'Botão condicional', 1122 icon: '<rect x="3" y="9" width="18" height="6" rx="3"/><path d="M8 12h.01M12 12h.01M16 12h.01"/>', 1123 oQueE: 'Um botão (ou ação) que aparece, some ou fica desabilitado dependendo de uma condição do sistema â a tela não decide sozinha, ela reflete uma regra.', 1124 quandoUsar: 'Toda vez que uma ação só deveria estar disponÃvel sob certas circunstâncias â carrinho vazio, formulário incompleto, prazo vencido.', 1125 comoFunciona: [ 1126 'Você define a condição no backend.', 1127 'A tela consulta esse estado antes de renderizar o botão.', 1128 'O botão nasce habilitado, desabilitado ou oculto conforme a condição.', 1129 'Qualquer mudança na condição deveria atualizar o botão, não só no carregamento inicial.' 1130 ], 1131 pedidoConfuso: 'O botão de finalizar some à s vezes.', 1132 pedidoClaro: 'O botão "Finalizar compra" só fica habilitado quando o carrinho tem pelo menos 1 item e a forma de pagamento foi selecionada â a condição vem do backend, a tela só reflete.', 1133 segundoExemplo: 'Um botão "Aprovar" que só aparece pra quem tem a permissão certa â a mesma lógica de condição, aplicada a controle de acesso em vez de estado do pedido.', 1134 errosComuns: [ 1135 'Descrever só o visual ("deixa cinza") sem dizer qual regra decide isso.', 1136 'Esquecer de dizer o que acontece quando a condição muda depois da tela já carregada.' 1137 ], 1138 termoTecnico: 'Renderização condicional (conditional rendering)', 1139 termosRelacionados: ['regra condicional', 'condição', 'estado da interface'] 1140 }, 1141 { 1142 nome: 'Formulário bloqueado por regra', 1143 icon: '<rect x="4" y="4" width="16" height="16" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M15 15l3 3M18 15l-3 3"/>', 1144 oQueE: 'Um envio de formulário recusado não por erro de preenchimento, mas por uma regra de negócio â a tela precisa explicar isso diferente de um erro de validação comum.', 1145 quandoUsar: 'Quando existe uma regra que pode impedir a ação mesmo com todos os campos corretos â limite atingido, cadastro duplicado, janela de tempo fechada.', 1146 comoFunciona: [ 1147 'O formulário valida os campos normalmente primeiro.', 1148 'Ao enviar, o backend checa a regra de negócio.', 1149 'Se a regra bloquear, devolve um motivo especÃfico.', 1150 'A tela mostra esse motivo, diferente da mensagem genérica de "campo inválido".' 1151 ], 1152 pedidoConfuso: 'Não deixa cadastrar se não puder.', 1153 pedidoClaro: 'Ao tentar se inscrever numa turma lotada, o formulário passa na validação normal, mas o backend recusa com a regra "vagas esgotadas" â a tela mostra "Esta turma não tem mais vagas" em vez do erro genérico de formulário.', 1154 segundoExemplo: 'Tentar aplicar um cupom de primeira compra numa conta que já comprou antes â os campos estão certos, a regra de negócio que barra.', 1155 errosComuns: [ 1156 'Misturar a mensagem de bloqueio por regra com a de erro de validação, confundindo o usuário sobre o que ele precisa corrigir.' 1157 ], 1158 termoTecnico: 'Validação de regra de negócio (business rule validation)', 1159 termosRelacionados: ['bloqueio por regra', 'regra de negócio', 'validação de acesso'] 1160 }, 1161 { 1162 nome: 'Feedback de ação automática', 1163 icon: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 3"/>', 1164 oQueE: 'O que a tela mostra enquanto (e depois que) algo acontece sozinho no backend â sem isso, o usuário fica sem saber se algo está rodando, travou, ou já terminou.', 1165 quandoUsar: 'Sempre que um pedido de tela envolve algo que o sistema faz sozinho (automação, processamento, integração) â é preciso pedir também o que a tela mostra durante esse tempo.', 1166 comoFunciona: [ 1167 'A ação automática começa no backend.', 1168 'A tela entra num estado de "processando" (loading, mensagem, Ãcone).', 1169 'Quando termina, a tela atualiza pro resultado (sucesso, erro, ou novo estado).', 1170 'Se demorar muito, a tela deveria avisar isso também.' 1171 ], 1172 pedidoConfuso: 'Mostra que tá carregando.', 1173 pedidoClaro: 'Enquanto o pagamento é processado automaticamente, a tela mostra "Confirmando pagamento..." com um spinner; se passar de 10 segundos, troca pra "Isso está demorando mais que o normal" sem travar a navegação.', 1174 segundoExemplo: 'Um upload que dispara processamento em segundo plano â a tela mostra "Em processamento" e atualiza sozinha pra "Pronto" quando o backend termina.', 1175 errosComuns: [ 1176 'Pedir a automação no backend mas esquecer de pedir o que a tela mostra enquanto ela roda.',
1177 'Não dizer o que a tela faz se a automação falhar.' 1178 ], 1179 termoTecnico: 'Estado de carregamento assÃncrono (async loading state)', 1180 termosRelacionados: ['ação automática', 'notificação automática', 'processo em segundo plano'] 1181 }, 1182 { 1183 nome: 'Tela dependente de permissão', 1184 icon: '<path d="M12 15a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z"/><path d="M5 21c0-3.9 3.1-7 7-7s7 3.1 7 7"/>', 1185 oQueE: 'Quando o próprio layout da tela muda â não só o que é clicável, mas o que existe na tela â dependendo do papel ou permissão de quem está vendo.', 1186 quandoUsar: 'Painéis com mais de um tipo de usuário (admin, aluno, convidado) onde cada um deveria ver uma versão diferente da mesma tela, não a mesma tela com coisas desabilitadas.', 1187 comoFunciona: [ 1188 'A tela identifica o papel/permissão de quem está logado.', 1189 'Monta os blocos que essa pessoa tem permissão de ver.', 1190 'Blocos sem permissão nem chegam a ser enviados pro navegador, não é só escondidos via CSS.', 1191 'A mesma rota de tela serve conteúdo diferente por pessoa.' 1192 ], 1193 pedidoConfuso: 'Esconde as coisas de admin pra quem não é admin.', 1194 pedidoClaro: 'O dashboard mostra o card "Receita do mês" só pra quem tem o papel Financeiro â pra outros papéis, esse card nem é enviado na resposta da tela, não é só ocultado visualmente.', 1195 segundoExemplo: 'Uma barra lateral de navegação onde os itens de menu que aparecem mudam conforme o papel de quem logou.', 1196 errosComuns: [ 1197 'Esconder algo só no CSS/JS (qualquer um inspeciona e vê), quando deveria ser bloqueado também na origem do dado.' 1198 ], 1199 termoTecnico: 'Renderização baseada em permissão (permission-based rendering)', 1200 termosRelacionados: ['papel', 'permissão', 'visibilidade'] 1201 }, 1202 { 1203 nome: 'Estado visual sincronizado com histórico', 1204 icon: '<path d="M3 3v18h18"/><path d="m7 14 4-4 3 3 5-6"/>', 1205 oQueE: 'Uma indicação na tela (selo, texto, Ãcone) que reflete que algo mudou e ficou registrado â a tela vira uma janela pro histórico, não só pro estado atual.', 1206 quandoUsar: 'Quando é importante que quem vê a tela saiba que algo não é o valor original â foi editado, revertido, ou está em rascunho.', 1207 comoFunciona: [ 1208 'Toda mudança relevante gera uma entrada no histórico.', 1209 'A tela consulta se o item tem histórico recente.', 1210 'Mostra uma indicação visual discreta ("Editado há 2h").', 1211 'Clicar nessa indicação pode abrir o histórico completo.' 1212 ], 1213 pedidoConfuso: 'Mostra se foi editado.', 1214 pedidoClaro: 'Ao lado do preço do plano, um selo discreto "Editado há 2h por Maria" aparece sempre que houver uma entrada de histórico nas últimas 24h; passado esse prazo, o selo some.', 1215 segundoExemplo: 'Um documento colaborativo mostrando "Você está vendo uma versão restaurada" quando o conteúdo atual veio de uma reversão.', 1216 errosComuns: [ 1217 'Pedir o histórico só no backend e esquecer de pedir a pista visual â sem isso, ninguém sabe que aquele dado tem uma história.' 1218 ], 1219 termoTecnico: 'Indicador de estado auditável (audit-aware UI)', 1220 termosRelacionados: ['histórico de alterações', 'trilha de auditoria', 'rascunho vs. publicado'] 1221 } 1222 ] 1223 }, 1224 { 1225 stage: 'Aula 02', 1226 layout: 'timeline', 1227 sequenceCount: 4, 1228 connectors: ['leva ao próximo passo', 'leva ao próximo passo', 'fecha com'], 1229 title: 'Cenário completo: pedido de ponta a ponta', 1230 goal: 'Aprenda o framework de 4 passos pra estruturar qualquer pedido completo â tela e regra juntas â e aplique num cenário real inteiro.', 1231 focus: 'Antes de escrever um pedido de ponta a ponta, siga a ordem: primeiro a tela (interface pura), depois o estado inicial (a regra que decide o que ela mostra), depois o que é automático (o que o sistema faz sozinho), e por último quem vê o quê (permissão e histórico).', 1232 practice: 'Escolha um sistema que você usa (reserva de restaurante, biblioteca de livros, agendamento) e escreva um pedido completo cobrindo os 4 passos desta aula: a tela, o estado inicial, o que é automático e quem vê o quê.', 1233 exerciseFeedback: 'Não existe resposta única â o que importa é os 4 passos aparecerem claramente separados, sem misturar regra com visual no passo errado, e o pedido final ser algo que um dev, designer ou IA conseguiria implementar sem perguntar nada de volta.', 1234 lessons: [ 1235 'Aprenda a ordem certa de um pedido completo: interface antes de regra, estado antes de automação, automação antes de permissão.',
1236 'Veja o framework de 4 passos aplicado a um cenário real inteiro, do inÃcio ao fim.', 1237 'Feche o curso escrevendo seu próprio pedido de ponta a ponta.' 1238 ], 1239 conceitos: [ 1240 { 1241 nome: 'Descreva a tela', 1242 when: 'Primeiro passo', 1243 icon: '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9h18"/>', 1244 oQueE: 'O primeiro bloco de qualquer pedido completo: qual tela é, qual o objetivo dela, quais componentes aparecem e qual é a ação principal â o vocabulário de interface puro, sem regra ainda.', 1245 quandoUsar: 'Sempre no inÃcio de um pedido de ponta a ponta â antes de falar de regra, quem vai construir precisa saber que tela está sendo pedida.', 1246 comoFunciona: [ 1247 'Nomeie a tela e o objetivo dela em uma frase.', 1248 'Liste os componentes principais que aparecem.', 1249 'Diga qual é a ação principal que a tela existe pra permitir.', 1250 'Deixe pra descrever regra e comportamento nos próximos passos â aqui é só interface.' 1251 ], 1252 pedidoConfuso: 'Faz uma tela de inscrição.', 1253 pedidoClaro: 'Crie a tela "Inscrição no workshop": um card com nome do evento, data, vagas restantes, um formulário com nome e e-mail, e um botão "Confirmar inscrição" como ação principal.', 1254 segundoExemplo: 'Descrever a tela de checkout como "formulário de entrega + resumo do pedido + botão Finalizar compra", antes de falar de qualquer regra de pagamento.', 1255 errosComuns: [ 1256 'Já misturar regra de negócio nesse primeiro passo, perdendo a separação que ajuda quem vai construir.', 1257 'Esquecer de nomear a ação principal, deixando a tela sem objetivo claro.' 1258 ], 1259 termoTecnico: 'Especificação de interface (UI spec)', 1260 termosRelacionados: ['objetivo da tela', 'componente principal', 'ação primária'] 1261 }, 1262 { 1263 nome: 'Descreva o estado inicial', 1264 when: 'Depois de definir a tela', 1265 icon: '<circle cx="12" cy="12" r="9"/><path d="M9 12l2 2 4-4"/>', 1266 oQueE: 'O que decide o que a tela mostra ou permite antes de qualquer ação do usuário â a condição e o status por trás do que parece "só visual".', 1267 quandoUsar: 'Sempre que o que a tela mostra depende de alguma regra â vagas disponÃveis, prazo aberto, permissão de quem está vendo.', 1268 comoFunciona: [ 1269 'Pergunte: o que precisa ser verdade pra essa tela funcionar do jeito esperado?', 1270 'Descreva a condição usando o vocabulário de Estado e decisão.', 1271 'Diga o que a tela mostra quando a condição NÃO é atendida.', 1272 'Amarre o componente visual à condição: qual botão/mensagem muda quando o estado muda.' 1273 ], 1274 pedidoConfuso: 'Mostra as vagas certinho.', 1275 pedidoClaro: 'O card mostra "12 vagas restantes" enquanto o limite de 30 não for atingido; ao chegar em 0, o botão "Confirmar inscrição" vira desabilitado com o texto "Vagas esgotadas".', 1276 segundoExemplo: 'Um badge "Convidado" só aparece se o status do usuário for "pendente de confirmação" â a condição decide, o badge só reflete.', 1277 errosComuns: [ 1278 'Descrever só o estado "feliz" (vagas disponÃveis) e esquecer o que a tela faz quando a condição falha.', 1279 'Confundir estado inicial com automação â estado é o que já é verdade antes de qualquer ação; automação é o que muda sozinho depois.' 1280 ], 1281 termoTecnico: 'Estado inicial da tela (initial UI state)', 1282 termosRelacionados: ['condição', 'status', 'limite'] 1283 }, 1284 { 1285 nome: 'Descreva o que é automático', 1286 when: 'Enquanto o aluno usa a tela',
1287 icon: '<path d="M13 2 3 14h7l-1 8 10-12h-7l1-8z"/>', 1288 oQueE: 'O que o sistema faz sozinho depois que o usuário age na tela â e o que a tela mostra enquanto isso acontece, pra ninguém ficar no escuro.', 1289 quandoUsar: 'Sempre que uma ação do usuário dispara algo que não é instantâneo â confirmação por e-mail, processamento, integração com outro sistema.', 1290 comoFunciona: [ 1291 'Diga qual ação do usuário dispara o comportamento automático.', 1292 'Descreva o que o sistema faz sozinho.', 1293 'Diga o que a tela mostra enquanto isso roda.', 1294 'Descreva o que muda na tela quando o processo termina.' 1295 ], 1296 pedidoConfuso: 'Manda o e-mail de confirmação.', 1297 pedidoClaro: 'Ao clicar em "Confirmar inscrição", o sistema dispara automaticamente um e-mail de confirmação; a tela mostra "Confirmando sua vaga..." por até 3 segundos, e depois troca pra "Vaga confirmada! Verifique seu e-mail."', 1298 segundoExemplo: 'Um upload de comprovante que dispara verificação automática em segundo plano, com a tela mostrando "Em análise" até o sistema aprovar ou recusar sozinho.', 1299 errosComuns: [ 1300 'Pedir a automação sem pedir o feedback visual dela, deixando a tela travada sem explicação.', 1301 'Não dizer o que acontece se a automação falhar.' 1302 ], 1303 termoTecnico: 'Comportamento pós-ação (post-action behavior)', 1304 termosRelacionados: ['ação automática', 'notificação automática', 'feedback de ação automática'] 1305 }, 1306 { 1307 nome: 'Descreva quem vê o quê', 1308 when: 'Fechando o pedido', 1309 icon: '<path d="M12 15a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z"/><path d="M5 21c0-3.9 3.1-7 7-7s7 3.1 7 7"/>', 1310 oQueE: 'O fechamento do pedido: quem tem permissão de ver ou fazer o quê nessa tela, e se alguma parte precisa ficar registrada por ser sensÃvel.', 1311 quandoUsar: 'Sempre que a tela é usada por mais de um tipo de pessoa (aluno vs. organizador, cliente vs. admin) ou envolve dado que precisa de rastro.', 1312 comoFunciona: [ 1313 'Liste quem usa essa tela (papéis diferentes).', 1314 'Diga o que cada papel pode ver ou fazer de diferente.', 1315 'Se a ação for sensÃvel, diga se precisa virar um registro de histórico/auditoria.', 1316 'Feche o pedido conferindo se os 4 passos desta aula foram cobertos.' 1317 ], 1318 pedidoConfuso: 'Só o organizador vê tudo.', 1319 pedidoClaro: 'A tela "Lista de inscritos" mostra nome e e-mail só pra quem tem o papel Organizador; participantes comuns veem só a contagem total. Toda remoção manual de um inscrito por um organizador fica registrada no histórico com quem removeu e quando.', 1320 segundoExemplo: 'Um painel financeiro visÃvel só pro papel Financeiro, com toda alteração de valor virando entrada de auditoria.', 1321 errosComuns: [ 1322 'Esquecer de checar se algum dado ali é sensÃvel o bastante pra precisar de histórico obrigatório.', 1323 'Fechar o pedido sem revisar se os 4 passos da aula foram realmente cobertos.' 1324 ], 1325 termoTecnico: 'Controle de acesso e rastreabilidade (access control & traceability)', 1326 termosRelacionados: ['permissão', 'visibilidade', 'trilha de auditoria'] 1327 } 1328 ], 1329 scenario: { 1330 title: 'Cenário completo: inscrição num workshop com vagas limitadas', 1331 intro: 'Um único fluxo real, amarrando os 4 passos desta aula â e até conceitos de aulas anteriores dos dois cursos.', 1332 steps: [ 1333 { text: 'Tela "Inscrição no workshop": card com nome do evento, vagas restantes, formulário (nome, e-mail) e botão "Confirmar inscrição".', tag: 'Descreva a tela' }, 1334 { text: 'Enquanto houver menos de 30 inscritos, o botão fica ativo e mostra "X vagas restantes"; ao bater 30, o botão desabilita e mostra "Vagas esgotadas".', tag: 'Descreva o estado inicial' }, 1335 { text: 'Ao confirmar, o sistema dispara um e-mail de confirmação automaticamente; a tela mostra "Confirmando sua vaga..." até o processo terminar, depois "Vaga confirmada!".', tag: 'Descreva o que é automático' }, 1336 { text: 'Se dois inscritos confirmarem a última vaga no mesmo segundo, só um consegue â o outro vê "Essa vaga acabou de ser preenchida".', tag: 'Operações simultâneas (curso Regras e Funcionamento)' }, 1337 { text: 'A lista de inscritos completa (nome, e-mail) só aparece pra quem tem o papel Organizador; participantes veem só o total.', tag: 'Descreva quem vê o quê' }, 1338 { text: 'Se um organizador remove um inscrito manualmente, essa ação vira uma entrada no histórico, com quem removeu e quando.', tag: 'Trilha de auditoria (curso Regras e Funcionamento)' } 1339 ] 1340 } 1341 } 1342]; 1343 1344// Slug do plano/curso "Dados e Informações" â precisa bater exatamente com 1345// o slug real criado no painel gestor (gerado automaticamente a partir do 1346// nome do curso, ver slugifyPlanName em functions/_shared/plans.js). 1347const DADOS_INFORMACOES_PLAN_SLUG = 'dados_e_informacoes'; 1348const APIS_QUE_FUNCIONAM_PLAN_SLUG = 'apis_que_funcionam'; 1349const SEGURANCA_APLICACOES_WEB_PLAN_SLUG = 'seguranca_aplicacoes_web'; 1350const PROTOTIPANDO_COM_IA_PLAN_SLUG = 'prototipando_com_ia'; 1351const UI_DESCOMPLICADA_PLAN_SLUG = 'ui_descomplicada'; 1352 1353function apiConceito(nome, oQueE, quandoUsar, pedidoConfuso, pedidoClaro, termoTecnico, termosRelacionados, extras = {}) { 1354 return { 1355 nome, 1356 oQueE, 1357 quandoUsar, 1358 pedidoConfuso, 1359 pedidoClaro, 1360 termoTecnico, 1361 termosRelacionados, 1362 ...extras 1363 }; 1364} 1365 1366const apisQueFuncionamJourney = [ 1367 { 1368 stage: 'Aula 01', 1369 layout: 'grid', 1370 title: 'O que é uma API e quando pedir uma', 1371 goal: 'Entenda API como uma conversa organizada entre sistemas, sem precisar programar, para saber quando uma integração é realmente necessária.', 1372 focus: 'Antes de pedir uma API, pergunte: qual sistema precisa falar com qual outro, qual evento inicia a conversa e que resultado deve acontecer depois?', 1373 practice: 'Escolha um fluxo real, como pagamento aprovado, cadastro enviado ou certificado liberado, e descreva quem avisa quem, com quais dad
1373os e para qual ação.', 1374 exerciseFeedback: 'A resposta boa não usa apenas "integrar tudo". Ela mostra origem, destino, informação enviada e ação esperada.', 1375 lessons: [ 1376 'API é um jeito combinado de um sistema conversar com outro.', 1377 'Nem toda necessidade de tela ou relatório precisa virar uma API.', 1378 'Um pedido claro explica evento, sistema de origem, sistema de destino e resultado esperado.' 1379 ], 1380 conceitos: [ 1381 apiConceito('API', 'Um canal organizado para sistemas trocarem dados ou dispararem ações entre si.', 'Use quando uma informação precisa sair de um sistema e provocar algo em outro.', 'Preciso de uma API para integrar tudo.', 'Quando o pagamento for aprovado no Asaas, a plataforma deve receber o aviso, liberar o curso comprado e enviar o e-mail de acesso.', 'API (Application Programming Interface)', ['integração', 'sistema externo', 'comunicação entre sistemas']), 1382 apiConceito('Integração', 'A conexão prática entre dois ou mais sistemas para que um fluxo aconteça sem trabalho manual.', 'Use quando repetir a mesma ação manualmente gera atraso, erro ou retrabalho.', 'Integra com o pagamento.', 'Ao confirmar o pagamento, o gateway envia os dados do comprador e do curso para a plataforma liberar o acesso.', 'Integração de sistemas', ['automação', 'sincronização', 'gateway']), 1383 apiConceito('Sistema de origem e destino', 'Origem é quem envia a informação; destino é quem recebe e age a partir dela.', 'Use para evitar confusão sobre quem dispara o processo e quem deve mudar estado.', 'Um sistema manda para o outro.', 'O Asaas é a origem do evento de pagamento; a plataforma Como Pedir é o destino que libera o curso.', 'Source and target systems', ['origem', 'destino', 'fonte da verdade']) 1384 ], 1385 codigos: [ 1386 { codigo: '/evento-e-resultado' }, 1387 { codigo: '/nao-vira-api' } 1388 ] 1389 }, 1390 { 1391 stage: 'Aula 02', 1392 estimatedMinutes: 35, 1393 layout: 'grid', 1394 title: 'Métodos, rotas, endpoints e contratos', 1395 goal: 'Aprenda a nomear as peças de uma API para pedir consultas, cadastros e atualizações sem deixar o dev adivinhar a intenção.', 1396 focus: 'Antes de validar um endpoint, confira: método, rota, dados recebidos, resposta esperada e erros previstos.', 1397 practice: 'Transforme "preciso salvar progresso do aluno" em método, rota, payload, resposta e regras importantes.', 1398 exerciseFeedback: 'O pedido fica bom quando a ação principal aparece no método e a rota aponta para o recurso certo.', 1399 lessons: [ 1400 'Rota é o caminho do recurso dentro da API.', 1401 'Endpoint junta método e rota para indicar uma ação especÃfica.', 1402 'Contrato define o combinado de entrada, saÃda, permissões e erros.' 1403 ], 1404 conceitos: [ 1405 apiConceito('Método HTTP', 'A ação que indica se a API vai consultar, criar, alterar ou remover algo.', 'Use para deixar clara a intenção do pedido: GET consulta, POST cria, PATCH atualiza parte, DELETE remove.', 'Faz uma rota de aluno.', 'GET /alunos/{id}/acesso consulta se o aluno pode entrar na plataforma.', 'HTTP method', ['GET', 'POST', 'PATCH']), 1406 apiConceito('Rota e endpoint', 'Rota é o caminho; endpoint é o método somado a esse caminho.', 'Use quando precisa especificar exatamente onde a chamada chega e o que ela faz.', 'Cria um endpoint aÃ.', 'POST /alunos cria um aluno; GET /alunos/{id} consulta um aluno especÃfico.', 'Endpoint', ['rota', 'recurso', 'URL']), 1407 apiConceito('Contrato da API', 'O combinado que define dados enviados, resposta, status e erros esperados.', 'Use antes de desenvolver, testar ou contratar uma integração.', 'Retorna os dados do aluno.', 'A resposta deve trazer aluno_id, nome, curso, acesso_ativo e pagamento_confirmado.', 'API contract', ['payload', 'resposta', 'status HTTP']) 1408 ], 1409 codigos: [ 1410 { codigo: '/metodo-pela-intencao' }, 1411 { codigo: '/contrato-completo' } 1412 ] 1413 }, 1414 { 1415 stage: 'Aula 03', 1416 layout: 'grid', 1417 title: 'Parâmetros, payloads, headers e status HTTP', 1418 goal: 'Entenda onde cada informação entra na chamada da API e como interpretar o resultado que volta.', 1419 focus: 'Separe identificadores na rota, filtros na busca, dados principais no payload, credenciais nos headers e resultado no status HTTP.', 1420 practice: 'Especifique uma consulta de pagamentos confirmados de um aluno, indicando rota, filtros, headers, payload e resposta.', 1421 exerciseFeedback: 'Uma boa resposta separa bem: rota identifica o aluno, query filtra status, payload não é necessário em consulta.', 1422 lessons: [ 1423 'Parâmetros de rota identificam um item especÃfico.', 1424 'Payload carrega os dados principais de criação ou atualização.', 1425 'Status HTTP ajuda a saber se deu certo, faltou dado, não há permissão ou algo falhou.' 1426 ], 1427 conceitos: [ 1428 apiConceito('Parâmetros', 'Informações usadas para identificar ou filtrar o que a API deve buscar.', 'Use rota para IDs e busca para filtros, ordenação e paginação.', 'Lista os pagamentos.', 'GET /alunos/{aluno_id}/pagamentos?status=confirmado lista pagamentos confirmados daquele aluno.', 'Parameters', ['path parameter', 'query string', 'filtro']), 1429 apiConceito('Payload', 'O corpo da requisição com os dados principais enviados para criar ou atualizar algo.', 'Use em POST, PATCH ou PUT quando a ação precisa carregar informações.', 'Manda os dad
1429os do aluno.', 'POST /alunos recebe nome, email e curso_id no corpo da requisição.', 'Request payload', ['body', 'JSON', 'dados enviados']), 1430 apiConceito('Headers e status', 'Headers levam instruções técnicas; status informa o resultado da chamada.', 'Use para autenticação, formato e leitura clara de sucesso ou erro.', 'Se der erro, avisa.', 'Authorization vai no header; 401 indica token ausente, 403 sem permissão e 404 recurso não encontrado.', 'Headers and HTTP status', ['Authorization', 'Content-Type', '401']) 1431 ], 1432 codigos: [ 1433 { codigo: '/separa-entrada' }, 1434 { codigo: '/status-por-cenario' } 1435 ] 1436 }, 1437 { 1438 stage: 'Aula 04', 1439 layout: 'groups', 1440 title: 'Autenticação em APIs: tokens, sessões e chaves', 1441 goal: 'Entenda como uma API identifica quem está chamando e como separa aluno, gestor e sistema externo.', 1442 focus: 'Antes de proteger uma API, defina quem chama, como prova a identidade, quanto tempo vale o acesso e quais ações são permitidas.', 1443 practice: 'Descreva como um gestor autenticado poderia consultar alunos ativos sem permitir que um aluno comum use o mesmo endpoint.', 1444 exerciseFeedback: 'A resposta certa separa autenticação de autorização: primeiro quem é, depois o que pode fazer.', 1445 lessons: [ 1446 'Autenticação responde quem está fazendo a chamada.', 1447 'Autorização responde o que essa pessoa ou sistema pode fazer.', 1448 'Tokens, sessões e chaves resolvem cenários diferentes.' 1449 ], 1450 groups: [ 1451 { title: 'Identidade', desc: 'Como a API reconhece quem está chamando.' }, 1452 { title: 'Permissão', desc: 'O que aquela identidade pode executar.' } 1453 ], 1454 conceitos: [ 1455 apiConceito('Token', 'Credencial temporária enviada geralmente no header Authorization.', 'Use quando uma aplicação precisa chamar a API em nome de um usuário ou acesso temporário.', 'Protege com login.', 'Os endpoints da área do aluno exigem Authorization: Bearer token e só retornam dados do próprio aluno.', 'Bearer token', ['JWT', 'access token', 'Authorization'], { grupo: 0 }), 1456 apiConceito('Sessão', 'Estado de login mantido pelo navegador, normalmente por cookie seguro.', 'Use em painéis web, área do aluno e área administrativa.', 'Mantém o usuário logado.', 'Após login, a sessão do gestor permite abrir o painel sem reenviar senha a cada requisição.', 'Session authentication', ['cookie', 'login', 'sessão segura'], { grupo: 0 }), 1457 apiConceito('Chave de API', 'Credencial usada por uma integração ou sistema externo.', 'Use para chamadas servidor para servidor, com permissões limitadas e rotação.', 'Usa uma chave geral.', 'A integração de pagamento usa uma chave própria que só pode enviar eventos autorizados.', 'API key', ['x-api-key', 'credencial', 'integração externa'], { grupo: 1 }) 1458 ], 1459 codigos: [ 1460 { codigo: '/quem-esta-chamando' }, 1461 { codigo: '/credencial-por-caso' } 1462 ] 1463 }, 1464 { 1465 stage: 'Aula 05', 1466 layout: 'grid', 1467 title: 'Validação, erros e respostas bem desenhadas', 1468 goal: 'Aprenda a pedir APIs que conferem dados antes de agir e devolvem mensagens úteis quando algo dá errado.', 1469 focus: 'Toda ação deve prever campos obrigatórios, formato, regra de negócio, permissão, status HTTP e mensagem clara.', 1470 practice: 'Descreva a resposta de API para um aluno tentando criar senha com link expirado.', 1471 exerciseFeedback: 'Uma resposta boa informa o problema sem vazar token, hash, banco de dados ou detalhes internos.', 1472 lessons: [ 1473 'Validação evita salvar dado incompleto, duplicado ou sem sentido.', 1474 'Erro bom explica o problema, o campo afetado e como corrigir.', 1475 'Resposta de sucesso confirma o que aconteceu e devolve dados úteis.' 1476 ], 1477 conceitos: [ 1478 apiConceito('Validação', 'Checagem feita antes de aceitar ou processar uma informação.', 'Use para campos obrigatórios, formato, duplicidade e regras de negócio.', 'Confere os dados.', 'O campo email é obrigatório, deve ter formato válido e não pode repetir um cadastro existente.', 'Validation', ['campo obrigatório', 'formato', 'regra de negócio']), 1479 apiConceito('Erro desenhado', 'Resposta de erro pensada para orientar pessoa, tela e suporte.', 'Use para evitar mensagens genéricas como "falha" ou "tente novamente".', 'Se der erro mostra uma mensagem.', 'Retornar 409 com código EMAIL_JA_CADASTRADO e mensagem "Este e-mail já está cadastrado".', 'Error response design', ['código de erro', 'mensagem', 'status HTTP']), 1480 apiConceito('Não vazar detalhes internos', 'Evitar expor banco, token, stack trace ou regra sensÃvel na resposta pública.', 'Use em toda API que responde para navegador, app ou sistema externo.', 'Mostra o erro real.', 'Responder "Este e-mail já está cadastrado" em vez de mostrar SQLITE_CONSTRAINT.', 'Safe error handling', ['stack trace', 'dados sensÃveis', 'log interno']) 1481 ], 1482 codigos: [ 1483 { codigo: '/valida-antes-de-agir' }, 1484 { codigo: '/erro-com-codigo' } 1485 ] 1486 }, 1487 { 1488 stage: 'Aula 06', 1489 layout: 'timeline', 1490 title: 'Webhooks: quando usar, como receber e como reprocessar', 1491 goal: 'Entenda webhook como aviso automático entre sistemas e aprenda a receber, registrar e reprocessar eventos sem perder controle.', 1492 focus: 'Defina sistema que envia, endpoint que recebe, tipos de evento, validação de origem, resposta rápida e reprocessamento.', 1493 practice: 'Descreva o webhook de um boleto confirmado dois dias depois da compra.', 1494 exerciseFeedback: 'O desenho fica completo quando inclui evento_id, validação de origem, ação esperada e plano para falha parcial.', 1495 lessons: [ 1496 'Webhook é o outro sistema avisando que algo aconteceu.', 1497 'A API deve receber, validar, registrar e responder rapidamente.', 1498 'Reprocessamento evita que uma falha temporária vire perda definitiva.' 1499 ], 1500 sequenceCount: 3, 1501 connectors: ['avisa', 'valida', 'registra'], 1502 conceitos: [ 1503 apiConceito('Webhook', 'Aviso automático enviado por um sistema quando um evento acontece.', 'Use quando sua plataforma precisa reagir a pagamento, cancelamento, formulário, entrega ou outro evento externo.', 'Quando o pagamento confirmar, libera o aluno.', 'POST /webhooks/pagamentos recebe pagamento.confirmado e inicia a liberação do curs
1503o.', 'Webhook', ['evento', 'callback', 'notificação']), 1504 apiConceito('Evento', 'O fato especÃfico que aconteceu e precisa ser tratado pela plataforma.', 'Use para diferenciar pagamento.confirmado, pagamento.recusado, assinatura.cancelada e outros cenários.', 'Recebe status do pagamento.', 'Se tipo = pagamento.confirmado, libera acesso; se tipo = pagamento.estornado, bloqueia ou sinaliza revisão.', 'Event type', ['pagamento.confirmado', 'payload', 'status']), 1505 apiConceito('Reprocessamento', 'Capacidade de tentar tratar novamente um evento que falhou ou ficou incompleto.', 'Use quando enviar e-mail, atualizar acesso ou chamar outro serviço pode falhar temporariamente.', 'Tenta de novo se falhar.', 'Se o e-mail falhar, o evento fica registrado como falha parcial e pode ser reenviado pelo gestor.', 'Retry / reprocessing', ['fila', 'tentativa', 'falha parcial']) 1506 ], 1507 codigos: [ 1508 { codigo: '/webhook-por-tipo' }, 1509 { codigo: '/plano-de-reprocessamento' } 1510 ] 1511 }, 1512 { 1513 stage: 'Aula 07', 1514 estimatedMinutes: 45, 1515 layout: 'grid', 1516 title: 'Segurança e idempotência em integrações', 1517 goal: 'Aprenda a proteger chamadas externas e impedir que eventos repetidos criem matrÃculas, cobranças ou e-mails duplicados.', 1518 focus: 'Toda integração deve validar origem, registrar identificador único e saber o que fazer quando recebe a mesma chamada outra vez.', 1519 practice: 'Descreva como tratar um webhook de pagamento aprovado que pode chegar duas vezes.', 1520 exerciseFeedback: 'O melhor desenho retorna sucesso para evento repetido, mas não executa de novo a ação principal.', 1521 lessons: [ 1522 'Segurança protege a entrada da integração.', 1523 'Idempotência protege o resultado contra repetição.', 1524 'Logs ajudam suporte e auditoria a entender o que aconteceu.' 1525 ], 1526 conceitos: [ 1527 apiConceito('Idempotência', 'Garantia de que repetir a mesma chamada não duplica o resultado.', 'Use em pagamentos, matrÃcula, envio de e-mail, criação de pedido e qualquer ação crÃtica.', 'Não deixa duplicar.', 'Se evento_id já foi processado, responder sucesso e não liberar o curso nem reenviar e-mail outra vez.', 'Idempotency', ['evento_id', 'duplicidade', 'reprocessamento']), 1528 apiConceito('Validação de origem', 'Checagem que confirma se a chamada veio de uma fonte confiável.', 'Use em webhooks, integrações externas e endpoints sensÃveis.', 'Confia no que chegar.', 'Validar assinatura do webhook antes de processar pagamento confirmado.', 'Webhook signature validation', ['assinatura', 'token', 'chave secreta']), 1529 apiConceito('Registro de integração', 'Histórico do que chegou, quando chegou e qual foi o resultado.', 'Use para suporte, auditoria, reprocessamento e investigação de falhas.', 'Salva um log.', 'Registrar evento_id, pagamento_id, aluno, curso, status, resultado e mensagem de erro se houver.', 'Integration log', ['auditoria', 'histórico', 'observabilidade']) 1530 ], 1531 codigos: [ 1532 { codigo: '/idempotente-de-verdade' }, 1533 { codigo: '/valida-a-origem' } 1534 ] 1535 }, 1536 { 1537 stage: 'Aula 08', 1538 estimatedMinutes: 45, 1539 layout: 'grid', 1540 title: 'Projeto final: desenhar uma API com webhook para um fluxo real', 1541 goal: 'Aplique o curso inteiro criando uma especificação clara de integração para liberar acesso após pagamento confirmado.', 1542 focus: 'Junte objetivo, sistemas envolvidos, endpoint, payload, headers, validação, erros, idempotência, logs e fluxo final.', 1543 practice: 'Monte uma especificação completa para compra de curso, confirmação de pagamento e liberação automática de acesso.', 1544 exerciseFeedback: 'O projeto está pronto quando outra pessoa consegue entender o fluxo sem perguntar "quem envia?", "quem recebe?" ou "o que acontece se falhar?".', 1545 lessons: [ 1546 'Projeto final não é programar: é saber pedir e revisar a integração.', 1547 'O fluxo precisa prever sucesso, erro, duplicidade e reprocessamento.', 1548 'Uma especificação clara reduz retrabalho entre negócio, design e desenvolvimento.' 1549 ], 1550 conceitos: [ 1551 apiConceito('Especificação de integração', 'Documento curto que explica como sistemas conversam em um fluxo real.', 'Use antes de desenvolver, contratar, estimar ou revisar uma API.', 'Faz integração com pagamento.', 'Gateway envia POST /webhooks/pagamentos; plataforma valida assinatura, libera curso, envia e-mail e registra evento.', 'Integration specification', ['contrato', 'fluxo', 'endpoint']), 1552 apiConceito('Fluxo ponta a ponta', 'Sequência completa desde o evento inicial até o resultado visÃvel para o usuário.', 'Use para não esquecer etapas invisÃveis como e-mail, log, falha parcial e suporte.', 'Quando comprar libera.', 'Aluno compra, gateway confirma, webhook chega, plataforma valida, matrÃcula é
1552criada, e-mail é enviado e progresso aparece no painel.', 'End-to-end flow', ['jornada', 'processo', 'automação']), 1553 apiConceito('Checklist de entrega', 'Lista final que confirma se a integração está pronta para ser implementada ou revisada.', 'Use no fechamento de briefing, aprovação de escopo e testes.', 'Confere se está ok.', 'Validar endpoint, payload, autenticação, status, erros, idempotência, logs e reprocessamento antes de publicar.', 'Delivery checklist', ['QA', 'aceite', 'teste']) 1554 ], 1555 codigos: [ 1556 { codigo: '/especifica-a-integracao' }, 1557 { codigo: '/fluxo-ponta-a-ponta' } 1558 ] 1559 }, 1560 { 1561 stage: 'Aula 09', 1562 estimatedMinutes: 30, 1563 layout: 'grid', 1564 title: 'Códigos Secretos: a régua de integrações do curso inteiro', 1565 goal: 'Aula bônus. Recapitula as 8 aulas e reúne os 16 comandos que cobrem quando integrar, contrato, parâmetros, autenticação, validação, webhook, idempotência e especificação.', 1566 focus: 'Antes de pedir ou revisar uma integração, passe a régua: dá pra nomear evento, origem e destino? o contrato tem entrada, saÃda e erros? a credencial combina com quem chama? o webhook trata cada tipo de evento e resiste à repetição?', 1567 practice: 'Pegue uma integração real que você precisa pedir ou revisar esta semana. Rode pelo menos 4 códigos desta lista sobre ela e junte tudo numa especificação só.', 1568 exerciseFeedback: 'Não existe resposta única. O que importa: a especificação final não deixa buraco â evento, sistemas, contrato, autenticação e comportamento de falha ficam explÃcitos, não implÃcitos.', 1569 lessons: [ 1570 'Reconheça, numa integração pronta, quais decisões já foram tomadas e quais ficaram em aberto.', 1571 'Monte a régua de revisão que você vai usar em qualquer API ou webhook daqui pra frente.', 1572 'Combine vários códigos numa especificação única, sem contradição.' 1573 ], 1574 conceitos: [], 1575 bonus: true 1576 } 1577]; 1578 1579const prototipandoComIaJourney = [ 1580 { stage: 'Aula 01', layout: 'grid', title: 'O que é vibecoding e onde ele ajuda de verdade', goal: 'Use IA para explorar e prototipar ideias sem confundir velocidade com produto pronto.', focus: 'Comece pelo problema, público e resultado; a ferramenta vem depois.', practice: 'Descreva uma ideia com problema, público, resultado e limite da primeira versão.', exerciseFeedback: 'Uma boa resposta define para quem é, qual dor resolve e o que ficará fora.', lessons: ['IA acelera exploração, mas não decide o produto.', 'Protótipo serve para aprender antes de construir tudo.', 'Limites controlam o escopo.'], codigos: [{ codigo: '/problema' }, { codigo: '/limite' }], conceitos: [apiConceito('Vibecoding', 'Uso de linguagem natural e IA para explorar, prototipar e construir software.', 'Use para transformar uma ideia em algo visual ou funcional que possa ser revisado.', 'A IA faz o sistema inteiro.', 'Use IA para criar um protótipo navegável com dados fictÃcios e limite explÃcito.', 'Vibe coding', ['protótipo', 'IA', 'escopo']), apiConceito('Protótipo', 'Versão simplificada para testar ideia e fluxo antes da construção completa.', 'Use para validar direção com produto, design e usuários.', 'Faz a versão final rapidinho.', 'Demonstre cadastro e conclusão de tarefas, sem integração real.', 'Prototype', ['MVP', 'fluxo', 'validação'])] }, 1581 { stage: 'Aula 02', layout: 'grid', title: 'Como transformar uma ideia em escopo claro', goal: 'Quebre uma ideia ampla em objetivo, público, fluxo, dados e critérios de sucesso.', focus: 'Um escopo responde o que será feito, para quem, em qual ordem e como saber que funcionou.', practice: 'Transforme uma agenda de consultas em escopo de primeira versão.', exerciseFeedback: 'O escopo bom tem começo, caminho e resultado; não é uma lista infinita.', lessons: ['Objetivo orienta decisões.', 'Fluxo principal vem antes das exceções.', 'Critério de sucesso evita opinião solta.'], codigos: [{ codigo: '/escopo' }, { codigo: '/criterio' }], conceitos: [apiConceito('Escopo', 'Limite combinado do que entra e do que fica fora.', 'Use antes de pedir telas, código ou protótipo.', 'Faz uma agenda completa.', 'Na primeira versão, o paciente vê horários fictÃcios e confirma; pagamentos ficam fora.', 'Scope', ['MVP', 'prioridade']), apiConceito('Critério de sucesso', 'Sinal observável de que o protótipo cumpriu seu objetivo.', 'Use para revisar uma saÃda da IA.', 'Quando estiver bonito está pronto.', 'Cinco pessoas encontram e confirmam um horário sem orientação.', 'Success criterion', ['teste', 'aceite'])] }, 1582 { stage: 'Aula 03', layout: 'groups', title: 'Prompts para criar telas, fluxos e componentes', goal: 'Dê contexto, estrutura e restrições para a IA gerar uma interface revisável.', focus: 'Peça objetivo, público, conteúdo, estados, ações e entrega esperada.', practice: 'Escreva um prompt para uma solicitação de orçamento com estados vazio, carregando, erro e sucesso.', exerciseFeedback: 'O prompt completo descreve comportamento e estados, não só estilo.', lessons: ['Contexto reduz respostas genéricas.', 'Estados fazem parte da tela.', 'Componentes têm função e c
1582omportamento.'], codigos: [{ codigo: '/contexto' }, { codigo: '/estados' }], groups: [{ title: 'Contexto', desc: 'Para quem é e qual resultado a tela produz.' }, { title: 'Comportamento', desc: 'O que acontece antes, durante e depois de cada ação.' }], conceitos: [apiConceito('Briefing para IA', 'Contexto organizado sobre problema, público, objetivo e limites.', 'Use antes de pedir uma tela ou fluxo.', 'Faz uma tela bonita.', 'Crie orçamento para pessoas leigas, com dados mÃnimos e confirmação de recebimento.', 'AI brief', ['contexto', 'escopo']), apiConceito('Estado de interface', 'Condição da tela que comunica o que acontece e qual ação é possÃvel.', 'Use em carregamento, erro, vazio e sucesso.', 'Se der erro avisa.', 'Durante envio, desabilite o botão; em erro, explique e permita tentar novamente.', 'UI state', ['erro', 'sucesso'])] }, 1583 { stage: 'Aula 04', layout: 'grid', title: 'Prompts para corrigir bugs e melhorar código', goal: 'Peça investigação e correção sem mascarar o problema nem aceitar mudança arriscada.', focus: 'Descreva sintoma, reprodução, ambiente, esperado e limite da mudança.', practice: 'Peça correção para botão que funciona no desktop e falha no celular.', exerciseFeedback: 'O pedido permite reproduzir e conferir regressões.', lessons: ['Sintoma não é causa.', 'Reprodução orienta investigação.', 'Correção precisa de verificação.'], codigos: [{ codigo: '/reproduzir' }, { codigo: '/nao-quebrar' }], conceitos: [apiConceito('Reprodução de bug', 'Passos que fazem o problema aparecer de forma verificável.', 'Use para investigar erro real.', 'Ãs vezes não funciona.', 'Em 375px, tocar duas vezes cria duas tentativas de cobrança.', 'Bug reproduction', ['sintoma', 'ambiente']), apiConceito('Regressão', 'Problema novo causado por uma alteração.', 'Use em correções e refatorações.', 'Arruma e vê se continua.', 'Verifique checkout desktop, campos, duplo clique e erro após o ajuste.', 'Regression', ['teste', 'aceite'])] }, 1584 { stage: 'Aula 05', layout: 'timeline', title: 'Como revisar o que a IA gerou', goal: 'Revise intenção, conteúdo, comportamento, acessibilidade, segurança e manutenção.', focus: 'A saÃda da IA é uma proposta, não autoridade sobre produto ou código.', practice: 'Revise um protótipo gerado por IA usando checklist de produto e comportamento.', exerciseFeedback: 'A revisão encontra ao menos um risco ou pergunta não respondida.', lessons: ['Compare com o objetivo.', 'Teste caminhos felizes e problemas.', 'Pergunte o que foi inventado ou omitido.'], codigos: [{ codigo: '/revisar' }, { codigo: '/perguntar' }], sequenceCount: 3, connectors: ['entenda', 'teste', 'decida'], conceitos: [apiConceito('Revisão crÃtica', 'Avaliação da saÃda da IA contra objetivo, regras e riscos.', 'Use antes de aprovar ou publicar.', 'A IA fez, está certo.', 'Compare com critérios do briefing e registre correções.', 'Critical review', ['aceite', 'risco']), apiConceito('Lacuna de especificação', 'Decisão importante que não foi descrita.', 'Use para encontrar comportamento inventado pela IA.', 'Depois a gente decide.', 'Defina o comportamento sem conexão antes de aprovar o fluxo.', 'Specification gap', ['regra', 'exceção'])] }, 1585 { stage: 'Aula 06', layout: 'groups', title: 'Como organizar arquivos, versões e entregas', goal: 'Organize prompts, arquivos, versões, decisões e revisões para o projeto continuar.', focus: 'Nomes, versão atual, decisões e próximos passos precisam ficar visÃveis.', practice: 'Descreva uma estrutura de entrega para protótipo com dados fictÃcios e pendências.', exerciseFeedback: 'Outra pessoa localiza a versão atual e entende o que mudou.', lessons: ['Nomes claros reduzem procura.', 'Versão atual precisa ser identificável.', 'Entrega separa pronto, pendente e descartado.'], codigos: [{ codigo: '/estrutura' }, { codigo: '/versao' }], groups: [{ title: 'Encontrar', desc: 'Pastas e nomes para localizar a entrega.' }, { title: 'Entender', desc: 'Decisões, versão atual e pendências.' }], conceitos: [apiConceito('Entrega reproduzÃvel', 'Pacote que outra pessoa consegue abrir e continuar.', 'Use em protótipos compartilhados.', 'Mande os arquivos.', 'Entregue README, instruções, dados fictÃcios e limitações.', 'Reproducible handoff', ['documentação', 'handoff']), apiConceito('Registro de decisão', 'Nota que explica escolha, motivo e impacto.', 'Use para decisões que serão revisadas.', 'Escolhe o melhor jeito.', 'Registre alternativas descartadas e risco restante.', 'Decision record', ['histórico', 'trade-off'])] }, 1586 { stage: 'Aula 07', layout: 'grid', title: 'Limites, riscos e segurança ao usar IA para programar', goal: 'Use IA com responsabilidade, protegendo dados, credenciais, código e usuários.', focus: 'Nunca entregue segredo ou dado pessoal sem entender o risco.', practice: 'Crie regras para usar IA em projeto com dados de clientes e serviços externos.', exerciseFeedback: 'Separe dados compartilháveis, dados a remover e decisões que exigem revisão humana.', lessons: ['Não cole segredos em prompts.', 'SaÃdas podem ter falhas.', 'Decisões sensÃveis exigem revisão.'], codigos: [{ codigo: '/sem-segredo' }, { codigo: '/humano' }], conceitos: [apiConceito('Dado sensÃvel no prompt', 'Informação que pode causar exposição ou dano quando envi
1586ada a ferramenta externa.', 'Use para decidir o que anonimizar ou remover.', 'Cola o banco inteiro.', 'Envie exemplo fictÃcio e remova tokens, senhas e dados pessoais.', 'Sensitive data handling', ['privacidade', 'segredo']), apiConceito('Revisão humana', 'Conferência antes de aceitar saÃda de IA em contexto de risco.', 'Use em autenticação, pagamentos e permissões.', 'Se compilou pode subir.', 'Revise permissões, dependências e erros antes de publicar.', 'Human review', ['aprovação', 'segurança'])] }, 1587 { stage: 'Aula 08', layout: 'grid', title: 'Projeto final: criar um protótipo funcional guiado por IA', goal: 'Junte problema, escopo, prompts, revisão, organização e segurança em um protótipo pequeno.', focus: 'O projeto deve ser pequeno o bastante para terminar e claro o bastante para revisar.', practice: 'Escolha uma ideia, escreva briefing, gere, revise e registre a entrega.', exerciseFeedback: 'O projeto apresenta problema, fluxo, limites, estados, revisão, estrutura e riscos.', lessons: ['Um protótipo mostra uma decisão.', 'Documentação faz parte da entrega.', 'Limitações explÃcitas aumentam confiança.'], codigos: [{ codigo: '/prototipo' }, { codigo: '/entrega' }], conceitos: [apiConceito('Protótipo funcional', 'Versão pequena que permite interagir e aprender.', 'Use antes de investir na construção final.', 'Faz um sistema real.', 'Crie fluxo navegável com dados fictÃcios e limites visÃveis.', 'Functional prototype', ['MVP', 'fluxo']), apiConceito('Handoff', 'Transferência organizada para quem revisa ou desenvolve.', 'Use ao compartilhar resultado.', 'Está pronto, olha aÃ.', 'Entregue instruções, critérios, limitações e pendências.', 'Handoff', ['entrega', 'documentação'])] }, 1588 { stage: 'Aula 09', layout: 'grid', title: 'Códigos Secretos: a régua do protótipo com IA', bonus: true, goal: 'Recapitule as oito aulas e use os códigos para transformar ideia solta em protótipo revisável e seguro.', focus: 'Passe pela régua: problema, escopo, contexto, estados, revisão, entrega, segurança e protótipo.', practice: 'Use pelo menos quatro códigos em um pedido e explique por que cada um entrou.', exerciseFeedback: 'Conecte cada código a uma decisão concreta e reconheça um limite ou risco.', lessons: ['A régua reúne o método.', 'Códigos são atalhos de intenção.', 'A saÃda ainda precisa de revisão humana.'], conceitos: [] } 1589]; 1590 1591const uiDescomplicadaJourney = [ 1592 { 1593 stage: 'Aula 01', layout: 'grid', title: 'A anatomia de uma interface', 1594 goal: 'Aprenda a enxergar uma tela como uma composição de blocos, e não como um desenho inteiro impossÃvel de explicar.', 1595 focus: 'Comece pelo propósito da tela e nomeie estrutura, conteúdo, ação e estado antes de discutir cores ou estilo.', 1596 practice: 'Escolha uma tela real e descreva seu propósito, três blocos principais e a ação mais importante.', 1597 exerciseFeedback: 'Uma boa resposta explica o que a tela ajuda a fazer e nomeia blocos observáveis, sem cair em âuma tela bonitaâ.', 1598 lessons: ['Uma interface organiza informação para apoiar uma ação.', 'Componente é uma peça reutilizável com função e c
1598omportamento.', 'Nomear blocos reduz ruÃdo entre produto, design, desenvolvimento e IA.'], 1599 conceitos: [ 1600 apiConceito('Interface', 'A superfÃcie pela qual uma pessoa percebe informações, toma decisões e interage com um sistema.', 'Use quando precisar explicar a experiência de uma tela ou fluxo completo.', 'Faz uma tela moderna.', 'Crie uma interface de cadastro que ajude uma pessoa leiga a preencher dados, corrigir erros e confirmar o envio.', 'User interface (UI)', ['tela', 'interação', 'experiência']), 1601 apiConceito('Componente', 'Peça de interface com estrutura, função e comportamento próprios, como botão, card, campo ou modal.', 'Use para pedir partes especÃficas que podem se repetir ou ser revisadas isoladamente.', 'Coloca um negócio pra clicar.', 'Use um botão primário âSalvarâ com estados normal, carregando, sucesso e erro.', 'UI component', ['elemento', 'bloco', 'padrão']), 1602 apiConceito('Hierarquia de conteúdo', 'Ordem de importância que ajuda a pessoa a saber o que ler, decidir ou fazer primeiro.', 'Use antes de escolher tamanho, posição, contraste ou destaque visual.', 'Deixa o tÃtulo maior.', 'Destaque o problema no tÃtulo, explique o contexto em uma frase e deixe âComeçar revisãoâ como ação principal.', 'Content hierarchy', ['prioridade', 'ênfase', 'escaneabilidade']) 1603 ], 1604 exerciseFields: [ 1605 { key: 'proposito', label: 'Qual é o propósito da tela?', help: 'Descreva a ação principal que a pessoa precisa realizar.', placeholder: 'Ex.: acompanhar e concluir uma tarefa.' }, 1606 { key: 'blocos', label: 'Quais blocos aparecem?', help: 'Nomeie pelo menos três componentes visÃveis.', placeholder: 'Ex.: header, card de resumo, lista e botão.' }, 1607 { key: 'acao', label: 'Qual é a ação principal?', help: 'Escreva o texto ou resultado esperado do CTA.', placeholder: 'Ex.: começar a tarefa e ver a confirmação.' } 1608 ], 1609 exerciseModelAnswer: 'Propósito: ajudar a pessoa a acompanhar e concluir uma tarefa. Blocos: header com contexto, card de resumo, lista de tarefas e botão primário. Ação principal: selecionar uma tarefa e marcar como concluÃda, recebendo confirmação.' 1610 }, 1611 { 1612 stage: 'Aula 02', layout: 'grid', title: 'Hierarquia visual e decisão', 1613 goal: 'Organize tÃtulos, textos, ações e destaques para que a pessoa entenda a tela sem precisar decifrá-la.', 1614 focus: 'A hierarquia deve refletir a decisão mais importante, não apenas aumentar o que parece bonito.', 1615 practice: 'Reescreva uma tela com tÃtulo, explicação, ação principal e ação secundária, justificando a ordem.', 1616 exerciseFeedback: 'A resposta fica consistente quando a hierarquia acompanha a intenção: contexto, decisão principal e alternativa segura.', 1617 lessons: ['Peso visual vem de tamanho, contraste, posição, espaço e repetição.', 'CTA primário indica a ação mais importante daquele momento.', 'Texto curto e especÃfico reduz esforço de interpretação.'], 1618 conceitos: [ 1619 apiConceito('Peso visual', 'Força com que um elemento chama atenção em comparação com os demais.', 'Use para decidir o que deve ser percebido primeiro numa tela.', 'Deixa tudo chamativo.', 'O tÃtulo tem maior peso; o botão principal usa contraste; ações secundárias ficam discretas.', 'Visual weight', ['contraste', 'tamanho', 'posição']), 1620 apiConceito('CTA', 'Chamada para ação que indica o próximo passo esperado da pessoa.', 'Use quando uma tela precisa conduzir uma decisão ou avanço.', 'Coloca um botão aqui.', 'O botão âRevisar pedidoâ é o CTA principal; âVoltarâ permanece secundário.', 'Call to action', ['botão', 'conversão', 'próximo passo']), 1621 apiConceito('Escaneabilidade', 'Facilidade de entender uma tela ao percorrê-la rapidamente com os olhos.', 'Use em dashboards, listas, páginas de produto e qualquer tela com muita informação.', 'Deixa fácil de ler.', 'Agrupe informações relacionadas, use tÃtulos descritivos e destaque apenas os dados que orientam decisão.', 'Scannability', ['leitura rápida', 'agrupamento', 'densidade']) 1622 ], 1623 exerciseFields: [ 1624 { key: 'decisao', label: 'Qual decisão a tela apoia?', help: 'Diga o que a pessoa precisa decidir ou fazer.', placeholder: 'Ex.: confirmar o horário escolhido.' }, 1625 { key: 'ordem', label: 'Qual será a ordem de leitura?', help: 'Liste tÃtulo, contexto, ação e alternativa.', placeholder: 'Ex.: tÃtulo â resumo â confirmar â voltar.' }, 1626 { key: 'justificativa', label: 'Por que essa hierarquia?', help: 'Explique como o destaque reduz dúv
1626ida ou esforço.', placeholder: 'Ex.: o CTA aparece depois que a pessoa confere o resumo.' } 1627 ] 1628 }, 1629 { 1630 stage: 'Aula 03', layout: 'groups', title: 'Layout, espaço e responsividade', 1631 goal: 'Desenhe uma estrutura que se adapta a diferentes telas sem perder ordem, leitura ou ação principal.', 1632 focus: 'Pense em relações e prioridades: o que fica lado a lado, o que empilha e o que pode desaparecer em telas menores.', 1633 practice: 'Descreva como uma tela desktop se transforma no celular, incluindo colunas, espaçamentos e ordem dos blocos.', 1634 exerciseFeedback: 'Uma boa resposta explica o comportamento em pelo menos dois tamanhos, não apenas diz âserá responsivoâ.', 1635 lessons: ['Layout define relações entre blocos, não só posições fixas.', 'Espaço em branco separa grupos e cria ritmo de leitura.', 'Responsividade adapta conteúdo, interação e prioridade ao contexto.'], 1636 groups: [{ title: 'Estrutura', desc: 'Colunas, alinhamento, largura e espaçamento entre grupos.' }, { title: 'Adaptação', desc: 'O que empilha, reduz, oculta ou muda de posição no mobile.' }], 1637 conceitos: [ 1638 apiConceito('Grid', 'Sistema de colunas e linhas que organiza blocos de forma consistente.', 'Use para explicar alinhamento e proporções sem depender de coordenadas soltas.', 'Coloca três coisas lado a lado.', 'Use uma grade de três cards no desktop e uma coluna única no celular, mantendo a ordem de prioridade.', 'Grid layout', ['coluna', 'linha', 'alinhamento']), 1639 apiConceito('Espaçamento', 'Distância intencional entre elementos e grupos de uma interface.', 'Use para separar nÃveis de conteúdo e evitar que a tela pareça apertada ou fragmentada.', 'Dá um espaço aÃ.', 'Use 24px entre seções, 16px dentro de cards e 8px entre label e campo.', 'Spacing', ['margem', 'padding', 'ritmo']), 1640 apiConceito('Responsividade', 'Capacidade de uma interface se adaptar a diferentes larguras, dispositivos e formas de interação.', 'Use ao definir o comportamento em desktop, tablet e celular.', 'Faz funcionar no celular também.', 'No celular, a grade empilha, o menu vira botão e o CTA permanece visÃvel sem exigir zoom.', 'Responsive design', ['mobile first', 'breakpoint', 'adaptação']) 1641 ], 1642 exerciseFields: [ 1643 { key: 'desktop', label: 'Como fica no desktop?', help: 'Descreva colunas, largura e ordem.', placeholder: 'Ex.: formulário à esquerda e resumo à direita.' }, 1644 { key: 'mobile', label: 'Como fica no celular?', help: 'Explique o que empilha, reduz ou muda.', placeholder: 'Ex.: resumo vem depois do formulário em uma coluna.' }, 1645 { key: 'prioridade', label: 'O que nunca pode sumir?', help: 'Indique conteúdo ou ação essencial.', placeholder: 'Ex.: tÃtulo, campo principal e botão continuar.' } 1646 ] 1647 }, 1648 { 1649 stage: 'Aula 04', layout: 'grid', title: 'Formulários que orientam', 1650 goal: 'Crie campos que explicam o que precisam, evitam erros e ajudam a pessoa a concluir uma tarefa com confiança.', 1651 focus: 'Um formulário bom reduz perguntas: o label, o formato esperado, o erro e o próximo passo estão claros.', 1652 practice: 'Modele um formulário de cadastro com campos, ajuda, validações, erro e confirmação de sucesso.', 1653 exerciseFeedback: 'O formulário está bem descrito quando cada campo tem propósito, formato e retorno compreensÃvel.', 1654 lessons: ['Label identifica o dado pedido; placeholder não deve substituir o label.', 'Validação deve orientar a correção no lugar certo.', 'Sucesso e erro precisam confirmar o que aconteceu e o que fazer depois.'], 1655 conceitos: [ 1656 apiConceito('Label', 'Texto associado a um campo que informa qual dado deve ser preenchido.', 'Use em todo campo de formulário, inclusive quando existe placeholder ou Ãcone.', 'Coloca um campo de nome.', 'O label âNome completoâ fica visÃvel acima do campo e permanece legÃvel quando o campo recebe foco.', 'Form label', ['campo', 'formulário', 'acessibilidade']), 1657 apiConceito('Validação inline', 'Retorno apresentado próximo ao campo para explicar se o valor está correto ou como corrigir.', 'Use para evitar que a pessoa descubra todos os erros apenas depois de enviar.', 'Mostra os erros no formulário.', 'Se o e-mail estiver inválido, mostre a mensagem abaixo do campo e preserve o valor digitado.', 'Inline validation', ['erro', 'mensagem de ajuda', 'formato']), 1658 apiConceito('Affordance', 'Pista visual ou textual que indica como um elemento pode ser usado.', 'Use em botões, campos, links e controles que precisam ser reconhecidos sem tentativa e erro.', 'Deixa claro o que clicar.', 'O botão tem texto de ação, contraste e estado de foco; o campo tem label e formato esperado.', 'Affordance', ['pista de uso', 'descoberta', 'interação']) 1659 ], 1660 exerciseFields: [ 1661 { key: 'campos', label: 'Quais campos existem?', help: 'Liste somente os dados necessários.', placeholder: 'Ex.: nome, e-mail e telefone.' }, 1662 { key: 'validacao', label: 'O que pode dar errado?', help: 'Descreva formato ou regra de cada campo.', placeholder: 'Ex.: e-mail obrigatório e com formato válido.' }, 1663 { key: 'retorno', label: 'Qual retorno aparece?', help: 'Explique erro, carregamento e sucesso.', placeholder: 'Ex.: mensagem no campo e confirmação após envio.' } 1664 ] 1665 }, 1666 { 1667 stage: 'Aula 05', layout: 'timeline', title: 'Estados que comunicam', 1668 goal: 'Faça a interface explicar o que está acontecendo antes, durante e depois de cada ação â inclusive quando algo falha.', 1669 focus: 'Estado não é detalhe visual: ele informa se a pessoa pode agir, esperar, corrigir ou tentar novamente.', 1670 practice: 'Descreva os estados vazio, carregando, sucesso e erro de uma lista de pedidos.', 1671 exerciseFeedback: 'A resposta está completa quando cada estado explica situação, mensagem e ação possÃvel.', 1672 lessons: ['Estado vazio orienta o primeiro passo.', 'Carregamento protege contra dúvida e cliques repetidos.', 'Erro deve oferecer recuperação quando ela for possÃvel.'], 1673 sequenceCount: 4, connectors: ['prepara', 'aguarda', 'confirma'], 1674 conceitos: [ 1675 apiConceito('Estado vazio', 'Situação em que ainda não existe conteúdo para mostrar, mas existe um próximo passo possÃvel.', 'Use em primeira utilização, filtros sem resultado e listas após exclusão.', 'Não tem nada aqui.', 'Você ainda não criou pedidos. Comece pelo botão âNovo pedidoâ ou ajuste o filtro.', 'Empty state', ['primeiro uso', 'lista vazia', 'orientação']), 1676 apiConceito('Estado de carregamento', 'Indicação de que o sistema está processando ou buscando algo.', 'Use quando a resposta não é imediata e a pessoa precisa entender que a ação foi recebida.', 'Coloca um spinner.', 'Enquanto os pedidos carregam, preserve a estrutura da lista e desabilite apenas ações afetadas.', 'Loading state', ['progresso', 'espera', 'feedback']), 1677 apiConceito('Estado de erro', 'Representação de uma falha que explica o impacto e indica como recuperar.', 'Use quando uma operação não pode continuar ou precisa ser repetida.', 'Deu erro.', 'Mostre âNão foi possÃvel carregar os pedidosâ com botão âTentar novamenteâ e canal de suporte.', 'Error state', ['recuperação', 'mensagem', 'fallback']), 1678 apiConceito('Estado de sucesso', 'Confirmação de que a ação terminou e comunica o resultado alcançado.', 'Use depois de salvar, enviar, concluir ou alterar algo importante.', 'Mostra que deu certo.', 'Após salvar, mostre âPedido criadoâ e ofereça âVer pedidoâ como próximo passo.', 'Success state', ['confirmação', 'resultado', 'feedback']) 1679 ], 1680 exerciseFields: [ 1681 { key: 'vazio', label: 'O que aparece no vazio?', help: 'Dê mensagem e próximo passo.', placeholder: 'Ex.: ainda não há pedidos; botão Criar pedido.' }, 1682 { key: 'erro', label: 'Como a pessoa se recupera?', help: 'Explique mensagem e ação disponÃvel.', placeholder: 'Ex.: erro de rede e botão Tentar novamente.' }, 1683 { key: 'sucesso', label: 'Como o sucesso é confirmado?', help: 'Mostre resultado e próximo passo.', placeholder: 'Ex.: pedido criado; botão Ver pedido.' } 1684 ] 1685 }, 1686 { 1687 stage: 'Aula 06', layout: 'groups', title: 'Navegação e padrões de interação', 1688 goal: 'Escolha o padrão certo para orientar, alternar, revelar ou confirmar conteúdo sem criar caminhos confusos.', 1689 focus: 'O padrão deve combinar com a quantidade de opções, a importância do contexto e a frequência da ação.', 1690 practice: 'Escolha entre navegação, abas, acordeão, modal e menu para cinco necessidades de uma área do aluno.',
1691 exerciseFeedback: 'A escolha fica forte quando você explica por que o padrão ajuda naquele contexto e qual alternativa evitaria.', 1692 lessons: ['Navegação muda de área; abas trocam conteúdo relacionado.', 'Acordeão revela detalhes sem tirar a pessoa do contexto.', 'Modal interrompe o fluxo e deve ser reservado para decisões ou tarefas focadas.'], 1693 groups: [{ title: 'Orientar', desc: 'Navegação, breadcrumbs e abas mostram onde a pessoa está.' }, { title: 'Revelar', desc: 'Menus, acordeões e modais controlam conteúdo progressivo.' }], 1694 conceitos: [ 1695 apiConceito('Abas', 'Padrão que alterna entre conteúdos relacionados mantendo o mesmo contexto de tela.', 'Use quando as opções pertencem à mesma área e a pessoa pode trocar entre elas.', 'Coloca umas abas.', 'Use abas âVisão geralâ, âAulasâ e âCertificadoâ para conteúdos do mesmo curso.', 'Tabs', ['navegação local', 'conteúdo relacionado', 'aba ativa']), 1696 apiConceito('Acordeão', 'Controle que expande e recolhe blocos de conteúdo sob demanda.', 'Use para perguntas frequentes, detalhes técnicos ou informações secundárias.', 'Esconde os detalhes.', 'Cada item de polÃtica abre seu conteúdo sem fechar automaticamente os demais.', 'Accordion', ['conteúdo progressivo', 'expandir', 'recolher']), 1697 apiConceito('Modal', 'Janela sobreposta que concentra uma tarefa ou decisão sem mudar de página.', 'Use para confirmação, edição curta ou detalhe que precisa de foco temporário.', 'Abre uma janelinha.', 'Antes de excluir o pedido, abra confirmação com consequência, cancelar e excluir definitivamente.', 'Modal dialog', ['overlay', 'confirmação', 'foco']) 1698 ], 1699 exerciseFields: [ 1700 { key: 'padroes', label: 'Quais padrões você escolheu?', help: 'Associe cada necessidade a um padrão.', placeholder: 'Ex.: abas para áreas relacionadas; modal para confirmação.' }, 1701 { key: 'motivo', label: 'Por que cada padrão?', help: 'Explique contexto, frequência e impacto.', placeholder: 'Ex.: modal concentra decisão sem perder a página.' }, 1702 { key: 'risco', label: 'Qual risco de uso?', help: 'Cite um padrão que poderia confundir.', placeholder: 'Ex.: muitas abas podem esconder conteúdo importante.' } 1703 ] 1704 }, 1705 { 1706 stage: 'Aula 07', layout: 'grid', title: 'Acessibilidade e mobile como critério', 1707 goal: 'Projete para mais pessoas desde o inÃcio, tratando contraste, foco, toque, leitura e diferentes formas de navegação como requisitos.', 1708 focus: 'Acessibilidade não é acabamento: muda conteúdo, estrutura, interação e critério de qualidade.', 1709 practice: 'Revise uma tela para teclado e celular, registrando pelo menos três ajustes verificáveis.', 1710 exerciseFeedback: 'Uma boa revisão descreve teste e resultado, não apenas adjetivos como âmais acessÃvelâ.', 1711 lessons: ['Contraste e tamanho influenciam leitura.', 'Foco visÃvel permite navegar sem mouse.', 'Alvos de toque precisam de espaço e não podem depender só de cor.'], 1712 conceitos: [ 1713 apiConceito('Contraste', 'Diferença perceptÃvel entre texto, fundo e elementos que ajuda a leitura e a identificação de controles.', 'Use para revisar textos, botões, bordas, estados e conteúdo em diferentes condições de luz.', 'Usa uma cor que combine.', 'O texto principal mantém contraste suficiente com o fundo e o botão continua distinguÃvel sem depender apenas da cor.', 'Color contrast', ['legibilidade', 'cor', 'WCAG']), 1714 apiConceito('Foco visÃvel', 'Indicação clara de qual elemento receberá a próxima ação do teclado ou tecnologia assistiva.', 'Use em links, botões, campos, menus e modais navegáveis por teclado.', 'Dá pra usar no teclado.', 'Ao pressionar Tab, o foco percorre a ordem lógica e aparece com contorno visÃvel em cada controle.', 'Visible focus', ['teclado', 'ordem de foco', 'navegação']), 1715 apiConceito('Alvo de toque', 'Ãrea interativa com tamanho e espaçamento suficientes para ser acionada com precisão em tela sensÃvel ao toque.', 'Use em botões, links, Ãcones e controles de celular.', 'Deixa os botões maiores.', 'Separe ações de excluir e editar e garanta área de toque confortável sem exigir precisão de um pixel.', 'Touch target', ['mobile', 'gesto', 'precisão']) 1716 ], 1717 exerciseFields: [ 1718 { key: 'teste', label: 'Como você vai testar?', help: 'Escolha teclado, celular, zoom ou contraste.', placeholder: 'Ex.: navegar só com Tab em tela de 375px.' }, 1719 { key: 'achado', label: 'Qual problema encontrou?', help: 'Descreva algo observável.', placeholder: 'Ex.: foco some no botão e Ãcones ficam muito próximos.' }, 1720 { key: 'ajuste', label: 'Qual ajuste fará?', help: 'Escreva a mudança e o resultado esperado.', placeholder: 'Ex.: criar contorno de foco e separar os alvos.' } 1721 ] 1722 }, 1723 { 1724 stage: 'Aula 08', layout: 'grid', title: 'Projeto final: especificar uma tela completa', 1725 goal: 'Conecte propósito, conteúdo, layout, estados, responsividade e acessibilidade em uma especificação que outra pessoa consiga construir.', 1726 focus: 'Uma boa especificação não descreve apenas aparência: ela torna decisões, comportamentos e critérios observáveis.', 1727 practice: 'Escolha uma tela real e entregue propósito, estrutura, componentes, estados, comportamento mobile e critérios de aceite.', 1728 exerciseFeedback: 'O projeto está pronto quando outra pessoa consegue construir e revisar a tela sem depender de adivinhações.', 1729 lessons: ['Especificar é tornar decisões compartilháveis.', 'Critério de aceite transforma opinião em verificação.', 'Handoff bom registra contexto, limites e pendências.'], 1730 conceitos: [ 1731 apiConceito('Critério de aceite de UI', 'Condição observável que define quando uma tela ou interação está pronta.', 'Use para alinhar produto, design, desenvolvimento e revisão.', 'A tela precisa ficar boa.', 'Em 375px, a pessoa encontra o CTA, envia o formulário e entende o erro sem rolagem horizontal.', 'UI acceptance criteria', ['teste', 'pronto', 'qualidade']), 1732 apiConceito('Handoff', 'Entrega organizada que permite a outra pessoa entender, construir ou continuar um trabalho.', 'Use ao passar uma tela do planejamento para design, desenvolvimento ou cliente.', 'Está pronto, dá uma olhada.', 'Entregue objetivo, fluxo, estados, medidas, textos, referências, critérios e pendências.', 'Design handoff', ['entrega', 'documentação', 'continuidade']), 1733 apiConceito('Especificação de interface', 'Documento ou briefing que descreve a intenção, estrutura e comportamento de uma tela.', 'Use antes de construir ou pedir uma tela para IA, dev ou designer.', 'Cria uma tela de pedidos.', 'Especifique usuário, objetivo, componentes, estados, dados, responsividade e critérios de aceite.', 'UI specification', ['briefing', 'fluxo', 'comportamento']) 1734 ], 1735 exerciseFields: [ 1736 { key: 'tela', label: 'Qual tela você está especificando?', help: 'Dê um nome e contexto de uso.', placeholder: 'Ex.: tela de confirmação de consulta no celular.' }, 1737 { key: 'estrutura', label: 'Como ela funciona?', help: 'Liste conteúdo, componentes e estados.', placeholder: 'Ex.: tÃtulo, resumo, CTA, erro, sucesso e carregamento.' }, 1738 { key: 'aceite', label: 'Como saberemos que está pronta?', help: 'Escreva critérios observáveis.', placeholder: 'Ex.: usuário confirma sem rolagem horizontal e entende o resultado.' } 1739 ] 1740 }, 1741 { 1742 stage: 'Aula 09', layout: 'grid', title: 'Códigos Secretos da UI', bonus: true, 1743 goal: 'Recapitule as oito aulas e transforme pedidos vagos de interface em instruções claras para IA, design e desenvolvimento.', 1744 focus: 'Passe pela régua: anatomia, hierarquia, layout, formulário, estados, padrões, acessibilidade e aceite.', 1745 practice: 'Use pelo menos quatro códigos em um pedido único e explique a decisão que c
1745ada um torna explÃcita.', 1746 exerciseFeedback: 'Conecte cada código a uma decisão observável e revise se o pedido ainda deixa alguma lacuna importante.', 1747 lessons: ['Códigos são atalhos de intenção, não substitutos de contexto.', 'A tela precisa ser entendida em diferentes estados e tamanhos.', 'Qualidade aparece quando o resultado pode ser testado.'], 1748 conceitos: [] 1749 } 1750]; 1751 1752uiDescomplicadaJourney[0].visualMarkup = ` 1753 <section class="ui-visual-lab" aria-label="Laboratório visual: anatomia de uma tela"> 1754 <div class="ui-visual-lab-header"><div><p class="ui-visual-kicker">Laboratório visual</p><h4>Veja a anatomia antes de descrevê-la</h4><p>Uma tela não é um bloco único: ela combina contexto, conteúdo e ação.</p></div><span class="ui-visual-stamp">01 · observar</span></div> 1755 <div class="ui-visual-lab-grid"> 1756 <div class="ui-visual-screen"> 1757 <div class="ui-screen-top"><strong>minhas tarefas</strong><span>terça, 10 set.</span><button type="button" aria-label="Abrir menu">â¢â¢â¢</button></div> 1758 <div class="ui-screen-hero"><span class="ui-screen-label">CONTEXTO</span><h5>Escolha o que fazer hoje</h5><p>Uma pequena decisão agora deixa o resto do dia mais claro.</p><button type="button">Começar revisão <span>â</span></button></div> 1759 <div class="ui-screen-list"><div class="ui-screen-list-head"><span>PRÃXIMAS TAREFAS</span><b>3 abertas</b></div><div class="ui-screen-task"><i></i><span>Revisar briefing do projeto</span><em>agora</em></div><div class="ui-screen-task"><i></i><span>Enviar retorno para o time</span><em>16:00</em></div></div> 1760 </div> 1761 <div class="ui-visual-legend"><div><span class="ui-visual-index ui-visual-index-blue">01</span><div><strong>Header</strong><p>Contexto: onde estou e o que encontro aqui.</p></div></div><div><span class="ui-visual-index ui-visual-index-pink">02</span><div><strong>Hero</strong><p>Objetivo: explica a decisão que importa agora.</p></div></div><div><span class="ui-visual-index ui-visual-index-lime">03</span><div><strong>Lista / cards</strong><p>Conteúdo: organiza as opções que a pessoa pode revisar.</p></div></div><div><span class="ui-visual-index ui-visual-index-black">04</span><div><strong>CTA</strong><p>Ação: transforma entendimento em próximo passo.</p></div></div></div> 1762 </div> 1763 <p class="ui-visual-caption">Pergunta de designer: se você remover o texto, ainda consegue explicar o papel de cada bloco?</p> 1764 </section> 1765`; 1766 1767uiDescomplicadaJourney[1].visualMarkup = ` 1768 <section class="ui-visual-lab ui-visual-lab-contrast" aria-label="Laboratório visual: hierarquia de decisão"> 1769 <div class="ui-visual-lab-header"><div><p class="ui-visual-kicker">Laboratório visual · compare</p><h4>Uma tela, três nÃveis de atenção</h4><p>O visual precisa responder: o que eu leio, o que eu decido e onde eu clico?</p></div><span class="ui-visual-stamp">02 · priorizar</span></div> 1770 <div class="ui-visual-lab-grid"> 1771 <div class="ui-visual-screen"> 1772 <div class="ui-screen-top"><strong>soluções para sua equipe</strong><span>passo 01 de 03</span><button type="button" aria-label="Abrir menu">â¢â¢â¢</button></div> 1773 <div class="ui-screen-choice-intro"><span class="ui-screen-label">CONTEXTO</span><h5>O que você precisa organizar?</h5><p>Escolha um caminho para começar. Você poderá revisar antes de enviar.</p></div> 1774 <div class="ui-screen-choice-list"><article class="ui-screen-choice ui-screen-choice-featured"><div><span class="ui-choice-tag">RECOMENDADO</span><strong>Organizar pedidos</strong><p>Centralize solicitações e acompanhe cada etapa.</p></div><button type="button">Começar <span>â</span></button></article><article class="ui-screen-choice"><div><strong>Consultar histórico</strong><p>Veja o que já foi solicitado pela equipe.</p></div><button type="button">Ver detalhes</button></article></div> 1775 </div> 1776 <div class="ui-visual-legend"><div><span class="ui-visual-index ui-visual-index-blue">01</span><div><strong>Contexto</strong><p>O tÃtulo explica a situação antes de pedir uma decisão.</p></div></div><div><span class="ui-visual-index ui-visual-index-pink">02</span><div><strong>Ãnfase</strong><p>O caminho recomendado recebe destaque sem apagar a alternativa.</p></div></div><div><span class="ui-visual-index ui-visual-index-lime">03</span><div><strong>Ação principal</strong><p>O CTA usa verbo e deixa o próximo passo previsÃvel.</p></div></div></div> 1777 </div> 1778 <p class="ui-visual-caption">Teste rápido: cubra os botões com a mão. Ainda fica claro qual opção é recomendada?</p> 1779 </section> 1780`; 1781 1782uiDescomplicadaJourney[2].visualMarkup = ` 1783 <section class="ui-visual-lab ui-visual-lab-responsive" aria-label="Laboratório visual: layout responsivo"> 1784 <div class="ui-visual-lab-header"><div><p class="ui-visual-kicker">Laboratório visual · adapte</p><h4>A mesma tarefa, dois contextos</h4><p>Responsividade não é apenas diminuir: é reorganizar prioridades para cada tela.</p></div><span class="ui-visual-stamp">03 · adaptar</span></div> 1785 <div class="ui-responsive-stage"><div class="ui-device ui-device-desktop"><div class="ui-device-bar"><span></span><strong>desktop · 1280px</strong><i></i></div><div class="ui-device-body"><aside><b>Como Pedir</b><span>Visão geral</span><span class="is-active">Meus pedidos</span><span>Configurações</span></aside><main>
1785<div class="ui-device-heading"><div><small>MEUS PEDIDOS</small><h5>Acompanhe suas solicitações</h5></div><button>+ Novo pedido</button></div><div class="ui-device-cards"><article><small>ABERTOS</small><strong>08</strong><span>precisam de atenção</span></article><article><small>EM REVISÃO</small><strong>03</strong><span>aguardando retorno</span></article><article><small>CONCLUÃDOS</small><strong>21</strong><span>neste mês</span></article></div></main></div></div><div class="ui-device ui-device-mobile"><div class="ui-device-bar"><span></span><strong>mobile · 375px</strong><i></i></div><div class="ui-device-mobile-body"><div class="ui-mobile-header"><b>Meus pedidos</b><button aria-label="Abrir menu">â°</button></div><small>RESUMO DO DIA</small><h5>Acompanhe suas solicitações</h5><button class="ui-mobile-cta">+ Novo pedido</button><div class="ui-mobile-card"><span>ABERTOS</span><strong>08</strong><em>precisam de atenção</em></div><div class="ui-mobile-card"><span>EM REVISÃO</span><strong>03</strong><em>aguardando retorno</em></div></div></div></div> 1786 <div class="ui-responsive-note"><span class="ui-visual-index ui-visual-index-lime">â</span><p><strong>O que mudou?</strong> A sidebar virou menu, os três cards viraram uma sequência vertical e o CTA continuou visÃvel no contexto certo.</p></div> 1787 </section> 1788`; 1789uiDescomplicadaJourney[2].conceitos[0].grupo = 0; 1790uiDescomplicadaJourney[2].conceitos[1].grupo = 0; 1791uiDescomplicadaJourney[2].conceitos[2].grupo = 1; 1792 1793uiDescomplicadaJourney[3].visualMarkup = ` 1794 <section class="ui-visual-lab ui-visual-lab-form" aria-label="Laboratório visual: formulário que orienta"> 1795 <div class="ui-visual-lab-header"><div><p class="ui-visual-kicker">Laboratório visual · acompanhe o estado</p><h4>O campo também conversa</h4><p>Label, ajuda, erro e sucesso formam uma sequência de orientação.</p></div><span class="ui-visual-stamp">04 · orientar</span></div> 1796 <div class="ui-form-stage"><div class="ui-form-panel"><div class="ui-form-panel-head"><small>FORMULÃRIO DE ORÃAMENTO</small><strong>Conte um pouco sobre o projeto</strong><span>Etapa 1 de 2</span></div><label class="ui-demo-field"><span>Nome completo <b>*</b></span><input value="Marina Costa" readonly><em>Como você gostaria de ser chamada?</em></label><label class="ui-demo-field ui-demo-field-error"><span>E-mail profissional <b>*</b></span><input value="marina@" readonly aria-invalid="true"><em>Digite um e-mail válido, como [email protected].</em></label><button class="ui-demo-submit" type="button">Continuar <span>â</span></button></div><div class="ui-form-panel ui-form-success"><div class="ui-success-icon">â</div><small>ESTADO DE SUCESSO</small><h5>Pedido recebido</h5><p>Agora o time pode revisar os dados e retornar com os próximos passos.</p><button type="button">Ver resumo</button></div></div> 1797 <div class="ui-form-legend"><span><i class="ui-form-dot ui-form-dot-label"></i><strong>Label</strong> diz o que informar.</span><span><i class="ui-form-dot ui-form-dot-help"></i><strong>Ajuda</strong> reduz dúvida antes do erro.</span><span><i class="ui-form-dot ui-form-dot-error"></i><strong>Erro</strong> explica como corrigir.</span><span><i class="ui-form-dot ui-form-dot-success"></i><strong>Sucesso</strong> confirma o resultado.</span></div> 1798 </section> 1799`; 1800 1801uiDescomplicadaJourney[4].visualMarkup = ` 1802 <section class="ui-visual-lab ui-visual-lab-states" aria-label="Laboratório visual: estados de interface"> 1803 <div class="ui-visual-lab-header"><div><p class="ui-visual-kicker">Laboratório visual · comunique</p><h4>A mesma lista, quatro momentos</h4><p>Um estado responde três perguntas: o que aconteceu, o que posso fazer e o que devo esperar?</p></div><span class="ui-visual-stamp">05 · responder</span></div> 1804 <div class="ui-state-board"> 1805 <article class="ui-state-card ui-state-empty"><div class="ui-state-top"><span class="ui-state-dot"></span><small>VAZIO</small><b>01</b></div><div class="ui-state-illustration ui-state-illustration-empty"><i>ï¼</i></div><h5>Nenhum pedido ainda</h5><p>Comece uma solicitação para acompanhar o andamento por aqui.</p><button type="button">Criar pedido <span>â</span></button></article> 1806 <article class="ui-state-card ui-state-loading"><div class="ui-state-top"><span class="ui-state-dot"></span><small>CARREGANDO</small><b>02</b></div><div class="ui-state-skeleton"><i></i><i></i><i></i></div><h5>Buscando seus pedidos</h5><p>
1806O sistema está consultando os dados. Aguarde um instante.</p><div class="ui-state-progress"><span></span></div></article> 1807 <article class="ui-state-card ui-state-error"><div class="ui-state-top"><span class="ui-state-dot"></span><small>ERRO</small><b>03</b></div><div class="ui-state-illustration ui-state-illustration-error"><i>!</i></div><h5>Não foi possÃvel carregar</h5><p>Seus pedidos continuam seguros. Tente novamente ou verifique sua conexão.</p><button type="button">Tentar novamente â»</button></article> 1808 <article class="ui-state-card ui-state-success"><div class="ui-state-top"><span class="ui-state-dot"></span><small>SUCESSO</small><b>04</b></div><div class="ui-state-success-count"><strong>03</strong><span>pedidos encontrados</span></div><div class="ui-state-mini-row"><i></i><span>Orçamento do projeto</span><b>em análise</b></div><div class="ui-state-mini-row"><i></i><span>Atualização de cadastro</span><b>concluÃdo</b></div><p class="ui-state-note">Resultado visÃvel. Agora a pessoa sabe onde continuar.</p></article> 1809 </div> 1810 <div class="ui-state-legend"><span><b>Vazio</b> orienta o primeiro passo.</span><span><b>Carregando</b> explica a espera.</span><span><b>Erro</b> oferece recuperação.</span><span><b>Sucesso</b> confirma o resultado.</span></div> 1811 <p class="ui-visual-caption">Pergunta de designer: em cada estado, a pessoa entende o que aconteceu sem precisar adivinhar?</p> 1812 </section> 1813`; 1814 1815uiDescomplicadaJourney[5].visualMarkup = ` 1816 <section class="ui-visual-lab ui-visual-lab-patterns" aria-label="Laboratório visual: padrões de interação"> 1817 <div class="ui-visual-lab-header"><div><p class="ui-visual-kicker">Laboratório visual · escolha</p><h4>O padrão muda a conversa</h4><p>Abas preservam contexto, acordeões revelam detalhes e modais concentram decisões.</p></div><span class="ui-visual-stamp">06 · orientar</span></div> 1818 <div class="ui-pattern-stage"> 1819 <div class="ui-pattern-window"><div class="ui-pattern-bar"><span>curso · ui descomplicada</span><b>área do aluno</b></div><div class="ui-pattern-content"><small>MEU CURSO</small><h5>UI Descomplicada</h5><div class="ui-tabs"><button class="is-active" type="button">Visão geral</button><button type="button">Aulas</button><button type="button">Certificado</button></div><div class="ui-tab-panel"><strong>Continue de onde parou</strong><p>Aula 06 · Navegação e padrões de interação</p><button type="button">Continuar aula <span>â</span></button></div><div class="ui-accordion"><div><button type="button"><span>Como funciona o projeto final?</span><b>ï¼</b></button></div><div class="is-open"><button type="button"><span>O que vou aprender?</span><b>â</b></button><p>Você aprende a escolher padrões conforme contexto, frequência e impacto da ação.</p></div></div></div></div> 1820 <div class="ui-pattern-decision"><div class="ui-pattern-decision-head"><span class="ui-visual-index ui-visual-index-lime">?</span><div><small>DECISÃO DE PADRÃO</small><strong>Precisa interromper?</strong></div></div><p>Use a menor interrupção possÃvel. Reserve o modal para confirmação ou tarefa que exige foco.</p><div class="ui-pattern-options"><div class="ui-pattern-option"><span class="ui-pattern-symbol">â</span><div><strong>ABAS</strong><small>Conteúdos relacionados</small></div></div><div class="ui-pattern-option"><span class="ui-pattern-symbol">â</span><div><strong>ACORDEÃO</strong><small>Detalhes sob demanda</small></div></div><div class="ui-pattern-option ui-pattern-option-modal"><span class="ui-pattern-symbol">â¡</span><div><strong>MODAL</strong><small>Decisão concentrada</small></div></div></div></div> 1821 </div> 1822 <div class="ui-pattern-flow"><span>necessidade</span><i>â</i><span>contexto</span><i>â</i><span>padrão</span><i>â</i><span>comportamento esperado</span></div> 1823 <p class="ui-visual-caption">Pergunta de designer: se você trocar o padrão, a pessoa perde contexto, descobre mais rápido ou precisa confirmar uma decisão?</p> 1824 </section> 1825`; 1826 1827uiDescomplicadaJourney[6].visualMarkup = ` 1828 <section class="ui-visual-lab ui-visual-lab-accessibility" aria-label="Laboratório visual: acessibilidade e mobile"> 1829 <div class="ui-visual-lab-header"><div><p class="ui-visual-kicker">Laboratório visual · teste</p><h4>Uma tela, duas formas de navegar</h4><p>Acessibilidade aparece quando o foco, a leitura e o toque continuam compreensÃveis sem depender do mouse ou da cor.</p></div><span class="ui-visual-stamp">07 · incluir</span></div> 1830 <div class="ui-access-stage"> 1831 <div class="ui-access-desktop"><div class="ui-access-browser"><span></span><span></span><span></span><b>checkout · revisão do pedido</b></div><div class="ui-access-screen"><small>ETAPA 2 DE 3</small><h5>Revise antes de enviar</h5><p>Confira os dados e escolha como receber o retorno.</p><div class="ui-access-field"><label>Nome completo</label><div>Marina Costa</div></div><div class="ui-access-field ui-access-focus"><label>E-mail</label><div>[email protected]</div><em>Foco visÃvel · próximo com Tab</em></div><div class="ui-access-actions"><button class="ui-access-secondary" type="button">Voltar</button><button type="button">Enviar pedido <span>â</span></button></div><div class="ui-focus-order"><i>01</i><span>
1831Nome</span><i>02</i><span>E-mail</span><i>03</i><span>Enviar</span></div></div></div> 1832 <div class="ui-access-mobile"><div class="ui-access-mobile-top"><span>mobile · 375px</span><b>9:41</b></div><div class="ui-access-mobile-body"><small>REVISÃO</small><h5>Quase lá!</h5><p>Confirme os dados do pedido.</p><button class="ui-touch-target ui-touch-target-active" type="button"><i>â</i><span>Receber por e-mail</span><b>selecionado</b></button><button class="ui-touch-target" type="button"><i></i><span>Receber por WhatsApp</span><b>toque</b></button><button class="ui-mobile-cta" type="button">Enviar pedido <span>â</span></button><small class="ui-touch-note">Ãreas separadas · texto + Ãcone · sem depender só da cor</small></div></div> 1833 </div> 1834 <div class="ui-access-checks"><span><b>01 · Foco</b> aparece em cada etapa.</span><span><b>02 · Ordem</b> acompanha a lógica da tela.</span><span><b>03 · Toque</b> tem espaço para acertar.</span><span><b>04 · Cor</b> não carrega a informação sozinha.</span></div> 1835 <p class="ui-visual-caption">Pergunta de designer: alguém conseguiria concluir esta tela com teclado, leitor de tela ou toque impreciso?</p> 1836 </section> 1837`; 1838 1839uiDescomplicadaJourney[7].visualMarkup = ` 1840 <section class="ui-final-studio" aria-label="Estúdio do projeto final"> 1841 <div class="ui-final-studio-header"><div><p class="ui-final-eyebrow">Estúdio de projeto · entrega final</p><h4>Transforme uma necessidade em uma tela que pode ser construÃda</h4><p>Você vai conectar intenção, estrutura, comportamento, estados, mobile e critérios de aceite em uma única entrega.</p></div><span class="ui-final-badge">08 · entregar</span></div> 1842 <div class="ui-final-canvas"><div class="ui-final-canvas-top"><span>PROJETO · CHECKOUT DE CONSULTA</span><b>RASCUNHO 01</b></div><div class="ui-final-map"><article class="ui-final-map-card ui-final-map-context"><small>01 · CONTEXTO</small><h5>Confirmar uma consulta sem dúvida</h5><p>Para pessoas que precisam agendar pelo celular.</p><span class="ui-final-pin">briefing</span></article><div class="ui-final-arrow">â</div><article class="ui-final-map-card ui-final-map-screen"><small>02 · TELA</small><div class="ui-final-mini-screen"><b>Confirmar horário</b><span>terça, 10 set. · 14:30</span><button type="button">Confirmar consulta</button></div><span class="ui-final-pin">estrutura</span></article><div class="ui-final-arrow">â</div><article class="ui-final-map-card ui-final-map-proof"><small>03 · PROVA</small><div class="ui-final-proof-row"><i>â</i><span>CTA visÃvel em 375px</span></div><div class="ui-final-proof-row"><i>â</i><span>Erro explica como corrigir</span></div><div class="ui-final-proof-row"><i>â</i><span>Sucesso mostra próximo passo</span></div><span class="ui-final-pin">aceite</span></article></div></div> 1843 <div class="ui-final-delivery"><div><p class="ui-final-eyebrow">Pacote de entrega</p><h5>O que outra pessoa precisa para continuar?</h5><p>Um bom handoff reduz adivinhação: contexto, tela, estados e critérios ficam no mesmo lugar.</p></div><div class="ui-final-checklist"><span><i>â</i>Briefing</span><span><i>â</i>Blueprint visual</span><span><i>â</i>Estados</span><span><i>â</i>Critérios de aceite</span><span><i>+</i>Pendências visÃveis</span></div></div> 1844 <div class="ui-final-rubric-strip"><span><b>Clareza</b> a decisão está explÃcita?</span><span><b>Completude</b> os estados foram descritos?</span><span><b>Continuidade</b> outra pessoa consegue seguir?</span></div> 1845 </section> 1846`; 1847 1848uiDescomplicadaJourney[8].visualMarkup = ` 1849 <section class="ui-codes-lab" aria-label="Laboratório visual: Códigos Secretos da UI"> 1850 <div class="ui-codes-lab-header"><div><p class="ui-final-eyebrow">Bônus de encerramento · repertório</p><h4>Um código transforma intenção em instrução</h4><p>Use atalhos de linguagem para pedir decisões especÃficas sem voltar a frases vagas como âdeixa bonitoâ ou âfaz responsivoâ.</p></div><span class="ui-final-badge">09 · dominar</span></div> 1851 <div class="ui-code-transform"><div class="ui-code-column ui-code-confused"><small>ANTES · PEDIDO VAGO</small><blockquote>âCria uma tela bonita para meus pedidos.â</blockquote><span class="ui-code-tag ui-code-tag-red">sem contexto</span></div><div class="ui-code-transform-arrow">â</div><div class="ui-code-column ui-code-clear"><small>DEPOIS · PEDIDO COM CÃDIGOS</small><blockquote>â/nomear /priorizar /estados-ui /mobile /aceite-uiâ</blockquote><span class="ui-code-tag ui-code-tag-lime">decisões visÃveis</span></div></div> 1852 <div class="ui-code-stack"><div class="ui-code-stack-head"><span>MONTE SEU PEDIDO</span><b>combine intenções</b></div><div class="ui-code-chips"><span><b>/nomear</b> blocos</span><span><b>/priorizar</b> decisão</span><span><b>/estados-ui</b> comportamento</span><span><b>/mobile</b> adaptação</span><span><b>/aceite-ui</b> pronto</span></div><div class="ui-code-output"><small>SAÃDA ESPERADA</small><p>Uma especificação que outra pessoa consegue entender, testar e continuar.</p><span>contexto + estrutura + comportamento + critérios</span></div></div> 1853 <div class="ui-codes-rules"><span><b>01</b> Código não substitui contexto.</span><span><b>02</b> Cada código torna uma decisão explÃcita.</span><span><b>03</b> O resultado precisa ser observável.</span></div> 1854 <p class="ui-visual-caption">Desafio final: escolha cinco códigos e escreva um pedido para uma tela real do seu trabalho.</p> 1855 </section> 1856`; 1857
1858uiDescomplicadaJourney[8].codigos = [ 1859 { codigo: '/anatomia' }, 1860 { codigo: '/hierarquia' }, 1861 { codigo: '/estados-ui' }, 1862 { codigo: '/mobile' }, 1863 { codigo: '/aceite-ui' } 1864]; 1865 1866const uiDescomplicadaCodigos = [ 1867 ['/nomear', '/priorizar'], 1868 ['/decisao', '/escaneavel'], 1869 ['/grade', '/adaptar'], 1870 ['/campo', '/orientar'], 1871 ['/vazio', '/recuperar'], 1872 ['/padrao', '/contexto'], 1873 ['/teclado', '/toque'], 1874 ['/aceite', '/handoff-ui'] 1875]; 1876uiDescomplicadaJourney.slice(0, 8).forEach((item, index) => { 1877 item.codigos = uiDescomplicadaCodigos[index].map(codigo => ({ codigo })); 1878}); 1879 1880prototipandoComIaJourney[0].exerciseFields = [ 1881 { key: 'problema', label: 'Qual problema existe?', help: 'Descreva a dor, não a solução.', placeholder: 'Ex.: pessoas esquecem tarefas importantes.' }, 1882 { key: 'publico', label: 'Quem enfrenta isso?', help: 'Diga para quem o protótipo será útil.', placeholder: 'Ex.: pessoas que precisam organizar o dia.' }, 1883 { key: 'resultado', label: 'Qual resultado você espera?', help: 'Explique o que a pessoa conseguirá fazer.', placeholder: 'Ex.: escolher e concluir as tarefas de hoje.' }, 1884 { key: 'limite', label: 'O que fica fora agora?', help: 'Defina o limite da primeira versão.', placeholder: 'Ex.: sem colaboração ou notificações nesta versão.' } 1885]; 1886 1887prototipandoComIaJourney[1].exerciseFields = [ 1888 { key: 'objetivo', label: 'Qual é o objetivo?', help: 'Descreva a mudança que a primeira versão precisa produzir.', placeholder: 'Ex.: permitir que a clÃnica organize e confirme consultas.' }, 1889 { key: 'publico', label: 'Quem vai usar?', help: 'Escolha o usuário principal desta versão.', placeholder: 'Ex.: recepcionistas de uma clÃnica pequena.' }, 1890 { key: 'fluxo', label: 'Qual é o fluxo principal?', help: 'Liste as ações na ordem em que acontecem.', placeholder: 'Ex.: escolher data, ver horário, confirmar consulta.' }, 1891 { key: 'dados', label: 'Quais dados são necessários?', help: 'Inclua somente os dados indispensáveis para o fluxo.', placeholder: 'Ex.: nome, especialidade, data e horário.' }, 1892 { key: 'sucesso', label: 'Como saberemos que funcionou?', help: 'Defina um resultado que possa ser observado ou testado.', placeholder: 'Ex.: a pessoa confirma um horário sem pedir ajuda.' }, 1893 { key: 'fora', label: 'O que fica fora desta versão?', help: 'Liste uma função importante que será deixada para depois.', placeholder: 'Ex.: pagamento e lembretes automáticos ficam fora agora.' } 1894]; 1895 1896prototipandoComIaJourney[1].exerciseModelAnswer = 'Objetivo: permitir que a clÃnica organize e confirme consultas. Público: recepcionistas de uma clÃnica pequena. Fluxo: escolher especialidade, ver horários disponÃveis e confirmar consulta. Dados: nome, especialidade, data e horário. Sucesso: cinco pessoas conseguem confirmar um horário sem orientação. Fora: pagamento e lembretes automáticos nesta primeira versão.'; 1897 1898prototipandoComIaJourney[2].exerciseFields = [ 1899 { key: 'contexto', label: 'Para quem é a tela?', help: 'Descreva o usuário e a situação em que ele usará o cadastro.', placeholder: 'Ex.: pessoa leiga solicitando um orçamento pelo celular.' }, 1900 { key: 'objetivo', label: 'Qual é o objetivo?', help: 'Explique o que a pessoa precisa conseguir fazer.', placeholder: 'Ex.: enviar os dados para receber um orçamento.' }, 1901 { key: 'conteudo', label: 'O que precisa aparecer?', help: 'Liste os campos, textos e ações indispensáveis.', placeholder: 'Ex.: nome, e-mail, serviço, mensagem e botão Enviar orçamento.' }, 1902 { key: 'estados', label: 'Quais estados devem existir?', help: 'Descreva o que acontece no inÃcio, erro, envio e sucesso.', placeholder: 'Ex.: formulário vazio, erro nos campos, enviando e confirmação.' }, 1903 { key: 'entrega', label: 'O que você quer receber da IA?', help: 'Defina o formato da resposta ou protótipo esperado.', placeholder: 'Ex.: estrutura da tela, textos dos estados e comportamento de cada ação.' } 1904]; 1905 1906prototipandoComIaJourney[2].exerciseModelAnswer = 'Contexto: pessoa leiga solicitando um orçamento pelo celular. Objetivo: enviar os dados para receber um orçamento. Conteúdo: nome, e-mail, serviço, mensagem e botão Enviar orçamento. Estados: formulário vazio, erro nos campos, enviando, erro de envio e confirmação. Entrega: estrutura da tela, textos dos estados e comportamento de cada ação.'; 1907 1908// Os dois conceitos da aula ocupam grupos diferentes para tornar visÃvel a 1909// distinção entre explicar a tela e explicar o que acontece nela. 1910prototipandoComIaJourney[2].conceitos[0].grupo = 0; 1911prototipandoComIaJourney[2].conceitos[1].grupo = 1; 1912 1913prototipandoComIaJourney[3].exerciseFields = [ 1914 { key: 'sintoma', label: 'Qual é o sintoma?', help: 'Descreva o que a pessoa vê ou sente, sem tentar adivinhar a causa.', placeholder: 'Ex.: o botão Continuar não responde no celular.' }, 1915 { key: 'reproducao', label: 'Como reproduzir?', help: 'Liste os passos exatos que fazem o problema aparecer.', placeholder: 'Ex.: abrir checkout, preencher os dados e tocar duas vezes em Continuar.' }, 1916 { key: 'ambiente', label: 'Em qual ambiente acontece?', help: 'Informe dispositivo, navegador, tela ou condição relevante.', placeholder: 'Ex.: iPhone, largura de 375px, Safari, tela de checkout.' }, 1917 { key: 'esperado', label: 'O que deveria acontecer?', help: 'Descreva o resultado correto para a pessoa.', placeholder: 'Ex.: processar uma tentativa e mostrar a mensagem de andamento.' }, 1918 { key: 'limite', label: 'O que precisa ser preservado?', help: 'Defina o limite da correção e os cenários que não podem quebrar.', placeholder: 'Ex.: manter o comportamento no desktop e evitar cobrança duplicada.' } 1919]; 1920 1921prototipandoComIaJourney[3].exerciseModelAnswer = 'Sintoma: o botão Continuar não responde no celular. Reprodução: abrir checkout, preencher os dados e tocar duas vezes em Continuar. Ambiente: iPhone, largura de 375px, Safari. Esperado: processar uma tentativa e mostrar a mensagem de andamento. Preservar: comportamento no desktop e proteção contra cobrança duplicada.'; 1922 1923prototipandoComIaJourney[3].conceitos[0].comoFunciona = [ 1924 'Registre o sintoma com as palavras que a pessoa usaria, sem atribuir c
1924ausa antes da investigação.', 1925 'Liste os passos na ordem exata, incluindo dados de teste, tela, dispositivo e ação realizada.', 1926 'Separe o resultado observado do resultado esperado.', 1927 'Anexe evidência mÃnima, como mensagem, horário, captura ou resposta técnica relevante.', 1928 'Só depois formule hipóteses e peça à IA uma investigação limitada.' 1929]; 1930prototipandoComIaJourney[3].conceitos[0].segundoExemplo = 'Em vez de âo login está ruimâ, registre: âno Android 375px, depois de tocar em Entrar com os campos válidos, o botão fica carregando e nenhuma mensagem apareceâ.'; 1931prototipandoComIaJourney[3].conceitos[0].errosComuns = ['Confundir sintoma com causa.', 'Omitir dispositivo, navegador ou versão.', 'Descrever apenas o que tentou, sem dizer o que esperava ver.']; 1932prototipandoComIaJourney[3].conceitos[1].comoFunciona = [ 1933 'Identifique o comportamento que funcionava antes da mudança.', 1934 'Repita o cenário original e o cenário alterado com os mesmos dados.', 1935 'Compare desktop, celular, fluxo feliz, erro e acessibilidade quando forem afetados.', 1936 'Registre qual mudança introduziu o problema e qual proteção deve permanecer.', 1937 'Aprove a correção somente depois de retestar o bug e o caminho legÃtimo.' 1938]; 1939prototipandoComIaJourney[3].conceitos[1].segundoExemplo = 'Adicionar validação ao formulário pode impedir o envio correto se o campo de telefone mudar de formato. A correção precisa proteger o caso inválido sem quebrar o cadastro válido.'; 1940prototipandoComIaJourney[3].conceitos[1].comparacao = 'Reprodução de bug descreve como fazer o problema aparecer; regressão verifica se uma mudança criou um problema novo em algo que já funcionava.'; 1941prototipandoComIaJourney[3].conceitos[1].errosComuns = ['Testar somente o caso que motivou a mudança.', 'Corrigir o sintoma com uma exceção frágil.', 'Não registrar o cenário preservado nem o resultado do reteste.']; 1942 1943prototipandoComIaJourney[4].sequenceCount = 2; 1944prototipandoComIaJourney[4].connectors = ['compare']; 1945prototipandoComIaJourney[4].exerciseFields = [ 1946 { key: 'intencao', label: 'A saÃda atende à intenção?', help: 'Compare o que foi pedido com o que a IA realmente entregou.', placeholder: 'Ex.: atende ao objetivo de permitir que a pessoa solicite orçamento.' }, 1947 { key: 'conteudo', label: 'O conteúdo está correto?', help: 'Aponte informações ausentes, inventadas ou confusas.', placeholder: 'Ex.: falta explicar prazo de retorno e o campo serviço está sem orientação.' }, 1948 { key: 'comportamento', label: 'O comportamento foi previsto?', help: 'Verifique ações, estados, erros e retorno após cada interação.', placeholder: 'Ex.: falta estado de envio e mensagem quando a tentativa falha.' }, 1949 { key: 'acessibilidade', label: 'O que precisa de acessibilidade?', help: 'Observe leitura, contraste, foco, teclado e clareza dos rótulos.', placeholder: 'Ex.: o erro precisa ser anunciado e o foco deve ir para o primeiro campo inválido.' }, 1950 { key: 'risco', label: 'Qual risco ou lacuna existe?', help: 'Registre uma decisão importante que a IA omitiu ou inventou.', placeholder: 'Ex.: não está claro quais dados são armazenados após o envio.' }, 1951 { key: 'decisao', label: 'Qual é a próxima decisão?', help: 'Diga o que será aprovado, corrigido, testado ou perguntado.', placeholder: 'Ex.: corrigir os estados antes de aprovar o protótipo.' } 1952]; 1953 1954prototipandoComIaJourney[4].exerciseModelAnswer = 'Intenção: atende ao objetivo de permitir que a pessoa solicite orçamento. Conteúdo: falta explicar prazo de retorno e orientar o campo serviço. Comportamento: falta estado de envio e mensagem de falha. Acessibilidade: anunciar erros e mover foco para o primeiro campo inválido. Risco: não está claro quais dados são armazenados. Decisão: corrigir os estados e retestar antes de aprovar.'; 1955prototipandoComIaJourney[4].scenario = { 1956 title: 'Revisão guiada: a IA entregou uma tela âprontaâ', 1957 intro: 'A aparência está boa, mas a revisão precisa descobrir o que foi atendido, omitido ou inventado.', 1958 steps: [ 1959 { text: 'Pedido: criar um cadastro de orçamento para pessoas leigas, com nome, e-mail, serviço e mensagem.', tag: 'Intenção' }, 1960 { text: 'SaÃda: a tela tem campos e botão, mas não explica prazo, não mostra estado de envio e não define o que acontece em caso de erro.', tag: 'Lacuna' }, 1961 { text: 'Revisão: conferir conteúdo, comportamento, acessibilidade, segurança e manutenção antes de aprovar.', tag: 'Checklist' }, 1962 { text: 'Decisão: pedir correções especÃficas e retestar o fluxo completo, em vez de aceitar porque a tela está bonita.', tag: 'Próximo passo' } 1963 ] 1964}; 1965prototipandoComIaJourney[4].conceitos[0].comoFunciona = ['Releia a intenção e c
1965ompare cada promessa com a saÃda.', 'Teste o caminho principal e tente provocar erro, vazio e repetição.', 'Confira texto, hierarquia, acessibilidade, dados e permissões.', 'Registre acertos, riscos, lacunas e perguntas abertas.', 'Converta a revisão em decisões para a próxima versão.']; 1966prototipandoComIaJourney[4].conceitos[0].segundoExemplo = 'Uma tela pode estar visualmente consistente e ainda assim não dizer o que acontece depois do envio. A revisão transforma essa impressão em uma pergunta verificável: qual mensagem aparece e como a pessoa tenta novamente?'; 1967prototipandoComIaJourney[4].conceitos[0].errosComuns = ['Avaliar apenas estética.', 'Aceitar comportamento que não foi pedido.', 'Listar problemas sem decidir o próximo passo.']; 1968prototipandoComIaJourney[4].conceitos[1].comoFunciona = ['Procure decisões necessárias que não aparecem no briefing nem na interface.', 'Marque o que a IA inventou, como regras, textos, dados ou permissões.', 'Formule perguntas que possam ser respondidas pelo responsável pelo produto.', 'Não implemente uma suposição importante antes de confirmar a regra.', 'Atualize o pedido ou a documentação com a decisão tomada.']; 1969prototipandoComIaJourney[4].conceitos[1].segundoExemplo = 'Se o protótipo mostra âseus dados foram enviadosâ, ainda falta saber se eles foram armazenados, para quem serão encaminhados e como a pessoa corrige um e-mail errado.'; 1970prototipandoComIaJourney[4].conceitos[1].errosComuns = ['Confundir detalhe visual com especificação completa.', 'Deixar perguntas importantes escondidas no código.', 'Tratar uma resposta inventada pela IA como decisão do produto.']; 1971 1972prototipandoComIaJourney[5].conceitos[0].grupo = 0; 1973prototipandoComIaJourney[5].conceitos[1].grupo = 1; 1974prototipandoComIaJourney[5].exerciseFields = [ 1975 { key: 'versao', label: 'Qual é a versão atual?', help: 'Dê um nome ou número que permita reconhecer a entrega certa.', placeholder: 'Ex.: Protótipo agenda v0.3 â revisão do fluxo de confirmação.' }, 1976 { key: 'estrutura', label: 'Onde cada coisa está?', help: 'Liste as pastas ou arquivos principais e a finalidade de cada um.', placeholder: 'Ex.: /telas, /componentes, /dados-ficticios, /decisoes e README.' }, 1977 { key: 'decisao', label: 'Qual decisão foi registrada?', help: 'Explique uma escolha, o motivo e o impacto para o projeto.', placeholder: 'Ex.: usar dados fictÃcios para testar o fluxo sem integração externa.' }, 1978 { key: 'pendencias', label: 'O que ainda está pendente?', help: 'Separe o que está pronto, em revisão e fora desta versão.', placeholder: 'Ex.: pronto: fluxo; revisão: textos; fora: pagamento real.' }, 1979 { key: 'continuidade', label: 'Como outra pessoa continua?', help: 'Diga o que ela precisa abrir, testar e saber antes de alterar.', placeholder: 'Ex.: ler o README, abrir a versão v0.3 e seguir os critérios de teste.' } 1980]; 1981prototipandoComIaJourney[5].exerciseModelAnswer = 'Versão: Protótipo agenda v0.3 â revisão do fluxo de confirmação. Estrutura: /telas, /componentes, /dados-ficticios, /decisoes e README. Decisão: usar dados fictÃcios para testar o fluxo sem integração externa. Pendências: fluxo pronto, textos em revisão e pagamento real fora. Continuidade: ler o README, abrir a versão v0.3 e seguir os critérios de teste.'; 1982prototipandoComIaJourney[5].conceitos[0].comoFunciona = ['Dê nomes previsÃveis para pastas, arquivos e versões.', 'Separe o que é interface, componente, dado fictÃcio, referência e documentação.', 'Inclua um README com como abrir, testar e entender as limitações.', 'Mantenha apenas uma versão claramente identificada como atual.', 'Revise se outra pessoa encontra o que precisa sem depender de explicação oral.']; 1983prototipandoComIaJourney[5].conceitos[0].segundoExemplo = 'Em vez de enviar âa pasta do protótipoâ, entregue /prototipo-v0.3 com README, /telas, /dados-ficticios, /decisoes e /pendencias, cada item com uma finalidade clara.'; 1984prototipandoComIaJourney[5].conceitos[0].errosComuns = ['Misturar rascunho e versão atual.', 'Usar nomes como final-final-2.', 'Depender de arquivos ou dados que só existem no computador de quem criou.']; 1985prototipandoComIaJourney[5].conceitos[1].comoFunciona = ['Registre a decisão tomada, as alternativas consideradas e o motivo.', 'Anote impacto, risco restante e o que faria a decisão mudar.', 'Diferencie decisão confirmada de pergunta em aberto.', 'Ligue a decisão aos arquivos, telas ou critérios afetados.', 'Atualize o registro quando uma nova evidência mudar o caminho.']; 1986prototipandoComIaJourney[5].conceitos[1].segundoExemplo = 'âUsaremos dados fictÃcios nesta versão porque ainda não há integração com o calendário; quando o fluxo for aprovado, a equipe avaliará autenticação e sincronização.â'; 1987prototipandoComIaJourney[5].conceitos[1].errosComuns = ['Registrar apen
1987as o resultado sem o motivo.', 'Esconder decisões importantes no chat.', 'Tratar pendência como falha sem dizer quem precisa decidir e qual é o próximo passo.']; 1988 1989Object.assign(prototipandoComIaJourney[6], { 1990 practice: 'Prepare um pedido para revisar um formulário de orçamento: substitua dados de clientes por exemplos fictÃcios, remova credenciais e defina o que precisa ser testado antes da publicação.', 1991 exerciseFields: [ 1992 { key: 'compartilhar', label: 'O que ajuda a IA a entender?', help: 'Descreva o problema e o comportamento esperado com informações fictÃcias.', placeholder: 'Descreva o contexto necessário...' }, 1993 { key: 'remover', label: 'O que deve sair do pedido?', help: 'Identifique dados pessoais e credenciais que não são necessários à revisão.', placeholder: 'Liste o que você removeria...' }, 1994 { key: 'substituir', label: 'Como criar um exemplo seguro?', help: 'Use valores inventados que preservem o formato necessário ao teste.', placeholder: 'Escreva um exemplo fictÃcio...' }, 1995 { key: 'revisar', label: 'O que exige revisão humana?', help: 'Indique decisões sobre acesso, armazenamento e envio das informações.', placeholder: 'Explique quem precisa conferir e o quê...' }, 1996 { key: 'testar', label: 'Como conferir a entrega?', help: 'Descreva um teste de sucesso e um de falha, usando dados fictÃcios.', placeholder: 'Registre os resultados esperados...' }, 1997 { key: 'prompt', label: 'Monte seu pedido final', help: 'Junte contexto, limites, revisão e testes em uma instrução para a IA.', placeholder: 'Escreva seu pedido aqui...' } 1998 ], 1999 exerciseModelAnswer: 'Compartilhar: estrutura do formulário e descrição do erro. Remover: nomes reais, e-mails de clientes, senhas e chaves. Substituir: Cliente Exemplo e [email protected]. Revisar: quem pode consultar os pedidos e onde serão armazenados. Testar: envio válido confirma recebimento; falha informa o problema e permite tentar novamente. Pedido: revise este formulário com dados fictÃcios, identifique dúvidas sobre acesso e armazenamento e proponha testes antes de publicar.', 2000 scenario: { 2001 title: 'Antes de enviar: revise o próprio pedido', 2002 intro: 'Caso fictÃcio: uma equipe quer ajuda da IA para corrigir um formulário de orçamento. O material disponÃvel inclui mensagens de clientes e configurações do serviço de e-mail.', 2003 steps: [ 2004 { text: 'Descreva o sintoma e o resultado esperado. Compartilhe somente o trecho necessário para entender o problema.', tag: 'Contexto útil' }, 2005 { text: 'Troque as mensagens reais por exemplos inventados e remova senhas, tokens e chaves. Apagar apenas o nome pode deixar outras informações identificáveis.', tag: 'Preparar o exemplo' }, 2006 { text: 'Peça à IA que registre dúvidas sobre quem recebe e acessa os pedidos. A pessoa responsável pelo produto confirma essas decisões.', tag: 'Revisão humana' }, 2007 { text: 'Teste envio, falha e tentativa repetida com dados fictÃcios. Registre os resultados e as pendências antes da publicação.', tag: 'Verificação' } 2008 ] 2009 } 2010}); 2011Object.assign(prototipandoComIaJourney[6].conceitos[0], { 2012 comoFunciona: ['Identifique o contexto mÃnimo necessário para explicar o problema.', 'Localize dados pessoais e credenciais no texto, código e imagens.', 'Crie exemplos inteiramente fictÃcios com o mesmo formato.', 'Confira se os exemplos ainda permitem reproduzir o comportamento.', 'Revise o material completo antes de enviar.'], 2013 segundoExemplo: 'Para investigar uma validação de e-mail, use [email protected]. Não é necessário copiar a lista de clientes para explicar um erro de formato.', 2014 errosComuns: ['Remover o nome e manter telefone, endereço ou mensagem identificável.', 'Colar uma chave real dentro de um exemplo de código.', 'Enviar uma base inteira quando um único registro fictÃcio explica o problema.'] 2015}); 2016Object.assign(prototipandoComIaJourney[6].conceitos[1], { 2017 comoFunciona: ['Compare a entrega com o objetivo e os limites do pedido.', 'Confirme com o responsável quem pode acessar e alterar os dados.', 'Execute os testes previstos e registre resultados observados.', 'Peça revisão técnica quando a mudança envolver autenticação, permissões ou serviços externos.', 'Deixe pendências explÃcitas e identifique quem decide a publicação.'], 2018 segundoExemplo: 'A IA sugere guardar os pedidos no navegador. A equipe precisa avaliar se isso atende ao uso compartilhado, à persistência e à s regras de acesso antes de aceitar.', 2019 errosComuns: ['Considerar a explicação da IA como prova de que o código funciona.', 'Aprovar a publicação sem executar o fluxo.', 'Deixar uma decisão sobre acesso implÃcita no código.'] 2020}); 2021 2022Object.assign(prototipandoComIaJourney[7], { 2023 finalStudio: true, 2024 estimatedMinutes: 120, 2025 goal: 'Crie, teste e apresente um protótipo guiado por IA. Sua entrega deve permitir que outra pessoa percorra o fluxo e entenda suas decisões.', 2026 practice: 'Construa um protótipo de solicitação de orçamento com dados fictÃcios ou adapte uma ideia própria de tamanho equivalente. Execute os testes e registre abaixo as evidências e pendências.', 2027 lessons: ['Retome seu escopo: escolha um público, uma tarefa principal e o que ficará fora.', 'Peça o protótipo à IA, percorra o fluxo e revise a primeira saÃda.', 'Teste os estados inicial, inválido, enviando, falha e sucesso com dados fictÃcios.', 'Entregue a versão identificada, instruções para abrir, resultados dos testes e limitações.'], 2028 scenario: { 2029 title: 'Seu projeto: do pedido à demonstração', 2030 intro: 'Exemplo didático: uma pessoa solicita orçamento pelo celular. O envio será simulado e isso deve ficar explÃcito na tela. Você pode usar outra ideia, preservando um fluxo pequeno e testável.', 2031 steps: [ 2032 { text: 'Defina o recorte: nome fictÃcio, e-mail de exemplo, serviço e mensagem. Pagamento, login e envio real ficam fora desta versão.', tag: 'Planejar' }, 2033 { text: 'Peça à IA um protótipo navegável com rótulos claros, uso por teclado e estados de erro e sucesso. Informe como deseja abrir e executar a entrega.', tag: 'Construir' }, 2034 { text: 'Abra o resultado. Envie campos vazios, corrija os dad
2034os e percorra o fluxo válido. Simule uma falha de envio e confira se é possÃvel tentar novamente.', tag: 'Testar' }, 2035 { text: 'Registre um problema observado e peça uma correção especÃfica. Repita o teste que falhou e confira se o caminho válido continua funcionando.', tag: 'Revisar' }, 2036 { text: 'Identifique a versão e demonstre o fluxo. Entregue instruções, decisões, testes executados e pendências. Informe claramente que nenhum orçamento real foi enviado.', tag: 'Apresentar' } 2037 ] 2038 }, 2039 exerciseFields: [ 2040 { key: 'escopo', label: '01 · Qual problema seu projeto resolve?', help: 'Informe público, tarefa principal e limite da versão.', placeholder: 'Descreva seu recorte...' }, 2041 { key: 'prompt', label: '02 · Qual pedido você enviou à IA?', help: 'Inclua contexto, campos, estados e formato da entrega.', placeholder: 'Registre o prompt utilizado...' }, 2042 { key: 'prototipo', label: '03 · Onde está a versão para revisão?', help: 'Informe nome ou link da versão e explique como abri-la. Não inclua credenciais.', placeholder: 'Identifique sua entrega e as instruções...' }, 2043 { key: 'testes', label: '04 · O que você realmente testou?', help: 'Para cada teste, registre ação, resultado esperado e observado. Identifique o que não foi testado.', placeholder: 'Relate os testes e seus resultados...' }, 2044 { key: 'revisao', label: '05 · O que mudou após a revisão?', help: 'Descreva uma correção e o resultado do reteste. Se não houve correção, registre como revisou.', placeholder: 'Explique o que observou e decidiu...' }, 2045 { key: 'entrega', label: '06 · Quais são as limitações e próximos passos?', help: 'Liste simulações, pendências e decisões necessárias antes de uso real.', placeholder: 'Registre o que outra pessoa precisa saber...' } 2046 ], 2047 exerciseModelAnswer: 'Exemplo ilustrativo â use evidências do seu próprio projeto. Escopo: pessoa solicita orçamento pelo celular; sem envio real. Pedido: formulário com dados fictÃcios e estados inicial, inválido, enviando, falha e sucesso. Versão: orçamento-v0.1, com instruções no README. Testes: envio vazio mostra erros; envio válido apresenta confirmação de simulação; falha permite tentar novamente. Revisão: corrigido rótulo do e-mail e repetido o teste. Limitações: dados não são enviados a uma empresa; integração e revisão de acesso permanecem pendentes. O preenchimento deste registro, por si só, não comprova que o protótipo funciona.' 2048}); 2049Object.assign(prototipandoComIaJourney[7].conceitos[0], { 2050 comoFunciona: ['Escolha uma hipótese pequena que possa ser demonstrada.', 'Defina as telas, ações e estados necessários ao fluxo.', 'Use dados fictÃcios e identifique cada integração simulada.', 'Percorra o fluxo com outra pessoa e observe onde surgem dúvidas.', 'Registre o que aprendeu e decida o que revisar.'], 2051 segundoExemplo: 'Uma agenda permite selecionar um horário e ver uma confirmação simulada. Isso ajuda a testar a compreensão do fluxo, mas não comprova que reservas reais serão protegidas contra duplicidade.', 2052 errosComuns: ['Apresentar uma simulação como operação real.', 'Adicionar funções que impedem terminar o fluxo principal.', 'Confundir uma tela renderizada com uma jornada testada.'] 2053}); 2054Object.assign(prototipandoComIaJourney[7].conceitos[1], { 2055 comoFunciona: ['Identifique a versão e como abrir a entrega.', 'Explique objetivo, escopo e decisões tomadas.', 'Liste testes executados com seus resultados.', 'Marque simulações, pendências e riscos conhecidos.', 'Peça que outra pessoa abra e percorra o fluxo seguindo as instruções.'], 2056 segundoExemplo: 'O pacote orçamento-v0.1 inclui protótipo, README e notas de revisão. Uma pessoa consegue abrir, testar um envio fictÃcio e localizar as limitações sem depender do histórico de conversa com a IA.', 2057 errosComuns: ['Enviar somente uma captura da tela.', 'Declarar testes como aprovados sem executá-los.', 'Omitir instruções, arquivos necessários ou limitações.'] 2058}); 2059 2060Object.assign(prototipandoComIaJourney[8], { 2061 estimatedMinutes: 30, 2062 goal: 'Leve o método para seu próximo projeto. Escolha os códigos que ajudam a explicar sua intenção e transforme cada um em uma instrução concreta.',
2063 focus: 'Os códigos são lembretes do curso. Uma ferramenta de IA só entende sua intenção quando você explica o que cada código significa no pedido.', 2064 practice: 'Retome seu projeto final e escreva um pedido de próxima versão usando pelo menos quatro códigos. Explique a função de cada um, o resultado esperado e como você vai conferir a entrega.', 2065 lessons: [ 2066 'Planejar: /problema e /limite definem o recorte; /escopo e /criterio tornam a entrega verificável.', 2067 'Construir: /contexto e /estados descrevem a experiência; /reproduzir e /nao-quebrar orientam correções.', 2068 'Revisar e organizar: /revisar e /perguntar revelam pendências; /estrutura e /versao preparam a continuidade.', 2069 'Entregar: /sem-segredo e /humano orientam cuidados; /prototipo e /entrega reúnem o projeto para revisão.', 2070 'Selecione os códigos pertinentes. Explique suas instruções em linguagem natural e confira o resultado antes de aceitar.' 2071 ], 2072 exerciseFields: [ 2073 { key: 'objetivo', label: '01 · Qual é a próxima melhoria?', help: 'Escolha uma mudança pequena para o projeto final.', placeholder: 'Descreva o objetivo e quem se beneficia...' }, 2074 { key: 'codigos', label: '02 · Quais códigos ajudam neste pedido?', help: 'Escolha pelo menos quatro e explique a função de cada um.', placeholder: 'Liste os códigos e suas justificativas...' }, 2075 { key: 'pedido', label: '03 · Escreva seu pedido completo', help: 'Expanda os códigos em instruções que a IA consiga entender sem conhecer este curso.', placeholder: 'Junte contexto, ações, limites e entrega...' }, 2076 { key: 'verificacao', label: '04 · Como você vai conferir?', help: 'Descreva testes com resultado esperado e o que precisa continuar funcionando.', placeholder: 'Registre os cenários de revisão...' }, 2077 { key: 'limites', label: '05 · O que fica para uma decisão futura?', help: 'Informe limites, dúvidas e decisões que precisam de confirmação.', placeholder: 'Registre o que ficou fora ou em aberto...' }, 2078 { key: 'aprendizado', label: '06 · O que mudou na sua forma de pedir?', help: 'Compare seu primeiro pedido do curso com este. Cite uma melhoria concreta.', placeholder: 'Explique o que você passou a especificar...' } 2079 ], 2080 exerciseModelAnswer: 'Exemplo didático: melhorar a mensagem de falha do orçamento. /contexto: pessoa leiga usa o celular. /estados: explicar enviando, falha e sucesso simulado. /nao-quebrar: preservar os campos preenchidos e o fluxo válido. /entrega: registrar alteração, testes e pendências. Pedido: revise o formulário para esse público; durante o envio mostre andamento; na falha preserve os campos e permita tentar novamente; no sucesso informe que é uma simulação. Entregue a versão identificada e os resultados dos testes. Conferir: simular falha, repetir envio e testar o caminho válido. Fora: envio real de e-mail. Aprendizado: passei a descrever o que acontece após cada ação.' 2081}); 2082 2083const segurancaAplicacoesWebJourney = [ 2084 { 2085 stage: 'Aula 01', 2086 estimatedMinutes: 35, 2087 layout: 'grid', 2088 title: 'Fundamentos da segurança em aplicações web', 2089 goal: 'Entenda segurança como redução de risco, não como medo ou promessa absoluta, e aprenda a olhar uma aplicação com mentalidade defensiva.', 2090 focus: 'Antes de revisar um sistema, defina autorização ética, ambiente de teste, impacto possÃvel e o que precisa ser protegido.', 2091 practice: 'Escolha uma aplicação real e liste: dados importantes, ações crÃticas, usuários envolvidos e o pior impacto caso algo seja acessado indevidamente.', 2092 exerciseFeedback: 'A boa resposta separa ativo, risco, impacto e limite de teste autorizado. Segurança começa com contexto claro.', 2093 lessons: [ 2094 'Risco combina probabilidade, impacto e exposição.', 2095 'Teste de segurança só deve acontecer com autorização explÃcita.', 2096 'Uma visão defensiva procura proteger pessoas, dados e continuidade do serviço.' 2097 ], 2098 conceitos: [ 2099 apiConceito('Risco de segurança', 'A chance de uma falha causar dano real a pessoas, dados, dinheiro ou operação. Risco não é só a existência técnica de um bug: ele combina o que pode acontecer, quem seria afetado, quão fácil é abusar e quais controles já reduzem o problema.', 'Use para priorizar o que precisa ser corrigido primeiro e para explicar por que uma falha merece atenção agora, depois ou apenas monitoramento.', 'Deixa mais seguro.', 'Priorizar o fluxo de recuperação de senha porque ele pode dar acesso indevido à conta do aluno, tem rota pública e afeta dados pessoais, certificados e histórico de pagamento.', 'Security risk', ['impacto', 'probabilidade', 'exposição'], { comoFunciona: ['Identifique o que pode dar errado em uma tela, API ou integração.', 'Defina o impacto: dado vazado, dinheiro perdido, acesso indevido, indisponibilidade ou dano operacional.', 'Avalie a probabilidade: precisa estar logado? é rota pública? exige conhecimento raro? pode ser automatizado?', 'Observe a exposição: quantas pessoas, registros, integrações ou ambientes ficam alcançáveis.', 'Priorize a correção que reduz mais dano com menor risco de regressão.'], segundoExemplo: 'Um botão desalinhado e um endpoint que libera certificado de outro aluno são bugs, mas só o segundo vira risco de segurança relevante porque cruza impacto, probabilidade e exposição.', comparacao: 'Impacto mede o tamanho do dano; probabilidade mede a chance de acontecer; exposição mede quanto o alvo está acessÃvel. Risco nasce da comb
2099inação dos três.', errosComuns: ['Tratar todo problema como crÃtico sem explicar impacto.', 'Focar só em invasão e esquecer vazamento, fraude, indisponibilidade e erro operacional.', 'Priorizar pela técnica mais assustadora em vez do dano real para usuário e negócio.'] }), 2100 apiConceito('Ativo protegido', 'Algo que tem valor e precisa de proteção: dados, conta, pagamento, conteúdo, certificado, configuração, integração ou reputação. Um ativo protegido não precisa ser apenas um arquivo secreto; pode ser qualquer coisa que, se for vista ou alterada indevidamente, gere dano.', 'Use para explicar o que está em jogo antes de discutir vulnerabilidade, controle ou correção. Sem saber o ativo, a conversa fica genérica demais.', 'Protege o sistema.', 'Proteger dados pessoais dos alunos, cobranças, sessões administrativas, emissão de certificados, cupons de parceiros e conteúdo pago, cada um com regra própria de acesso e registro.', 'Protected asset', ['dado sensÃvel', 'conta', 'recurso crÃtico'], { comoFunciona: ['Liste o que a aplicação guarda, mostra ou permite alterar.', 'Separe ativos por tipo: dados pessoais, dinheiro, acesso, conteúdo, operação e configuração.', 'Defina quem deveria acessar cada ativo e em qual situação.', 'Relacione cada ativo aos fluxos onde ele aparece: login, checkout, painel, certificado, webhook ou suporte.', 'Use essa lista para guiar permissões, logs, validação e testes.'], segundoExemplo: 'Em uma escola online, aulas pagas, histórico financeiro, progresso do aluno e credenciais do gestor são ativos diferentes, cada um com risco próprio.', comparacao: 'Ativo protegido é o que precisa ser defendido; controle é a medida usada para defender; vulnerabilidade é a falha que ameaça esse ativo.', errosComuns: ['Dizer âproteger o sistemaâ sem listar dados, contas, ações e integrações concretas.', 'Proteger apenas banco de dados e esquecer tokens, logs, arquivos e configurações.', 'Aplicar a mesma regra para ativos com riscos diferentes, como comentário público e dado financeiro.'] }), 2101 apiConceito('Autorização ética', 'Permissão clara para testar uma aplicação, com escopo, ambiente, horário, dados permitidos e limites definidos. Ela protege usuários, empresa e quem testa, porque separa aprendizado defensivo de acesso indevido.', 'Use antes de qualquer varredura, tentativa de exploração, teste invasivo, automação, análise de produção ou reprodução de vulnerabilidade.', 'Vou testar vulnerabilidade.', 'Testar apenas o ambiente sandbox autorizado, com contas fictÃcias, sem acessar dados reais, sem afetar disponibilidade e registrando evidências defensivas suficientes para correção.', 'Authorized security testing', ['escopo', 'ambiente de teste', 'responsabilidade'], { comoFunciona: ['Defina qual aplicação, domÃnio, ambiente e conta podem ser usados.', 'Combine o que está fora do limite: produção, dados reais, força bruta, negação de serviço ou terceiros.', 'Use dados fictÃcios e evidência mÃnima, sem copiar informação sensÃvel.', 'Pare o teste se surgir risco de dano e comunique o responsável.', 'Registre achados com passos autorizados e sugestão de correção.'], segundoExemplo: 'à aceitável testar IDOR com dois alunos fictÃcios no sandbox; não é aceitável trocar IDs em produção para ver dados de clientes reais.', comparacao: 'Autorização ética não é burocracia: é o controle que transforma curiosidade técnica em revisão defensiva responsável.', errosComuns: ['Testar produção sem autorização formal.', 'Usar dados reais quando um ambiente controlado resolveria o aprendizado.', 'Achar que âera só um testeâ justifica acessar conta, arquivo ou dado de outra pessoa.'] }) 2102 ], 2103 codigos: [ 2104 { codigo: '/risco' }, 2105 { codigo: '/ativos' } 2106 ], 2107 scenario: { 2108 title: 'Cenário completo: primeira revisão de segurança de uma escola online', 2109 intro: 'Antes de falar em ferramenta, o time organiza o que precisa proteger e qual teste é permitido.', 2110 steps: [ 2111 { text: 'O time lista dados de alunos, cobranças, aulas pagas, certificados e painel gestor como ativos protegidos.', tag: 'Ativo protegido' }, 2112 { text: 'A recuperação de senha e o login do gestor entram como riscos prioritários porque podem abrir acesso indevido.', tag: 'Risco de segurança' }, 2113 { text: 'A revisão fica limitada ao ambiente sandbox, com dados fictÃcios e horário combinado.', tag: 'Autorização ética' }, 2114 { text: 'Cada achado precisa trazer impacto, evidência defensiva e sugestão de correção.', tag: 'Relato responsável' } 2115 ] 2116 } 2117 }, 2118 { 2119 stage: 'Aula 02', 2120 estimatedMinutes: 35, 2121 layout: 'grid', 2122 title: 'Como ataques web acontecem', 2123 goal: 'Aprenda os pontos de entrada mais comuns de uma aplicação: URL, parâmetros, formulários, cookies, headers e uploads.',
2124 focus: 'Toda entrada enviada pelo usuário ou por outro sistema deve ser tratada como não confiável até ser validada.', 2125 practice: 'Mapeie uma tela de login ou checkout e identifique quais dados entram por rota, formulário, cookie, header e chamada de API.', 2126 exerciseFeedback: 'A resposta fica forte quando mostra por onde o dado entra e qual validação deveria existir antes de processar.', 2127 lessons: [ 2128 'Ataques geralmente começam em entradas comuns da aplicação.', 2129 'Parâmetros, cookies e headers também carregam decisões importantes.', 2130 'Mapear entradas ajuda a descobrir onde validar, bloquear ou registrar.' 2131 ], 2132 conceitos: [ 2133 apiConceito('Ponto de entrada', 'Qualquer lugar por onde dados chegam ao sistema: formulário, parâmetro de URL, header, cookie, upload, webhook, importação, busca ou chamada feita por outro serviço. Ataques costumam começar justamente por entradas comuns que parecem inofensivas.', 'Use para revisar formulários, APIs, uploads, URLs e integrações antes de pensar em solução. Se você não sabe por onde o dado entra, não sabe onde validar.', 'Confere os campos.', 'Validar dados que chegam pelo formulário de checkout, query string de cupom, parâmetros de aula, cookie de sessão e webhook de pagamento antes de calcular preço, liberar acesso ou exibir conteúdo.', 'Entry point', ['input', 'formulário', 'requisição'], { comoFunciona: ['Abra o fluxo e liste todos os lugares onde o usuário ou sistema externo envia algo.', 'Inclua entradas visÃveis, como campos, e invisÃveis, como headers, cookies e payloads de API.', 'Para cada entrada, defina formato esperado, tamanho máximo, origem e consequência.', 'Valide no servidor antes de gravar, consultar banco, chamar integração ou renderizar resposta.', 'Registre entradas crÃticas quando ajudam auditoria ou suporte.'], segundoExemplo: 'No checkout, cursos selecionados, cupom, e-mail, origem de parceiro, evento do gateway e retorno pós-pagamento são pontos de entrada diferentes.', comparacao: 'Ponto de entrada é a porta; entrada não confiável é a postura de segurança aplicada a tudo que passa por essa porta.', errosComuns: ['Revisar só campos visÃveis e esquecer query string, cookie, header e webhook.', 'Assumir que uma entrada é segura porque veio do próprio frontend.', 'Não documentar o que c
2133ada entrada pode causar depois de processada.'] }), 2134 apiConceito('Entrada não confiável', 'Dado recebido de fora do controle direto do backend, mesmo quando vem de uma tela bonita, app oficial, parceiro conhecido ou navegador autenticado. O usuário pode alterar requisições, repetir eventos, trocar parâmetros e chamar APIs sem passar pela interface.', 'Use para evitar confiar cegamente no navegador, app, parceiro, webhook, arquivo ou payload. A regra forte é: valide antes de usar.', 'O front já valida.', 'Revalidar no backend o curso comprado, o valor cobrado, o cupom aplicado, o aluno logado, o dono do recurso e a assinatura do webhook antes de liberar matrÃcula.', 'Untrusted input', ['validação no servidor', 'payload', 'parâmetro'], { comoFunciona: ['Receba o dado sem assumir que ele é verdadeiro.', 'Normalize formato quando necessário: texto, número, e-mail, URL, slug ou ID.', 'Compare com regras internas: plano existe, preço confere, cupom vale, sessão pertence ao aluno.', 'Recuse valores fora do esperado com mensagem clara e sem vazar detalhe interno.', 'Use logs para entradas sensÃveis ou rejeições importantes.'], segundoExemplo: 'Mesmo que o botão da interface não permita preço zero, alguém pode enviar payload manualmente. O backend deve recalcular o preço a partir do banco.', comparacao: 'Validação no frontend melhora experiência; validação no servidor protege a regra. Uma complementa a outra, mas só a do servidor é barreira real.', errosComuns: ['Confiar em campo hidden, disabled ou valor vindo do localStorage.', 'Validar só tipo e esquecer regra de negócio.', 'Aceitar payload de webhook sem assinatura ou segredo de origem.'] }), 2135 apiConceito('SuperfÃcie de ataque', 'Conjunto de telas, rotas, APIs, arquivos, integrações, permissões e automações que podem ser alcançados ou influenciados por usuários, parceiros, sistemas externos ou tráfego público. Quanto maior e menos controlada a superfÃcie, maior o esforço de proteção.', 'Use para reduzir exposição, priorizar revisão e decidir onde colocar controles primeiro. Ela ajuda a transformar ârevisar tudoâ em mapa de áreas crÃticas.', 'Tem muita coisa aberta.', 'Revisar rotas públicas, login, upload, checkout, webhook, redefinição de senha, certificados, cupons e endpoints administrativos como superfÃcie principal antes de publicar o curso.', 'Attack surface', ['rota pública', 'endpoint', 'exposição'], { comoFunciona: ['Liste tudo que pode receber acesso direto ou indireto.', 'Separe por exposição: público, autenticado, administrativo, integração externa ou interno.', 'Marque quais itens mexem com dados, dinheiro, permissões, arquivos ou disponibilidade.', 'Remova o que não precisa estar exposto e proteja o que precisa ficar aberto.', 'Repita o mapa quando novas rotas, cursos, webhooks ou uploads forem criados.'], segundoExemplo: 'Uma página pública de vendas, uma API de login e um webhook de pagamento pertencem à superfÃcie mesmo que só uma delas apareça no menu.', comparacao: 'Exposição mede o alcance de um item; superfÃcie de ataque é o mapa completo desses itens acessÃveis.', errosComuns: ['Achar que rota sem link no menu não é acessÃvel.', 'Esquecer ambientes de teste publicados, arquivos estáticos e endpoints antigos.', 'Mapear só frontend e deixar APIs e integrações fora da revisão.'] }) 2136 ], 2137 codigos: [ 2138 { codigo: '/mapeia-entradas' }, 2139 { codigo: '/nao-confie-no-front' } 2140 ], 2141 scenario: { 2142 title: 'Cenário completo: mapa de entradas do checkout', 2143 intro: 'A mesma compra recebe dados por vários caminhos, e todos precisam ser conferidos no servidor.', 2144 steps: [ 2145 { text: 'O aluno escolhe cursos e o navegador envia slugs no checkout.', tag: 'Ponto de entrada' }, 2146 { text: 'O cupom chega por campo de texto e não pode definir sozinho o valor final.', tag: 'Entrada não confiável' }, 2147 { text: 'O gateway envia um webhook depois do pagamento e também precisa validação de origem.', tag: 'Integração externa' }, 2148 { text: 'Login, checkout, cupom, webhook e painel gestor formam a superfÃcie inicial de revisão.', tag: 'SuperfÃcie de ataque' } 2149 ] 2150 } 2151 }, 2152 { 2153 stage: 'Aula 03', 2154 estimatedMinutes: 45, 2155 layout: 'groups', 2156 title: 'Autenticação, sessão e senhas', 2157 goal: 'Entenda como falhas de login, sessão e senha podem permitir acesso indevido mesmo quando a tela parece funcionar para o usuário comum.', 2158 focus: 'Separe quatro decisões: como a pessoa prova identidade, como o sistema limita abuso, quanto tempo a sessão dura e como o acesso é encerrado ou recuperado.', 2159 practice: 'Escreva uma especificação de login seguro para o gestor: senha, MFA, limite de tentativas, mensagem de erro, duração da sessão, logout e recuperação de senha.', 2160 exerciseFeedback: 'A resposta boa não diz só "login seguro"; ela define tentativa, bloqueio, sessão, expiração, logout, recuperação e o que nunca deve aparecer na mensagem pública.', 2161 lessons: [ 2162 'Autenticação confirma quem a pessoa diz ser.', 2163 'Sessão mantém o acesso depois do login e precisa expirar com segurança.', 2164 'Mensagens e limites de tentativa reduzem abuso sem revelar informação sensÃvel.' 2165 ], 2166 groups: [ 2167 { title: 'Entrada', desc: 'Senha, MFA e recuperação de acesso.' }, 2168 { title: 'Continuidade', desc: 'Sessão, expiração e encerramento seguro.' } 2169 ], 2170 conceitos: [ 2171 apiConceito('Authentication Bypass', 'Falha que permite entrar ou executar ação protegida sem passar corretamente pelo login.', 'Use para revisar páginas, APIs e atalhos que deveriam exigir autenticação antes de responder.', 'Só esconde o botão do gestor.', 'Toda rota administrativa valida a sessão no backend antes de listar alunos, pagamentos ou configurações, mesmo que alguém chame a API direto.', 'Authentication bypass', ['login', 'sessão', 'rota protegida'], { grupo: 0, comoFunciona: ['A pessoa tenta abrir uma tela ou API protegida.', 'O backend confere se existe sessão válida antes de buscar dados.', 'Se não houver sessão, responde bloqueio e não executa a ação.', 'A interface só melhora a experiência;
2171 a proteção real fica no servidor.'], errosComuns: ['Confiar apenas em esconder links e botões no frontend.', 'Proteger a página HTML, mas esquecer as rotas de API que devolvem os dados.'], segundoExemplo: 'Mesmo que alguém abra /api/admin/students manualmente, a API deve recusar sem sessão administrativa válida.' }), 2172 apiConceito('Brute Force', 'Tentativas repetidas de adivinhar senha, código MFA ou token de recuperação.', 'Use para pedir limite de tentativas, atraso progressivo, bloqueio temporário e registro de auditoria.', 'Se errar senha, deixa tentar de novo.', 'Após 5 tentativas de login do gestor em 60 segundos, bloquear temporariamente novas tentativas, responder mensagem genérica e registrar o evento.', 'Brute force attack', ['rate limit', 'tentativa de login', 'bloqueio temporário'], { grupo: 0, comoFunciona: ['O sistema conta tentativas por e-mail, IP ou combinação dos dois.', 'Ao passar do limite, novas tentativas são recusadas por um perÃodo curto.', 'A mensagem pública continua genérica para não confirmar se o e-mail existe.', 'O evento fica registrado para revisão do gestor ou suporte.'], errosComuns: ['Bloquear só por e-mail e permitir trocar o e-mail para continuar tentando.', 'Mostrar mensagens diferentes para e-mail inexistente e senha errada, ajudando enumeração de contas.'], segundoExemplo: 'O mesmo cuidado vale para código MFA e link de redefinição de senha: tentativa repetida também precisa limite.' }), 2173 apiConceito('Session Hijacking', 'Uso indevido de uma sessão válida que foi roubada, copiada, vazada ou mantida aberta por tempo demais.', 'Use para proteger cookies, tokens, expiração, logout e reautenticação em ações sensÃveis.', 'Mantém o gestor logado pra sempre.', 'Sessões administrativas expiram por tempo e inatividade, usam cookie/token protegido e são invalidadas quando o gestor faz logout.', 'Session hijacking', ['cookie seguro', 'token de sessão', 'logout'], { grupo: 1, comoFunciona: ['Depois do login, o servidor cria uma sessão com identificador difÃcil de adivinhar.', 'Esse identificador deve trafegar de forma protegida e expirar.', 'Logout remove a sessão para impedir reutilização.', 'Ações crÃticas podem pedir nova confirmação mesmo com sessão ativa.'], errosComuns: ['Sessão sem expiração em painel administrativo.', 'Logout que só muda a tela, mas não invalida o token no servidor.'], comparacao: 'Authentication Bypass pula o login; Session Hijacking usa uma sessão que já existia. Os dois levam a acesso indevido, mas a correção muda.' }) 2174 ], 2175 codigos: [ 2176 { codigo: '/protege-no-servidor' }, 2177 { codigo: '/rate-limit-login' } 2178 ], 2179 scenario: { 2180 title: 'Cenário completo: login do gestor sob tentativa repetida', 2181 intro: 'Uma tela de login segura precisa proteger entrada, sessão, mensagens e encerramento de acesso.', 2182 steps: [ 2183 { text: 'A rota administrativa rejeita requisições sem sessão válida, mesmo se alguém chamar a API direto.', tag: 'Authentication Bypass' }, 2184 { text: 'Senha e MFA são verificados no servidor; a mensagem de erro continua genérica quando algo não confere.', tag: 'Prova de identidade' }, 2185 { text: 'Depois de várias tentativas falhas, o rate limit bloqueia temporariamente novas tentativas e registra auditoria.', tag: 'Brute Force' }, 2186 { text: 'A sessão criada expira por tempo e inatividade, e o logout invalida o acesso.', tag: 'Session Hijacking' }, 2187 { text: 'A recuperação de senha invalida tokens anteriores pendentes e nunca revela se uma conta existe para terceiros.', tag: 'Recuperação segura' } 2188 ] 2189 } 2190 }, 2191 { 2192 stage: 'Aula 04', 2193 estimatedMinutes: 45, 2194 layout: 'grid', 2195 title: 'Autorização e controle de acesso', 2196 goal: 'Aprenda a diferença entre estar logado e ter permissão para ver, alterar, exportar ou apagar um recurso especÃfico.', 2197 focus: 'Toda ação protegida deve responder quatro perguntas: quem é a pessoa, qual recurso ela quer acessar, qual papel ela tem e se existe relação legÃtima com aquele recurso.', 2198 practice: 'Especifique as regras para aluno, gestor e parceiro acessarem certificados, pedidos e dados de alunos sem misturar permissões.', 2199 exerciseFeedback: 'O ponto central é checar permissão no backend usando usuário, papel, recurso e relação de propriedade. Se a regra depende só de esconder botão, ela ainda está fraca.', 2200 lessons: [ 2201 'Autorização decide o que uma identidade autenticada pode fazer.', 2202 'IDOR acontece quando trocar um ID dá acesso ao recurso de outra pessoa.', 2203 'Permissão precisa estar no servidor, não só na interface.' 2204 ], 2205 conceitos: [ 2206 apiConceito('Broken Access Control', 'Falha em regras de permissão que permite ver, alterar, exportar ou apagar algo que aquela pessoa não deveria acessar.', 'Use para revisar telas administrativas, área do aluno, painel de parceiro, APIs internas e qualquer rota que muda dados.', 'Se logou, pode ver tudo.', 'Aluno só acessa matrÃcula, progresso e certificado ligados ao próprio ID de sessão; parceiro só vê vendas atribuÃdas a ele; gestor vê dados administrativos conforme sessão válida.', 'Broken access control', ['permissão', 'papel', 'recurso'], { comoFunciona: ['A pessoa autentica e recebe uma identidade no sistema.', 'Cada rota protegida confere o papel dessa identidade.', 'A rota também confere se o recurso solicitado pertence ou está autorizado para aquela identidade.', 'Se a regra falhar, o servidor bloqueia antes de buscar ou alterar dados sensÃveis.'], segundoExemplo: 'Um parceiro pode ver comissão e vendas atribuÃdas ao próprio cupom, mas não deve listar todos os alunos da plataforma.', errosComuns: ['Confundir login com permissão total.', 'Validar permissão apenas na tela e esquecer a API.', 'Permitir exportação de dados sem checar o mesmo nÃvel de acesso da listagem.'] }), 2207 apiConceito('IDOR', 'Falha em que alterar um identificador na URL, query string ou payload permite acessar recurso de outra pessoa.', 'Use quando rotas usam IDs de aluno, pedido, certificado, pagamento, cupom, ticket ou arquivo.', 'Busca certificado por ID.', 'Antes de mostrar certificado por ID, confirmar que ele pertence ao aluno logado ou que a sessão é de gestor autorizado.', 'Insecure Direct Object Reference', ['id de recurso', 'dono do recurso', 'autorização'], { comoFunciona: ['A URL ou payload carrega um identificador, como certificate_id ou order_id.', 'O servidor busca o registro
2207solicitado.', 'Antes de responder, compara o dono do registro com a identidade da sessão.', 'Se não pertencer ou não houver papel autorizado, retorna bloqueio.'], segundoExemplo: 'Em /api/student/support-tickets?id=123, o ticket 123 só deve abrir se for do aluno logado; conhecer o número não prova permissão.', errosComuns: ['Achar que IDs longos ou aleatórios substituem autorização.', 'Checar apenas se o registro existe, não se pertence à pessoa logada.', 'Permitir ação em lote com IDs misturados sem validar cada item.'] }), 2208 apiConceito('Dono do recurso', 'A pessoa, conta, parceiro, turma ou organização que tem relação legÃtima com aquele registro.', 'Use para definir acesso por propriedade quando vários usuários usam a mesma aplicação.', 'Mostra os pedidos.', 'Um aluno vê apenas pedidos vinculados ao próprio cadastro, mesmo que conheça outro order_id; o gestor vê pedidos por regra administrativa registrada.', 'Resource owner', ['propriedade', 'escopo', 'registro'], { comoFunciona: ['Cada registro crÃtico guarda uma referência ao dono ou ao escopo: student_id, partner_id, organization_id ou course_plan.', 'A sessão informa quem está pedindo acesso.', 'O backend compara sessão e registro antes de responder.', 'A regra administrativa precisa ser explÃcita quando alguém pode ver recursos de terceiros.'], comparacao: 'Papel diz o tipo de usuário; dono do recurso diz a relação daquele usuário com um registro especÃfico. Um aluno e outro aluno têm o mesmo papel, mas donos diferentes.', errosComuns: ['Guardar o dono do recurso só no frontend.', 'Não definir dono para registros compartilhados, como pedidos, tickets ou certificados.', 'Deixar uma pessoa trocar o owner_id no payload para assumir recurso de outra.'] }) 2209 ], 2210 codigos: [ 2211 { codigo: '/confere-dono' }, 2212 { codigo: '/sem-id-livre' } 2213 ], 2214 scenario: { 2215 title: 'Cenário completo: certificado acessado pelo aluno certo', 2216 intro: 'Estar logado não basta; o sistema precisa confirmar papel, recurso e relação com o registro solicitado.', 2217 steps: [ 2218 { text: 'O aluno abre a página de certificado usando um token ou identificador.', tag: 'Recurso solicitado' }, 2219 { text: 'O backend identifica a sessão e descobre qual aluno está fazendo a requisição.', tag: 'Identidade autenticada' }, 2220 { text: 'O sistema busca o certificado e confere se o student_id do certificado é o mesmo da sessão.', tag: 'Dono do recurso' }, 2221 { text: 'Se o aluno trocar o ID por outro certificado, a resposta é bloqueada antes de renderizar qualquer dado.', tag: 'IDOR' }, 2222 { text: 'Gestor autenticado pode consultar certificados por uma regra administrativa separada e auditável.', tag: 'Broken Access Control' } 2223 ] 2224 } 2225 }, 2226 { 2227 stage: 'Aula 05', 2228 estimatedMinutes: 50, 2229 layout: 'grid', 2230 title: 'Injeções e execução indevida', 2231 goal: 'Entenda por que dados digitados não podem virar comando e como pedir consultas seguras, validação de entrada e saÃda renderizada sem execução indevida.', 2232 focus: 'Separe dado de comando: o usuário informa valores, mas não deve controlar SQL, HTML, JavaScript, template ou qualquer instrução interna da aplicação.', 2233 practice: 'Escreva uma especificação defensiva para proteger uma busca de alunos, um campo de observação do gestor e um comentário exibido publicamente.', 2234 exerciseFeedback: 'A resposta boa combina consulta parametrizada, validação de entrada, limite de tamanho, escaping na saÃda e testes com caracteres perigosos tratados como texto.', 2235 lessons: [ 2236 'SQL Injection acontece quando entrada externa consegue interferir na consulta ao banco.', 2237 'XSS acontece quando conteúdo externo é exibido como código executável no navegador.', 2238 'Validação de entrada e escaping de saÃda são proteções complementares: uma não substitui a outra.' 2239 ], 2240 conceitos: [ 2241 apiConceito('SQL Injection', 'Falha em que texto enviado pelo usuário altera a intenção de uma consulta ao banco de dados.', 'Use para pedir queries parametrizadas em login, busca, filtros, relatórios, checkout e qualquer rota que consulte ou grave dados.', 'Busca direto no banco com o texto digitado.', 'A busca de alunos usa parâmetros preparados, valida tamanho do termo e nunca concatena o texto digitado dentro do SQL.', 'SQL injection', ['query parametrizada', 'banco de dados', 'validação'], { comoFunciona: ['A aplicação recebe um valor externo, como busca, e-mail ou filtro.', 'Esse valor deve ser passado como parâmetro da consulta, não misturado ao texto do comando SQL.', 'O banco trata o valor como dado comum, mesmo que contenha aspas ou sÃmbolos.', 'A resposta da API não mostra erro interno de banco se algo falhar.'], segundoExemplo: 'No login, e-mail e senha são valores da consulta; eles nunca devem mudar a estrutura do SELECT.', errosComuns: ['Montar SQL por concatenação porque parece mais rápido.', 'Validar apenas no frontend e esquecer que alguém pode chamar a API direto.', 'Expor erro interno como SQLITE_CONSTRAINT ou stack trace para o usuário.'] }), 2242 apiConceito('Cross-Site Scripting', 'Falha em que conteúdo vindo de usuário, integração ou banco aparece na página e executa JavaScript indevido.', 'Use para revisar comentários, nomes exibidos, campos de descrição, mensagens de suporte, HTML salvo e qualquer conteúdo livre.', 'Mostra o texto do usuário do jeito que veio.', 'Escapar nome, observação e c
2242omentário antes de renderizar, garantindo que tags apareçam como texto e não como script.', 'XSS', ['escaping', 'HTML', 'script'], { comoFunciona: ['Uma pessoa envia conteúdo por formulário, API ou integração.', 'O sistema salva ou devolve esse conteúdo.', 'Em algum momento, a página renderiza o conteúdo no navegador.', 'Se a saÃda não for tratada para o contexto certo, o navegador pode interpretar texto como código.'], segundoExemplo: 'Um nome de aluno exibido no painel gestor também precisa escaping; não é só campo público que pode causar problema.', errosComuns: ['Achar que XSS só acontece em comentários públicos.', 'Usar innerHTML com conteúdo vindo de usuário sem escaping.', 'Sanitizar uma vez ao salvar e depois renderizar em contextos diferentes sem novo cuidado.'] }), 2243 apiConceito('Escaping', 'Tratamento que transforma caracteres especiais em texto seguro para o contexto onde serão exibidos.', 'Use quando dados externos aparecem em HTML, atributo, URL, JSON, Markdown ou texto dentro de script.', 'Limpa o texto.', 'Renderizar `<script>` como texto visÃvel, não como código executável, e tratar aspas corretamente quando o dado aparece em atributo HTML.', 'Output escaping', ['sanitização', 'contexto', 'saÃda segura'], { comoFunciona: ['Identifique onde o dado vai aparecer: HTML, atributo, URL, JSON ou outro contexto.', 'Aplique escaping próprio daquele contexto.', 'Renderize o valor tratado, nunca o texto cru vindo do usuário.', 'Teste caracteres especiais para confirmar que aparecem como texto.'], comparacao: 'Validação decide se o dado pode entrar; escaping decide como o dado pode sair sem virar código. Em muitos fluxos você precisa dos dois.', errosComuns: ['Usar o mesmo tratamento para HTML, URL e atributo como se fossem contextos iguais.', 'Chamar escaping de sanitização e achar que qualquer biblioteca resolve todo caso.', 'Escapar no lugar errado e depois concatenar novamente em HTML bruto.'] }) 2244 ], 2245 codigos: [ 2246 { codigo: '/query-parametrizada' }, 2247 { codigo: '/escapa-na-saida' } 2248 ], 2249 scenario: { 2250 title: 'Cenário completo: busca e comentário sem execução indevida', 2251 intro: 'O mesmo texto digitado pode afetar banco de dados e tela se não for tratado no contexto certo.', 2252 steps: [ 2253 { text: 'A busca de alunos recebe texto livre, mas o backend valida tamanho e usa parâmetros preparados no SQL.', tag: 'SQL Injection' }, 2254 { text: 'Um campo de observação do gestor pode conter caracteres de HTML, mas isso não deve virar código.', tag: 'Entrada externa' }, 2255 { text: 'Ao salvar, a API registra o conteúdo como dado comum e não mostra erro interno de banco em caso de falha.', tag: 'Resposta segura' }, 2256 { text: 'Ao exibir no painel, a interface escapa o conteúdo para o contexto correto.', tag: 'Escaping' }, 2257 { text: 'O teste de aceite confirma que aspas, sinais de menor/maior e tags aparecem como texto, sem execução.', tag: 'XSS' } 2258 ] 2259 } 2260 }, 2261 { 2262 stage: 'Aula 06', 2263 estimatedMinutes: 45, 2264 layout: 'timeline', 2265 title: 'CSRF, clickjacking e redirecionamentos', 2266 goal: 'Aprenda três falhas que abusam do navegador, da sessão ativa ou da confiança em links aparentemente legÃtimos.', 2267 focus: 'A aplicação precisa confirmar intenção, origem e destino antes de aceitar ações sensÃveis, renderizar dentro de outras páginas ou redirecionar o usuário.', 2268 practice: 'Especifique defesas para alterar senha, abrir o painel gestor em navegador e redirecionar o aluno depois do login.', 2269 exerciseFeedback: 'A resposta boa separa as defesas: token CSRF ou SameSite para ação sensÃvel, headers anti-frame para clickjacking e allowlist de caminhos internos para redirecionamento.', 2270 lessons: [ 2271 'CSRF tenta usar uma sessão ativa para enviar ação sem intenção real da pessoa.', 2272 'Clickjacking tenta esconder uma ação legÃtima dentro de uma interface enganosa.', 2273 'Open Redirect usa a confiança no seu domÃnio para levar o usuário a um destino perigoso.' 2274 ], 2275 sequenceCount: 3, 2276 connectors: ['intenção', 'origem', 'destino'], 2277 conceitos: [ 2278 apiConceito('CSRF', 'Ataque que tenta fazer o navegador autenticado enviar uma ação sem consentimento real do usuário.', 'Use para proteger formulários e rotas sensÃveis quando a sessão viaja automaticamente, como em cookies.', 'Confia que está logado.', 'Alterar senha exige sessão válida, confirmação da senha atual, token CSRF ou cookie SameSite adequado, e rejeita requisições sem essa proteção.', 'Cross-Site Request Forgery', ['token CSRF', 'SameSite', 'ação sensÃvel'], { comoFunciona: ['A pessoa está logada em uma aplicação legÃtima.', 'Outra página tenta induzir o navegador a enviar uma requisição para essa aplicação.', 'Como cookies podem viajar automaticamente, o servidor poderia achar que a ação é legÃtima.', 'A proteção exige um sinal de intenção/origem que a página externa não consegue produzir.'], segundoExemplo: 'Cancelar matrÃcula, alterar e-mail, trocar senha e ativar/desativar cupom são ações que merecem proteção adicional.', errosComuns: ['Achar que CSRF só afeta formulário antigo e ignorar rotas POST/PATCH/DELETE.', 'Proteger apenas a tela, mas aceitar a ação sensÃvel pela API sem token ou verificação equivalente.', 'Usar GET para ação que muda estado, como cancelar ou excluir.'] }), 2279 apiConceito('Clickjacking', 'Técnica que coloca uma página legÃtima dentro de um frame invisÃvel ou enganoso para induzir clique indevido.', 'Use para proteger painéis, checkout, login, confirmação de pagamento e ações administrativas.', 'Pode abrir dentro de qualquer site.', 'Enviar headers de segurança para impedir que o painel gestor seja exibido dentro de iframe externo e reduzir cliques enganados.', 'Clickjacking', ['iframe', 'frame-ancestors', 'X-Frame-Options'], { comoFunciona: ['Um site externo tenta carregar uma página sua dentro de um iframe.', 'A pessoa vê outra interface por cima ou uma composição enganosa.', 'O clique pode atingir um botão real da sua aplicação sem a pessoa perceber.', 'Headers como frame-ancestors bloqueiam esse encaixe fora dos domÃnios permitidos.'], segundoExemplo: 'Uma tela de "confirmar exclusão" no gestor não deve poder ser embutida por outro domÃnio.', errosComuns: ['Confiar só em JavaScript para sair do iframe.', 'Permitir qualquer origem embutir telas administrativas.', 'Esquecer que checkout e login também são telas sensÃveis.'] }), 2280 apiConceito('Open Redirect', 'Falha em que uma URL confiável redireciona para qualquer destino informado por parâmetro.', 'Use para validar links de retorno depois de login, checkout, convite, redefinição de senha ou compartilhamento.', 'Depois do login, volta para qualquer link enviado na URL.', 'Após login, aceitar retorno apenas para caminhos internos permitidos, como /painel-aluno, /gestor ou /planos, recusando URLs externas.', 'Open redirect', ['redirect', 'allowlist', 'URL de retorno'], { comoFunciona: ['A aplicação recebe um parâmetro de retorno, como ?next=.', 'Se aceitar qualquer URL externa, o domÃnio legÃtimo vira trampolim para phishing.', 'A correção compara o destino com uma allowlist de caminhos internos.', 'Quando o destino não é permitido, a aplicação usa uma rota padrão segura.'], segundoExemplo: 'Um link com domÃnio real da plataforma pode terminar levando a uma página falsa de pagamento se o redirect aceitar destino externo.', errosComuns: ['Validar apenas se a URL começa com https.', 'Permitir //dominio-externo ou URLs codificadas sem normalizar antes.', 'Usar redirect livre em links de convite e recuperação de senha.'] }) 2281 ], 2282 codigos: [ 2283 { codigo: '/acao-sensivel-protegida' }, 2284 { codigo: '/redirect-so-interno' } 2285 ], 2286 scenario: { 2287 title: 'Cenário completo: alterar senha sem cair em abuso de navegador', 2288 intro: 'A ação é legÃtima, mas precisa confirmar intenção, impedir clique enganado e val
2288idar para onde o usuário volta depois.', 2289 steps: [ 2290 { text: 'O formulário de alterar senha exige sessão válida e confirmação da senha atual.', tag: 'Ação sensÃvel' }, 2291 { text: 'A requisição inclui token CSRF ou proteção equivalente para provar que saiu da tela legÃtima.', tag: 'CSRF' }, 2292 { text: 'A rota usa método que muda estado, nunca GET, e rejeita chamadas sem proteção.', tag: 'Regra de API' }, 2293 { text: 'O painel não pode ser embutido em páginas externas invisÃveis ou enganosas.', tag: 'Clickjacking' }, 2294 { text: 'Depois do login, o retorno só aceita caminhos internos permitidos; destino externo cai numa rota padrão segura.', tag: 'Open Redirect' } 2295 ] 2296 } 2297 }, 2298 { 2299 stage: 'Aula 07', 2300 estimatedMinutes: 45, 2301 layout: 'groups', 2302 title: 'Dados sensÃveis, JWT e exposição de informações', 2303 goal: 'Entenda como vazamentos acontecem por resposta, log, token, erro ou configuração fraca.', 2304 focus: 'Antes de expor dados, pergunte quem precisa ver, por quanto tempo, em qual detalhe e o que nunca deve aparecer publicamente.', 2305 practice: 'Revise uma resposta de API de perfil do aluno e marque quais campos devem aparecer, ocultar ou ir apenas para log interno.', 2306 exerciseFeedback: 'A resposta boa evita CPF, token, segredo, stack trace e dado financeiro detalhado em respostas públicas.', 2307 lessons: [ 2308 'Dado sensÃvel exige acesso mÃnimo e justificativa clara.', 2309 'JWT mal configurado pode carregar informação demais ou validar assinatura de forma errada.', 2310 'Logs e mensagens de erro também podem vazar segredos.' 2311 ], 2312 groups: [ 2313 { title: 'Dados', desc: 'O que pode aparecer para usuário, suporte e relatório.' }, 2314 { title: 'Credenciais', desc: 'Tokens, segredos e configurações que não devem vazar.' } 2315 ], 2316 conceitos: [ 2317 apiConceito('Sensitive Data Exposure', 'Exposição indevida de dados pessoais, financeiros, tokens, segredos ou detalhes internos em telas, APIs, logs, exportações ou mensagens de erro.', 'Use para revisar respostas, logs, relatórios, exports, telas de suporte e integrações que manipulam dados de pessoas reais.', 'Retorna tudo do aluno.', 'Perfil público retorna apenas nome, e-mail e cursos ativos; CPF, hash de senha, tokens, chaves internas e dados financeiros detalhados nunca saem na resposta pública.', 'Sensitive data exposure', ['dado sensÃvel', 'log', 'resposta pública'], { grupo: 0, comoFunciona: ['A aplicação busca dados no banco para montar uma tela ou resposta de API.', 'Antes de responder, o backend escolhe apenas os campos necessários para aquele contexto.', 'Dados sensÃveis ficam mascarados, omitidos ou restritos a papéis especÃficos.', 'Logs internos também evitam registrar segredo, token, senha, CPF completo ou payload financeiro desnecessário.'], segundoExemplo: 'Uma exportação de alunos pode precisar de nome e e-mail, mas não precisa incluir hash de senha, token de convite ou histórico completo de pagamento.', errosComuns: ['Retornar o objeto inteiro do banco por conveniência.', 'Mascarar dado na tela, mas deixar o valor completo na API.', 'Gravar tokens e payloads sensÃveis em logs permanentes sem necessidade.'] }), 2318 apiConceito('JWT Misconfiguration', 'Erro na criação, conteúdo, expiração ou validação de um JWT que enfraquece autenticação e autorização.', 'Use para revisar assinatura, algoritmo, expiração, escopo, rotação e dados colocados dentro do token.', 'Guarda tudo no token.', 'JWT contém apenas identificador e escopo necessário, expira rápido, valida assinatura no servidor e nunca carrega dados sensÃveis como senha, CPF ou permissões livres para o usuário alterar.', 'JWT misconfiguration', ['token', 'assinatura', 'expiração'], { grupo: 1, comoFunciona: ['O servidor emite um token assinado após autenticação.', 'Cada requisição protegida valida assinatura, expiração e escopo.', 'O token carrega apenas dados mÃnimos para identificar a sessão ou permissão.', 'Quando o risco é alto, o sistema usa sessão revogável ou revalidação adicional.'], segundoExemplo: 'Um token de aluno pode identificar o aluno e a sessão, mas a lista de cursos ativos deve ser conferida no servidor para refletir bloqueios e expirações.', errosComuns: ['Colocar dados sensÃveis dentro do JWT porque ele parece escondido.', 'Aceitar token expirado para evitar atrito.', 'Confiar em permissões vindas do token sem conferir estado atual no banco.'] }), 2319 apiConceito('Segredo de aplicação', 'Chave privada usada para assinar tokens, chamar serviços externos, validar webhooks ou acessar recursos protegidos.', 'Use para separar segredo de código, frontend, logs, banco exportável e mensagens de erro.', 'Coloca a chave no front.', 'RESEND_API_KEY e chaves de pagamento ficam em secrets do ambiente, nunca aparecem em JavaScript público, HTML, repositório, log ou resposta de API.', 'Application secret', ['API key', 'variável de ambiente', 'credencial'], { grupo: 1, comoFunciona: ['A chave é criada no serviço externo ou ambiente de deploy.', 'O backend lÃ
2319ª a chave por variável segura em tempo de execução.', 'O frontend chama o backend, não o serviço externo diretamente com a chave privada.', 'Se houver suspeita de vazamento, a chave é rotacionada e o uso antigo é revogado.'], segundoExemplo: 'A assinatura de webhook deve ser validada com segredo no servidor; colocar esse segredo no navegador permitiria falsificar chamadas.', errosComuns: ['Comitar .env ou .dev.vars no repositório.', 'Mostrar chave em erro de configuração.', 'Usar a mesma chave para produção, sandbox e testes locais.'] }) 2320 ], 2321 codigos: [ 2322 { codigo: '/minimo-necessario' }, 2323 { codigo: '/token-sem-segredo' } 2324 ], 2325 scenario: { 2326 title: 'Cenário completo: resposta de perfil com o mÃnimo necessário', 2327 intro: 'Uma API útil não precisa devolver tudo que existe no banco.', 2328 steps: [ 2329 { text: 'O perfil do aluno retorna nome, e-mail e cursos ativos.', tag: 'Dado necessário' }, 2330 { text: 'Hash de senha, tokens, CPF completo e chaves internas ficam fora da resposta.', tag: 'Sensitive Data Exposure' }, 2331 { text: 'Se houver token de sessão, ele carrega apenas identificador e escopo mÃnimo.', tag: 'JWT Misconfiguration' }, 2332 { text: 'Chaves de envio de e-mail e pagamento vivem em variáveis de ambiente.', tag: 'Segredo de aplicação' } 2333 ] 2334 } 2335 }, 2336 { 2337 stage: 'Aula 08', 2338 estimatedMinutes: 45, 2339 layout: 'grid', 2340 title: 'Arquivos, uploads e inclusão de arquivos', 2341 goal: 'Aprenda por que upload e caminho de arquivo precisam de validação forte antes de salvar, abrir ou executar qualquer conteúdo.', 2342 focus: 'Defina tipo permitido, tamanho, armazenamento, nome seguro, varredura e regra para nunca executar arquivo enviado pelo usuário.', 2343 practice: 'Especifique um upload seguro de comprovante em PDF ou imagem, incluindo tipo, tamanho, local de armazenamento e mensagem de erro.', 2344 exerciseFeedback: 'A resposta boa não confia só na extensão; ela valida tipo real, renomeia, isola e impede execução.', 2345 lessons: [ 2346 'Upload inseguro pode virar execução de código, vazamento ou sobrescrita.', 2347 'Path Traversal tenta escapar da pasta esperada usando caminhos manipulados.', 2348 'Incluir arquivo por parâmetro é perigoso quando o usuário controla o caminho.' 2349 ], 2350 conceitos: [ 2351 apiConceito('File Upload Vulnerability', 'Falha em upload que aceita arquivo perigoso, grande demais, com tipo falso ou salvo em local onde pode ser executado ou exposto indevidamente.', 'Use para proteger comprovantes, avatares, anexos, importações, material de aula e qualquer entrada de arquivo.', 'Deixa anexar qualquer arquivo.', 'Aceitar só PDF/JPG/PNG até 5MB, validar tipo real no servidor, renomear o arquivo, salvar fora de pasta executável e negar extensões perigosas mesmo que venham disfarçadas.', 'File upload vulnerability', ['upload', 'tipo de arquivo', 'armazenamento'], { comoFunciona: ['O usuário envia um arquivo pelo navegador ou API.', 'O servidor valida tamanho, tipo real, extensão permitida e necessidade do arquivo.', 'O arquivo recebe nome interno novo e é salvo em local isolado.', 'Download ou visualização passam por permissão e não executam o conteúdo enviado.'], segundoExemplo: 'Um avatar deve virar imagem processada ou armazenada de modo seguro; o nome original do arquivo não deve decidir caminho nem tipo.', errosComuns: ['Confiar apenas na extensão .jpg.', 'Salvar upload dentro de pasta pública executável.', 'Permitir arquivo grande demais e abrir risco de consumo de armazenamento ou memória.'] }), 2352 apiConceito('Path Traversal', 'Tentativa de acessar arquivos fora da pasta permitida manipulando caminhos como ../, barras, encoding ou nomes absolutos.', 'Use quando a aplicação abre, baixa, importa ou remove arquivos por nome informado pelo usuário.', 'Baixa pelo nome do arquivo enviado na URL.', 'A API recebe um file_id, confere permissão no banco e monta internamente o caminho do arquivo, sem aceitar caminho livre na URL.', 'Path traversal', ['caminho de arquivo', '../', 'download'], { comoFunciona: ['A requisição pede um arquivo por nome, caminho ou identificador.', 'O risco aparece quando o usuário controla partes do caminho no servidor.', 'A proteção troca caminho livre por ID interno e normaliza qualquer valor necessário.', 'O servidor confirma que o arquivo final continua dentro da pasta permitida.'], segundoExemplo: 'Em vez de /download?file=../../secrets, prefira /download?id=abc123 e resolva o arquivo pelo banco.', errosComuns: ['Remover apenas a sequência ../ e esquecer variações codificadas.', 'Concatenar pasta base com texto vindo da URL.', 'Permitir apagar arquivo por caminho informado no payload.'] }), 2353 apiConceito('File Inclusion', 'Falha em que a aplicação inclui, interpreta ou executa arquivo escolhido por entrada externa.', 'Use para evitar parâmetros que definem template, página, script, idioma, tema ou arquivo interno.', 'Carrega a página pelo parâmetro.', 'Permitir apenas templates internos mapeados em allowlist, nunca caminho enviado pelo usuário, e impedir URL externa como fonte de inclusão.', 'Local/Remote File Inclusion', ['LFI', 'RFI', 'allowlist'], { comoFunciona: ['A aplicação recebe uma escolha de página, idioma, tema ou template.', 'Se essa escolha vira caminho direto, um usuário pode tentar incluir arquivo indevido.', 'A proteção converte opções ace
2353itas em nomes internos controlados pelo servidor.', 'Arquivos enviados por usuário nunca são tratados como código ou template.'], segundoExemplo: 'Um parâmetro ?template=certificado deve aceitar valores como certificado_padrao, não caminho de arquivo.', errosComuns: ['Confundir incluir arquivo com baixar arquivo.', 'Permitir URL remota como template para facilitar customização.', 'Reaproveitar upload de usuário como HTML renderizado sem isolamento.'] }) 2354 ], 2355 codigos: [ 2356 { codigo: '/upload-seguro' }, 2357 { codigo: '/sem-caminho-livre' } 2358 ], 2359 scenario: { 2360 title: 'Cenário completo: envio seguro de comprovante', 2361 intro: 'Upload seguro trata arquivo como dado externo, não como algo confiável.', 2362 steps: [ 2363 { text: 'O formulário aceita apenas PDF, JPG ou PNG dentro do tamanho permitido.', tag: 'File Upload Vulnerability' }, 2364 { text: 'O servidor valida o tipo real e troca o nome por um identificador interno.', tag: 'Armazenamento seguro' }, 2365 { text: 'Download usa ID salvo no banco, não caminho livre vindo da URL.', tag: 'Path Traversal' }, 2366 { text: 'Nenhum arquivo enviado é incluÃdo como template ou código executável.', tag: 'File Inclusion' } 2367 ] 2368 } 2369 }, 2370 { 2371 stage: 'Aula 09', 2372 estimatedMinutes: 40, 2373 layout: 'grid', 2374 title: 'SSRF e comunicação entre servidores', 2375 goal: 'Entenda riscos quando o servidor faz chamadas para URLs informadas por usuário ou integração.', 2376 focus: 'Toda chamada servidor-servidor precisa limitar destino, protocolo, rede interna e tempo de resposta.', 2377 practice: 'Descreva uma importação por URL segura, impedindo acesso a localhost, IP interno e metadados da nuvem.', 2378 exerciseFeedback: 'A resposta boa usa allowlist de domÃnio, bloqueio de rede interna, timeout e log do destino chamado.', 2379 lessons: [ 2380 'SSRF usa o servidor como intermediário para acessar destinos proibidos.', 2381 'URLs livres são perigosas em importação, preview, webhook configurável e captura de imagem.', 2382 'Allowlist é mais segura do que tentar bloquear alguns casos conhecidos.' 2383 ], 2384 conceitos: [ 2385 apiConceito('SSRF', 'Falha em que o servidor é induzido a chamar um endereço interno, restrito ou inesperado a partir de uma URL informada externamente.', 'Use quando usuário informa URL para importar, pré-visualizar, capturar imagem, configurar webhook ou sincronizar dados.', 'Busca qualquer URL que o usuário mandar.', 'Importação aceita apenas domÃnios aprovados, bloqueia localhost, IP privado e metadados internos, e registra qual destino foi chamado.', 'Server-Side Request Forgery', ['URL externa', 'rede interna', 'allowlist'], { comoFunciona: ['A aplicação recebe uma URL externa para buscar dados.', 'O servidor, não o navegador do usuário, faz a chamada.', 'Se não houver restrição, a URL pode apontar para rede interna ou metadados do ambiente.', 'A proteção valida destino final, bloqueia redes internas e usa allowlist quando possÃvel.'], segundoExemplo: 'Um preview de imagem por URL pode virar risco se o servidor aceitar endereço interno em vez de apenas domÃnios de mÃdia permitidos.', errosComuns: ['Bloquear só localhost escrito por extenso e esquecer 127.0.0.1, IPv6, redirecionamentos e IP privado.', 'Validar a URL antes, mas seguir redirect para destino proibido depois.', 'Permitir qualquer protocolo em vez de limitar a HTTPS.'] }), 2386 apiConceito('Allowlist', 'Lista explÃcita de destinos, valores, protocolos ou formatos permitidos antes de executar uma ação.', 'Use quando a escolha segura é pequena, conhecida e controlável pela aplicação.', 'Bloqueia alguns domÃnios ruins.', 'Permitir webhooks e importações apenas para domÃnios cadastrados, verificados e necessários para o produto.', 'Allowlist', ['lista permitida', 'validação', 'destino confiável'], { comoFunciona: ['O time define o conjunto de opções realmente necessárias.', 'A entrada externa é normalizada antes de comparar.', 'A aplicação aceita apenas o que está na lista permitida.', 'Qualquer valor fora da lista cai em erro claro e registro interno.'], segundoExemplo: 'No retorno pós-login, permitir /painel-aluno e /gestor é mais seguro que tentar bloquear todos os domÃnios externos possÃveis.', errosComuns: ['Criar blockl
2386ist infinita de casos ruins.', 'Comparar texto sem normalizar domÃnio, protocolo e redirects.', 'Deixar operador cadastrar qualquer domÃnio sem verificação.'] }), 2387 apiConceito('Timeout', 'Limite de tempo para uma chamada externa responder antes de ser encerrada com falha controlada.', 'Use para evitar travamento, fila presa, consumo abusivo de recursos e experiência ruim.', 'Espera até responder.', 'A chamada para integração externa expira em 5 segundos, registra falha parcial e permite reprocessamento controlado.', 'Request timeout', ['resiliência', 'chamada externa', 'limite'], { comoFunciona: ['O servidor inicia uma chamada para outro serviço.', 'Um temporizador define quanto tempo a aplicação aceita esperar.', 'Se estourar o limite, a chamada é cancelada ou tratada como falha.', 'O usuário recebe mensagem clara e o sistema registra o evento para tentativa futura.'], segundoExemplo: 'Na validação de pagamento, timeout evita deixar checkout pendurado se o gateway demorar demais.', errosComuns: ['Não definir timeout e prender o processo indefinidamente.', 'Repetir chamadas sem limite e piorar uma instabilidade externa.', 'Mostrar erro técnico cru em vez de registrar internamente e orientar o usuário.'] }) 2388 ], 2389 codigos: [ 2390 { codigo: '/allowlist-destino' }, 2391 { codigo: '/timeout-externo' } 2392 ], 2393 scenario: { 2394 title: 'Cenário completo: importar dados por URL com destino controlado', 2395 intro: 'Quando o servidor chama uma URL externa, ele precisa saber para onde está indo.', 2396 steps: [ 2397 { text: 'O usuário informa uma URL para importar um arquivo ou feed.', tag: 'Ponto de entrada' }, 2398 { text: 'O backend aceita apenas domÃnios previamente permitidos.', tag: 'Allowlist' }, 2399 { text: 'Endereços internos, localhost e metadados de nuvem são bloqueados.', tag: 'SSRF' }, 2400 { text: 'A chamada tem timeout e registro do destino consultado.', tag: 'Timeout' } 2401 ] 2402 } 2403 }, 2404 { 2405 stage: 'Aula 10', 2406 estimatedMinutes: 45, 2407 layout: 'timeline', 2408 title: 'Race Condition e falhas de fluxo', 2409 goal: 'Aprenda como ações simultâneas podem duplicar cobrança, matrÃcula, cupom, estoque ou qualquer recurso limitado.', 2410 focus: 'A aplicação precisa tratar repetição, concorrência e ordem dos eventos nas ações crÃticas.', 2411 practice: 'Descreva como impedir que duas pessoas usem o último cupom disponÃvel ao mesmo tempo.', 2412 exerciseFeedback: 'A resposta boa define identificador único, trava/transação, rechecagem final e mensagem para quem perdeu a disputa.', 2413 lessons: [ 2414 'Race condition acontece quando a ordem de eventos simultâneos muda o resultado.', 2415 'Duplo clique, webhook repetido e estoque limitado são sinais de alerta.', 2416 'Idempotência e transação reduzem duplicidade e inconsistência.' 2417 ], 2418 sequenceCount: 4, 2419 connectors: ['checa', 'reserva', 'confirma', 'registra'], 2420 conceitos: [ 2421 apiConceito('Race Condition', 'Falha causada por duas ou mais operações disputando o mesmo recurso ao mesmo tempo e produzindo um resultado incorreto.', 'Use em cupom limitado, matrÃcula, estoque, saldo, vaga, pagamento, reembolso e emissão de certificado.', 'Se tiver vaga, cadastra.', 'Reservar a última vaga dentro de uma transação, revalidar disponibilidade antes de confirmar e responder claramente para quem chegou depois.', 'Race condition', ['concorrência', 'operação simultânea', 'recurso limitado'], { comoFunciona: ['Duas requisições chegam quase ao mesmo tempo.', 'As duas leem o mesmo estado inicial, como "1 cupom restante".', 'Sem trava ou transação, as duas podem confirmar a ação.', 'A correção torna a checagem e a reserva uma operação única e consistente.'], segundoExemplo: 'Em certificado, duas abas não deveriam emitir dois certificados diferentes para a mesma conclusão se a regra permite apenas um registro ativo.', errosComuns: ['Testar só com um usuário e achar que o fluxo está seguro.', 'Conferir disponibilidade antes da transação e c
2421onfirmar depois sem revalidar.', 'Resolver no botão desabilitado do frontend, mas deixar a API aceitar duplicidade.'] }), 2422 apiConceito('Transação', 'Bloco de operações que deve confirmar tudo junto ou desfazer tudo se qualquer parte falhar.', 'Use em pagamento, pedido, matrÃcula, estoque, cupom, certificado e qualquer fluxo que grava em mais de uma tabela.', 'Salva em várias tabelas e torce para dar certo.', 'Criar pedido, itens do pedido e matrÃcula pendente na mesma transação para evitar cobrança sem matrÃcula ou matrÃcula sem pedido.', 'Database transaction', ['atomicidade', 'rollback', 'consistência'], { comoFunciona: ['O servidor inicia uma transação no banco.', 'Executa todas as gravações relacionadas dentro desse bloco.', 'Se uma etapa falha, desfaz o conjunto inteiro.', 'Se tudo passa, confirma o estado final de uma vez.'], segundoExemplo: 'Ao aplicar cupom no checkout, pedido e desconto precisam nascer consistentes para não cobrar valor diferente do registrado.', errosComuns: ['Gravar pedido antes e matrÃcula depois sem plano de falha intermediária.', 'Misturar chamada externa lenta dentro de transação de banco.', 'Não criar restrição única quando o banco poderia impedir duplicidade.'] }), 2423 apiConceito('Idempotência', 'Garantia de que repetir a mesma ação não duplica o resultado nem causa efeito colateral repetido.', 'Use em botões, webhooks, pagamentos, reprocessamentos, envio de e-mail e criação de registros crÃticos.', 'Se clicar duas vezes, cria duas matrÃculas.', 'Usar chave idempotente por cobrança ou evento para não criar duas matrÃculas, dois e-mails ou dois pedidos para a mesma confirmação.', 'Idempotency', ['duplicidade', 'evento repetido', 'chave única'], { comoFunciona: ['Cada ação crÃtica recebe um identificador único estável.', 'Antes de processar, o servidor verifica se aquele identificador já foi tratado.', 'Se já foi, retorna o resultado conhecido ou sucesso sem repetir efeito.', 'Se ainda não foi, processa e registra o identificador.'], segundoExemplo: 'Webhook de pagamento pode chegar mais de uma vez; a plataforma deve reconhecer o payment_id/event_id e não liberar o curso duas vezes.', errosComuns: ['Gerar uma chave nova a cada tentativa, tornando a idempotência inútil.', 'Aplicar idempotência só no frontend.', 'Responder erro para evento repetido quando o melhor comportamento é sucesso sem repetir ação.'] }) 2424 ], 2425 codigos: [ 2426 { codigo: '/transacao-unica' }, 2427 { codigo: '/chave-idempotente' } 2428 ], 2429 scenario: { 2430 title: 'Cenário completo: último cupom disponÃvel', 2431 intro: 'Dois usuários podem tentar consumir o mesmo benefÃcio ao mesmo tempo.', 2432 steps: [ 2433 { text: 'Duas compras chegam quase juntas usando o mesmo cupom limitado.', tag: 'Race Condition' }, 2434 { text: 'O servidor abre uma transação, confere disponibilidade e reserva uma vez só.', tag: 'Transação' }, 2435 { text: 'A segunda compra recebe mensagem clara de cupom indisponÃvel.', tag: 'Rechecagem final' }, 2436 { text: 'Se o pagamento mandar webhook repetido, a matrÃcula não duplica.', tag: 'Idempotência' } 2437 ] 2438 } 2439 }, 2440 { 2441 stage: 'Aula 11', 2442 estimatedMinutes: 40, 2443 layout: 'grid', 2444 title: 'Como reportar, priorizar e corrigir vulnerabilidades', 2445 goal: 'Aprenda a transformar uma descoberta de segurança em relato claro, priorização e plano de correção sem sensacionalismo.', 2446 focus: 'Um bom relatório explica evidência, impacto, passos de reprodução autorizados, severidade, correção sugerida e reteste.', 2447 practice: 'Escreva um relatório curto para IDOR em certificado, incluindo impacto, passos, evidência e correção esperada.', 2448 exerciseFeedback: 'A resposta boa permite corrigir e retestar sem expor dados reais nem incentivar exploração fora do escopo.', 2449 lessons: [ 2450 'Evidência boa prova o problema sem aumentar o dano.', 2451 'Severidade depende de impacto, alcance e facilidade de exploração.', 2452 'Correção só termina depois do reteste.' 2453 ], 2454 conceitos: [ 2455 apiConceito('Relatório de vulnerabilidade', 'Documento que descreve uma falha de segurança com contexto, impacto, evidência, passos autorizados de reprodução e sugestão de correção.', 'Use para comunicar segurança a de
2455senvolvimento, produto, suporte, jurÃdico e gestão sem transformar o achado em alarme solto.', 'Tem um bug grave no certificado.', 'IDOR permite aluno A tentar abrir certificado de aluno B trocando o ID; impacto: exposição indevida de dados de certificado; correção esperada: checar ownership no backend antes de responder.', 'Vulnerability report', ['evidência', 'impacto', 'reprodução'], { comoFunciona: ['Dê um tÃtulo claro para a falha.', 'Explique onde ela acontece e qual usuário/perfil é afetado.', 'Mostre evidência mÃnima, usando conta de teste ou dados fictÃcios.', 'Descreva impacto, correção esperada e como retestar depois.'], segundoExemplo: 'Em vez de "login inseguro", escreva: "Rate limit ausente no login do gestor permite tentativas repetidas de senha sem bloqueio temporário".', errosComuns: ['Relatar só a técnica sem explicar impacto no negócio.', 'Colar dados reais sensÃveis como evidência.', 'Misturar várias falhas diferentes em um único relatório sem prioridade.'] }), 2456 apiConceito('Severidade', 'Classificação da urgência de uma vulnerabilidade considerando impacto, exposição, facilidade de abuso, quantidade de pessoas afetadas e controles existentes.', 'Use para ordenar correções sem tratar tudo como crÃtico nem empurrar risco sério para depois.', 'Arruma quando der.', 'Prioridade alta para falha que expõe dados pessoais sem autenticação; prioridade média para falha restrita a gestor autenticado com baixo impacto e trilha de auditoria.', 'Severity', ['prioridade', 'impacto', 'risco'], { comoFunciona: ['Avalie que dado, dinheiro, acesso ou operação pode ser afetado.', 'Veja se a falha exige login, papel especÃfico ou conhecimento difÃcil.', 'Estime quantas pessoas/registros podem ser atingidos.', 'Classifique urgência e combine prazo realista de correção.'], comparacao: 'Risco é o problema em si; severidade é a etiqueta usada para decidir ordem de correção. Um bug pode ser tecnicamente interessante e ainda ter severidade baixa.', errosComuns: ['Chamar tudo de crÃtico e perder credibilidade.', 'Baixar severidade só porque "ninguém explorou ainda".', 'Ignorar contexto: produção, sandbox, dados reais e dados fictÃcios têm pesos diferentes.'] }), 2457 apiConceito('Reteste', 'Nova verificação após a correção para confirmar que a falha foi resolvida e que a proteção não quebrou o fluxo legÃtimo.', 'Use antes de fechar incidente, publicar release ou marcar uma correção de segurança como concluÃda.', 'Já corrigiu, pode fechar.', 'Repetir o fluxo autorizado depois do patch e confirmar que outro aluno recebe 403 ao tentar acessar certificado que não pertence a ele, enquanto o dono legÃtimo continua conseguindo abrir.', 'Retest', ['validação', 'correção', 'QA'], { comoFunciona: ['Pegue os mesmos passos autorizados do relatório.', 'Execute novamente depois da correção.', 'Confirme que o abuso foi bloqueado.', 'Confirme também que o uso legÃtimo continua funcionando.', 'Registre resultado, data, ambiente e evidência final.'], segundoExemplo: 'Após criar rate limit, teste tanto várias tentativas inválidas quanto um login correto depois do perÃodo de bloqueio.', errosComuns: ['Retestar só o caso de ataque e esquecer o fluxo normal.', 'Testar em ambiente diferente daquele em que a correção foi aplicada.', 'Fechar o item sem registrar evidência do resultado.'] }) 2458 ], 2459 codigos: [ 2460 { codigo: '/relato-claro' }, 2461 { codigo: '/retesta-os-dois-lados' } 2462 ], 2463 scenario: { 2464 title: 'Cenário completo: relato de IDOR sem expor dado real', 2465 intro: 'O relatório precisa provar o problema e ajudar a corrigir, sem aumentar o dano.', 2466 steps: [ 2467 { text: 'O achado descreve que trocar um ID permite tentar abrir certificado de outro aluno.', tag: 'Relatório de vulnerabilidade' }, 2468 { text: 'A evidência usa contas de teste, oculta dados pessoais e captura apenas o necessário.', tag: 'Evidência responsável' },
2469 { text: 'A severidade considera exposição de dados, facilidade de abuso, ambiente e alcance.', tag: 'Severidade' }, 2470 { text: 'A correção esperada é checar ownership no backend antes de responder.', tag: 'Plano de correção' }, 2471 { text: 'Depois do patch, o mesmo teste deve receber 403, e o certificado do próprio aluno deve continuar abrindo.', tag: 'Reteste' } 2472 ] 2473 } 2474 }, 2475 { 2476 stage: 'Aula 12', 2477 estimatedMinutes: 50, 2478 layout: 'grid', 2479 title: 'Projeto final defensivo', 2480 goal: 'Monte um checklist de revisão defensiva para uma aplicação web real, conectando todos os conceitos do curso.', 2481 focus: 'Feche o curso com um plano de revisão que cubra login, permissão, entrada, dados, arquivos, integrações, concorrência e resposta a falhas.', 2482 practice: 'Crie um checklist de segurança para checkout + área do aluno + gestor, com pelo menos uma verificação por tema do curso.', 2483 exerciseFeedback: 'O projeto fica pronto quando alguém consegue aplicar o checklist, registrar evidências e priorizar correções.', 2484 lessons: [ 2485 'Checklist defensivo transforma teoria em rotina de revisão.', 2486 'Cada item deve ter critério observável de aprovação.', 2487 'Segurança melhora por ciclos: revisar, corrigir, retestar e registrar.' 2488 ], 2489 conceitos: [ 2490 apiConceito('Checklist defensivo', 'Lista prática de verificações de segurança para revisar uma aplicação antes de publicar, depois de uma mudança sensÃvel ou em ciclos periódicos.', 'Use para organizar revisão recorrente por área do sistema: login, permissão, entrada, dados, arquivos, integrações, concorrência, logs e headers.', 'Confere segurança geral.', 'Checklist inclui: rotas protegidas exigem sessão; aluno não acessa recurso de outro; entradas são validadas no backend; uploads são isolados; webhooks têm idempotência; ações crÃticas têm log.', 'Security checklist', ['revisão', 'critérios de aceite', 'controle'], { comoFunciona: ['Divida a aplicação por fluxos crÃticos.', 'Para cada fluxo, liste riscos aprendidos no curso.', 'Transforme cada risco em uma pergunta verificável.', 'Registre resultado: ok, pendente, não aplicável ou precisa decisão.', 'Revise de novo depois das correções.'], segundoExemplo: 'No Como Pedir, um checklist mÃnimo cobre checkout, login do aluno, login do gestor, certificados, cupons, webhooks e painel de parceiros.', errosComuns: ['Criar checklist genérico demais, impossÃvel de testar.', 'Usar checklist uma vez e abandonar depois do deploy.', 'Marcar item como ok sem evidência observável.'] }), 2491 apiConceito('Critério de aceite', 'Condição objetiva que mostra se uma proteção foi implementada corretamente e pode ser validada por teste ou revisão.', 'Use para evitar tarefas vagas como "melhorar segurança", "proteger login" ou "deixar upload seguro".', 'Melhora o login.', 'Após 5 tentativas inválidas em 60 segundos, a API retorna bloqueio temporário, mantém mensagem pública genérica e registra evento de auditoria.', 'Acceptance criteria', ['teste', 'validação', 'pronto'], { comoFunciona: ['Comece com o risco que precisa ser reduzido.', 'Defina comportamento esperado em sucesso e falha.', 'Inclua limite, mensagem, registro ou permissão quando for relevante.', 'Escreva como alguém vai validar o resultado.', 'Só aceite a entrega quando o critério puder ser observado.'], segundoExemplo: 'Para IDOR: "aluno A recebe 403 ao acessar pedido do aluno B; aluno B continua acessando o próprio pedido".', errosComuns: ['Aceitar critério subjetivo como "ficou seguro".', 'Descrever só o caminho feliz e esquecer o abuso que deve ser bloqueado.', 'Não combinar mensagem de erro e registro interno.'] }), 2492 apiConceito('Plano de correção', 'Sequência priorizada de mudanças para reduzir riscos encontrados, com responsável, prazo, ambiente, validação e ordem de execução.', 'Use quando há várias falhas e é preciso decidir o que corrigir primeiro sem paralisar o produto.', 'Corrige tudo.', 'Corrigir primeiro acesso indevido sem login, depois vazamento de dados em log, depois endurecer headers; cada item tem dono, critério de aceite e reteste.', 'Remediation plan', ['priorização', 'responsável', 'reteste'], { comoFunciona: ['Agrupe achados por severi
2492dade e área afetada.', 'Escolha correções que reduzem maior impacto primeiro.', 'Defina responsável, prazo e ambiente de validação.', 'Aplique mudanças pequenas e verificáveis.', 'Reteste e registre o fechamento de cada item.'], segundoExemplo: 'Se checkout tem race condition e sitemap tem cabeçalho faltando, a race condition entra antes porque pode afetar pagamento e acesso.', errosComuns: ['Tentar corrigir tudo de uma vez e aumentar risco de regressão.', 'Começar pelo item mais fácil quando existe falha crÃtica aberta.', 'Não reservar tempo para reteste depois do patch.'] }) 2493 ], 2494 codigos: [ 2495 { codigo: '/checklist-por-fluxo' }, 2496 { codigo: '/prioriza-por-impacto' } 2497 ], 2498 scenario: { 2499 title: 'Cenário completo: checklist final antes de publicar', 2500 intro: 'O fechamento do curso vira um material que pode ser usado numa aplicação real.', 2501 steps: [ 2502 { text: 'A revisão começa pelos fluxos crÃticos: checkout, login, sessão, permissões, certificados e painel gestor.', tag: 'Checklist defensivo' }, 2503 { text: 'Cada item vira pergunta verificável: "sem sessão recebe 401?", "outro aluno recebe 403?", "webhook repetido não duplica?".', tag: 'Critério de aceite' }, 2504 { text: 'Falhas são ordenadas por impacto, exposição e facilidade de exploração.', tag: 'Plano de correção' }, 2505 { text: 'Cada correção tem responsável, ambiente, prazo e evidência esperada.', tag: 'Execução' }, 2506 { text: 'Depois do ajuste, o time retesta o abuso e o fluxo legÃtimo, registra o resultado e só então fecha o item.', tag: 'Ciclo defensivo' } 2507 ] 2508 } 2509 }, 2510 { 2511 stage: 'Aula 13', 2512 estimatedMinutes: 30, 2513 layout: 'grid', 2514 title: 'Códigos Secretos: a régua de segurança do curso inteiro', 2515 goal: 'Aula bônus. Recapitula as 12 aulas e reúne os 24 comandos que cobrem risco, entrada, autenticação, acesso, injeção, navegador, dados sensÃveis, arquivos, SSRF, concorrência, relato e correção.', 2516 focus: 'Antes de aprovar um pedido de sistema ou revisar um código, passe a régua: tem ponto de entrada não validado? a rota confere sessão e dono do recurso? a saÃda está protegida contra script? existe chance de duplicidade ou corrida? o relato tem impacto e correção esperada?', 2517 practice: 'Pegue uma funcionalidade real que você precisa revisar esta semana. Rode pelo menos 5 códigos desta lista sobre ela e junte tudo num checklist só.', 2518 exerciseFeedback: 'Não existe resposta única. O que importa: o checklist final não deixa buraco â cada código aplicado virou uma verificação especÃfica (sessão, dono do recurso, validação de entrada, escaping, transação, allowlist), não uma frase genérica como "ficou seguro".', 2519 lessons: [ 2520 'Reconheça, num pedido ou código pronto, quais riscos já foram tratados e quais ficaram de fora.', 2521 'Monte a régua de revisão defensiva que você vai usar em qualquer aplicação daqui pra frente.', 2522 'Combine vários códigos num checklist único, sem repetir nem deixar lacuna.' 2523 ], 2524 conceitos: [], 2525 bonus: true 2526 } 2527]; 2528 2529const dadosInformacoesJourney = [ 2530 { 2531 stage: 'Aula 01', 2532 layout: 'grid', 2533 title: 'Cadastro e regras de campo', 2534 goal: 'Aprenda o vocabulário básico de como um sistema recebe e guarda uma informação nova: o que é um cadastro, quando um campo é obrigatório, quando ele não pode se repetir, e como o sistema confere se o valor digitado faz sentido.', 2535 focus: 'Antes de pedir uma tela de cadastro, pergunte: quais campos são realmente obrigatórios? Algum deles não pode se repetir entre registros diferentes? Existe um formato especÃfico que o valor precisa seguir?', 2536 practice: 'Escolha um cadastro que você usa no dia a dia (cliente, produto, funcionário) e escreva: quais campos são obrigatórios, qual campo não pode se repetir entre registros, e qual validação de formato os campos mais importantes precisam ter.', 2537 exerciseFeedback: 'Não existe resposta única aqui â o que importa é cada regra estar especÃfica: quais campos exatamente são obrigatórios (não "os principais"), qual valor não pode se repetir e o que acontece se alguém tentar repetir, e qual é o formato exato esperado em cada validação. Releia e veja se um dev entenderia sem perguntar nada de volta.', 2538 lessons: [ 2539 'Aprenda o que realmente acontece quando um cadastro é criado.', 2540 'Veja a diferença entre um campo obrigatório e um campo que precisa ser único.', 2541 'Pratique como descrever a validação de um campo sem deixar o formato em aberto.' 2542 ], 2543 conceitos: [ 2544 { 2545 nome: 'Cadastro', 2546 oQueE: 'O ato de criar um novo registro dentro do sistema, guardando pela primeira vez as informações de algo ou alguém â é a porta de entrada de qualquer dado que vai existir no sistema.', 2547 quandoUsar: 'Use sempre que o sistema precisa passar a lembrar de algo que ainda não existe nele: um cliente novo, um produto novo, uma reserva nova.', 2548 pedidoConfuso: 'Cria lá um jeito de adicionar cliente novo.',
2549 pedidoClaro: 'A tela "Novo cliente" pede nome, e-mail e telefone. Ao salvar, o sistema cria um registro novo na base de clientes, com um identificador único gerado automaticamente e a data de criação registrada.', 2550 comoFunciona: [ 2551 'O usuário preenche os campos do formulário de cadastro.', 2552 'Ao confirmar, o sistema confere se os campos obrigatórios e as validações passaram.', 2553 'Se passou, cria um registro novo com um identificador único e guarda a data/hora da criação.', 2554 'Se não passou, mostra o que falta corrigir sem criar nada.' 2555 ], 2556 segundoExemplo: 'Um app de tarefas cria um novo registro de tarefa assim que você digita o tÃtulo e aperta Enter â mesmo sem preencher prazo ou descrição, que são opcionais.', 2557 errosComuns: [ 2558 'Não deixar claro o que é obrigatório vs. opcional no pedido, fazendo o dev adivinhar.', 2559 'Esquecer de pedir o que acontece quando o cadastro dá certo (confirmação, redirecionamento).' 2560 ], 2561 termoTecnico: 'Cadastro (create record)', 2562 termosRelacionados: ['criar registro', 'novo registro', 'inserção de dados'] 2563 }, 2564 { 2565 nome: 'Campo obrigatório', 2566 oQueE: 'Uma informação que o sistema exige estar preenchida antes de aceitar o cadastro ou a alteração â sem ela, a ação não é permitida.', 2567 quandoUsar: 'Use quando o sistema não consegue funcionar direito sem aquela informação â um pedido sem endereço de entrega, uma conta sem e-mail de contato.', 2568 pedidoConfuso: 'Não deixa salvar sem preencher os principais.', 2569 pedidoClaro: 'Os campos "Nome" e "E-mail" são obrigatórios no cadastro de cliente. Enquanto estiverem vazios, o botão "Salvar" fica desabilitado e aparece "Campo obrigatório" em vermelho abaixo de cada um.', 2570 comoFunciona: [ 2571 'Você define quais campos não podem ficar vazios.', 2572 'O sistema confere isso antes de salvar qualquer coisa.', 2573 'Se algum obrigatório estiver vazio, bloqueia o salvamento e aponta exatamente qual campo falta.', 2574 'Só libera o salvamento quando todos os obrigatórios estão preenchidos.' 2575 ], 2576 errosComuns: [ 2577 'Marcar campo demais como obrigatório, tornando o cadastro cansativo sem necessidade real.', 2578 'Não avisar QUAL campo está faltando, só dizer "preencha os campos obrigatórios" de forma genérica.' 2579 ], 2580 termoTecnico: 'Campo obrigatório (required field)', 2581 termosRelacionados: ['campo requerido', 'preenchimento obrigatório', 'validação de presença'] 2582 }, 2583 { 2584 nome: 'Campo único', 2585 oQueE: 'Uma informação que não pode se repetir entre dois registros diferentes â o sistema impede cadastrar duas vezes o mesmo valor nesse campo.', 2586 quandoUsar: 'Use quando duplicar aquele valor causaria confusão ou erro real â dois clientes com o mesmo e-mail, dois produtos com o mesmo código.', 2587 quandoNaoUsar: 'Não use em campos onde repetir é normal e esperado, como o campo "Cidade" num cadastro de endereço â várias pessoas moram na mesma cidade sem problema nenhum.', 2588 pedidoConfuso: 'Não deixa cadastrar o mesmo e-mail duas vezes.', 2589 pedidoClaro: 'O campo "E-mail" não pode se repetir entre clientes. Se alguém tentar cadastrar um e-mail que já existe, o sistema bloqueia e mostra "Este e-mail já está cadastrado" em vez de criar um segundo registro.', 2590 comoFunciona: [ 2591 'Você define qual campo não pode ter valor repetido.', 2592 'Ao tentar salvar, o sistema confere se já existe outro registro com o mesmo valor nesse campo.', 2593 'Se existir, bloqueia e explica o motivo.', 2594 'Se não existir, salva normalmente.' 2595 ], 2596 segundoExemplo: 'Um sistema de cupons de desconto não deixa cadastrar dois cupons com o mesmo código â o segundo cadastro é bloqueado com "Já existe um cupom com este código".', 2597 termoTecnico: 'Campo único (unique constraint)', 2598 termosRelacionados: ['restrição de unicidade', 'valor duplicado', 'chave única'] 2599 }, 2600 { 2601 nome: 'Validação de campo', 2602 oQueE: 'Uma regra que confere se o valor digitado num campo está no formato ou dentro dos limites esperados, antes de aceitar aquele dado.', 2603 quandoUsar: 'Use sempre que um campo tem um formato especÃfico esperado â CPF, e-mail, telefone, ou um valor numérico que precisa ficar dentro de uma faixa.', 2604 pedidoConfuso: 'Confere se o CPF tá certo.', 2605 pedidoClaro: 'O campo "CPF" precisa ter 11 dÃgitos e passar pelo cálculo de dÃgito verificador. Se o valor for inválido, mostrar "CPF inválido" embaixo do campo assim que o usuário sair dele, sem deixar salvar o formulário inteiro.', 2606 comoFunciona: [ 2607 'Você define a regra de formato ou limite esperado pro campo.', 2608 'O sistema confere o valor digitado contra essa regra.', 2609 'Se não bater, mostra uma mensagem especÃfica explicando o que está errado.', 2610 'Se bater, aceita o valor normalmente.' 2611 ], 2612 segundoExemplo: 'Um campo "Quantidade" numa loja online só aceita números inteiros entre 1 e 99 â digitar "0" ou "abc" mostra "Digite um número entre 1 e 99".', 2613 errosComuns: [ 2614 'Validar só no clique de salvar, obrigando o usuário a de
2614scobrir todos os erros de uma vez no final.', 2615 'Mostrar mensagem de erro genérica ("valor inválido") em vez de explicar o formato esperado.' 2616 ], 2617 termoTecnico: 'Validação de campo (field validation)', 2618 termosRelacionados: ['formato esperado', 'regra de validação', 'checagem de dado'] 2619 } 2620 ], 2621 codigos: [ 2622 { codigo: '/obrigatorio-ou-nao' }, 2623 { codigo: '/campo-unico' } 2624 ] 2625 }, 2626 { 2627 stage: 'Aula 02', 2628 layout: 'diagram', 2629 diagramCount: 1, 2630 diagramNodeLeft: 'Um cadastro', 2631 diagramNodeRight: 'Outro cadastro', 2632 diagramIntro: 'Como uma informação se liga a outra · clique na conexão pra ver o conteúdo completo', 2633 diagramTraitsCaption: 'Um problema que a boa modelagem evita · não é sobre a conexão em si', 2634 title: 'Dados que se conectam', 2635 goal: 'Aprenda a descrever quando uma informação depende de outra pra fazer sentido, e o problema real que aparece quando a mesma coisa acaba registrada duas vezes sem querer.', 2636 focus: 'Antes de pedir uma tela ou funcionalidade, pergunte: essa informação faz sentido sozinha, ou ela pertence a outra? Se um cadastro for apagado, o que acontece com quem depende dele? Existe risco de a mesma pessoa/coisa ser cadastrada duas vezes?', 2637 practice: 'Pegue dois cadastros do seu sistema que se conectam (um pedido e um cliente, por exemplo) e descreva: como um se liga ao outro, e o que acontece se tentarem cadastrar a mesma pessoa/coisa de novo.', 2638 exerciseFeedback: 'Não existe resposta única aqui â o que importa é ficar claro qual lado "pertence" ao outro (um pedido pertence a um cliente, não o contrário) e o que exatamente conta como duplicado (mesmo CPF? mesmo e-mail? nome parecido?). Releia e veja se a regra de "isso é a mesma pessoa/coisa" está especÃfica o bastante pra um dev implementar.', 2639 lessons: [ 2640 'Aprenda a diferença entre uma informação independente e uma que depende de outra pra existir.', 2641 'Veja por que "relacionamento" não é sobre sistemas se conectando, é sobre dados dentro do mesmo sistema se referenciando.', 2642 'Pratique como descrever o que conta como registro duplicado antes que isso vire um problema real.' 2643 ], 2644 conceitos: [ 2645 { 2646 nome: 'Relacionamento entre informações', 2647 icon: '<path d="M10 13a5 5 0 0 0 7 7l3-3a5 5 0 0 0-7-7"/><path d="M14 11a5 5 0 0 0-7-7L4 7a5 5 0 0 0 7 7"/>', 2648 oQueE: 'Quando um dado se refere a outro pra fazer sentido completo â um pedido pertence a um cliente, uma resposta pertence a um formulário, um comentário pertence a um post.', 2649 quandoUsar: 'Use sempre que uma informação sozinha fica incompleta sem saber a quem ou a que ela pertence â praticamente todo cadastro do mundo real se conecta a outro de alguma forma.', 2650 pedidoConfuso: 'Liga o pedido no cliente certo.', 2651 pedidoClaro: 'Todo pedido deve estar vinculado a exatamente um cliente. Ao abrir o pedido, o sistema mostra nome e histórico desse cliente. Se o cliente for excluÃdo, os pedidos antigos continuam existindo, só mostram "Cliente removido" no lugar do nome.', 2652 comoFunciona: [ 2653 'Você identifica quais dados dependem de outros pra fazer sentido.', 2654 'Cada registro dependente guarda uma referência ao registro do qual ele depende.', 2655 'Ao consultar o dado dependente, o sistema busca junto as informações do outro lado da relação.', 2656 'Você decide o que acontece do lado dependente se o outro lado for removido â normalmente não some, só perde a referência.' 2657 ], 2658 segundoExemplo: 'Numa plataforma de cursos, cada certificado se relaciona a um aluno e a um curso especÃfico â sem os dois, o certificado não faz sentido sozinho.', 2659 errosComuns: [
2660 'Não decidir o que acontece do lado dependente quando o outro lado é removido, deixando dado "órfão" sem explicação.', 2661 'Duplicar a mesma informação nos dois lados em vez de relacionar, criando risco de ficarem desincronizadas.' 2662 ], 2663 termoTecnico: 'Relacionamento entre informações (data relationship)', 2664 termosRelacionados: ['referência', 'vÃnculo entre registros', 'chave estrangeira'] 2665 }, 2666 { 2667 nome: 'Registro duplicado', 2668 icon: '<rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>', 2669 oQueE: 'Quando a mesma pessoa, produto ou informação real acaba criada como dois (ou mais) registros diferentes no sistema, geralmente sem querer.', 2670 quandoUsar: 'Use quando existe risco real de a mesma coisa ser cadastrada mais de uma vez â clientes que se cadastram de novo por engano, produtos importados de fontes diferentes.', 2671 pedidoConfuso: 'Evita cadastro repetido.', 2672 pedidoClaro: 'Antes de criar um cliente novo, o sistema confere se já existe um com o mesmo CPF. Se existir, mostra "Já encontramos um cadastro com este CPF â deseja usar o existente?" em vez de criar um segundo registro automaticamente.', 2673 comoFunciona: [ 2674 'Você define qual combinação de campos identifica "a mesma coisa" de verdade (nem sempre é um campo único só).', 2675 'Antes de criar um registro novo, o sistema busca por algo parecido usando esses critérios.', 2676 'Se encontrar algo muito parecido, avisa e deixa a pessoa decidir (usar o existente ou confirmar que é diferente mesmo).', 2677 'Casos já duplicados podem ser unidos manualmente depois, juntando o histórico dos dois num só.' 2678 ], 2679 errosComuns: [ 2680 'Confiar só num campo único (como e-mail) pra evitar duplicidade, quando a pessoa pode se cadastrar com e-mail diferente.', 2681 'Bloquear automaticamente sem deixar a pessoa confirmar â à s vezes duas coisas parecidas são mesmo diferentes.' 2682 ], 2683 termoTecnico: 'Registro duplicado (duplicate record)', 2684 termosRelacionados: ['deduplicação', 'unificação de cadastro', 'cadastro repetido'] 2685 }, 2686 { 2687 nome: 'Referência quebrada', 2688 icon: '<path d="M9 17H7a5 5 0 0 1 0-10h2"/><path d="M15 7h2a5 5 0 0 0 0-10h-2" stroke-dasharray="2 3"/><path d="M12 2v20" stroke-dasharray="2 3"/>', 2689 oQueE: 'Quando um dado aponta pra outro que não existe mais â o vÃnculo ficou "no ar", apontando pra um registro que já foi excluÃdo ou nunca existiu.', 2690 quandoUsar: 'Preste atenção nisso sempre que um registro puder ser excluÃdo enquanto outros ainda dependem dele â é o risco direto de não decidir com antecedência o que acontece com quem depende de algo removido.', 2691 pedidoConfuso: 'Não deixa dar erro se o cliente já foi apagado.', 2692 pedidoClaro: 'Se um cliente for excluÃdo, o sistema não permite a exclusão enquanto existirem pedidos vinculados a ele â mostra "Este cliente tem 3 pedidos ativos e não pode ser removido" em vez de deixar os pedidos com uma referência quebrada.', 2693 comoFunciona: [ 2694 'Antes de excluir um registro, o sistema confere se algo mais depende dele.', 2695 'Se depender, o sistema decide entre 3 caminhos: bloquear a exclusão, excluir em cascata o que depende dele, ou desvincular (deixar o dependente sem essa referência).', 2696 'Essa decisão precisa ser explÃcita â deixar sem decidir é o que gera referência quebrada.', 2697 'Sistemas bem modelados escolhem o comportamento certo por tipo de relação, não um padrão único pra tudo.' 2698 ], 2699 errosComuns: [
2700 'Não decidir o comportamento e deixar o banco de dados permitir a exclusão mesmo com dependentes â gera referência quebrada silenciosa.', 2701 'Usar exclusão em cascata em toda relação por padrão, apagando coisas que na verdade deveriam ser preservadas.' 2702 ], 2703 termoTecnico: 'Referência quebrada (orphaned reference / broken foreign key)', 2704 termosRelacionados: ['dado órfão', 'integridade referencial', 'exclusão em cascata'] 2705 }, 2706 { 2707 nome: 'Dependência circular', 2708 icon: '<path d="M17 2.1l4 4-4 4"/><path d="M3 12.6v-2a4 4 0 0 1 4-4h14"/><path d="M7 21.9l-4-4 4-4"/><path d="M21 11.4v2a4 4 0 0 1-4 4H3"/>', 2709 oQueE: 'Quando dois (ou mais) registros dependem um do outro numa cadeia fechada â A depende de B, que depende de A â deixando o sistema sem saber por onde começar.', 2710 quandoUsar: 'Vale verificar isso ao desenhar relacionamentos que podem se referenciar de volta â categorias que podem conter subcategorias, aprovações que dependem de outra aprovação.', 2711 pedidoConfuso: 'Não deixa criar uma categoria dentro dela mesma.', 2712 pedidoClaro: 'Uma categoria de produto pode ter uma categoria "pai", mas o sistema impede que ela vire pai (direto ou indiretamente) de uma categoria que já é ancestral dela â bloqueando a ação com "Isso criaria um ciclo entre categorias" antes de salvar.', 2713 comoFunciona: [ 2714 'Ao criar ou editar uma relação, o sistema percorre a cadeia de dependências a partir dela.', 2715 'Se, seguindo essa cadeia, ela chegar de volta no ponto de partida, existe um ciclo.', 2716 'A ação que criaria o ciclo é bloqueada antes de ser salva, com uma explicação do problema.', 2717 'Relações desse tipo (hierarquias que podem se referenciar) precisam dessa checagem desde o desenho, não como correção depois.' 2718 ], 2719 errosComuns: [ 2720 'Só descobrir a dependência circular quando o sistema trava tentando processar a cadeia (loop infinito).', 2721 'Permitir a relação sem checar ciclos, deixando dados hierárquicos inconsistentes.' 2722 ], 2723 termoTecnico: 'Dependência circular (circular reference)', 2724 termosRelacionados: ['ciclo de referências', 'hierarquia inconsistente', 'referência recursiva'] 2725 } 2726 ], 2727 codigos: [ 2728 { codigo: '/vincula-e-decide-o-resto' }, 2729 { codigo: '/evita-duplicado' } 2730 ] 2731 }, 2732 { 2733 stage: 'Aula 03', 2734 layout: 'grid', 2735 title: 'O que fica registrado', 2736 goal: 'Aprenda a diferença entre guardar o rastro de cada mudança que um dado sofreu, e apenas tirar algo de circulação sem apagar nada.', 2737 focus: 'Antes de pedir uma tela ou funcionalidade, pergunte: alguém precisa poder ver como esse dado mudou ao longo do tempo? Existe algo que precisa sair da lista principal sem deixar de existir?', 2738 practice: 'Pegue um dado importante do seu sistema (um pedido, um contrato) e descreva: o que deveria ficar registrado toda vez que ele muda, e em que situação ele deveria ser arquivado em vez de excluÃdo.', 2739 exerciseFeedback: 'Não existe resposta única aqui â o que importa é a diferença ficar clara: histórico é sobre GUARDAR CADA MUDANÃA (quem mudou o quê e quando), arquivamento é sobre TIRAR DE CIRCULAÃÃO sem apagar. Releia e veja se sua resposta não confundiu os dois.', 2740 lessons: [ 2741 'Aprenda o que exatamente fica guardado quando um sistema registra histórico de alterações.', 2742 'Veja a diferença entre arquivar algo e excluir de vez (isso volta na próxima aula).', 2743 'Pratique como decidir o que realmente precisa de histórico, sem registrar tudo por excesso de zelo.' 2744 ], 2745 conceitos: [ 2746 { 2747 nome: 'Histórico de alterações', 2748 oQueE: 'Um registro de cada mudança que um dado sofreu ao longo do tempo â o que era antes, o que passou a ser, quem mudou e quando.', 2749 quandoUsar: 'Use quando é importante poder responder "o que mudou aqui e quem fez isso" depois â contratos, preços, permissões, qualquer dado onde o passado importa tanto quanto o presente.', 2750 quandoNaoUsar: 'Não use pra todo campo do sistema â guardar histórico de um campo que muda toda hora sem importância real (como "última vez que a página foi visualizada") só gera dado inútil acumulado.', 2751 pedidoConfuso: 'Guarda o histórico de mudanças.', 2752 pedidoClaro: 'Toda vez que o preço de um produto for alterado, o sistema guarda o valor anterior, o valor novo, quem fez a alteração e a data. Essas mudanças aparecem numa lista "Histórico de preços" dentro da tela do produto.', 2753 comoFunciona: [ 2754 'Você decide quais campos precisam ter histórico rastreado.', 2755 'Toda vez que um desses campos muda, o sistema guarda uma entrada com valor antigo, valor novo, quem mudou e quando.', 2756 'Essas entradas nunca são apagadas nem sobrescritas â elas se acumulam.', 2757 'Uma tela mostra essa lista em ordem cronológica pra quem precisa consultar.' 2758 ], 2759 segundoExemplo: 'Um editor de documento colaborativo guarda cada versão salva, permitindo ver "quem mudou o parágrafo 3 ontem à s 14h".', 2760 errosComuns: [ 2761 'Guardar histórico de campos que não importam, inchando o banco de dados à toa.', 2762 'Permitir editar ou apagar uma entrada de histórico já registrada â isso quebra a confiança no próprio histórico.' 2763 ], 2764 termoTecnico: 'Histórico de alterações (audit trail / change log)', 2765 termosRelacionados: ['trilha de auditoria', 'log de mudanças', 'versionamento'] 2766 }, 2767 { 2768 nome: 'Arquivamento', 2769 oQueE: 'Tirar um registro da lista ativa/principal sem apagar nenhuma informação dele â ele continua existindo, só para de aparecer no dia a dia.', 2770 quandoUsar: 'Use quando algo não é mais relevante pro uso do dia a dia, mas ainda pode precisar ser consultado depois â um pedido antigo já finalizado, um funcionário que já saiu da empresa.', 2771 quandoNaoUsar: 'Não use quando o objetivo é realmente remover o dado de vez, por exemplo por pedido do próprio dono do dado â nesse caso o conceito certo é exclusão, não arquivamento.', 2772 pedidoConfuso: 'Tira os pedidos antigos da lista.', 2773 pedidoClaro: 'Pedidos com mais de 1 ano e já finalizados saem automaticamente da lista principal "Pedidos" e vão para uma seção "Arquivados", acessÃvel por um filtro. Nada nesses pedidos é apagado, só deixam de aparecer por padrão.', 2774 comoFunciona: [ 2775 'Você define o critério que torna um registro elegÃvel pra arquivamento (idade, status, inatividade).', 2776 'O registro ganha uma marcação de "arquivado" â continua no banco de dados, intacto.', 2777 'A lista principal, por padrão, esconde os registros marcados como arquivados.', 2778 'Um filtro ou seção separada permite consultar os arquivados quando necessário, e desarquivar se preciso.' 2779 ], 2780 segundoExemplo: 'Um app de e-mail arquiva mensagens que você marca como "concluÃdas" â elas somem da caixa de entrada, mas continuam pesquisáveis.', 2781 errosComuns: [ 2782 'Confundir arquivamento com exclusão e prometer "sumir para sempre" quando n
2782a verdade o dado continua existindo.', 2783 'Não dar um jeito fácil de consultar ou desarquivar o que foi arquivado, tornando a função inútil na prática.' 2784 ], 2785 termoTecnico: 'Arquivamento (archiving)', 2786 termosRelacionados: ['inativação', 'fora de circulação', 'arquivo morto'] 2787 } 2788 ], 2789 codigos: [ 2790 { codigo: '/historico-so-do-que-importa' }, 2791 { codigo: '/arquiva-nao-apaga' } 2792 ] 2793 }, 2794 { 2795 stage: 'Aula 04', 2796 layout: 'compare', 2797 compareSymbol: 'â ', 2798 title: 'Apagar não é sempre apagar', 2799 goal: 'Aprenda a diferença entre remover um dado de vez e apenas escondê-lo â uma decisão que muda tudo sobre o que ainda pode ser recuperado depois.', 2800 focus: 'Antes de pedir "excluir" alguma coisa, pergunte: isso precisa sumir de verdade e pra sempre, ou só precisa parar de aparecer, mantendo a possibilidade de recuperar depois? A resposta muda completamente como isso deve ser construÃdo.', 2801 practice: 'Pegue uma ação de "excluir" do seu sistema (excluir um pedido, uma conta, um comentário) e decida: deveria ser exclusão de verdade ou exclusão lógica? Escreva o motivo da escolha.', 2802 exerciseFeedback: 'Não existe resposta única â o que importa é o motivo da escolha estar claro: se existe qualquer chance de precisar recuperar, auditar, ou se há obrigação legal de manter o registro, é exclusão lógica; se o dado realmente não pode continuar existindo em lugar nenhum, é exclusão de verdade. Releia e veja se você não escolheu só "porque sim".', 2803 lessons: [ 2804 'Aprenda a diferença entre um dado que desaparece de vez e um que só fica escondido.', 2805 'Veja por que a maioria dos sistemas usa exclusão lógica como padrão, não exclusão de verdade.', 2806 'Pratique como decidir qual das duas faz sentido pra cada situação, em vez de assumir "excluir" sempre significa a mesma coisa.' 2807 ], 2808 conceitos: [ 2809 { 2810 nome: 'Exclusão', 2811 compareLabel: 'O dado desaparece de vez â não tem volta.', 2812 icon: '<path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/>', 2813 oQueE: 'A remoção definitiva de um dado do sistema â depois de excluÃdo, ele não existe mais em lugar nenhum e não pode ser recuperado.', 2814 quandoUsar: 'Use quando existe uma razão forte pra o dado realmente deixar de existir â pedido explÃcito do dono do dado (direito de exclusão), ou informação que nunca deveria ter sido salva.', 2815 quandoNaoUsar: 'Não use como padrão pra qualquer botão "excluir" â a maioria dos casos do dia a dia (excluir um pedido, um comentário) se resolve melhor com exclusão lógica, que permite desfazer.', 2816 comparacao: 'Diferente da exclusão lógica, aqui não existe "desfazer" â por isso costuma vir com uma confirmação extra, tipo digitar o nome da coisa que vai ser apagada.', 2817 pedidoConfuso: 'Apaga de vez quando o usuário pedir.', 2818 pedidoClaro: 'Ao clicar em "Excluir minha conta permanentemente", o sistema pede que o usuário digite a palavra "EXCLUIR" para confirmar. Depois disso, todos os dados pessoais são removidos do banco de dados de forma definitiva, sem possibilidade de recuperação.', 2819 comoFunciona: [ 2820 'O usuário solicita a exclusão de algo especÃfico.', 2821 'O sistema pede uma confirmação forte (não um clique simples), já que a ação não tem volta.', 2822 'Confirmado, o registro é removido de verdade do banco de dados.', 2823 'Nenhuma cópia do dado continua acessÃvel depois disso, respeitando o que foi prometido.' 2824 ], 2825 errosComuns: [ 2826 'Chamar de "exclusão" uma ação que na verdade é reversÃvel â isso quebra a confiança de quem pediu.',
2827 'Não confirmar de forma clara antes de uma ação sem volta, permitindo exclusão acidental.' 2828 ], 2829 termoTecnico: 'Exclusão definitiva (hard delete)', 2830 termosRelacionados: ['remoção permanente', 'apagar de vez', 'direito ao esquecimento'] 2831 }, 2832 { 2833 nome: 'Exclusão lógica', 2834 compareLabel: 'O dado só fica escondido â dá pra recuperar.', 2835 icon: '<path d="M17.94 17.94A10.94 10.94 0 0 1 12 20c-7 0-11-8-11-8a18.5 18.5 0 0 1 5.06-5.94"/><path d="M9.9 4.24A10.94 10.94 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-4.22 5"/><path d="M1 1l22 22"/>', 2836 oQueE: 'Marcar um registro como "excluÃdo" sem removê-lo de verdade do banco de dados â ele para de aparecer nas listas normais, mas continua existindo por trás.', 2837 quandoUsar: 'Use como padrão pra maioria das ações de "excluir" do dia a dia â permite desfazer, manter histórico, e cumprir obrigações legais de retenção de dados sem esconder isso do usuário.', 2838 comparacao: 'Diferente da exclusão de verdade, aqui existe "desfazer" â o dado só ficou invisÃvel, não sumiu.', 2839 pedidoConfuso: 'Exclui o pedido mas guarda escondido.', 2840 pedidoClaro: 'Ao clicar em "Excluir pedido", o sistema marca o pedido com uma data de exclusão e ele some da lista principal. O pedido continua no banco de dados e pode ser recuperado em até 30 dias através da seção "Lixeira".', 2841 comoFunciona: [ 2842 'O usuário pede pra excluir um registro.', 2843 'O sistema não remove nada â só grava uma marcação (e a data) dizendo que aquilo está "excluÃdo".', 2844 'As listas normais do sistema filtram automaticamente o que está marcado como excluÃdo, escondendo-o.', 2845 'Uma tela especÃfica (tipo "Lixeira") permite ver e restaurar o que foi excluÃdo, dentro de um prazo definido.' 2846 ], 2847 segundoExemplo: 'Ao excluir uma foto do celular, ela some do álbum principal mas fica disponÃvel em "Recentemente excluÃdos" por 30 dias antes de sumir de vez.', 2848 errosComuns: [ 2849 'Prometer "exclusão" pro usuário sem deixar claro que o dado continua existindo por trás â isso pode até virar problema de confiança/privacidade.', 2850 'Deixar o registro marcado como excluÃdo aparecer em algum lugar que deveria filtrá-lo (busca, relatório).' 2851 ], 2852 termoTecnico: 'Exclusão lógica (soft delete)', 2853 termosRelacionados: ['exclusão reversÃvel', 'marcação de exclusão', 'lixeira'] 2854 } 2855 ], 2856 codigos: [ 2857 { codigo: '/decide-o-tipo-de-exclusao' }, 2858 { codigo: '/lixeira-com-prazo' } 2859 ] 2860 }, 2861 { 2862 stage: 'Aula 05', 2863 layout: 'compare', 2864 compareSymbol: 'â', 2865 title: 'Dados que trocam de casa', 2866 goal: 'Aprenda a diferença entre trazer dados de fora pra dentro do sistema e tirar dados de dentro pra usar em outro lugar.', 2867 focus: 'Antes de pedir uma funcionalidade de "trazer" ou "tirar" dados, pergunte: de onde vêm os dados e em que formato? O que acontece se algum dado vier errado ou incompleto? Pra onde vão os dados exportados e em que formato eles precisam sair?', 2868 practice: 'Pegue uma situação real do seu sistema onde dados entram ou saem em lote (uma planilha de clientes, um relatório baixado) e descreva: o formato esperado, o que fazer com linhas inválidas, e o que exatamente sai no arquivo final.', 2869 exerciseFeedback: 'Não existe resposta única â o que importa é cobrir os dois lados de cada operação: pra importação, o que fazer quando algo vem errado (ignorar a linha? travar tudo? avisar e deixar corrigir?); pra exportação, exatamente quais campos saem e em qual formato. Releia e veja se as regras de erro estão especÃficas.', 2870 lessons: [ 2871 'Aprenda o que precisa ser decidido antes de pedir uma importação de dados em lote.', 2872 'Veja o que precisa ser decidido antes de pedir uma exportação de dados.', 2873 'Pratique como lidar com dados que vêm errados numa importação, em vez de assumir que tudo sempre chega perfeito.' 2874 ], 2875 conceitos: [ 2876 { 2877 nome: 'Importação', 2878 compareLabel: 'Dado de fora entrando no sistema.', 2879 icon: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5"/><path d="M12 15V3"/>', 2880 oQueE: 'Trazer um conjunto de dados de fora (uma planilha, um arquivo, outro sistema) e criar ou atualizar registros no sistema a partir deles, de uma vez só.', 2881 quandoUsar: 'Use quando alguém precisa cadastrar muitos registros de uma vez em vez de um por um â migrar clientes de uma planilha, importar um catálogo de produtos de um fornecedor.', 2882 pedidoConfuso: 'Deixa subir uma planilha de clientes.', 2883 pedidoClaro: 'A tela "Importar clientes" aceita um arquivo CSV com as colunas nome, e-mail e telefone (nessa ordem). Antes de importar de verdade, o sistema mostra uma prévia com quantas linhas são válidas e quantas têm erro, permitindo baixar um relatório das linhas com problema antes de confirmar.', 2884 comoFunciona: [
2885 'O usuário envia um arquivo num formato esperado (CSV, planilha).', 2886 'O sistema lê o arquivo linha por linha, validando cada uma contra as mesmas regras de um cadastro normal.', 2887 'Linhas válidas ficam prontas pra virar registros; linhas inválidas são listadas com o motivo do erro.', 2888 'O usuário confirma, e só as linhas válidas viram registros de verdade no sistema.' 2889 ], 2890 segundoExemplo: 'Uma ferramenta de e-mail marketing importa uma lista de contatos de um arquivo CSV, ignorando automaticamente linhas com e-mail em formato inválido e avisando quantas foram ignoradas.', 2891 errosComuns: [ 2892 'Travar a importação inteira por causa de 1 linha com erro, em vez de importar o que está certo e apontar o que não está.', 2893 'Não mostrar uma prévia antes de confirmar, fazendo a pessoa descobrir problemas só depois que tudo já foi importado.' 2894 ], 2895 termoTecnico: 'Importação de dados (data import)', 2896 termosRelacionados: ['upload em lote', 'carga de dados', 'importação em massa'] 2897 }, 2898 { 2899 nome: 'Exportação', 2900 compareLabel: 'Dado de dentro saindo do sistema.', 2901 icon: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M17 8l-5-5-5 5"/><path d="M12 3v12"/>', 2902 oQueE: 'Tirar um conjunto de dados de dentro do sistema e gerar um arquivo (planilha, PDF, CSV) que a pessoa pode baixar e usar em outro lugar.', 2903 quandoUsar: 'Use quando alguém precisa levar os dados pra fora do sistema â abrir numa planilha própria, mandar pra outro sistema, guardar um relatório.', 2904 pedidoConfuso: 'Deixa baixar os dados numa planilha.', 2905 pedidoClaro: 'O botão "Exportar" na tela de pedidos gera um arquivo CSV com número do pedido, cliente, data, valor total e status â respeitando os filtros aplicados na tela no momento do clique, não todos os pedidos do sistema.', 2906 comoFunciona: [ 2907 'O usuário decide o que exportar (todos os registros ou só os filtrados na tela).', 2908 'O sistema define exatamente quais campos vão pro arquivo, na ordem certa.', 2909 'Gera o arquivo no formato pedido (CSV, Excel, PDF).', 2910 'Disponibiliza pra download, direto ou por link/e-mail se for um arquivo grande que demora pra gerar.' 2911 ], 2912 segundoExemplo: 'Um sistema financeiro exporta o extrato do mês em PDF, com um layout pronto pra impressão, diferente da planilha CSV usada pra importar em outro sistema contábil.', 2913 errosComuns: [ 2914 'Exportar campos sensÃveis que a pessoa não deveria conseguir tirar do sistema em lote (senhas, dados de outros clientes).', 2915 'Não deixar claro se a exportação respeita os filtros aplicados na tela ou sempre traz tudo.' 2916 ], 2917 termoTecnico: 'Exportação de dados (data export)', 2918 termosRelacionados: ['download em lote', 'geração de relatório', 'extração de dados'] 2919 } 2920 ], 2921 codigos: [ 2922 { codigo: '/importa-com-previa' }, 2923 { codigo: '/exporta-so-o-necessario' } 2924 ] 2925 }, 2926 { 2927 stage: 'Aula 06', 2928 layout: 'timeline', 2929 sequenceCount: 2, 2930 connectors: ['permite'], 2931 title: 'Continuidade dos dados', 2932 goal: 'Aprenda a cadeia que garante que um dado sobrevive a um desastre: uma cópia é guardada periodicamente, pode ser trazida de volta se algo der errado, e existe um prazo definido até quando ela precisa continuar existindo.', 2933 focus: 'Antes de pedir uma funcionalidade que envolve dado importante, pergunte: existe uma cópia de segurança dele? Se algo for perdido, como isso volta? Até quando esse dado (ou a cópia dele) precisa continuar existindo por lei ou por polÃtica interna?', 2934 practice: 'Pegue um dado crÃtico do seu sistema (cadastro de clientes, histórico financeiro) e descreva: com que frequência ele deveria ser copiado, como a restauração funcionaria se algo desse errado, e por quanto tempo ele (ou a cópia) precisa ser mantido.', 2935 exerciseFeedback: 'Não existe resposta única â o que importa é a cadeia fazer sentido: a frequência do backup bate com o quanto dado a empresa ace
2935itaria perder (perder 1 dia de dados é aceitável? 1 hora?), a restauração tem um responsável e um processo claro, e o prazo de retenção tem um motivo real (lei, polÃtica) por trás, não é só um número chutado.', 2936 lessons: [ 2937 'Aprenda por que uma cópia de segurança sozinha não resolve nada sem um plano de restauração.', 2938 'Veja como retenção de dados define até quando manter algo guardado, mesmo que não seja mais usado no dia a dia.', 2939 'Pratique como descrever a frequência de backup em função do que a empresa pode se dar ao luxo de perder.' 2940 ], 2941 conceitos: [ 2942 { 2943 nome: 'Backup', 2944 when: 'Antes de qualquer problema acontecer', 2945 icon: '<path d="M3.05 13A9 9 0 1 0 6 5.3L3 8"/><path d="M3 3v5h5"/><path d="M12 7v5l4 2"/>', 2946 oQueE: 'Uma cópia de segurança dos dados, guardada separadamente, feita pra ser usada caso os dados originais sejam perdidos, corrompidos ou apagados por engano.', 2947 quandoUsar: 'Use pra qualquer dado que a empresa não pode se dar ao luxo de perder â cadastros de clientes, histórico financeiro, conteúdo pago pelos usuários.', 2948 pedidoConfuso: 'Faz um backup dos dados.', 2949 pedidoClaro: 'O banco de dados de clientes recebe um backup completo automático todo dia à s 3h da manhã, guardado por 30 dias, além de um backup incremental a cada 6 horas guardado por 7 dias.', 2950 comoFunciona: [ 2951 'Você decide com que frequência a cópia é feita, baseado em quanto dado seria aceitável perder no pior cenário.', 2952 'O sistema gera a cópia automaticamente, no horário definido, sem precisar de ação manual.', 2953 'A cópia fica guardada num lugar separado do dado original â se o original for perdido, a cópia não vai junto.', 2954 'Cópias antigas são descartadas conforme uma polÃtica de quantas cópias manter.' 2955 ], 2956 errosComuns: [ 2957 'Fazer backup mas nunca testar se ele realmente funciona na hora de restaurar.', 2958 'Guardar a cópia no mesmo lugar do dado original â se aquele lugar falhar, os dois somem juntos.' 2959 ], 2960 termoTecnico: 'Cópia de segurança (backup)', 2961 termosRelacionados: ['cópia de segurança', 'snapshot', 'rotina de backup'] 2962 }, 2963 { 2964 nome: 'Restauração', 2965 when: 'Depois que algo deu errado', 2966 icon: '<path d="M1 4v6h6"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/>', 2967 oQueE: 'Trazer os dados de volta a partir de uma cópia de segurança, depois que os dados originais foram perdidos, corrompidos ou apagados sem querer.', 2968 quandoUsar: 'Use quando algo deu errado o suficiente pra precisar recuperar dados a partir de uma cópia â uma falha grave, uma exclusão em massa acidental.', 2969 pedidoConfuso: 'Recupera os dados do backup se der problema.', 2970 pedidoClaro: 'Se for necessário restaurar, o time técnico escolhe o backup mais recente antes do problema, restaura primeiro num ambiente separado pra conferir a integridade, e só depois substitui os dados de produção â processo que deve levar no máximo 2 horas.', 2971 comoFunciona: [ 2972 'Identifica-se o problema e a partir de que momento os dados ficaram comprometidos.', 2973 'Escolhe-se a cópia de segurança mais recente anterior a esse momento.', 2974 'A cópia é trazida de volta, idealmente testada num ambiente separado antes de virar definitiva.', 2975 'Os dados restaurados substituem os dados problemáticos, e o que aconteceu depois do backup escolhido pode ser perdido â por isso a frequência do backup importa tanto.' 2976 ], 2977 segundoExemplo: 'Um editor de texto com "histórico de versões" permite restaurar o documento pra como ele estava numa versão salva anterior, descartando as mudanças feitas depois.', 2978 errosComuns: [
2979 'Não ter um processo testado de restauração â descobrir na hora do desespero que ninguém sabe como fazer.', 2980 'Restaurar direto em produção sem antes conferir se a cópia está Ãntegra.' 2981 ], 2982 termoTecnico: 'Restauração (restore / recovery)', 2983 termosRelacionados: ['recuperação de dados', 'restore', 'recuperação de desastre'] 2984 }, 2985 { 2986 nome: 'Retenção de dados', 2987 icon: '<rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/><path d="M12 14v3l2 1"/>', 2988 oQueE: 'A polÃtica que define por quanto tempo um dado (ou uma cópia dele) deve continuar sendo guardado, antes de poder ser descartado de verdade.', 2989 quandoUsar: 'Use sempre que existe uma obrigação legal, contratual ou de negócio sobre até quando um dado precisa continuar existindo â notas fiscais, registros financeiros, logs de acesso.', 2990 pedidoConfuso: 'Guarda os dados fiscais o tempo que precisar.', 2991 pedidoClaro: 'Notas fiscais emitidas devem ser mantidas no sistema por no mÃnimo 5 anos a partir da emissão, conforme exigência legal. Depois desse prazo, o sistema pode arquivá-las ou excluÃ-las conforme a polÃtica definida.', 2992 comoFunciona: [ 2993 'Você identifica o motivo do prazo (lei, contrato, polÃtica interna) e o tempo exato exigido.', 2994 'O sistema guarda, junto de cada dado sujeito a essa regra, a data a partir da qual a contagem começa.', 2995 'Enquanto o prazo não vence, o dado não pode ser excluÃdo de verdade, mesmo que o usuário peça.', 2996 'Depois que o prazo vence, o dado pode ser arquivado ou excluÃdo, conforme a decisão de negócio.' 2997 ], 2998 errosComuns: [ 2999 'Excluir um dado antes do prazo de retenção obrigatório vencer, gerando risco legal.', 3000 'Manter dado guardado pra sempre "por via das dúvidas", sem prazo nenhum â isso também é um risco, principalmente com dado pessoal.' 3001 ], 3002 termoTecnico: 'Retenção de dados (data retention)', 3003 termosRelacionados: ['prazo de guarda', 'polÃtica de retenção', 'tempo mÃnimo de armazenamento'] 3004 }, 3005 { 3006 nome: 'Expiração automática', 3007 icon: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 3"/><path d="M3 3l3 3M21 3l-3 3"/>', 3008 oQueE: 'Quando o próprio sistema remove, arquiva ou anonimiza um dado sozinho, assim que o prazo de retenção dele vence â sem precisar de alguém pedir manualmente.', 3009 quandoUsar: 'Use como consequência prática da retenção de dados: definir o prazo não adianta muito se alguém precisa lembrar de agir manualmente quando ele vence â a expiração automática fecha esse ciclo.', 3010 quandoNaoUsar: 'Não automatize a exclusão de dados cujo prazo de retenção envolve análise caso a caso (ex.: processos jurÃdicos em andamento) â nesses casos, a expiração deveria gerar um alerta pra revisão humana, não uma ação automática direta.', 3011 pedidoConfuso: 'Apaga sozinho depois de um tempo.', 3012 pedidoClaro: 'Logs de acesso com mais de 12 meses são excluÃdos automaticamente por uma rotina que roda todo dia 1º do mês, sem intervenção manual â exceto os logs marcados como "em investigação", que ficam de fora dessa rotina até serem liberados manualmente.', 3013 comparacao: 'Retenção de dados define QUANDO um dado pode deixar de existir; expiração automática é o mecanismo que executa essa decisão sozinho, sem depender de alguém lembrar.', 3014 comoFunciona: [ 3015 'Uma rotina automática roda periodicamente (diária, mensal) checando quais dados já passaram do prazo de retenção.', 3016 'Dados encontrados nessa checagem seguem a ação definida: exclusão, arquivamento ou anonimização.', 3017 'Casos que precisam de revisão humana (ex.: em disputa legal) ficam de fora da rotina automática por uma marcação explÃcita.',
3018 'A execução da rotina fica registrada, pra existir prova de quando e o que foi processado.' 3019 ], 3020 errosComuns: [ 3021 'Automatizar a exclusão sem uma forma de excluir casos especiais da rotina, apagando algo que precisava ser preservado.', 3022 'Não registrar a execução da rotina automática, ficando sem como provar depois o que foi removido e quando.' 3023 ], 3024 termoTecnico: 'Expiração automática (automatic data expiry / TTL)', 3025 termosRelacionados: ['rotina de limpeza', 'TTL (time to live)', 'purga automática'] 3026 } 3027 ], 3028 codigos: [ 3029 { codigo: '/backup-pelo-que-pode-perder' }, 3030 { codigo: '/prazo-de-retencao' } 3031 ] 3032 }, 3033 { 3034 stage: 'Aula 07', 3035 layout: 'groups', 3036 title: 'Privacidade e proteção', 3037 goal: 'Aprenda a diferença entre dado pessoal e dado sensÃvel, e o que fazer quando é preciso usar uma informação sem expor quem ela pertence.', 3038 focus: 'Antes de pedir uma tela ou relatório que envolve dado de gente real, pergunte: esse dado identifica uma pessoa? Alguma informação aqui é sensÃvel o bastante pra exigir cuidado redobrado? à possÃvel usar esse dado sem expor a identidade de quem ele pertence?', 3039 practice: 'Pegue um relatório ou tela do seu sistema que mostra dados de pessoas reais e descreva: quais campos são dados pessoais, quais (se houver) são sensÃveis, e se existe alguma versão desse relatório que poderia ser mostrada de forma anonimizada.', 3040 exerciseFeedback: 'Não existe resposta única â o que importa é a distinção ficar clara: dado pessoal é qualquer coisa que identifica uma pessoa (nome, e-mail, CPF); dado sensÃvel é uma categoria mais restrita e exige cuidado redobrado (saúde, orientação, dados financeiros detalhados); anonimização é a técnica que permite usar o dado sem conseguir voltar a saber de quem ele é.', 3041 lessons: [ 3042 'Aprenda a diferença entre dado pessoal e dado sensÃvel, e por que a segunda categoria exige mais cuidado.', 3043 'Veja como anonimização permite usar dado sem expor a identidade de quem ele pertence.', 3044 'Pratique como identificar, num sistema real, quais dados merecem esse cuidado extra.' 3045 ], 3046 groups: [ 3047 { title: 'O que precisa de cuidado extra', desc: 'Que tipos de dado identificam uma pessoa, e quais entre eles são especialmente delicados.' }, 3048 { 3049 title: 'Como proteger sem esconder', 3050 desc: 'O que fazer quando é preciso usar o dado (num relatório, numa análise) sem expor quem ele é.', 3051 note: 'Os dois andam juntos: só faz sentido pensar em anonimizar depois de saber exatamente o que no seu sistema é dado pessoal ou sensÃvel.' 3052 } 3053 ], 3054 scenario: { 3055 title: 'Cenário completo: relatório de uso de um app de saúde', 3056 intro: 'Um único fluxo real, mostrando onde cada conceito desta aula aparece.', 3057 steps: [ 3058 { text: 'O app guarda nome, e-mail e telefone de cada usuário â todos dados pessoais, protegidos por padrão.', tag: 'Dados pessoais' }, 3059 { text: 'O app também guarda o histórico de condições de saúde relatadas â isso é dado sensÃvel, com camada extra de proteção e acesso mais restrito.', tag: 'Dados sensÃveis' }, 3060 { text: 'O time de produto quer entender quais condições são mais comuns entre os usuários, sem precisar saber quem é quem.', tag: 'Necessidade de análise' }, 3061 { text: 'O relatório gerado mostra "34% dos usuários relataram X condição", sem nenhum nome, e-mail ou identificador que permita voltar a saber de quem é cada relato.', tag: 'Anonimização' } 3062 ] 3063 }, 3064 conceitos: [ 3065 { 3066 nome: 'Dados pessoais', 3067 grupo: 0, 3068 icon: '<circle cx="12" cy="8" r="4"/><path d="M4 21c0-4.4 3.6-8 8-8s8 3.6 8 8"/>', 3069 oQueE: 'Qualquer informação que identifica ou pode identificar uma pessoa especÃfica â nome, e-mail, CPF, telefone, endereço.', 3070 quandoUsar: 'Trate como dado pessoal qualquer campo que, sozinho ou combinado com outros, permita saber quem é a pessoa por trás daquele registro.', 3071 pedidoConfuso: 'Protege os dados dos usuários.', 3072 pedidoClaro: 'Os campos nome, e-mail, telefone e endereço do cliente são dados pessoais: só ficam visÃveis pra quem tem permissão de atendimento, nunca aparecem em relatórios agregados exportáveis por qualquer usuário do sistema, e o cliente pode solicitar a exclusão deles a qualquer momento.', 3073 comparacao: 'Todo dado sensÃvel é também dado pessoal, mas nem todo dado pessoal é sensÃvel â dado sensÃvel é uma categoria mais restrita, com regras mais rÃgidas ainda.', 3074 errosComuns: [
3075 'Não perceber que a combinação de vários campos "inofensivos" (cidade + idade + profissão) pode, junta, identificar alguém.', 3076 'Deixar dado pessoal visÃvel em telas ou relatórios que não precisavam dele pra funcionar.' 3077 ], 3078 termoTecnico: 'Dado pessoal (personal data)', 3079 termosRelacionados: ['informação identificável', 'PII', 'dado do titular'] 3080 }, 3081 { 3082 nome: 'Dados sensÃveis', 3083 grupo: 0, 3084 icon: '<path d="M12 2 4 5v6c0 5 3.4 9 8 11 4.6-2 8-6 8-11V5l-8-3Z"/>', 3085 oQueE: 'Uma categoria mais restrita de dado pessoal, que por sua natureza exige cuidado redobrado por causa do risco de discriminação ou dano se for exposto â saúde, orientação sexual, religião, dados financeiros detalhados.', 3086 quandoUsar: 'Trate como sensÃvel qualquer dado que, se vazado, pudesse causar prejuÃzo real ou discriminação contra a pessoa â não é sobre "informação embaraçosa", é sobre risco concreto.', 3087 pedidoConfuso: 'Esses dados de saúde precisam ser bem protegidos.', 3088 pedidoClaro: 'O campo "condições de saúde relatadas" é dado sensÃvel: acesso restrito só ao próprio usuário e a profissionais autorizados, criptografado no banco de dados, e toda consulta a esse campo especÃfico fica registrada em log de auditoria â diferente do nÃvel de proteção padrão dos outros dados pessoais.', 3089 comoFunciona: [ 3090 'Você identifica quais campos se encaixam nas categorias de dado sensÃvel (saúde, biometria, orientação, convicção religiosa/polÃtica, dados financeiros detalhados).', 3091 'Esses campos recebem controle de acesso mais restrito que o padrão de dado pessoal comum.', 3092 'Consultas a esses campos especÃficos ficam registradas em log de auditoria, não só a edição.', 3093 'Esses campos ficam de fora, por padrão, de qualquer exportação ou relatório em lote, mesmo que dados pessoais comuns estejam liberados.' 3094 ], 3095 errosComuns: [ 3096 'Tratar dado sensÃvel com o mesmo nÃvel de proteção de qualquer outro dado pessoal, sem a camada extra que ele exige.', 3097 'Incluir campo sensÃvel numa exportação em lote "por conveniência", mesmo sem necessidade real.' 3098 ], 3099 termoTecnico: 'Dado sensÃvel (sensitive data)', 3100 termosRelacionados: ['dado de categoria especial', 'informação restrita', 'dado protegido'] 3101 }, 3102 { 3103 nome: 'Anonimização', 3104 grupo: 1, 3105 icon: '<path d="M4 15c0-4 3-7 8-7s8 3 8 7"/><circle cx="8.5" cy="15" r="1.5"/><circle cx="15.5" cy="15" r="1.5"/><path d="M2 15h2M20 15h2"/>', 3106 oQueE: 'Transformar um dado de forma que não seja mais possÃvel saber a que pessoa especÃfica ele pertence â permite usar a informação (pra análise, relatório) sem expor identidade.', 3107 quandoUsar: 'Use quando você precisa analisar padrões num conjunto de dados (quantos usuários fazem X, qual a média de Y) sem precisar saber quem é cada pessoa individualmente.', 3108 quandoNaoUsar: 'Não funciona quando você ainda precisa identificar a pessoa depois â nesses casos, o conceito certo geralmente é apenas restringir o acesso, não anonimizar (que é irreversÃvel por definição).', 3109 pedidoConfuso: 'Tira os nomes do relatório.', 3110 pedidoClaro: 'O relatório de "condições de saúde mais relatadas" agrupa os dados em faixas (por região e faixa etária) e mostra só porcentagens agregadas â nenhum nome, e-mail ou identificador individual aparece, e não é possÃvel voltar a descobrir de quem é cada relato a partir do relatório.', 3111 comparacao: 'Diferente de só "esconder" o nome na tela (que ainda deixa o dado original recuperável por trás), anonimização de verdade remove a possibilidade de voltar a identificar a pessoa a partir daquele dado.', 3112 errosComuns: [ 3113 'Achar que só remover nome e e-mail já é suficie
3113nte â combinações de outros campos (CEP + idade + profissão) ainda podem reidentificar alguém.', 3114 'Chamar de "anonimizado" um dado que na verdade só está com acesso restrito, mas continua identificável por trás.' 3115 ], 3116 termoTecnico: 'Anonimização (anonymization)', 3117 termosRelacionados: ['dado agregado', 'reidentificação', 'privacidade por design'] 3118 }, 3119 { 3120 nome: 'Pseudonimização', 3121 grupo: 1, 3122 icon: '<rect x="3" y="11" width="18" height="10" rx="1"/><path d="M7 11V8a5 5 0 0 1 10 0v3"/><circle cx="12" cy="16" r="1.5"/>', 3123 oQueE: 'Substituir a identificação de uma pessoa por um código/token, guardando separadamente (e protegida) a chave que permite voltar a ligar o código à pessoa real â diferente de anonimizar, aqui ainda dá pra reidentificar se necessário.', 3124 quandoUsar: 'Use quando você precisa reduzir o risco de exposição de um dado (ex.: numa análise, num ambiente de testes) mas ainda existe uma razão legÃtima pra eventualmente voltar a identificar a pessoa â investigação de fraude, correção de um erro especÃfico.', 3125 quandoNaoUsar: 'Não é suficiente quando o objetivo é publicar ou compartilhar o dado amplamente sem risco nenhum de reidentificação â nesse caso o conceito certo é anonimização de verdade, que não guarda essa chave de volta.', 3126 pedidoConfuso: 'Troca o nome por um código.', 3127 pedidoClaro: 'No ambiente de testes, os nomes reais dos clientes são substituÃdos por códigos como "CLIENTE_4821" â a tabela que liga esse código ao cliente real fica só no ambiente de produção, com acesso restrito à equipe de dados, nunca exposta no ambiente de testes.', 3128 comparacao: 'Anonimização é uma via de mão única (não tem como voltar); pseudonimização guarda a chave de volta separada e protegida â é o meio-termo pra quando anonimizar de verdade tornaria o dado inútil pro que você precisa fazer com ele.', 3129 comoFunciona: [ 3130 'Cada identificador real (nome, CPF, e-mail) é substituÃdo por um código/token gerado.', 3131 'A tabela que liga o código de volta ao dado real fica separada, com acesso bem mais restrito que o dado pseudonimizado em si.', 3132 'Quem trabalha com o dado pseudonimizado no dia a dia não tem acesso a essa tabela de ligação.', 3133 'Reidentificar exige acesso explÃcito e justificado à tabela de ligação â não é algo que acontece sem querer.' 3134 ], 3135 errosComuns: [ 3136 'Guardar a tabela de ligação no mesmo lugar (ou com o mesmo nÃvel de acesso) do dado pseudonimizado, anulando a proteção.', 3137 'Tratar dado pseudonimizado como se já fosse anônimo pra fins de compartilhamento público â legalmente, geralmente ainda conta como dado pessoal.' 3138 ], 3139 termoTecnico: 'Pseudonimização (pseudonymization)', 3140 termosRelacionados: ['tokenização', 'dado codificado', 'chave de reidentificação'] 3141 } 3142 ], 3143 codigos: [ 3144 { codigo: '/separa-o-sensivel' }, 3145 { codigo: '/agrega-sem-identificar' } 3146 ] 3147 }, 3148 { 3149 stage: 'Aula 08', 3150 layout: 'grid', 3151 title: 'Onde tudo mora', 3152 goal: 'Feche a trilha entendendo onde os dados realmente ficam guardados no sistema, e como transformar tudo isso em números e listas que ajudam alguém a decidir algo.', 3153 focus: 'Antes de pedir um relatório ou uma tela de dados, pergunte: de onde exatamente esses números vêm? O relatório precisa ser gerado na hora ou pode ser algo calculado com antecedência? Quem vai usar esse relatório e pra decidir o quê?', 3154 practice: 'Pegue um relatório que você gostaria de ter no seu sistema e descreva: quais dados ele usa como fonte, como esses dados estão organizados, e o que exatamente a pessoa que olha o relatório precisa conseguir decidir com ele.', 3155 exerciseFeedback: 'Não existe resposta única aqui â o que importa é o relatório ter um propósito claro (decidir o quê?), não só "mostrar dados". Releia e veja se dá pra responder "e daÃ, o que alguém faz com esse número?" â se não der, o relatório provavelmente está incompleto.', 3156 lessons: [ 3157 'Aprenda, em termos simples, o que é um banco de dados e por que ele organiza tudo em tabelas relacionadas.', 3158 'Veja como um relatório transforma dado bruto em algo que ajuda alguém a decidir.', 3159 'Feche a trilha revisando como todos os conceitos do curs
3159o se conectam: cadastro â relacionamento â histórico â exclusão â backup â privacidade â relatório.' 3160 ], 3161 conceitos: [ 3162 { 3163 nome: 'Banco de dados', 3164 oQueE: 'O lugar onde o sistema guarda, organiza e recupera todas as informações â cadastros, pedidos, histórico â de forma estruturada, geralmente em tabelas que se relacionam entre si.', 3165 quandoUsar: 'à bom entender esse conceito sempre que for pedir algo que envolve grande volume de dados ou relação entre várias informações â praticamente todo sistema real depende de um banco de dados por trás.', 3166 pedidoConfuso: 'Guarda tudo direitinho no banco.', 3167 pedidoClaro: 'O sistema usa um banco de dados com tabelas separadas para clientes, pedidos e produtos, relacionadas entre si â um pedido referencia um cliente e um ou mais produtos, em vez de repetir essas informações em cada pedido.', 3168 comoFunciona: [ 3169 'Cada tipo de informação (cliente, pedido, produto) fica numa tabela própria.', 3170 'Cada registro dentro de uma tabela tem um identificador único.', 3171 'Tabelas se relacionam entre si através desses identificadores, evitando repetir a mesma informação em vários lugares.', 3172 'Quando o sistema precisa mostrar algo (como um pedido com o nome do cliente), ele busca e junta as informações das tabelas relacionadas na hora.' 3173 ], 3174 errosComuns: [ 3175 'Pedir pra "guardar tudo numa tabela só" por parecer mais simples, o que na prática gera repetição de dado e inconsistência.', 3176 'Não considerar como as tabelas vão se relacionar antes de pedir a funcionalidade, deixando essa decisão importante pro dev descobrir sozinho.' 3177 ], 3178 termoTecnico: 'Banco de dados (database)', 3179 termosRelacionados: ['tabela', 'estrutura de dados', 'armazenamento estruturado'] 3180 }, 3181 { 3182 nome: 'Relatório baseado em dados', 3183 oQueE: 'Uma visão organizada de informações do sistema, geralmente resumida ou agrupada, feita pra ajudar alguém a entender uma situação e tomar uma decisão.', 3184 quandoUsar: 'Use quando alguém precisa enxergar um panorama (não um registro individual) pra decidir algo â quanto foi vendido esse mês, quais produtos têm mais devolução, quantos usuários estão inativos.', 3185 pedidoConfuso: 'Faz um relatório de vendas.', 3186 pedidoClaro: 'O "Relatório mensal de vendas" mostra o total vendido por categoria de produto, comparado com o mês anterior, com o objetivo de ajudar o time comercial a decidir em qual categoria focar a próxima campanha. Atualiza automaticamente todo dia 1º, com dados até o último dia do mês anterior.', 3187 comoFunciona: [ 3188 'Você define qual decisão o relatório precisa ajudar a tomar â isso guia quais dados entram nele.', 3189 'O sistema busca os dados brutos das tabelas relevantes do banco de dados.', 3190 'Os dados são agrupados, somados ou comparados conforme o objetivo (por categoria, por perÃodo, por região).', 3191 'O resultado é apresentado de forma visual (tabela, gráfico) fácil de interpretar rapidamente.' 3192 ], 3193 segundoExemplo: 'Um relatório de "alunos em risco de desistência" cruza frequência nas aulas e progresso no curso, ajudando o time pedagógico a decidir quem contatar primeiro.', 3194 errosComuns: [ 3195 'Pedir um relatório sem saber que decisão ele deveria ajudar a tomar, resultando numa tela de números sem propósito claro.', 3196 'Misturar dado sensÃvel ou pessoal detalhado demais num relatório que deveria ser só uma visão agregada.' 3197 ], 3198 termoTecnico: 'Relatório baseado em dados (data report)', 3199 termosRelacionados: ['dashboard', 'visão agregada', 'análise de dados'] 3200 } 3201 ], 3202 codigos: [ 3203 { codigo: '/relaciona-nao-repete' }, 3204 { codigo: '/relatorio-com-proposito' } 3205 ] 3206 }, 3207 { 3208 stage: 'Aula 09', 3209 layout: 'grid',
3210 title: 'Códigos Secretos: a régua de dados do curso inteiro', 3211 goal: 'Aula bônus. Recapitula as 8 aulas e reúne os 16 comandos que cobrem cadastro, relacionamento, histórico, exclusão, importação/exportação, continuidade, privacidade e relatório.', 3212 focus: 'Antes de pedir algo que envolve dado, passe a régua: os campos obrigatórios e únicos estão nomeados? o relacionamento e o que fazer se o dono sumir estão definidos? é exclusão de vez ou lógica? existe backup, prazo de retenção e proteção pro dado sensÃvel?', 3213 practice: 'Pegue um cadastro ou relatório real que você precisa pedir ou revisar esta semana. Rode pelo menos 4 códigos desta lista sobre ele e junte tudo numa especificação só.', 3214 exerciseFeedback: 'Não existe resposta única. O que importa: a especificação final não deixa buraco â campos, relacionamento, histórico, exclusão, backup e privacidade ficam explÃcitos, não implÃcitos.', 3215 lessons: [ 3216 'Reconheça, num cadastro ou relatório pronto, quais decisões sobre dado já foram tomadas e quais ficaram em aberto.', 3217 'Monte a régua de revisão que você vai usar em qualquer funcionalidade que envolva dado daqui pra frente.', 3218 'Combine vários códigos numa especificação única, sem contradição.' 3219 ], 3220 conceitos: [], 3221 bonus: true 3222 } 3223]; 3224 3225const segurancaAcessosJourney = [ 3226 { 3227 stage: 'Aula 01', 3228 estimatedMinutes: 40, 3229 layout: 'timeline', 3230 title: 'Identidade, conta e login', 3231 goal: 'Entenda que login não é só uma tela: é o processo de confirmar quem está tentando entrar e iniciar um acesso controlado.', 3232 focus: 'Antes de pedir uma tela de login, defina quem é a pessoa, como a conta é criada, como a identidade é confirmada e o que acontece depois.', 3233 practice: 'Escolha uma plataforma que você conhece e descreva o caminho completo: criação da conta, confirmação, login, sessão iniciada e encerramento do acesso.', 3234 exerciseFeedback: 'Uma boa resposta separa identidade, login, sessão e acesso. Ela também prevê falhas sem revelar se o e-mail ou a senha estavam errados.', 3235 lessons: [ 3236 'Identidade é a representação de uma pessoa ou organização dentro do sistema.', 3237 'Cadastro cria a conta; login confirma a identidade; sessão mantém o reconhecimento.', 3238 'Uma conta pode estar pendente, ativa, bloqueada ou encerrada.', 3239 'Toda tela de login precisa prever sucesso, falha, espera, expiração e tentativa novamente.' 3240 ], 3241 connectors: ['confirma', 'cria', 'libera'], 3242 sequenceCount: 4, 3243 conceitos: [ 3244 { titulo: 'Identidade', definicao: 'A representação de uma pessoa ou organização dentro do sistema. Ela pode ter nome, e-mail, tipo de usuário, status e outros dados que ajudam a reconhecer a conta.', exemplo: 'Uma aluna tem uma conta identificada por seu e-mail e um status ativo.', confuso: 'Cria usuários para o sistema.', claro: 'Crie contas de alunos usando e-mail como identificador único. Cada conta deve ter nome, e-mail, data de criação e status.', comoFunciona: ['Defina os tipos de pessoa que usarão o sistema.', 'Escolha o identificador que não pode se repetir.', 'Liste os dados mÃnimos da conta.', 'Defina os estados possÃveis: convite pendente, ativo, bloqueado e encerrado.'], segundoExemplo: 'Um gestor e um aluno podem ter o mesmo nome, mas pertencem a contas diferentes e têm contextos distintos.', errosComuns: ['Usar âusuárioâ sem dizer quem é a pessoa.', 'Misturar nome de exibição com identificador da conta.', 'Criar conta sem definir status.'], termos: ['conta', 'identificador', 'status'] }, 3245 { titulo: 'Login', definicao: 'O momento em que a pessoa apresenta credenciais para o sistema confirmar que ela é dona da conta.', exemplo: 'A pessoa informa e-mail e senha, o servidor valida os dados e inicia uma sessão.', confuso: 'Faz um login seguro.', claro: 'Valide e-mail e senha no servidor. Em sucesso, crie uma sessão protegida; em falha, mostre uma mensagem genérica e permita tentar novamente.', comoFunciona: ['Receba as credenciais.', 'Valide formato e regras básicas.', 'Confirme os dados no servidor.', 'Crie a sessão somente depois da validação.', 'Redirecione para a área adequada.'], segundoExemplo: 'Uma conta bloqueada pode ter a senha correta e ainda assim não conseguir entrar.', errosComuns: ['Validar apenas no navegador.', 'Informar se o e-mail ou a senha está errado.', 'Redirecionar antes de confirmar a sessão.'], termos: ['credencial', 'autenticação', 'servidor'] }, 3246 { titulo: 'Sessão', definicao: 'O perÃodo em que o sistema reconhece a pessoa depois de um login válido. A sessão começa após a confirmação e termina por logout, expiração, bloqueio ou troca de senha.', exemplo: 'Depois de entrar, a pessoa abre outra página sem digitar a senha novamente porque a sessão continua válida.', confuso: 'Deixa a pessoa logada.', claro: 'Crie uma sessão protegida após o login e encerre-a no logout, após a expiração definida ou quando a conta for bloqueada.', comoFunciona: ['Defina quando a sessão começa.', 'Escolha sua duração e renovação.', 'Defina como o logout encerra o reconhecimento.', 'Liste eventos que invalidam a sessão.', 'Mostre uma orientação quando a sessão expirar.'], segundoExemplo: 'Ao trocar a senha, encerre sessões antigas para evitar que um acesso esquecido continue válido.', errosComuns: ['Tratar login e sessão como a mesma coisa.', 'Nunca expirar a sessão.', 'Deixar uma sessão ativa após bloqueio.'], termos: ['expiração', 'logout', 'sessão ativa'] }, 3247 { titulo: 'Acesso', definicao: 'O que a pessoa pode consultar ou fazer depois que sua identidade foi confirmada. Estar logado não significa poder ver tudo.', exemplo: 'Um aluno entra na plataforma, mas vê somente os cursos em que tem matrÃcula ativa.', confuso: 'Depois do login libera o painel.', claro: 'Após o login, direcione a pessoa para o painel correspondente e mostre apen
3247as os recursos permitidos para o tipo e o status da conta.', comoFunciona: ['Confirme a identidade.', 'Consulte o status e o contexto da conta.', 'Verifique o que pode ser exibido.', 'Bloqueie recursos fora do escopo.', 'Explique como solicitar acesso quando necessário.'], segundoExemplo: 'Um gestor pode acessar alunos e relatórios; um aluno pode acessar seu progresso e suas aulas.', errosComuns: ['Confundir estar logado com ter acesso total.', 'Esconder um botão sem proteger a operação no servidor.', 'Não diferenciar aluno, gestor e professor.'], termos: ['permissão', 'recurso', 'escopo'] } 3248 ], 3249 scenario: { title: 'Cenário completo: entrada de uma escola online', intro: 'Uma escola terá alunos, professores e gestores. O pedido inicial é apenas âpreciso de login para todo mundo entrarâ.', steps: [ 3250 { tag: 'Identificar', text: 'Separe os tipos de conta e diga quais dados identificam cada pessoa.' }, 3251 { tag: 'Cadastrar', text: 'Defina nome, e-mail, senha, confirmação de e-mail e estados da conta.' }, 3252 { tag: 'Confirmar', text: 'Descreva o que o servidor valida e quais mensagens aparecem quando algo falha.' }, 3253 { tag: 'Reconhecer', text: 'Explique quando a sessão começa, quando expira e como o logout funciona.' }, 3254 { tag: 'Orientar', text: 'Indique para onde cada tipo de pessoa vai depois do login e o que pode ver.' } 3255 ] }, 3256 exerciseFields: [ 3257 { key: 'tipo', label: '01 · Quem usa o sistema?', help: 'Liste os tipos de conta e o que cada pessoa precisa fazer.', placeholder: 'Aluno, professor, gestor...' }, 3258 { key: 'conta', label: '02 · Como a conta é criada?', help: 'Descreva dados, confirmação e estados possÃveis.', placeholder: 'A conta começa como...' }, 3259 { key: 'login', label: '03 · Como o login funciona?', help: 'Informe entrada, validação, sucesso e falha.', placeholder: 'A pessoa informa... O servidor...' }, 3260 { key: 'sessao', label: '04 · Quando o acesso começa e termina?', help: 'Defina sessão, logout, expiração e bloqueio.', placeholder: 'A sessão começa quando...' }, 3261 { key: 'pedido', label: '05 · Escreva o pedido completo', help: 'Junte identidade, login, sessão, acesso e estados.', placeholder: 'Crie um fluxo de acesso que...' } 3262 ], 3263 exerciseModelAnswer: 'Exemplo didático: alunos, professores e gestores têm contas identificadas por e-mail. O cadastro cria uma conta pendente e envia confirmação. O login valida e-mail e senha no servidor; erros usam uma mensagem genérica. O sucesso cria sessão protegida e leva cada pessoa ao seu painel. Logout, expiração, troca de senha e bloqueio encerram a sessão. Cada painel mostra somente recursos do tipo e status da conta.', 3264 codigos: [ 3265 { codigo: '/identidade-da-conta' }, 3266 { codigo: '/login-com-fluxo' }, 3267 { codigo: '/sessao-com-expiracao' }, 3268 { codigo: '/erro-sem-vazamento' } 3269 ] 3270 }, 3271 { 3272 stage: 'Aula 02', 3273 estimatedMinutes: 40, 3274 layout: 'access-flow', 3275 title: 'Sessão, cookies e tokens', 3276 goal: 'Entenda como o sistema continua reconhecendo uma pessoa depois do login e como pedir esse reconhecimento com duração e limites claros.', 3277 focus: 'Login confirma a identidade uma vez; sessão mantém o contexto. O pedido precisa dizer onde a credencial circula, quanto dura e como é invalidada.', 3278 practice: 'Compare uma área web e um aplicativo. Descreva qual mecanismo mantém o acesso em cada caso e o que deve acontecer quando a sessão expirar.', 3279 exerciseFeedback: 'Uma boa resposta diferencia cookie, token e sessão sem tratar nenhum mecanismo como solução universal. Ela define expiração, logout, renovação e falha.', 3280 lessons: [ 3281 'Login confirma a identidade; sessão mantém o reconhecimento entre requisições.', 3282 'Cookie é um mecanismo comum para transportar a referência de uma sessão no navegador.', 3283 'Token é uma credencial que precisa de escopo, duração e proteção contra uso indevido.', 3284 'Logout, expiração, troca de senha e bloqueio precisam invalidar o acesso quando necessário.' 3285 ], 3286 diagramIntro: 'A pessoa apresenta uma credencial; o sistema cria um contexto de sessão;
3286 cada requisição é conferida antes de liberar o próximo passo.', 3287 diagramNodeLeft: 'Pessoa / dispositivo', 3288 diagramNodeRight: 'Aplicação', 3289 diagramCount: 3, 3290 diagramTraitsCaption: 'Regras que atravessam o fluxo · não são apenas detalhes técnicos', 3291 conceitos: [ 3292 { titulo: 'Sessão', definicao: 'O contexto temporário que liga várias requisições à mesma pessoa depois de um login válido. A sessão permite navegar sem reenviar a senha a cada página.', exemplo: 'O aluno entra uma vez e consegue abrir painel, aulas e progresso enquanto a sessão continua válida.', confuso: 'Mantém logado para sempre.', claro: 'Crie uma sessão para o painel web com duração definida, renovação controlada e encerramento no logout, expiração, troca de senha ou bloqueio.', comoFunciona: ['Defina o evento que cria a sessão.', 'Escolha duração e renovação.', 'Associe a sessão à conta correta.', 'Valide a sessão em cada recurso protegido.', 'Invalide sessões quando houver mudança de risco.'], segundoExemplo: 'Um banco pode exigir nova confirmação depois de um perÃodo sem atividade ou antes de uma operação sensÃvel.', errosComuns: ['Confundir sessão com senha.', 'Não definir quando a sessão expira.', 'Aceitar uma sessão antiga depois de bloquear a conta.'], termos: ['cookie', 'expiração', 'logout'] }, 3293 { titulo: 'Cookie de sessão', definicao: 'Uma informação armazenada pelo navegador e enviada de volta ao site para ajudar a identificar a sessão. O cookie não deve carregar a senha nem virar uma credencial sem proteção.', exemplo: 'O navegador guarda uma referência protegida e a envia apenas ao domÃnio permitido.', confuso: 'Salva o login no navegador.', claro: 'Use cookie de sessão protegido pelo servidor, com escopo de domÃnio e caminho definidos, sem armazenar senha ou dados sensÃveis em texto aberto.', comoFunciona: ['O servidor cria a sessão.', 'O navegador recebe apenas a referência necessária.', 'O cookie limita onde e quando pode ser enviado.', 'O servidor consulta a sessão antes de responder.', 'Logout remove ou invalida a referência.'], segundoExemplo: 'Uma preferência de idioma pode ser um cookie comum; uma sessão autenticada exige controles mais fortes.', errosComuns: ['Guardar senha no cookie.', 'Usar o mesmo cookie para sessão e preferências sem separar os riscos.', 'Achar que esconder o cookie substitui a validação no servidor.'], termos: ['HttpOnly', 'Secure', 'SameSite'] }, 3294 { titulo: 'Token', definicao: 'Uma credencial que representa autorização para uma chamada ou conjunto de chamadas. Token não é sinônimo de sessão: ele precisa de escopo, duração, armazenamento e revogação definidos.', exemplo: 'Um aplicativo móvel recebe um token com acesso limitado à s funções daquela conta.', confuso: 'Gera um token para acessar tudo.', claro: 'Defina quem recebe o token, quais rotas ele pode usar, quando expira, como é renovado e como pode ser revogado sem expor a credencial principal.', comoFunciona: ['Defina o consumidor da API.', 'Limite o escopo do token.', 'Escolha validade curta e renovação segura.', 'Evite colocar dados secretos no conteúdo visÃvel.', 'Registre e revogue quando houver suspeita.'], segundoExemplo: 'Uma integração servidor a servidor pode usar uma chave própria com acesso somente à criação de pedidos.', errosComuns: ['Criar token sem validade.', 'Dar escopo administrativo por conveniência.', 'Colocar token em URL ou mensagem pública.'], termos: ['Bearer', 'escopo', 'revogação'] } 3295 ], 3296 scenario: { title: 'Cenário completo: painel web e aplicativo móvel', intro: 'A mesma escola terá um painel web para gestores e um aplicativo para alunos. O pedido âusa cookie no site e token no appâ ainda não explica os limites.', steps: [ 3297 { tag: 'Separar', text: 'Diga quem chama cada ambiente e qual tipo de sessão ou credencial faz sentido.' }, 3298 { tag: 'Proteger', text: 'Defina onde a referência fica, por quanto tempo vale e quais controles reduzem exposição.' }, 3299 { tag: 'Limitar', text: 'Especifique quais recursos cada sessão ou token pode usar.' }, 3300 { tag: 'Encerrar', text: 'Descreva logout, expiração, troca de senha, bloqueio e revogação.' }, 3301 { tag: 'Testar', text: 'Liste cenários de sessão válida, expirada, revogada, ausente e usada no recurso errado.' } 3302 ] }, 3303 exerciseFields: [ 3304 { key: 'ambientes', label: '01 · Quem chama o sistema?', help: 'Separe painel web, aplicativo e integrações externas.', placeholder: 'No painel web... No aplicativo...' },
3305 { key: 'mecanismo', label: '02 · Qual mecanismo mantém o acesso?', help: 'Explique quando usaria sessão por cookie ou token.', placeholder: 'Para o painel... Para a API...' }, 3306 { key: 'limites', label: '03 · Quais são os limites?', help: 'Defina duração, escopo, renovação e armazenamento.', placeholder: 'A credencial vale por...' }, 3307 { key: 'encerramento', label: '04 · Como o acesso termina?', help: 'Inclua logout, expiração, bloqueio e troca de senha.', placeholder: 'Quando acontecer..., o sistema...' }, 3308 { key: 'testes', label: '05 · Como você vai conferir?', help: 'Liste casos válidos e inválidos para a sessão.', placeholder: 'Testarei uma sessão...' } 3309 ], 3310 exerciseModelAnswer: 'Exemplo didático: o painel web usa sessão por cookie protegido e o aplicativo usa token com escopo de aluno. O painel exige renovação controlada; o token expira em perÃodo curto e pode ser revogado. Nenhuma credencial fica em URL. Logout, troca de senha e bloqueio invalidam acessos ativos. Os testes cobrem sessão ausente, válida, expirada, revogada e usada para acessar recurso de outro usuário.', 3311 codigos: [ 3312 { codigo: '/sessao-com-limite' }, 3313 { codigo: '/cookie-sem-senha' }, 3314 { codigo: '/token-com-escopo' } 3315 ] 3316 }, 3317 { 3318 stage: 'Aula 03', 3319 estimatedMinutes: 45, 3320 layout: 'groups', 3321 title: 'Papéis e permissões', 3322 goal: 'Aprenda a separar quem a pessoa é do que ela pode fazer, transformando âcada um vê uma coisaâ em regras de acesso verificáveis.', 3323 focus: 'Um papel organiza responsabilidades; uma permissão descreve uma ação sobre um recurso; a autorização decide se aquela ação pode acontecer agora.', 3324 practice: 'Escolha um painel conhecido e monte uma pequena matriz: pessoa, papel, recurso, ação permitida e motivo do bloqueio.', 3325 exerciseFeedback: 'Uma boa resposta não para em âadmin pode tudoâ. Ela nomeia recursos e ações, diferencia leitura de alteração e explica o que acontece quando a regra nega.', 3326 lessons: [ 3327 'Papel agrupa responsabilidades; não é uma autorização genérica para tudo.', 3328 'Permissão descreve uma ação sobre um recurso, como visualizar, criar, editar ou excluir.', 3329 'Autorização verifica a regra no momento da ação, no servidor.', 3330 'A regra precisa prever permitido, negado, recurso inexistente e tentativa de acesso fora do escopo.' 3331 ], 3332 groups: [ 3333 { title: 'Quem é a pessoa?', desc: 'Contexto e responsabilidade não são a mesma coisa que acesso.', note: 'Comece pelo papel, mas não use o nome do papel como atalho para âpode tudoâ.' }, 3334 { title: 'O que pode acontecer?', desc: 'Recurso e ação tornam a permissão observável.', note: 'Leia, crie, edite e exclua são ações diferentes, mesmo no mesmo recurso.' } 3335 ], 3336 conceitos: [ 3337 { titulo: 'Papel', definicao: 'Um agrupamento de responsabilidades que ajuda a organizar pessoas com necessidades parecidas. Papel dá contexto, mas não deve substituir a lista de ações permitidas.', exemplo: 'Aluno, professor e gestor podem ter responsabilidades diferentes na mesma escola.', confuso: 'Cria um perfil de administrador que pode tudo.', claro: 'Defina os papéis aluno, professor e gestor. Para cada papel, liste recursos e ações permitidas; não conceda acesso total por padrão.', comoFunciona: ['Liste as pessoas ou contextos existentes.', 'Agrupe responsabilidades semelhantes.', 'Relacione cada papel aos recursos necessários.', 'Revise exceções antes de liberar acesso amplo.'], segundoExemplo: 'Uma pessoa pode ser professora em um curso e aluna em outro, então papel pode depender do contexto.', errosComuns: ['Criar apenas usuário comum e administrador.', 'Usar âadminâ como solução para qualquer bloqueio.', 'Esquecer que uma pessoa pode ter mais de um papel.'], termos: ['função', 'contexto', 'responsabilidade'], grupo: 0 }, 3338 { titulo: 'Permissão', definicao: 'A autorização nomeada para executar uma ação sobre um recurso. Ela deve ser especÃfica o bastante para ser revisada e testada.', exemplo: 'A permissão âeditar aulaâ é diferente de âvisualizar aulaâ e de âpublicar aulaâ.', confuso: 'Dá acesso ao curs
3338o.', claro: 'Crie permissões separadas para visualizar aluno, editar aluno, alterar matrÃcula, publicar aula e emitir certificado.', comoFunciona: ['Nomeie o recurso.', 'Nomeie a ação.', 'Defina o papel ou contexto que recebe a permissão.', 'Registre o que acontece quando a permissão falta.', 'Teste leitura e alteração separadamente.'], segundoExemplo: 'Um professor pode editar o conteúdo da própria aula, mas não alterar o preço do curso.', errosComuns: ['Tratar acesso como uma chave única.', 'Misturar visualizar, editar e excluir.', 'Conceder permissão por tela, sem proteger a ação correspondente.'], termos: ['recurso', 'ação', 'escopo'], grupo: 1 }, 3339 { titulo: 'Autorização', definicao: 'A decisão tomada quando uma pessoa tenta executar uma ação. O sistema verifica identidade, papel, recurso, ação e contexto antes de permitir ou negar.', exemplo: 'O servidor recebe a tentativa de editar uma aula e confere se aquela pessoa pode fazer isso.', confuso: 'Se estiver logado, pode entrar.', claro: 'Em cada ação protegida, valide no servidor se a sessão pertence à pessoa certa e se o papel tem permissão para aquele recurso e contexto.', comoFunciona: ['Identifique quem está fazendo a ação.', 'Confirme que a sessão é válida.', 'Carregue papel, recurso e contexto.', 'Permita ou negue no servidor.', 'Registre a decisão quando a ação for sensÃvel.'], segundoExemplo: 'Esconder o botão âExcluirâ melhora a interface, mas a autorização precisa bloquear a requisição quando alguém tenta chamar a rota diretamente.', errosComuns: ['Confiar apenas em botão escondido.', 'Validar papel no navegador.', 'Retornar sucesso mesmo quando a ação foi negada.'], termos: ['decisão', 'servidor', 'negação'], grupo: 1 }, 3340 { titulo: 'Matriz de acesso', definicao: 'Uma tabela que cruza pessoas ou papéis, recursos e ações para deixar visÃvel quem pode fazer o quê.', exemplo: 'Aluno pode ver suas aulas; professor pode editar suas aulas; gestor pode administrar matrÃculas.', confuso: 'Cada perfil vê uma tela diferente.', claro: 'Monte uma matriz por papel, recurso e ação. Marque permitido, negado e condicionado; inclua exemplos de recursos pertencentes a outra pessoa.', comoFunciona: ['Liste papéis e c
3340ontextos.', 'Liste recursos reais.', 'Separe ações de leitura e alteração.', 'Marque condições como âsomente seus alunosâ.', 'Transforme cada linha crÃtica em cenário de teste.'], segundoExemplo: 'Dois professores podem editar aulas diferentes no mesmo curso porque a regra considera o dono do recurso.', errosComuns: ['Escrever matriz só com telas.', 'Não registrar condições e propriedade.', 'Não testar uma pessoa tentando acessar recurso de outra.'], termos: ['regra', 'propriedade', 'cenário'], grupo: 1 } 3341 ], 3342 scenario: { title: 'Cenário completo: painel de uma escola', intro: 'O gestor pede: âaluno vê suas aulas, professor cuida do conteúdo e gestor administra tudoâ. Transforme isso em regras que podem ser conferidas.', steps: [ 3343 { tag: 'Mapear', text: 'Liste papéis, recursos e ações reais: aulas, alunos, matrÃculas, certificados e preços.' }, 3344 { tag: 'Separar', text: 'Diferencie visualizar, criar, editar, publicar, excluir e administrar.' }, 3345 { tag: 'Condicionar', text: 'Inclua propriedade e contexto: professor edita suas aulas; aluno vê seus próprios dados.' }, 3346 { tag: 'Decidir', text: 'Descreva a resposta para permissão negada e para recurso que não existe.' }, 3347 { tag: 'Testar', text: 'Crie um caso permitido e um caso proibido para cada ação sensÃvel.' } 3348 ] }, 3349 exerciseFields: [ 3350 { key: 'papeis', label: '01 · Quais papéis existem?', help: 'Liste responsabilidades sem usar âadmin pode tudoâ como resposta.', placeholder: 'Aluno..., professor..., gestor...' }, 3351 { key: 'recursos', label: '02 · Quais recursos serão protegidos?', help: 'Use objetos reais do produto.', placeholder: 'Aula, matrÃcula, certificado...' }, 3352 { key: 'acoes', label: '03 · Quais ações cada papel pode fazer?', help: 'Separe visualizar, criar, editar, publicar e excluir.', placeholder: 'Aluno pode visualizar...' }, 3353 { key: 'condicoes', label: '04 · Quais condições limitam o acesso?', help: 'Inclua propriedade, curso, status ou contexto.', placeholder: 'Professor só pode...' }, 3354 { key: 'testes', label: '05 · Como a autorização será testada?', help: 'Escreva um cenário permitido e um negado.', placeholder: 'Se um aluno tentar..., o sistema...' } 3355 ], 3356 exerciseModelAnswer: 'Exemplo didático: aluno pode visualizar suas aulas e progresso; professor pode visualizar alunos do curso e editar o conteúdo das próprias aulas; gestor pode administrar matrÃculas e publicar aulas. A autorização é verificada no servidor em cada ação. Um professor tentando editar aula de outro curso recebe acesso negado e a tentativa sensÃvel é registrada.', 3357 codigos: [ 3358 { codigo: '/papel-nao-e-acesso-total' }, 3359 { codigo: '/recurso-e-acao' }, 3360 { codigo: '/autoriza-no-servidor' } 3361 ] 3362 }, 3363 { 3364 stage: 'Aula 04', 3365 estimatedMinutes: 45, 3366 layout: 'timeline', 3367 title: 'Dados sensÃveis e privacidade', 3368 goal: 'Aprenda a pedir dados com propósito, proteção e prazo, reduzindo exposição sem transformar privacidade em uma promessa vaga.', 3369 focus: 'Dado pessoal não deve ser coletado por hábito. Defina finalidade, acesso, armazenamento, retenção e descarte antes de desenhar o cadastro.', 3370 practice: 'Escolha um fluxo de matrÃcula e classifique cada campo: necessário, opcional, sensÃvel, quem acessa, por quanto tempo e como será removido.', 3371 exerciseFeedback: 'Uma boa resposta explica por que cada dado existe, limita quem consulta e define o que acontece quando a finalidade termina. âGuardar com segurançaâ sozinho não é uma regra testável.', 3372 lessons: [ 3373 'Dado pessoal identifica ou pode tornar uma pessoa identificável; dado sensÃvel exige cuidado ainda maior.', 3374 'Finalidade explica por que o sistema precisa de um campo e ajuda a evitar coleta excessiva.', 3375 'Minimização, acesso restrito e proteção reduzem o impacto de um vazamento.', 3376 'Retenção e descarte precisam ser definidos antes de o dado entrar no banco.' 3377 ], 3378 connectors: ['entender', 'limitar', 'proteger'], 3379 sequenceCount: 4, 3380 conceitos: [ 3381 { titulo: 'Dado pessoal', definicao: 'Informação relacionada a uma pessoa identificada ou que pode ser identificada, sozinha ou combinada com outros dad
3381os.', exemplo: 'Nome, e-mail, telefone e identificador de matrÃcula podem apontar para uma pessoa dentro do sistema.', confuso: 'à só qualquer informação do cadastro.', claro: 'Liste quais campos identificam a pessoa, por que cada um é necessário e quem poderá consultá-los.', comoFunciona: ['Liste os campos coletados.', 'Verifique se cada campo identifica alguém.', 'Relacione o campo a uma finalidade.', 'Defina acesso e retenção.', 'Revise se é possÃvel remover ou reduzir o dado.'], segundoExemplo: 'Um ID interno pode não ter significado fora do sistema, mas junto com a tabela de alunos ainda identifica uma pessoa.', errosComuns: ['Coletar dados âpara usar depoisâ.', 'Confundir dado público com dado sem risco.', 'Espalhar a mesma informação em vários lugares sem necessidade.'], termos: ['identificação', 'cadastro', 'titular'] }, 3382 { titulo: 'Dado sensÃvel', definicao: 'Categoria de dado pessoal que pode causar impacto maior se for exposta ou usada de forma inadequada, como saúde, biometria, religião ou origem racial.', exemplo: 'Uma informação de saúde usada para adaptação de uma atividade precisa de finalidade e acesso muito bem definidos.', confuso: 'à um dado importante para o negócio.', claro: 'Separe dados sensÃveis dos demais, documente a finalidade, restrinja o acesso e evite colocá-los em logs, URLs ou mensagens.', comoFunciona: ['Identifique se o campo pertence a uma categoria sensÃvel.', 'Defina a necessidade real da coleta.', 'Restrinja leitura e exportação.', 'Proteja armazenamento e trânsito.', 'Registre consultas e descarte quando a finalidade acabar.'], segundoExemplo: 'Um relatório pode mostrar apenas que uma adaptação é necessária, sem exibir o diagnóstico para quem não precisa conhecê-lo.', errosComuns: ['Gravar dado sensÃvel em log.', 'Mostrar a informação para toda a equipe.', 'Usar dado sensÃvel como filtro ou exemplo fictÃcio em ambiente real.'], termos: ['categoria especial', 'restrição', 'exposição'] }, 3383 { titulo: 'Finalidade e minimização', definicao: 'A regra de coletar somente o que é necessário para uma finalidade clara e comunicada.', exemplo: 'Para enviar um aviso de aula, o sistema precisa de um canal de contato; não precisa guardar todos os dados da famÃlia.', confuso: 'Pede todos os dados para ficar completo.', claro: 'Para cada campo, escreva a finalidade, o uso esperado e o que acontece se ele não for preenchido.', comoFunciona: ['Descreva o resultado que o fluxo precisa produzir.', 'Liste os dados indispensáveis.', 'Remova campos sem uso definido.', 'Separe o obrigatório do opcional.', 'Revise a coleta quando o produto mudar.'], segundoExemplo: 'Uma compra pode precisar do endereço de entrega, mas não da data de nascimento se ela não muda preço, entrega ou segurança.', errosComuns: ['Manter campo obrigatório por conveniência.', 'Copiar dados entre formulários sem revisar necessidade.', 'Usar a mesma finalidade para justificar qualquer coleta.'], termos: ['necessidade', 'transparência', 'coleta'] }, 3384 { titulo: 'Retenção e descarte', definicao: 'A regra que define por quanto tempo um dado permanece armazenado e como deixa de estar acessÃvel quando a finalidade termina.', exemplo: 'Um documento usado para confirmar um cadastro pode ter prazo de guarda e depois ser removido ou anonimizado.', confuso: 'Nunca apaga porque pode ser útil.', claro: 'Defina prazo, responsável e ação de encerramento: excluir, anonimizar, bloquear ou manter somente o registro exigido.', comoFunciona: ['Associe prazo a cada finalidade.', 'Identifique registros que precisam ser preservados.', 'Automatize ou agende a revisão.', 'Remova cópias, arquivos e Ãndices relacionados.', 'Registre a ação sem guardar o conteúdo descartado.'], segundoExemplo: 'Depois do encerramento de uma conta, o sistema pode bloquear o acesso, apagar dados de contato e manter apenas o registro financeiro obrigatório.', errosComuns: ['Definir prazo apenas no documento, sem rotina técnica.', 'Esquecer anexos e cópias de backup.', 'Apagar o registro de que uma ação ocorreu junto com o dado original.'], termos: ['prazo de guarda', 'anonimização', 'eliminação'] } 3385 ], 3386 scenario: { title: 'Cenário completo: matrÃcula em uma escola', intro: 'A escola pede nome, e-mail, telefone, documento, endereço e informações de saúde. Transforme esse cadastro em regras de necessidade, acesso e prazo.', steps: [ 3387 { tag: 'Classificar', text: 'Separe dados de identificação, contato, cobrança e informações sensÃveis.' }, 3388 { tag: 'Justificar', text: 'Escreva a finalidade de ca
3388da campo e remova o que não tiver uso definido.' }, 3389 { tag: 'Restringir', text: 'Defina quais papéis podem consultar, editar, exportar ou apenas receber um resultado resumido.' }, 3390 { tag: 'Proteger', text: 'Indique onde o dado não pode aparecer: URL, log, mensagem, planilha aberta ou resposta excessiva.' }, 3391 { tag: 'Encerrar', text: 'Defina prazo de retenção e a ação quando a matrÃcula ou a finalidade terminar.' } 3392 ] }, 3393 exerciseFields: [ 3394 { key: 'dados', label: '01 · Quais dados entram?', help: 'Liste somente campos necessários e marque os sensÃveis.', placeholder: 'Nome..., e-mail..., informação sensÃvel...' }, 3395 { key: 'finalidade', label: '02 · Para que cada dado serve?', help: 'Relacione campo e resultado que ele permite produzir.', placeholder: 'O e-mail serve para...' }, 3396 { key: 'acesso', label: '03 · Quem pode consultar?', help: 'Defina leitura, edição, exportação e resumo por papel.', placeholder: 'Aluno..., professor..., gestor...' }, 3397 { key: 'protecao', label: '04 · Onde o dado não pode aparecer?', help: 'Inclua logs, URLs, mensagens e telas.', placeholder: 'Nunca exibiremos...' }, 3398 { key: 'retencao', label: '05 · Quando o dado deixa de existir?', help: 'Defina prazo e ação: excluir, anonimizar ou bloquear.', placeholder: 'Ao terminar..., o sistema...' } 3399 ], 3400 exerciseModelAnswer: 'Exemplo didático: a matrÃcula coleta nome e e-mail para identificar e comunicar a pessoa; endereço só entra se houver entrega ou exigência operacional; informação de saúde fica separada, com acesso restrito e sem aparecer em logs ou exportações gerais. Cada finalidade tem prazo definido. Ao encerrar a matrÃcula, o sistema bloqueia o acesso, remove dados sem obrigação de guarda e registra a ação sem manter o conteúdo descartado.', 3401 codigos: [ 3402 { codigo: '/finalidade-antes-do-campo' }, 3403 { codigo: '/dado-sensivel-restrito' }, 3404 { codigo: '/prazo-e-descarte' } 3405 ] 3406 }, 3407 { 3408 stage: 'Aula 05', 3409 estimatedMinutes: 45, 3410 layout: 'timeline', 3411 title: 'Recuperação de acesso, expiração e bloqueio', 3412 goal: 'Aprenda a desenhar uma recuperação de acesso que ajude a pessoa sem criar uma nova porta de entrada para invasões.', 3413 focus: 'Recuperar uma conta exige provar controle de um canal, limitar tentativas, expirar o pedido e encerrar acessos antigos quando a credencial muda.', 3414 practice: 'Desenhe o fluxo âesqueci minha senhaâ de uma plataforma: inÃcio, envio, validação, troca, expiração, bloqueio e mensagem apresentada em cada etapa.', 3415 exerciseFeedback: 'Uma boa resposta não envia senha por e-mail nem aceita código infinito. Ela define validade, uso único, limite de tentativas, resposta sem vazamento e invalidação das sessões anteriores.', 3416 lessons: [ 3417 'Recuperação não confirma a senha antiga: ela cria uma prova temporária de controle de um canal confiável.', 3418 'Código e link de recuperação precisam ter validade curta, uso único e limite de tentativas.', 3419 'Expiração encerra uma oportunidade; bloqueio reduz tentativas abusivas e precisa de caminho de retorno.', 3420 'Depois de trocar a credencial, sessões antigas e pedidos de recuperação devem ser revogados quando o risco exigir.' 3421 ], 3422 connectors: ['iniciar', 'validar', 'encerrar'], 3423 sequenceCount: 4, 3424 conceitos: [ 3425 { titulo: 'Recuperação de acesso', definicao: 'Fluxo que permite à pessoa retomar uma conta sem conhecer a credencial anterior, depois de uma verificação temporária e controlada.', exemplo: 'A pessoa informa o e-mail, recebe um link de uso único e cria uma nova senha dentro do prazo.', confuso: 'Manda a senha por e-mail.', claro: 'Crie recuperação por link ou código temporário, sem revelar se a conta existe e sem enviar a senha anterior.', comoFunciona: ['Receba o identificador sem confirmar a existência da conta.', 'Envie a instrução pelo canal cadastrado.', 'Valide o segredo temporário.', 'Permita definir nova credencial.', 'Encerre o pedido e revise sessões ativas.'], segundoExemplo: 'O suporte pode iniciar uma recuperação assistida, mas precisa registrar a decisão e exigir uma verificação equivalente.', errosComuns: ['
3425Enviar a senha atual.', 'Mostrar âe-mail não cadastradoâ.', 'Permitir recuperação sem prazo ou sem registro.'], termos: ['canal confiável', 'credencial', 'verificação'] }, 3426 { titulo: 'Código de uso único', definicao: 'Segredo temporário que pode ser aceito uma única vez para confirmar uma etapa do fluxo.', exemplo: 'Um código de seis dÃgitos chega ao e-mail e deixa de funcionar depois do primeiro uso ou do vencimento.', confuso: 'Gera um código que vale até a pessoa usar quando quiser.', claro: 'Gere um código aleatório, com validade curta, uso único, limite de tentativas e armazenamento que não revele o valor original.', comoFunciona: ['Gere o código no servidor.', 'Associe-o à conta e à finalidade.', 'Defina expiração e tentativas.', 'Compare com proteção contra repetição.', 'Marque como usado e invalide códigos anteriores.'], segundoExemplo: 'Um código para trocar senha não deve funcionar para confirmar uma compra ou alterar o e-mail.', errosComuns: ['Reutilizar o mesmo código.', 'Colocar o código na URL por tempo indefinido.', 'Não invalidar o código após uma tentativa bem-sucedida.'], termos: ['uso único', 'tentativa', 'expiração'] }, 3427 { titulo: 'Expiração', definicao: 'Momento em que um link, código, sessão ou autorização deixa de ser aceito porque o prazo definido terminou.', exemplo: 'Um link de recuperação enviado há uma hora mostra que expirou e oferece iniciar o processo novamente.', confuso: 'O sistema deixa de funcionar do nada.', claro: 'Defina duração, relógio usado pelo servidor, mensagem de retorno e o caminho para solicitar uma nova tentativa.', comoFunciona: ['Defina o prazo no servidor.', 'Compare a validade em toda tentativa.', 'Não aceite o item vencido mesmo que o valor esteja correto.', 'Mostre uma recuperação clara.', 'Registre vencimento sem expor o segredo.'], segundoExemplo: 'Uma sessão pode expirar por tempo sem atividade, enquanto um código de recuperação expira por prazo fixo.', errosComuns: ['Confiar no relógio do navegador.', 'Manter link válido depois de trocar a senha.', 'Usar a mesma mensagem para erro interno e item expirado.'], termos: ['prazo', 'tempo sem atividade', 'renovação'] }, 3428 { titulo: 'Bloqueio e desbloqueio', definicao: 'Regra que interrompe novas tentativas quando há sinais de abuso ou risco, junto de um caminho controlado para retomar o acesso.', exemplo: 'Após várias tentativas inválidas, o fluxo reduz a velocidade e orienta uma recuperação segura.', confuso: 'Bloqueia para sempre quando errar.', claro: 'Defina o limite, a duração ou revisão do bloqueio, a mensagem genérica e o processo de desbloqueio sem permitir contornar a proteção.', comoFunciona: ['Conte tentativas no servidor.', 'Aplique atraso, limite ou bloqueio proporcional.', 'Evite informar qual parte da credencial falhou.', 'Ofereça recuperação independente do login.', 'Registre e revise bloqueios suspeitos.'], segundoExemplo: 'Uma conta pode exigir confirmação adicional após muitas tentativas, sem revelar ao atacante se o e-mail existe.', errosComuns: ['Bloquear por um único erro.', 'Permitir desbloqueio por pergunta fácil.', 'Deixar o suporte reativar a conta sem registrar a decisão.'], termos: ['limite', 'atraso progressivo', 'desbloqueio'] } 3429 ], 3430 scenario: { title: 'Cenário completo: âesqueci minha senhaâ', intro: 'Uma pessoa perdeu acesso ao e-mail usado no cadastro e pede um botão para recuperar a conta. Transforme esse pedido em um fluxo seguro e compreensÃvel.', steps: [ 3431 { tag: 'Iniciar', text: 'Receba o identificador sem confirmar se existe uma conta e explique o próximo passo.' }, 3432 { tag: 'Enviar', text: 'Use o canal confiável cadastrado e informe prazo, uso único e o que fazer se a mensagem não chegar.' }, 3433 { tag: 'Validar', text: 'Confira o código no servidor, limite tentativas e descarte pedidos anteriores quando necessário.' }, 3434 { tag: 'Trocar', text: 'Permita uma nova senha com regras claras e não reutilize a credencial anterior.' }, 3435 { tag: 'Encerrar', text: 'Invalide o link, códigos e sessões antigas; registre o evento sem expor o segredo.' } 3436 ] }, 3437 exerciseFields: [ 3438 { key: 'inicio', label: '01 · Como a recuperação começa?', help: 'Defina o identificador, a mensagem e o que não será revelado.', placeholder: 'A pessoa informa..., e o sistema responde...' }, 3439 { key: 'canal', label: '02 · Qual canal confirma o controle?', help: 'Explique por onde o link ou código chega e quais limites existem.', placeholder: 'O código é enviado para...' }, 3440 { key: 'validade', label: '03 · Qual validade e limite?', help: 'Defina prazo, uso único e tentativas.', placeholder: 'O código vale por..., com...' }, 3441 { key: 'bloqueio', label: '04 · Quando bloquear ou atrasar?', help: 'Descreva o comportamento após tentativas suspeitas.', placeholder: 'Depois de..., o sistema...' }, 3442 { key: 'encerramento', label: '05 · O que é invalidado depois?', help: 'Inclua sessões, códigos, links e registros.', placeholder: 'Ao trocar a senha..., o sistema...' } 3443 ], 3444 exerciseModelAnswer: 'Exemplo didático: a pessoa informa o e-mail e recebe a mesma resposta exista ou não uma conta. O servidor gera um código de uso único enviado ao canal cadastrado, válido por 15 minutos e com cinco tentativas. Após a troca da senha, o código e pedidos anteriores são invali
3444dados, sessões antigas são encerradas e o evento é registrado sem guardar o segredo. Tentativas excessivas recebem atraso progressivo e um caminho de recuperação controlado.', 3445 codigos: [ 3446 { codigo: '/recuperacao-sem-vazamento' }, 3447 { codigo: '/codigo-com-validade' }, 3448 { codigo: '/troca-encerra-sessoes' } 3449 ] 3450 }, 3451 { 3452 stage: 'Aula 06', 3453 estimatedMinutes: 45, 3454 layout: 'timeline', 3455 title: 'Auditoria, histórico e rastreabilidade', 3456 goal: 'Aprenda a pedir registros que expliquem o que aconteceu sem transformar logs em um depósito de dados sensÃveis.', 3457 focus: 'Um registro útil conecta pessoa, ação, recurso, momento e resultado. Ele precisa ser protegido, pesquisável e proporcional ao risco.', 3458 practice: 'Escolha uma ação sensÃvel â alterar permissão, trocar senha ou exportar dados â e defina quais eventos serão registrados e revisados.', 3459 exerciseFeedback: 'Uma boa resposta registra contexto suficiente para investigar, evita senha e token, diferencia evento técnico de decisão de negócio e define quem consulta o histórico.', 3460 lessons: [ 3461 'Auditoria responde perguntas sobre uma ação: quem fez, o quê, em qual recurso, quando e com qual resultado.', 3462 'Histórico de negócio ajuda a pessoa a entender mudanças; log técnico ajuda a equipe a investigar falhas.', 3463 'O registro precisa proteger dados sensÃveis, evitar segredos e manter integridade
3463contra alteração silenciosa.', 3464 'Rastreabilidade depende de busca, retenção, correlação e procedimento de revisão â não só de gravar linhas.' 3465 ], 3466 connectors: ['registrar', 'proteger', 'investigar'], 3467 sequenceCount: 4, 3468 conceitos: [ 3469 { titulo: 'Evento de auditoria', definicao: 'Registro estruturado de uma ação relevante, com contexto suficiente para entender quem tentou fazer o quê e qual foi o resultado.', exemplo: 'Uma alteração de permissão registra a conta, o recurso afetado, o horário, a origem e se foi aceita ou negada.', confuso: 'Salva tudo que acontece na tela.', claro: 'Defina eventos de risco, campos obrigatórios, resultado e regra de acesso ao histórico.', comoFunciona: ['Escolha ações que merecem registro.', 'Capture ator, recurso, ação, horário e resultado.', 'Associe uma referência de correlação.', 'Proteja o registro contra alteração indevida.', 'Defina consulta e retenção.'], segundoExemplo: 'Uma tentativa de exportar dados pode gerar evento mesmo quando a autorização nega a ação.', errosComuns: ['Registrar somente sucesso.', 'Gravar texto solto sem contexto.', 'Colocar senha ou token no evento.'], termos: ['ator', 'recurso', 'resultado'] }, 3470 { titulo: 'Histórico de mudanças', definicao: 'Visão compreensÃvel das alterações feitas em um item ao longo do tempo, com autor e momento de cada mudança.', exemplo: 'O histórico de uma matrÃcula mostra quem alterou o status de pendente para ativa e quando.', confuso: 'Mostra os logs do sistema para todo mundo.', claro: 'Apresente mudanças relevantes em linguagem clara, limite a visualização por permissão e diferencie valor antigo, novo e motivo.', comoFunciona: ['Escolha o objeto que terá histórico.', 'Registre campo, valor anterior e novo quando necessário.', 'Mostre autor e data no fuso definido.', 'Separe detalhe técnico de resumo para o usuário.', 'Permita consultar sem editar o passado.'], segundoExemplo: 'Um aluno vê que sua matrÃcula foi atualizada; somente o gestor autorizado acessa o contexto técnico completo.', errosComuns: ['Usar histórico como lixeira de dados.', 'Permitir editar o passado sem deixar evidência.', 'Exibir informação sensÃvel para quem só precisa do status.'], termos: ['valor anterior', 'motivo', 'linha do tempo'] }, 3471 { titulo: 'Integridade do registro', definicao: 'Garantia de que um evento não foi alterado ou removido sem que isso seja detectável.', exemplo: 'Um registro de auditoria protegido mantém a evidência mesmo quando alguém com acesso administrativo consulta o painel.', confuso: 'Coloca o log em uma tabela diferente.', claro: 'Defina quem pode escrever, consultar e administrar registros, como alterações são detectadas e qual cópia protegida existe.', comoFunciona: ['Restrinja escrita e exclusão.', 'Separe operação de consulta e administração.', 'Use encadeamento, assinatura ou armazenamento protegido quando necessário.', 'Monitore falhas de gravação.', 'Teste tentativa de alteração e remoção.'], segundoExemplo: 'Uma exportação periódica para armazenamento somente leitura ajuda a comparar o histórico original com a base operacional.', errosComuns: ['Confiar no mesmo administrador para apagar e investigar.', 'Não alertar quando o registro falha.', 'Confundir backup com prova de integridade.'], termos: ['imutabilidade', 'integridade', 'armazenamento protegido'] }, 3472 { titulo: 'Rastreabilidade', definicao: 'Capacidade de reconstruir a sequência de eventos de uma ação ou incidente, ligando requisições, decisões e efeitos.', exemplo: 'Um identificador de correlação conecta o pedido de troca de senha, o envio do código e a criação da nova sessão.', confuso: 'Tem um log para cada tela.', claro: 'Use um identificador de correlação, relógio consistente, contexto mÃnimo e consulta que permita seguir o fluxo completo.', comoFunciona: ['Gere uma referência por operação.', 'Propague-a entre serviços e tarefas.', 'Registre inÃcio, decisão e efeito.', 'Concentre eventos relacionados numa busca.', 'Documente como investigar o caso.'], segundoExemplo: 'Uma compra pode ser ligada ao webhook, à matrÃcula criada e ao e-mail enviado sem guardar o conteúdo completo de cada mensagem.', errosComuns: ['Usar somente o ID da pessoa.', 'Não sincronizar horário entre serviços.', 'Registrar eventos sem indicar se a ação terminou.'], termos: ['correlação', 'sequência', 'investigação'] } 3473 ], 3474 scenario: { title: 'Cenário completo: alteração de permissão', intro: 'Um gestor altera o papel de uma pessoa e depois surge uma dúvida sobre quem autorizou a mudança. Transforme o pedido em uma trilha investigável.', steps: [ 3475 { tag: 'Definir', text: 'Escolha o evento e os campos mÃnimos: ator, ação, recurso, contexto, horário e resultado.' }, 3476 { tag: 'Registrar', text: 'Grave a decisão permitida ou negada sem incluir senha, token ou conteúdo desnecessário.' },
3477 { tag: 'Proteger', text: 'Restrinja escrita, consulta e remoção; defina como detectar alteração indevida.' }, 3478 { tag: 'Relacionar', text: 'Conecte a alteração a pedido, tela, API e operação por um identificador de correlação.' }, 3479 { tag: 'Investigar', text: 'Descreva como uma pessoa autorizada encontra a sequência e qual ação toma ao detectar anomalia.' } 3480 ] }, 3481 exerciseFields: [ 3482 { key: 'evento', label: '01 · Qual ação será auditada?', help: 'Escolha uma ação sensÃvel e diga por que ela precisa de registro.', placeholder: 'Vamos registrar quando...' }, 3483 { key: 'campos', label: '02 · Quais campos entram?', help: 'Inclua ator, ação, recurso, horário e resultado.', placeholder: 'O evento terá...' }, 3484 { key: 'protecao', label: '03 · Como o registro é protegido?', help: 'Defina escrita, consulta, remoção e dados proibidos.', placeholder: 'Somente..., nunca...' }, 3485 { key: 'correlacao', label: '04 · Como seguir a sequência?', help: 'Explique correlação entre serviços e etapas.', placeholder: 'Usaremos o identificador...' }, 3486 { key: 'revisao', label: '05 · Quem revisa e quando?', help: 'Defina acesso, retenção e resposta a anomalias.', placeholder: 'A revisão acontece...' } 3487 ], 3488 exerciseModelAnswer: 'Exemplo didático: cada alteração de permissão registra o ator, a ação, o recurso, o contexto, data e hora, origem, resultado e identificador de correlação. Senhas, tokens e conteúdo sensÃvel ficam fora. A aplicação grava; a equipe autorizada consulta; remoções são bloqueadas ou deixam evidência. Uma busca por correlação reconstrói pedido, decisão e efeito, e anomalias geram revisão.', 3489 codigos: [ 3490 { codigo: '/auditoria-com-contexto' }, 3491 { codigo: '/historico-legivel' }, 3492 { codigo: '/rastreia-por-correlacao' } 3493 ] 3494 }, 3495 { 3496 stage: 'Aula 07', 3497 estimatedMinutes: 45, 3498 layout: 'groups', 3499 title: 'Riscos comuns em pedidos de sistema', 3500 goal: 'Aprenda a reconhecer pedidos aparentemente simples que podem abrir brechas de acesso, expor dados ou enfraquecer uma conta.', 3501 focus: 'Troque frases vagas como âdeixa públicoâ ou âfacilita o loginâ por regras verificáveis de proteção, escopo e recuperação.', 3502 practice: 'Escolha uma tela ou fluxo e faça uma revisão defensiva: quem acessa, que dado aparece, que credencial é exigida e qual abuso precisa ser bloqueado.', 3503 exerciseFeedback: 'Uma boa resposta aponta o risco, o comportamento seguro, o teste que comprova a proteção e a mensagem que a pessoa receberá.', 3504 lessons: [ 3505 'Acesso indevido acontece quando a pessoa consegue uma ação ou recurso fora do papel, propriedade ou contexto permitido.', 3506 'Vazamento pode nascer de resposta, log, URL, exportação, mensagem ou ambiente mal separado.', 3507 'Senha forte ajuda, mas proteção também depende de limite, sessão, recuperação e bloqueio.', 3508 'Link público precisa de escopo, prazo, revogação e decisão explÃcita sobre o que pode ser visto.' 3509 ], 3510 groups: [ 3511 { title: 'Onde o risco aparece?', desc: 'Pedidos de tela, API, cadastro e compartilhamento podem esconder consequências.', note: 'Leia a frase e procure quem ganha acesso, por quanto tempo e a qual dado.' }, 3512 { title: 'Como provar a proteção?', desc: 'Toda regra precisa de cenário permitido, negado e de recuperação.', note: 'Se não dá para testar, ainda está vaga.' } 3513 ], 3514 conceitos: [ 3515 { titulo: 'Acesso indevido', definicao: 'Uso de uma ação ou recurso por alguém que não deveria ter aquela permissão, propriedade ou condição.', exemplo: 'Um aluno altera a matrÃcula de outra pessoa trocando o ID na URL.', confuso: 'Esconde o botão para quem não pode.', claro: 'Valide no servidor identidade, papel, recurso e contexto; crie testes com recurso próprio e de outra pessoa.', comoFunciona: ['Liste o recurso protegido.', 'Defina dono, papel e condição.', 'Valide a regra no servidor.', 'Retorne negação sem vazar dados.', 'Teste acesso direto e variação de identificador.'], segundoExemplo: 'Um professor pode editar sua aula, mas recebe negação ao enviar uma requisição para a aula de outro curso.', errosComuns: ['Confiar na tela.', 'Usar IDs previsÃveis sem checagem.', 'Responder dados do recurso antes de autorizar.'], termos: ['controle de acesso', 'propriedade', 'negação'] , grupo: 0 }, 3516 { titulo: 'Vazamento de dados', definicao: 'Exposição de informação para pessoas, sistemas ou ambientes que não deveriam recebê-la.', exemplo: 'Uma resposta de API envia endereço e telefone mesmo quando a tela só precisava do nome.', confuso: 'Só existe vazamento quando alguém invade.', claro: 'Retorne o mÃnimo necessário, remova segredos de logs e controle exportações, URLs, mensagens e ambientes.', comoFunciona: ['Mapeie onde o dado aparece.', 'Reduza respostas ao necessário.', 'Separe ambientes e acessos.', 'Proteja logs e arquivos.', 'Teste usuário, suporte e exportação.'], segundoExemplo: 'Um erro detalhado exibido no navegador pode revelar tabela, caminho de arquivo ou credencial mesmo sem invasão.', errosComuns: ['
3516Enviar objeto completo por conveniência.', 'Colocar token em URL.', 'Usar dados reais em ambiente de teste.'], termos: ['exposição', 'resposta mÃnima', 'ambiente de teste'], grupo: 0 }, 3517 { titulo: 'Senha fraca', definicao: 'Credencial fácil de adivinhar, reutilizada ou protegida por regras insuficientes para o risco do sistema.', exemplo: 'Uma senha curta e repetida em vários serviços amplia o impacto de um vazamento externo.', confuso: 'Pede uma senha com sÃmbolo e está seguro.', claro: 'Defina tamanho mÃnimo, bloqueio de tentativas, recuperação segura, armazenamento protegido e orientação contra reutilização.', comoFunciona: ['Defina polÃtica proporcional ao risco.', 'Armazene somente representação protegida.', 'Limite tentativas e monitore abuso.', 'Ofereça troca e recuperação controladas.', 'Exija nova senha quando houver suspeita.'], segundoExemplo: 'Para uma ação sensÃvel, a pessoa pode precisar confirmar a senha ou usar uma etapa adicional mesmo com sessão válida.', errosComuns: ['Obrigar troca frequente sem motivo.', 'Guardar senha reversÃvel.', 'Confundir complexidade visual com resistência real.'], termos: ['força da senha', 'reutilização', 'tentativa'] , grupo: 1 }, 3518 { titulo: 'Link público sem controle', definicao: 'Endereço compartilhável que permite acesso além do escopo, prazo ou pessoa esperada.', exemplo: 'Um link de certificado pode ser público; um link de documento pessoal precisa de expiração ou autenticação.', confuso: 'Gera um link para qualquer pessoa ver.', claro: 'Defina conteúdo, público, validade, revogação e resposta quando o link for usado fora do contexto.', comoFunciona: ['Escolha o que o link representa.', 'Limite escopo e duração.', 'Evite dados excessivos na URL.', 'Permita revogar ou invalidar.', 'Registre uso e teste compartilhamento indevido.'], segundoExemplo: 'Um convite para uma turma pode expirar depois do aceite e não deve revelar a lista de alunos para quem recebeu o endereço.', errosComuns: ['Usar ID secreto como única proteção.', 'Nunca expirar link.', 'Deixar o conteúdo acessÃvel depois de revogar.'], termos: ['escopo', 'revogação', 'compartilhamento'], grupo: 1 } 3519 ], 3520 scenario: { title: 'Cenário completo: compartilhar um certificado', intro: 'O produto quer permitir que uma pessoa compartilhe um certificado por link. Transforme a ideia em uma decisão segura e testável.', steps: [ 3521 { tag: 'Definir', text: 'Diga exatamente qual conteúdo aparece e para quem o link serve.' }, 3522 { tag: 'Limitar', text: 'Escolha escopo, prazo, revogação e se haverá autenticação.' }, 3523 { tag: 'Reduzir', text: 'Remova dados que não ajudam a verificar o certificado.' }, 3524 { tag: 'Testar', text: 'Confira link válido, expirado, revogado, alterado e compartilhado com outra pessoa.' }, 3525 { tag: 'Responder', text: 'Defina mensagem clara para acesso negado ou conteúdo indisponÃvel sem revelar detalhes.' } 3526 ] }, 3527 exerciseFields: [ 3528 { key: 'risco', label: '01 · Qual risco está presente?', help: 'Escolha acesso indevido, vazamento, senha fraca ou link sem controle.', placeholder: 'O risco principal é...' }, 3529 { key: 'regra', label: '02 · Qual regra protege?', help: 'Escreva o comportamento esperado do servidor.', placeholder: 'O sistema deve...' }, 3530 { key: 'dados', label: '03 · O que pode aparecer?', help: 'Liste o mÃnimo necessário e o que deve ficar oculto.', placeholder: 'Será exibido..., nunca...' }, 3531 { key: 'testes', label: '04 · Quais testes provam?', help: 'Inclua permitido, negado, expirado e revogado quando fizer sentido.', placeholder: 'Testarei quando...' }, 3532 { key: 'recuperacao', label: '05 · Como a pessoa se recupera?', help: 'Defina mensagem e próximo passo sem vazamento.', placeholder: 'Se for negado ou expirado...' } 3533 ], 3534 exerciseModelAnswer: 'Exemplo didático: o link mostra somente nome, curso e autenticidade do certificado. Ele tem escopo de leitura, prazo definido e pode ser revogado. A API não retorna dados de contato nem aceita alteração pelo link. Os testes cobrem link válido, expirado, revogado, ID alterado e tentativa de acesso a outro re
3534curso. A mensagem informa que o conteúdo não está disponÃvel e orienta procurar o dono ou o suporte.', 3535 codigos: [ 3536 { codigo: '/teste-acesso-fora-do-escopo' }, 3537 { codigo: '/resposta-minima' }, 3538 { codigo: '/link-com-prazo' } 3539 ] 3540 }, 3541 { 3542 stage: 'Aula 08', 3543 estimatedMinutes: 55, 3544 layout: 'timeline', 3545 title: 'Projeto final: revisão defensiva de um fluxo', 3546 goal: 'Consolide o curso transformando um pedido de sistema em regras de acesso, proteção, testes e evidências que outra pessoa consiga revisar.', 3547 focus: 'O projeto final não é desenhar uma tela bonita: é demonstrar quem entra, o que pode fazer, quais dados aparecem, como o acesso termina e como provar que as regras funcionam.', 3548 practice: 'Escolha um fluxo de escola, loja ou equipe e entregue uma ficha defensiva com atores, estados, recursos, riscos, testes e decisões pendentes.', 3549 exerciseFeedback: 'Uma entrega completa conecta regra e evidência: cada decisão tem um cenário permitido, um negado ou expirado, uma mensagem segura e um registro de auditoria quando necessário.', 3550 lessons: [ 3551 'Comece pelo fluxo e pelas pessoas: identidade, sessão, papéis e recursos vêm antes da interface.', 3552 'Para cada ação, defina permissão, contexto, dado mÃnimo e resposta quando a regra negar.', 3553 'Inclua ciclo de vida: recuperação, expiração, bloqueio, revogação, retenção e descarte.', 3554 'Feche com checklist, evidências e decisões que ainda precisam de produto, jurÃdico ou operação.' 3555 ], 3556 connectors: ['mapear', 'proteger', 'provar'], 3557 sequenceCount: 4, 3558 conceitos: [ 3559 { titulo: 'Checklist defensivo', definicao: 'Lista de perguntas verificáveis que percorre um fluxo para encontrar riscos antes ou depois de uma mudança.', exemplo: 'O checklist pergunta se uma pessoa sem sessão recebe negação, se outro aluno acessa o recurso e se o evento sensÃvel fica registrado.', confuso: 'Confere segurança geral.', claro: 'Monte perguntas por identidade, sessão, autorização, dados, recuperação, auditoria e compartilhamento; marque evidência e pendência.', comoFunciona: ['Divida o fluxo em etapas.', 'Transforme cada risco em pergunta.', 'Defina resultado esperado.', 'Anexe evidência ou cenário de teste.', 'Registre pendências e responsável.'], segundoExemplo: 'Depois de publicar um link de certificado, o checklist verifica conteúdo, prazo, revogação, dados expostos e acesso fora do escopo.', errosComuns: ['Escrever perguntas vagas.', 'Marcar tudo como ok sem evidência.', 'Usar checklist só uma vez.'], termos: ['verificação', 'evidência', 'pendência'] }, 3560 { titulo: 'Critério de aceite', definicao: 'Condição observável que permite decidir se uma regra ou entrega está correta.', exemplo: 'âAluno não consegue editar a aulaâ é observável quando o teste chama a rota e recebe negação sem alterar o dado.', confuso: 'Quando estiver seguro, está pronto.', claro: 'Escreva critérios com pessoa, ação, recurso, condição e resposta esperada; inclua casos de erro e recuperação.', comoFunciona: ['Descreva o cenário.', 'Defina a ação.', 'Declare o resultado esperado.', 'Escolha evidência.', 'Revise com quem aprova a entrega.'], segundoExemplo: 'Um link expirado deve negar acesso, não revelar o conteúdo e orientar uma nova solicitação quando fizer sentido.', errosComuns: ['Usar adjetivos sem teste.', 'Cobrir só o caminho feliz.', 'Aceitar tela sem validar API e dados.'], termos: ['aceite', 'cenário', 'resultado esperado'] }, 3561 { titulo: 'Plano de correção', definicao: 'Sequência priorizada de ações para reduzir um risco, com responsável, impacto, prazo e forma de verificar o resultado.', exemplo: 'Após encontrar exportação excessiva, o plano reduz a resposta, testa papéis e revisa logs antes de publicar.', confuso: 'Corrige os problemas de segurança.', claro: 'Para cada risco, registre impacto, ação, responsável, prazo, dependência e teste de reteste.', comoFunciona: ['Descreva o risco e o impacto.', 'Escolha a correção mÃnima segura.', 'Atribua responsável e prioridade.', 'Defina reteste e evidência.', 'Feche ou reabra com motivo.'], segundoExemplo: 'Uma senha fraca pode exigir limite de tentativas agora e migração gradual de credenciais numa etapa posterior.', errosComuns: ['Priorizar pelo susto, sem impacto.', 'Corrigir sem retestar.', 'Deixar ação sem responsável.'], termos: ['prioridade', 'reteste', 'responsável'] }, 3562 { titulo: 'Decisão pendente', definicao: 'Questão que impede uma regra de ser fe
3562chada e precisa de escolha explÃcita antes da implementação ou publicação.', exemplo: 'O time ainda precisa decidir se o certificado será público ou exigirá autenticação.', confuso: 'Depois a gente vê.', claro: 'Liste a decisão, opções, risco de cada caminho, pessoa responsável e prazo para não transformar ambiguidade em comportamento inseguro.', comoFunciona: ['Escreva a pergunta concreta.', 'Apresente opções possÃveis.', 'Explique impacto e risco.', 'Defina quem decide.', 'Converta a decisão em regra e teste.'], segundoExemplo: 'A retenção de um documento pode depender de decisão jurÃdica; enquanto isso, o sistema restringe o acesso e evita novas cópias.', errosComuns: ['Esconder decisão dentro do código.', 'Liberar caminho mais amplo por padrão.', 'Não registrar o motivo da escolha.'], termos: ['opção', 'risco', 'responsável'] } 3563 ], 3564 scenario: { title: 'Projeto completo: área do aluno', intro: 'Uma escola quer uma área em que o aluno vê aulas e progresso, o professor edita conteúdo e o gestor administra matrÃculas. Entregue uma revisão defensiva antes da publicação.', steps: [ 3565 { tag: 'Mapear', text: 'Liste pessoas, estados da conta, sessões, papéis, recursos e ações.' }, 3566 { tag: 'Proteger', text: 'Defina autorização no servidor, dados mÃnimos, recuperação, expiração e compartilhamentos.' }, 3567 { tag: 'Testar', text: 'Escreva cenários permitido, negado, expirado, revogado, recurso inexistente e tentativa repetida.' }, 3568 { tag: 'Registrar', text: 'Escolha eventos de auditoria e a evidência que comprova cada critério de aceite.' }, 3569 { tag: 'Decidir', text: 'Separe pendências de produto, operação ou jurÃdico e atribua próximo passo.' } 3570 ] }, 3571 exerciseFields: [ 3572 { key: 'fluxo', label: '01 · Qual fluxo será revisado?', help: 'Defina inÃcio, pessoa principal e resultado esperado.', placeholder: 'O fluxo começa quando...' }, 3573 { key: 'regras', label: '02 · Quais regras protegem?', help: 'Resuma identidade, sessão, permissão e dados.', placeholder: 'A pessoa..., o servidor...' }, 3574 { key: 'testes', label: '03 · Quais cenários provam?', help: 'Inclua permitido, negado, expirado, revogado e erro.', placeholder: 'Vou testar...' }, 3575 { key: 'evidencias', label: '04 · Qual evidência será guardada?', help: 'Liste resposta, captura, registro, teste ou decisão.', placeholder: 'A evidência será...' }, 3576 { key: 'pendencias', label: '05 · O que ainda precisa de decisão?', help: 'Atribua responsável e próximo passo.', placeholder: 'Falta decidir..., responsável...' } 3577 ], 3578 exerciseModelAnswer: 'Exemplo didático: o aluno entra com sessão protegida, vê somente suas aulas e progresso e não edita conteúdo. Professor edita aulas do próprio curso; gestor administra matrÃculas. A API retorna dados mÃnimos e autoriza cada ação no servidor. Os testes cobrem sessão ausente, recurso de outra pessoa, expiração, revogação, tentativa repetida e link compartilhado. Cada risco tem evidência, responsável e pendência registrada.', 3579 codigos: [ 3580 { codigo: '/checklist-por-fluxo' }, 3581 { codigo: '/criterio-observavel' }, 3582 { codigo: '/risco-com-responsavel' } 3583 ] 3584 }, 3585 { 3586 stage: 'Aula 09', 3587 estimatedMinutes: 35, 3588 layout: 'grid', 3589 title: 'Códigos Secretos: a régua de Segurança e Acessos', 3590 goal: 'Aula bônus. Recapitule as oito aulas e reúna os comandos curtos que transformam decisões de segurança em pedidos claros e verificáveis.', 3591 focus: 'Passe a régua antes de pedir uma tela ou API: identidade, sessão, permissão, dados, recuperação, auditoria, riscos e critérios de aceite precisam aparecer no pedido.', 3592 practice: 'Escolha um fluxo real e aplique pelo menos cinco Códigos Secretos das aulas. Junte os resultados em um pedido único, com cenários permitidos, negados e de recuperação.', 3593 exerciseFeedback: 'Não existe resposta única. O pedido final precisa ligar cada código a uma decisão concreta, sem esconder pendências atrás de âdeixe seguroâ.', 3594 lessons: [ 3595 'Reconheça quais decisões de acesso e proteção já estão explÃcitas num pedido.', 3596 'Use os códigos da aula certa para preencher lacunas sem repetir regras.', 3597 'Feche o pedido com testes, evidências, responsável e decisão pendente.' 3598 ], 3599 conceitos: [], 3600 bonus: true 3601 } 3602]; 3603
3604segurancaAcessosJourney.forEach(aula => { 3605 aula.conceitos = aula.conceitos.map(conceito => ({ 3606 nome: conceito.titulo, 3607 oQueE: conceito.definicao, 3608 quandoUsar: conceito.exemplo, 3609 pedidoConfuso: conceito.confuso, 3610 pedidoClaro: conceito.claro, 3611 termoTecnico: conceito.titulo, 3612 termosRelacionados: conceito.termos, 3613 comoFunciona: conceito.comoFunciona, 3614 segundoExemplo: conceito.segundoExemplo, 3615 errosComuns: conceito.errosComuns, 3616 grupo: conceito.grupo 3617 })); 3618}); 3619 3620// Primeira aula visual do curso de automações. O conteúdo começa pelo 3621// raciocÃnio de processo antes de apresentar ferramentas: o aluno aprende a 3622// separar repetição, decisão e resultado observável. 3623const automacoesJourney = [ 3624 { 3625 stage: 'Aula 01', 3626 estimatedMinutes: 40, 3627 layout: 'grid', 3628 showCodesInline: true, 3629 title: 'O que automatizar â e o que manter manual', 3630 goal: 'Aprenda a encontrar uma rotina repetitiva, descrevê-la com precisão e decidir onde a automação ajuda sem retirar a responsabilidade humana.', 3631 focus: 'Antes de abrir n8n, Make, Zapier ou Manychat, transforme a ideia âquero automatizarâ em um fluxo com gatilho, dados, decisão, ação e resultado.', 3632 practice: 'Escolha uma rotina que acontece toda semana. Mapeie o que inicia o processo, quais dad
3632os entram, o que pode ser decidido por regra e qual resultado precisa ficar registrado.', 3633 exerciseFeedback: 'Uma boa resposta deixa claro o começo, o meio e o fim do fluxo. Se ainda houver âe depois vejoâ, falta definir uma saÃda ou uma decisão humana. Revise também se outra pessoa conseguiria executar o fluxo apenas lendo sua resposta.', 3634 visualMarkup: ` 3635 <div class="mt-8 border-2 border-mondrian-black bg-white p-5 lg:p-7" aria-label="Mapa visual de uma automação"> 3636 <p class="font-mono text-xs uppercase tracking-[0.22em] text-warm-gray mb-5">Mapa visual · da rotina ao resultado</p> 3637 <div class="grid grid-cols-1 md:grid-cols-5 gap-2 items-stretch"> 3638 <div class="border-2 border-mondrian-black bg-blue-50 p-4"><span class="font-mono text-xs font-bold">01</span><strong class="block mt-2">Gatilho</strong><span class="text-sm text-warm-gray">algo acontece</span></div> 3639 <div class="hidden md:flex items-center justify-center text-2xl font-bold">â</div> 3640 <div class="border-2 border-mondrian-black bg-yellow-50 p-4"><span class="font-mono text-xs font-bold">02</span><strong class="block mt-2">Dados</strong><span class="text-sm text-warm-gray">o que chegou</span></div> 3641 <div class="hidden md:flex items-center justify-center text-2xl font-bold">â</div> 3642 <div class="border-2 border-mondrian-black bg-red-50 p-4"><span class="font-mono text-xs font-bold">03</span><strong class="block mt-2">Decisão</strong><span class="text-sm text-warm-gray">regra ou pessoa</span></div> 3643 </div> 3644 <div class="flex justify-center text-2xl font-bold py-2" aria-hidden="true">â</div> 3645 <div class="grid grid-cols-1 md:grid-cols-3 gap-2"> 3646 <div class="border-2 border-mondrian-black bg-green-50 p-4"><span class="font-mono text-xs font-bold">04</span><strong class="block mt-2">Ação</strong><span class="text-sm text-warm-gray">o sistema executa</span></div> 3647 <div class="border-2 border-mondrian-black bg-white p-4"><span class="font-mono text-xs font-bold">05</span><strong class="block mt-2">Resultado</strong><span class="text-sm text-warm-gray">alguém consegue conferir</span></div> 3648 <div class="border-2 border-mondrian-black bg-gray-50 p-4"><span class="font-mono text-xs font-bold">06</span><strong class="block mt-2">Responsável</strong><span class="text-sm text-warm-gray">quem acompanha exceções</span></div> 3649 </div> 3650 <div class="mt-7 grid grid-cols-1 lg:grid-cols-2 gap-2"> 3651 <div class="border-2 border-mondrian-black p-5 bg-white"><p class="font-mono text-xs uppercase tracking-widest mb-3">Bons candidatos</p><ul class="space-y-2 text-sm"><li><strong>Lead novo:</strong> registrar, classificar e avisar a equipe.</li><li><strong>Pedido aprovado:</strong> atualizar status e enviar confirmação.</li><li><strong>Relatório semanal:</strong> reunir dados e entregar um resumo.</li></ul></div> 3652 <div class="border-2 border-mondrian-black p-5 bg-gray-50"><p class="font-mono text-xs uppercase tracking-widest mb-3">Mantenha manual quando...</p><ul class="space-y-2 text-sm"><li>o caso exige empatia ou interpretação;</li><li>o erro pode causar prejuÃzo ou exposição de dados;</li><li>a regra ainda muda toda semana.</li></ul></div> 3653 </div> 3654 </div>`, 3655 lessons: [ 3656 'Automação tira repetição da rotina; ela não tira a responsabilidade pelo resultado.', 3657 'Todo fluxo precisa de um gatilho, dados de entrada, uma decisão, uma ação e um resultado observável.', 3658 'Mantenha a decisão com uma pessoa quando houver contexto, risco, exceção ou impacto sensÃvel.', 3659 'Defina como saberemos que funcionou e o que acontece quando algo der errado antes de escolher a ferramenta.', 3660 'Comece pequeno: um gatilho, uma condição e uma ação. Só adicione novas etapas depois de observar o primeiro ciclo.', 3661 'Uma automação confiável tem dono, registro do que aconteceu e um caminho claro para a exceção.' 3662 ], 3663 conceitos: [ 3664 { nome: 'Gatilho', oQueE: 'O evento que inicia um fluxo automático.', quandoUsar: 'Quando um formulário é enviado, um pagamento é aprovado ou uma mensagem chega.', pedidoConfuso: 'âQuando tiver cliente novo, faz o processo.â', pedidoClaro: 'âQuando o formulário de orçamento for enviado, crie um registro com nome, e-mail e origem.â', comoFunciona: 'O sistema observa um evento definido e inicia as próximas etapas.', segundoExemplo: 'Um webhook re
3664cebido depois que uma loja confirma o pagamento.', quandoNaoUsar: 'Quando o evento não tem fonte confiável ou não pode ser identificado de forma única.', errosComuns: 'Usar horários vagos ou eventos que ninguém consegue verificar.', termosRelacionados: ['evento', 'webhook', 'entrada'] }, 3665 { nome: 'Ação', oQueE: 'A tarefa executada depois que o gatilho e as regras são atendidos.', quandoUsar: 'Para criar registro, enviar aviso, atualizar uma planilha ou iniciar uma conversa.', pedidoConfuso: 'âNotifica o time.â', pedidoClaro: 'âEnvie um aviso no canal comercial com o nome do lead e um link para o registro.â', comoFunciona: 'A automação transforma os dados recebidos em uma operação definida.', segundoExemplo: 'Atualizar o status do pedido e guardar o horário da atualização.', quandoNaoUsar: 'Quando ainda não está claro quem recebe a saÃda ou como conferir que ela aconteceu.', errosComuns: 'Não definir destinatário, formato, permissão ou condição de execução.', termosRelacionados: ['operação', 'saÃda', 'integração'] }, 3666 { nome: 'Decisão humana', oQueE: 'O ponto em que uma pessoa avalia contexto, risco ou exceção antes de continuar.', quandoUsar: 'Quando o caso não cabe em uma regra segura ou pode afetar uma pessoa, cliente ou negócio.', pedidoConfuso: 'âSe parecer importante, manda para alguém.â', pedidoClaro: 'âSe o valor superar R$ 5.000 ou faltar documento, pause e atribua ao responsável financeiro.â', comoFunciona: 'A automação prepara o contexto e deixa a escolha explÃcita para a pessoa certa.', segundoExemplo: 'Um pedido com informação inconsistente fica em revisão em vez de ser enviado ao cliente.', quandoNaoUsar: 'Quando a regra é objetiva, estável e pode ser testada sem interpretação.', errosComuns: 'Esconder a decisão em uma regra frágil ou não definir quem assume a fila.', termosRelacionados: ['exceção', 'aprovação', 'responsável'] } 3667 ], 3668 scenario: { 3669 title: 'Cenário completo · um lead pede contato', 3670 intro: 'A equipe diz âautomatiza os leadsâ. Antes de escolher a ferramenta, transforme a frase em um fluxo verificável.', 3671 steps: [ 3672 { tag: 'Gatilho', text: 'O formulário de contato é enviado com nome, e-mail, interesse e origem.' }, 3673 { tag: 'Dados', text: 'O sistema valida o e-mail e guarda os campos em um registro único.' }, 3674 { tag: 'Decisão', text: 'Se o interesse for empresarial, encaminha ao comercial;
3674 caso contrário, entra na fila geral.' }, 3675 { tag: 'Ação', text: 'Envia uma confirmação ao lead e uma notificação para a fila correta.' }, 3676 { tag: 'Resultado', text: 'O registro fica com status, responsável e horário para revisão.' }, 3677 { tag: 'Exceção', text: 'Se o e-mail for inválido ou a integração falhar, não dispara uma mensagem incompleta: marca ârevisão necessáriaâ e avisa o responsável.' } 3678 ] 3679 }, 3680 exerciseFields: [ 3681 { key: 'rotina', label: 'Qual rotina repetitiva você quer melhorar?', help: 'Descreva a situação atual em uma frase.', placeholder: 'Toda vez que...' }, 3682 { key: 'gatilho', label: 'O que inicia o fluxo?', help: 'Escreva um evento que possa ser observado.', placeholder: 'Quando...' }, 3683 { key: 'dados', label: 'Quais dados entram?', help: 'Liste apenas os dados necessários para agir.', placeholder: 'Nome, e-mail, pedido...' }, 3684 { key: 'decisao', label: 'Onde entra uma regra ou uma pessoa?', help: 'Indique uma condição ou exceção.', placeholder: 'Se..., então...; caso contrário...' }, 3685 { key: 'resultado', label: 'Como saberemos que funcionou?', help: 'Defina uma evidência observável.', placeholder: 'Ao final, deve existir...' } 3686 ], 3687 exerciseModelAnswer: 'Quando um formulário de orçamento for enviado, validar nome e e-mail, registrar a origem e encaminhar leads empresariais ao comercial. Enviar confirmação ao lead, registrar status ânovoâ e deixar casos sem e-mail válido para revisão manual.', 3688 codigos: [ 3689 { codigo: '/separa-repeticao-de-decisao' }, 3690 { codigo: '/gatilho-acao-resultado' } 3691 ] 3692 } 3693]; 3694 3695// Registro das trilhas que usam o mecanismo de cardâmodal (renderAulaJourney/ 3696// conceitosSectionMarkup/openConceitoModal). Cada página que usa esse 3697// mecanismo declara `<body data-journey="...">` com a chave correspondente; 3698// sem esse atributo, cai no padrão (Regras e Funcionamento), preservando o 3699// comportamento de antes. 3700const AULA_JOURNEY_REGISTRY = { 3701 'regras-e-funcionamento': { 3702 journey: conceitoJourney, 3703 planSlug: REGRAS_FUNCIONAMENTO_PLAN_SLUG, 3704 courseLabel: 'Regras e Funcionamento', 3705 basePath: 'regras-e-funcionamento', 3706 lessonIdPrefix: 'rf' 3707 }, 3708 'do-pedido-ao-sistema': { 3709 journey: pedidoCompletoJourney, 3710 planSlug: 'equipe', 3711 courseLabel: 'Do Pedido ao Sistema', 3712 basePath: 'do-pedido-ao-sistema', 3713 lessonIdPrefix: 'dp' 3714 }, 3715 'dados-e-informacoes': { 3716 journey: dadosInformacoesJourney, 3717 planSlug: DADOS_INFORMACOES_PLAN_SLUG, 3718 courseLabel: 'Dados e Informações', 3719 basePath: 'dados-e-informacoes', 3720 lessonIdPrefix: 'di' 3721 }, 3722 'apis-que-funcionam': { 3723 journey: apisQueFuncionamJourney, 3724 planSlug: APIS_QUE_FUNCIONAM_PLAN_SLUG, 3725 courseLabel: 'APIs que Funcionam', 3726 basePath: 'apis-que-funcionam', 3727 lessonIdPrefix: 'api' 3728 }, 3729 'seguranca-aplicacoes-web': { 3730 journey: segurancaAplicacoesWebJourney, 3731 planSlug: SEGURANCA_APLICACOES_WEB_PLAN_SLUG, 3732 courseLabel: 'Do Zero a Segurança em Aplicações Web', 3733 basePath: 'seguranca-aplicacoes-web', 3734 lessonIdPrefix: 'sec' 3735 }, 3736 'prototipando-com-ia': { 3737 journey: prototipandoComIaJourney, 3738 planSlug: PROTOTIPANDO_COM_IA_PLAN_SLUG, 3739 courseLabel: 'Vibecoding na Prática: da Ideia ao Protótipo', 3740 basePath: 'prototipando-com-ia', 3741 lessonIdPrefix: 'ia' 3742 }, 3743 'ui-descomplicada': { 3744 journey: uiDescomplicadaJourney, 3745 planSlug: UI_DESCOMPLICADA_PLAN_SLUG, 3746 courseLabel: 'UI Descomplicada: Crie Interfaces que Orientam', 3747 basePath: 'ui-descomplicada', 3748 lessonIdPrefix: 'ui' 3749 }, 3750 'seguranca-e-acessos': { 3751 journey: segurancaAcessosJourney, 3752 planSlug: 'seguranca_e_acessos', 3753 courseLabel: 'Segurança e Acessos', 3754 basePath: 'seguranca-e-acessos', 3755 lessonIdPrefix: 'sa' 3756 }, 3757 'automacoes': { 3758 journey: automacoesJourney, 3759 planSlug: 'automacoes_que_funcionam', 3760 courseLabel: 'Automações que Funcionam: do Gatilho ao Resultado', 3761 basePath: 'automacoes', 3762 lessonIdPrefix: 'aut' 3763 } 3764}; 3765 3766// Exemplos visuais das aulas bônus. Cada passo é texto, nunca HTML fornecido pelo aluno. 3767// Os exemplos visuais são carregados da API protegida para alunos com matrÃcula ativa.
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.