rumo-a-maxima-potencia

SKILL.md — Jornada Rumo à Máxima Potência

```

rumo-a-maxima-potencia 0 Updated 2mo ago

Resources

27
GitHub

Install

npx skillscat add rumo-a-maxima-potencia/rmp

Install via the SkillsCat registry.

SKILL.md

SKILL.md — Jornada Rumo à Máxima Potência

Padrões, Convenções e Guia de Implementação


1. Identidade Visual e Design System

1.1 Paleta de Cores

MARCA PRINCIPAL
- Primary Green:     #9ACD32 (Verde Lima — Máxima Potência)
- Primary Dark:      #1A1A1A (Fundo escuro — herdado do tema existente)
- Primary Gradient:  linear-gradient(135deg, #FFD700, #9ACD32) — Amarelo para Verde
- Accent Orange:     #FF6B35 (CTAs, alertas importantes)

FASES DA JORNADA
- Ignição:           #FF6B35 (Laranja energético)
- Aquecimento:       #F7C948 (Amarelo quente)
- Aceleração:        #85BB65 (Verde médio)
- Turbinagem:        #45B7D1 (Azul turbo)
- Expansão:          #7B68EE (Roxo expansão)
- Máxima Potência:   #9ACD32 (Verde brilhante)

ZONAS DO DIAGNÓSTICO
- Zona Crítica:      #FF4444
- Zona de Alerta:    #FF8C00
- Zona de Construção:#F7C948
- Zona de Consolidação:#85BB65
- Zona de Excelência:#9ACD32

STATUS
- Sucesso:           #22C55E
- Alerta:            #F59E0B
- Erro:              #EF4444
- Info:              #3B82F6
- Pendente:          #6B7280

SUPERFÍCIES (tema escuro)
- Background:        #0A0A0A
- Card:              #1A1A1A
- Card Hover:        #252525
- Border:            #2A2A2A
- Text Primary:      #FFFFFF
- Text Secondary:    #A0A0A0
- Text Muted:        #666666

1.2 Tipografia

- Títulos: Inter Bold ou equivalente sans-serif
- Corpo: Inter Regular, 14-16px
- Dados/Números: Tabular figures (font-variant-numeric: tabular-nums)
- Frases motivacionais: Inter Light Italic, 18px

1.3 Componentes Visuais Chave

Medidor de Potência (SVG)

Semicírculo com gradiente de vermelho → verde
- Ponteiro animado (CSS transition 1.5s ease-in-out)
- Valor percentual no centro em fonte grande (48px bold)
- Label abaixo: nome da fase atual
- Marcações a cada 20% no arco
- Fundo do arco: #2A2A2A (sutil)
- Arco preenchido: gradiente conforme valor
  0-20%: vermelho → laranja
  20-40%: laranja → amarelo
  40-60%: amarelo → verde claro
  60-80%: verde claro → verde médio
  80-100%: verde médio → verde brilhante (#9ACD32)

Hexágono dos Pilares

6 segmentos dispostos em hexágono regular
Cada segmento representa um pilar do diagnóstico
- Centro: ícone ou sigla do pilar
- Preenchimento: cor proporcional à nota (escala de cor das zonas)
- Hover: expande levemente + tooltip com detalhes
- Animação: "pulse" sutil nos pilares com nota baixa (atenção)

Cards de Fase (Timeline)

Layout vertical com linha conectora
Cada card:
- Ícone da fase (emoji ou SVG custom)
- Nome da fase
- Status: ✅ Completa | ◉ Atual | 🔒 Bloqueada
- Data (se completa ou agendada)
- Badge (se desbloqueado)

Estado visual:
- Completa: Borda na cor da fase, opacidade 100%, badge visível
- Atual: Borda pulsante, fundo com glow sutil
- Bloqueada: Opacidade 40%, ícone de cadeado, sem interação

2. Padrões de Código

2.1 Estrutura de Arquivos

src/
├── app/
│   ├── (admin)/admin/          # Rotas do super admin
│   ├── (client)/portal/        # Rotas do portal do cliente
│   └── api/                    # API routes
├── components/
│   ├── admin/                  # Componentes exclusivos do admin
│   ├── client/                 # Componentes exclusivos do portal
│   ├── shared/                 # Componentes compartilhados
│   │   ├── PotencyGauge.tsx    # Medidor de potência
│   │   ├── PillarHexagon.tsx   # Hexágono dos pilares
│   │   ├── PhaseTimeline.tsx   # Timeline de fases
│   │   ├── BadgeDisplay.tsx    # Exibição de badges
│   │   └── RichTextEditor.tsx  # Editor rico (Tiptap)
│   └── ui/                     # shadcn/ui (já existente)
├── lib/
│   ├── supabase/
│   │   ├── client.ts           # Cliente Supabase (já existe)
│   │   ├── admin.ts            # Cliente admin (service role)
│   │   └── types.ts            # Types gerados do DB
│   ├── ai/
│   │   ├── prompts.ts          # Templates de prompt por tipo de reunião
│   │   ├── generate.ts         # Função de geração de resumos
│   │   └── context.ts          # Montagem de contexto acumulativo
│   ├── gamification/
│   │   ├── calculator.ts       # Cálculo do medidor de potência
│   │   ├── badges.ts           # Definição de badges e regras
│   │   └── phases.ts           # Definição de fases
│   ├── indicators/
│   │   ├── defaults.ts         # Indicadores pré-criados (seed data)
│   │   ├── validation.ts       # Validação inteligente de valores
│   │   └── charts.ts           # Helpers para gráficos
│   └── constants/
│       ├── phases.ts           # Constantes das fases
│       ├── meeting-types.ts    # Tipos de reunião e campos
│       └── labels.ts           # Labels em português
├── hooks/
│   ├── useCompany.ts           # Hook de dados da empresa
│   ├── useMeeting.ts           # Hook de dados da reunião
│   ├── useIndicators.ts        # Hook de indicadores
│   └── useGamification.ts     # Hook de gamificação
└── types/
    ├── company.ts
    ├── meeting.ts
    ├── indicator.ts
    └── gamification.ts

2.2 Padrão de API Routes

// app/api/companies/route.ts — PADRÃO PARA TODAS AS ROTAS
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';
import { z } from 'zod';

// 1. Schema de validação com Zod
const createCompanySchema = z.object({
  name: z.string().min(1, 'Nome é obrigatório'),
  sector: z.string().optional(),
  summary: z.string().optional(),
  leader_name: z.string().optional(),
  diagnostic_id: z.string().uuid().optional(),
});

// 2. Handler com try/catch e respostas padronizadas
export async function POST(request: Request) {
  try {
    const supabase = createRouteHandlerClient({ cookies });
    
    // 3. Verificar autenticação
    const { data: { user }, error: authError } = await supabase.auth.getUser();
    if (authError || !user) {
      return NextResponse.json({ error: 'Não autorizado' }, { status: 401 });
    }
    
    // 4. Verificar role (admin/owner)
    const { data: membership } = await supabase
      .from('organization_members')
      .select('role')
      .eq('user_id', user.id)
      .single();
    
    if (!membership || !['owner', 'admin'].includes(membership.role)) {
      return NextResponse.json({ error: 'Acesso negado' }, { status: 403 });
    }
    
    // 5. Validar input
    const body = await request.json();
    const validated = createCompanySchema.parse(body);
    
    // 6. Executar operação
    const { data, error } = await supabase
      .from('companies')
      .insert({ ...validated, organization_id: membership.organization_id })
      .select()
      .single();
    
    if (error) throw error;
    
    return NextResponse.json(data, { status: 201 });
  } catch (error) {
    // 7. Erro de validação Zod
    if (error instanceof z.ZodError) {
      return NextResponse.json(
        { error: 'Dados inválidos', details: error.errors },
        { status: 400 }
      );
    }
    // 8. Erro genérico
    console.error('Erro ao criar empresa:', error);
    return NextResponse.json(
      { error: 'Erro interno. Tente novamente.' },
      { status: 500 }
    );
  }
}

2.3 Padrão de Componentes

// components/shared/PhaseTimeline.tsx — PADRÃO
'use client';

import { PHASES } from '@/lib/constants/phases';
import { cn } from '@/lib/utils';

interface PhaseTimelineProps {
  currentPhase: number; // 0-6 (0 = não iniciou)
  meetings: MeetingSummary[];
  onPhaseClick?: (meetingNumber: number) => void;
  variant?: 'admin' | 'client'; // Admin vê tudo, cliente vê só publicados
}

export function PhaseTimeline({ currentPhase, meetings, onPhaseClick, variant = 'client' }: PhaseTimelineProps) {
  return (
    <div className="relative">
      {/* Linha conectora vertical */}
      <div className="absolute left-6 top-0 bottom-0 w-0.5 bg-border" />
      
      {PHASES.map((phase, index) => {
        const meeting = meetings.find(m => m.meeting_number === phase.number);
        const isCompleted = meeting?.status === 'published';
        const isCurrent = phase.number === currentPhase + 1;
        const isLocked = phase.number > currentPhase + 1;
        
        // Cliente não vê fases não publicadas como clicáveis
        const isClickable = variant === 'admin' || isCompleted;
        
        return (
          <div
            key={phase.number}
            className={cn(
              'relative flex items-start gap-4 pb-8',
              isLocked && 'opacity-40',
              isClickable && 'cursor-pointer hover:bg-card/50 rounded-lg p-2 -m-2',
            )}
            onClick={() => isClickable && onPhaseClick?.(phase.number)}
          >
            {/* Nó da timeline */}
            <div className={cn(
              'relative z-10 w-12 h-12 rounded-full flex items-center justify-center border-2',
              isCompleted && `bg-[${phase.color}] border-[${phase.color}]`,
              isCurrent && `border-[${phase.color}] animate-pulse`,
              isLocked && 'border-muted bg-muted',
            )}>
              {isCompleted ? '✅' : isLocked ? '🔒' : phase.icon}
            </div>
            
            {/* Conteúdo */}
            <div>
              <h3 className="font-semibold text-lg">
                Fase {phase.number} — {phase.name}
              </h3>
              {isCompleted && meeting?.meeting_date && (
                <p className="text-sm text-muted-foreground">
                  Concluída em {formatDate(meeting.meeting_date)}
                </p>
              )}
              {isCurrent && (
                <p className="text-sm" style={{ color: phase.color }}>
                  Fase atual
                </p>
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
}

3. Prompts de IA por Tipo de Reunião

3.1 Estrutura Base do Prompt

// lib/ai/prompts.ts

interface AIContext {
  companyName: string;
  sector: string;
  diagnosticSummary: string;      // Análise do diagnóstico
  diagnosticScores: PillarScore[]; // Notas por pilar
  previousMeetings: MeetingSummary[]; // Resumos anteriores
  currentTranscription: string;    // Transcrição da reunião atual
  adminNotes?: string;             // Notas de contexto do admin
  recentIndicators?: IndicatorEntry[]; // Indicadores recentes
}

const SYSTEM_PROMPT = `
Você é um consultor empresarial sênior analisando reuniões de mentoria do programa "Rumo à Máxima Potência".
Seu papel é gerar resumos executivos claros, diretos e orientados a ação.

REGRAS:
- Escreva em português brasileiro formal mas acessível
- Use dados concretos da transcrição (números, nomes, datas mencionados)
- Conecte com o diagnóstico original quando relevante
- Se houver reuniões anteriores, referencie evolução ou regressão
- Foque em FATOS da reunião, não em suposições
- Formato: parágrafos curtos, diretos, com bullet points para itens de ação
- Tom: profissional, construtivo, orientado a resultado
- NUNCA invente dados que não estejam na transcrição
`;

3.2 Prompt da Reunião 01 (Ignição)

const MEETING_01_PROMPT = (ctx: AIContext) => `
${SYSTEM_PROMPT}

CONTEXTO DA EMPRESA:
- Empresa: ${ctx.companyName} (${ctx.sector})
- Diagnóstico 360: ${ctx.diagnosticSummary}
- Notas dos pilares: ${JSON.stringify(ctx.diagnosticScores)}
${ctx.adminNotes ? `- Notas adicionais do mentor: ${ctx.adminNotes}` : ''}

TRANSCRIÇÃO DA REUNIÃO 01 (BOARD INICIAL):
${ctx.currentTranscription}

TAREFA:
Gere o campo "Expectativas" — um resumo executivo do que o empresário espera do programa.
Extraia da transcrição:
1. O que motivou a busca pela mentoria
2. Quais áreas o empresário considera mais urgentes
3. Onde ele quer chegar em 6 meses
4. Medos, preocupações ou resistências mencionadas
5. Recursos e disposição demonstrados

Compare as expectativas do empresário com o que o diagnóstico revelou.
Se houver desalinhamento (ex: empresário foca em vendas mas diagnóstico mostra processos como crítico), destaque isso.

Formato: 3-5 parágrafos, máximo 500 palavras.
`;

3.3 Prompt das Reuniões 02, 03, 05 (Follow-up)

const MEETING_FOLLOWUP_PROMPT = (ctx: AIContext) => `
${SYSTEM_PROMPT}

CONTEXTO DA EMPRESA:
- Empresa: ${ctx.companyName} (${ctx.sector})
- Diagnóstico original: ${ctx.diagnosticSummary}
${ctx.previousMeetings.map(m => `
- Reunião ${m.meeting_number} (${m.phase_name}):
  Avanços: ${m.advances_summary || 'N/A'}
  Dores: ${m.pain_points_summary || 'N/A'}
`).join('')}
${ctx.recentIndicators?.length ? `
- Indicadores recentes do cliente:
${ctx.recentIndicators.map(i => `  ${i.name}: ${i.value}`).join('\n')}
` : ''}
${ctx.adminNotes ? `- Notas do mentor: ${ctx.adminNotes}` : ''}

TRANSCRIÇÃO DA REUNIÃO:
${ctx.currentTranscription}

TAREFAS (gere cada seção separadamente):

## AVANÇOS
Extraia e organize os progressos concretos mencionados na reunião:
- O que foi implementado desde a última reunião
- Resultados quantitativos mencionados
- Mudanças de comportamento ou mindset observadas
- Ações do plano que foram executadas
Compare com as dores da reunião anterior: alguma foi resolvida?
Formato: 2-4 parágrafos, máximo 300 palavras.

---SEPARADOR---

## DORES
Identifique os obstáculos, dificuldades e preocupações:
- Ações que não foram executadas e por quê
- Novos problemas surgidos
- Resistências internas (equipe, cultura, hábitos)
- Limitações externas (mercado, fornecedores, regulação)
- Preocupações financeiras ou operacionais
Formato: 2-4 parágrafos, máximo 300 palavras.

---SEPARADOR---

## AJUSTE DO PLANO DE ACELERAÇÃO
Com base nos avanços e dores, proponha ajustes práticos:
- Ações que devem continuar (estão funcionando)
- Ações que devem ser modificadas (ajustar abordagem)
- Ações que devem ser abandonadas (não fizeram sentido)
- Novas ações sugeridas com base na reunião
Formato: lista de ações com responsável (se mencionado) e prazo (se mencionado). Máximo 400 palavras.
`;

3.4 Prompt da Reunião 04 (Turbinagem — Ciclo 90 dias)

const MEETING_04_PROMPT = (ctx: AIContext) => `
${SYSTEM_PROMPT}

CONTEXTO COMPLETO (metade da jornada):
- Empresa: ${ctx.companyName} (${ctx.sector})
- Diagnóstico original: ${ctx.diagnosticSummary}
- Histórico de todas as reuniões anteriores:
${ctx.previousMeetings.map(m => `
  Reunião ${m.meeting_number}: Avanços: ${m.advances_summary} | Dores: ${m.pain_points_summary}
`).join('')}
${ctx.recentIndicators?.length ? `
- Evolução dos indicadores:
${ctx.recentIndicators.map(i => `  ${i.name}: ${i.value}`).join('\n')}
` : ''}
${ctx.adminNotes ? `- Notas do mentor: ${ctx.adminNotes}` : ''}

TRANSCRIÇÃO DA REUNIÃO 04 (CICLO DE 90 DIAS):
${ctx.currentTranscription}

TAREFAS:

## AVANÇOS
Faça um balanço da primeira metade da jornada:
- Principais conquistas acumuladas desde a Fase 1
- Indicadores que melhoraram
- Pilares do diagnóstico que evoluíram
- Mudanças culturais ou estruturais observadas
Formato: 3-5 parágrafos, máximo 400 palavras.

---SEPARADOR---

## DORES
Identifique o que ainda persiste ou surgiu:
- Dores recorrentes que não foram resolvidas
- Novos desafios que emergiram com o crescimento
- Gaps entre o planejado e o executado
Formato: 2-4 parágrafos, máximo 300 palavras.
`;

3.5 Prompt da Reunião 06 (Máxima Potência — Encerramento)

const MEETING_06_PROMPT = (ctx: AIContext) => `
${SYSTEM_PROMPT}

CONTEXTO COMPLETO DA JORNADA (6 meses):
- Empresa: ${ctx.companyName} (${ctx.sector})
- Diagnóstico original: ${ctx.diagnosticSummary} (Nota: ${ctx.diagnosticScores})
- Todas as reuniões:
${ctx.previousMeetings.map(m => `
  Reunião ${m.meeting_number} (${m.phase_name}): 
  Avanços: ${m.advances_summary}
  Dores: ${m.pain_points_summary}
`).join('')}
${ctx.recentIndicators?.length ? `
- Evolução completa dos indicadores:
${ctx.recentIndicators.map(i => `  ${i.name}: ${i.value}`).join('\n')}
` : ''}
${ctx.adminNotes ? `- Notas do mentor: ${ctx.adminNotes}` : ''}

TRANSCRIÇÃO DA REUNIÃO 06 (ENCERRAMENTO):
${ctx.currentTranscription}

TAREFAS:

## AVANÇOS (Balanço Final)
Síntese executiva da transformação completa:
- Onde a empresa estava (diagnóstico) vs onde está agora
- Top 5 conquistas da jornada
- Indicadores mais expressivos de melhoria
- Mudanças de mentalidade e cultura observadas
Formato: 4-6 parágrafos, máximo 500 palavras. Tom celebratório mas factual.

---SEPARADOR---

## DORES (Desafios Remanescentes)
O que ainda precisa de atenção após a jornada:
- Pilares que ainda estão abaixo do ideal
- Processos iniciados mas não finalizados
- Riscos identificados para os próximos meses
Formato: 2-3 parágrafos, máximo 250 palavras.

---SEPARADOR---

## PRÓXIMA ETAPA DE CRESCIMENTO
Com base em tudo que foi discutido na reunião final:
- Qual é o próximo horizonte de crescimento recomendado
- Que tipo de suporte a empresa precisará (nova jornada, consultoria pontual, etc.)
- 3 prioridades para os próximos 90 dias pós-jornada
- Recomendação sobre reaplicação do Diagnóstico 360
Formato: 3-4 parágrafos, máximo 350 palavras.
`;

4. Validações e Regras de Negócio

4.1 Reuniões

// lib/constants/meeting-types.ts

export const MEETING_CONFIG = {
  1: {
    type: 'board_initial',
    phase: 'ignition',
    phaseName: 'Ignição',
    board: 'lucas_rebeca', // Fixo
    fields: {
      expectations_summary: { required: true, aiGenerated: true },
      advances_summary: { required: false, aiGenerated: false },
      pain_points_summary: { required: false, aiGenerated: false },
      plan_adjustments_summary: { required: false, aiGenerated: false },
      next_growth_stage: { required: false, aiGenerated: false },
    },
    attachments: {
      recording: { required: true },
      diagnostic: { required: false }, // Pode já estar vinculado
      soar_matrix: { required: false },
      acceleration_plan: { required: false },
    },
  },
  2: {
    type: 'followup',
    phase: 'warmup',
    phaseName: 'Aquecimento',
    board: 'selectable', // Admin escolhe lucas ou rebeca
    fields: {
      expectations_summary: { required: false, aiGenerated: false },
      advances_summary: { required: true, aiGenerated: true },
      pain_points_summary: { required: true, aiGenerated: true },
      plan_adjustments_summary: { required: true, aiGenerated: true },
      next_growth_stage: { required: false, aiGenerated: false },
    },
    attachments: {
      recording: { required: true },
    },
  },
  3: {
    type: 'followup',
    phase: 'acceleration',
    phaseName: 'Aceleração',
    board: 'selectable',
    fields: {
      expectations_summary: { required: false, aiGenerated: false },
      advances_summary: { required: true, aiGenerated: true },
      pain_points_summary: { required: true, aiGenerated: true },
      plan_adjustments_summary: { required: true, aiGenerated: true },
      next_growth_stage: { required: false, aiGenerated: false },
    },
    attachments: {
      recording: { required: true },
    },
  },
  4: {
    type: 'cycle_90',
    phase: 'turbo',
    phaseName: 'Turbinagem',
    board: 'lucas_rebeca',
    fields: {
      expectations_summary: { required: false, aiGenerated: false },
      advances_summary: { required: true, aiGenerated: true },
      pain_points_summary: { required: true, aiGenerated: true },
      plan_adjustments_summary: { required: false, aiGenerated: false },
      next_growth_stage: { required: false, aiGenerated: false },
    },
    attachments: {
      recording: { required: true },
      acceleration_plan_90d: { required: false },
    },
  },
  5: {
    type: 'followup',
    phase: 'expansion',
    phaseName: 'Expansão',
    board: 'selectable',
    fields: {
      expectations_summary: { required: false, aiGenerated: false },
      advances_summary: { required: true, aiGenerated: true },
      pain_points_summary: { required: true, aiGenerated: true },
      plan_adjustments_summary: { required: true, aiGenerated: true },
      next_growth_stage: { required: false, aiGenerated: false },
    },
    attachments: {
      recording: { required: true },
    },
  },
  6: {
    type: 'closing',
    phase: 'max_potency',
    phaseName: 'Máxima Potência',
    board: 'lucas_rebeca',
    fields: {
      expectations_summary: { required: false, aiGenerated: false },
      advances_summary: { required: true, aiGenerated: true },
      pain_points_summary: { required: true, aiGenerated: true },
      plan_adjustments_summary: { required: false, aiGenerated: false },
      next_growth_stage: { required: true, aiGenerated: true },
    },
    attachments: {
      recording: { required: true },
    },
  },
} as const;

4.2 Validação de Indicadores

// lib/indicators/validation.ts

export function validateIndicatorEntry(
  newValue: number,
  previousValue: number | null,
  dataType: string,
): { valid: boolean; warning?: string } {
  // Sem valor anterior = sem comparação
  if (previousValue === null) return { valid: true };
  
  // Percentuais não podem passar de 100
  if (dataType === 'percentage' && newValue > 100) {
    return { valid: false, warning: 'Percentual não pode ser maior que 100%' };
  }
  
  // Valores negativos não aceitos para currency e number
  if (['currency', 'number'].includes(dataType) && newValue < 0) {
    return { valid: false, warning: 'Valor não pode ser negativo' };
  }
  
  // Variação > 50% gera alerta (mas não bloqueia)
  const variation = Math.abs((newValue - previousValue) / previousValue);
  if (variation > 0.5) {
    const direction = newValue > previousValue ? 'aumento' : 'redução';
    const pct = Math.round(variation * 100);
    return {
      valid: true,
      warning: `Este valor representa uma ${direction} de ${pct}% em relação ao mês anterior. Confirma?`,
    };
  }
  
  return { valid: true };
}

4.3 Cálculo de Gamificação

// lib/gamification/calculator.ts

export function calculatePotencyScore(
  completedPhases: number,
  indicatorsOnTime: number,
  totalExpectedIndicators: number,
): number {
  // 80% do score vem das fases completadas
  const phaseScore = (completedPhases / 6) * 80;
  
  // 20% vem dos indicadores preenchidos em dia
  const indicatorScore = totalExpectedIndicators > 0
    ? (indicatorsOnTime / totalExpectedIndicators) * 20
    : 20; // Se não há indicadores configurados, ganha o bônus cheio
  
  return Math.round(phaseScore + indicatorScore);
}

export function getPhaseForMeeting(meetingNumber: number): Phase {
  const phases: Record<number, Phase> = {
    1: { name: 'Ignição', code: 'ignition', color: '#FF6B35', icon: '⚡' },
    2: { name: 'Aquecimento', code: 'warmup', color: '#F7C948', icon: '🔥' },
    3: { name: 'Aceleração', code: 'acceleration', color: '#85BB65', icon: '⏩' },
    4: { name: 'Turbinagem', code: 'turbo', color: '#45B7D1', icon: '🌀' },
    5: { name: 'Expansão', code: 'expansion', color: '#7B68EE', icon: '🚀' },
    6: { name: 'Máxima Potência', code: 'max_potency', color: '#9ACD32', icon: '👑' },
  };
  return phases[meetingNumber];
}

5. Seed Data — Indicadores Padrão

-- seed_indicators.sql
INSERT INTO indicator_templates (name, description, data_type, unit, frequency, is_required, is_active, display_order)
VALUES
  ('Faturamento Mensal', 'Receita bruta total do mês', 'currency', 'R$', 'monthly', true, true, 1),
  ('Ticket Médio', 'Valor médio por venda/contrato', 'currency', 'R$', 'monthly', false, true, 2),
  ('Clientes Ativos', 'Número total de clientes ativos no mês', 'number', NULL, 'monthly', false, true, 3),
  ('Contatos Topo de Funil', 'Leads ou contatos iniciais gerados', 'number', NULL, 'monthly', false, true, 4),
  ('Contatos Fundo de Funil', 'Leads qualificados / em negociação', 'number', NULL, 'monthly', false, true, 5),
  ('Taxa de Conversão', 'Percentual de leads convertidos em clientes', 'percentage', '%', 'monthly', false, true, 6),
  ('Custos Variáveis', 'Total de custos variáveis do mês', 'currency', 'R$', 'monthly', false, true, 7),
  ('Despesas Fixas', 'Total de despesas fixas do mês', 'currency', 'R$', 'monthly', false, true, 8),
  ('EBITDA', 'Lucro antes de juros, impostos, depreciação e amortização', 'currency', 'R$', 'monthly', false, false, 9),
  ('Lucro Líquido', 'Resultado final após todas as deduções', 'currency', 'R$', 'monthly', false, false, 10),
  ('Número de Funcionários', 'Quadro total de colaboradores', 'number', NULL, 'monthly', false, false, 11),
  ('NPS', 'Net Promoter Score (0-100)', 'number', NULL, 'monthly', false, false, 12),
  ('Satisfação do Cliente', 'Índice de satisfação dos clientes', 'percentage', '%', 'monthly', false, false, 13);

6. Checklist de Qualidade por Entrega

Antes de cada Pull Request:

□ TypeScript compila sem erros (npx tsc --noEmit)
□ Sem console.log com dados sensíveis
□ RLS testado: admin vê, cliente vê apenas o permitido
□ Rotas protegidas: sem acesso anônimo a dados
□ Labels em português em toda a interface
□ Loading state em todas as operações assíncronas
□ Error handling com mensagem amigável
□ Mobile responsivo (testar em 375px)
□ Não afeta módulo de diagnóstico existente (testar PDF generation)
□ Dados de teste criados e removidos

Antes de deploy:

□ Migrations rodam em banco limpo
□ Seed data de indicadores inserido
□ Storage buckets criados com policies corretas
□ Variáveis de ambiente configuradas
□ Fluxo completo testado: cadastro → reunião → publicação → portal
□ Login cliente testado: criação → ativação → acesso → indicadores
□ Gamificação testada: badge desbloqueia ao publicar reunião
□ PDF do diagnóstico continua funcionando normalmente