| name | league-architect |
| description | Especialista em Regras de Negócio, Formatos de Liga SaaS, Lógica Financeira e Disputas do Super Cartola. Guardião das regras oficiais, fórmulas de cálculo, premiações e punições. Use para criar/ajustar configs de liga, calcular finanças, definir regras de disputas ou validar implementações de negócio. |
League Architect Skill
🎯 Missão
Garantir precisão absoluta nas regras de negócio e cálculos financeiros do Super Cartola Manager.
1. 📊 Regras Financeiras Críticas
1.1 Precisão Decimal
function formatarValor(valor) {
return Number(valor.toFixed(2));
}
function formatarParaUI(valor) {
return valor.toFixed(2).replace('.', ',');
}
formatarValor(105.4045)
formatarParaUI(105.40)
1.2 Mitos & Micos da Rodada
const BONUS_RODADA = {
mito: {
valor: 20.00,
descricao: '1º lugar da rodada',
posicao: 1
},
mico: {
valor: -20.00,
descricao: 'Último lugar da rodada',
posicao: 'ultima'
}
};
function calcularMitoMico(participantes, rodada) {
const sorted = participantes
.filter(p => p.pontos_rodada > 0)
.sort((a, b) => b.pontos_rodada - a.pontos_rodada);
if (sorted.length === 0) return [];
const mito = sorted[0];
const mico = sorted[sorted.length - 1];
return [
{ participante_id: mito._id, tipo: 'mito', valor: 20.00 },
{ participante_id: mico._id, tipo: 'mico', valor: -20.00 }
];
}
1.3 Zonas Financeiras (Tabela 32 Times)
const ZONAS_32_TIMES = {
G1: { min: 1, max: 1, valor: 100.00, descricao: 'Campeão/Mito' },
G2: { min: 2, max: 2, valor: 60.00, descricao: 'Vice' },
G3: { min: 3, max: 3, valor: 40.00, descricao: '3º Lugar' },
G4: { min: 4, max: 6, valor: 20.00, descricao: 'Top 6' },
G5: { min: 7, max: 9, valor: 10.00, descricao: 'Top 9' },
G6: { min: 10, max: 11, valor: 5.00, descricao: 'Top 11' },
: { : , : , : , : },
: { : , : , : -, : },
: { : , : , : -, : },
: { : , : , : -, : },
: { : , : , : -, : },
: { : , : , : -, : },
: { : , : , : -, : }
};
() {
(totalParticipantes !== ) {
.(, totalParticipantes);
}
( [zona, config] .()) {
(posicao >= config. && posicao <= config.) {
{
zona,
: config.,
: config.
};
}
}
{ : , : , : };
}
1.4 Acertos Financeiros (CRÍTICO)
function calcularSaldoAcertos(participanteId, ligaId, temporada) {
const acertos = await AcertoFinanceiro.find({
participante_id: participanteId,
liga_id: ligaId,
temporada
});
let totalPagamentos = 0;
let totalRecebimentos = 0;
acertos.forEach(acerto => {
if (acerto.tipo === 'pagamento') {
totalPagamentos += acerto.valor;
} else if (acerto.tipo === 'recebimento') {
totalRecebimentos += acerto.valor;
}
});
return formatarValor(totalPagamentos - totalRecebimentos);
}
const exemplo = {
saldoTemporada: -203.46,
pagamento: 204.00,
saldoAcertos: 204.00 - 0,
saldoFinal: -203.46 + 204.00
};
2. 🏆 Formatos de Liga
2.1 SuperCartola (32 Times)
const LIGA_SUPERCARTOLA = {
id: '684cb1c8af923da7c7df51de',
nome: 'SuperCartola',
formato: '32_times',
temporada: '2026',
config: {
min_participantes: 32,
max_participantes: 32,
inscricao: {
valor: 200.00,
moeda: 'BRL'
},
disputas: [
'pontos_corridos',
'mata_mata',
'artilheiro',
'luva_de_ouro',
'melhor_do_mes',
'top10_mitos',
'top10_micos'
],
zonas: ZONAS_32_TIMES,
premiacoes: {
pontos_corridos: {
primeiro: 1000.00,
segundo: 500.00,
terceiro: 300.00
},
mata_mata: {
campeao: 800.00,
vice: 400.00
}
}
}
};
2.2 Cartoleiros do Sobral (Dinâmica R30+)
const LIGA_SOBRAL = {
id: '684d821cf1a7ae16d1f89572',
nome: 'Cartoleiros do Sobral',
formato: 'dinamico',
temporada: '2026',
config: {
min_participantes: 4,
max_participantes: 6,
regra_r30: {
rodada_inicio: 30,
participantes_ativos: 4,
excluir_inativos: true
},
zonas_variavel: {
6: {
G1: { min: 1, max: 1, valor: 50.00 },
G2: { min: 2, max: 2, valor: 20.00 },
NEUTRO: { min: 3, max: 4, valor: 0 },
Z1: { min: 5, max: 5, valor: - },
: { : , : , : - }
},
: {
: { : , : , : },
: { : , : , : },
: { : , : , : - },
: { : , : , : - }
}
}
}
};
() {
config = .;
totalAtivos = rodada >= config..
? config..
: participantes.;
zonas = config.[totalAtivos];
( [zona, regra] .(zonas)) {
(posicao >= regra. && posicao <= regra.) {
{
zona,
: regra.,
:
};
}
}
{ : , : };
}
3. 🎮 Disputas Específicas
3.1 Pontos Corridos
const PONTOS_CORRIDOS_CONFIG = {
pontos_vitoria: 3,
pontos_empate: 1,
pontos_derrota: 0,
criterios_desempate: [
'pontos_acumulados',
'vitorias',
'saldo_pontos',
'pontos_marcados',
'confronto_direto'
]
};
function calcularClassificacaoPontosCorridos(participantes, rodadas) {
const tabela = participantes.map(p => ({
participante_id: p._id,
nome: p.nome,
pontos: 0,
jogos: 0,
vitorias: 0,
empates: 0,
derrotas: 0,
pontos_marcados: 0,
pontos_sofridos: 0,
saldo: 0
}));
rodadas.forEach(rodada => {
const ranking = rodada.ranking.sort((a, b) => b.pontos - a.);
ranking.( {
participante = tabela.( t..(item.));
participante.++;
participante. += item.;
(index === ) {
participante. += .;
participante.++;
}
(item. === ranking[index - ].) {
participante. += .;
participante.++;
}
{
participante.++;
}
});
});
tabela.( {
t. = tabela
.( !other..(t.))
.( sum + other., ) / (tabela. - );
t. = t. - t.;
});
tabela.( {
(a. !== b.) b. - a.;
(a. !== b.) b. - a.;
(a. !== b.) b. - a.;
b. - a.;
});
}
3.2 Mata-Mata
const MATA_MATA_FASES = {
32: ['oitavas', 'quartas', 'semi', 'final'],
16: ['oitavas', 'quartas', 'semi', 'final'],
8: ['quartas', 'semi', 'final'],
4: ['semi', 'final']
};
function gerarChaveamentoMataMata(participantes, criterio = 'pontos_corridos') {
const numParticipantes = participantes.length;
const fases = MATA_MATA_FASES[numParticipantes];
if (!fases) {
throw new Error(`Número inválido de participantes: ${numParticipantes}`);
}
const classificados = [...participantes].sort((a, b) => {
return b[criterio] - a[criterio];
});
const primeiraFase = fases[0];
const confrontos = [];
for (let i = 0; i < classificados.length / 2; i++) {
confrontos.push({
: primeiraFase,
: i + ,
: classificados[i],
: classificados[classificados. - - i],
: ,
:
});
}
{ fases, confrontos };
}
3.3 Top 10 (Mitos & Micos)
function calcularTop10(tipo, rodadas) {
const contador = {};
rodadas.forEach(rodada => {
const ranking = rodada.ranking.sort((a, b) => b.pontos - a.pontos);
let vencedor;
if (tipo === 'mitos') {
vencedor = ranking[0];
} else {
vencedor = ranking[ranking.length - 1];
}
if (vencedor) {
const id = vencedor.participante_id.toString();
contador[id] = (contador[id] || 0) + 1;
}
});
return Object.entries(contador)
.map(([id, count]) => ({ participante_id: id, quantidade: count }))
.sort((a, b) => b.quantidade - a.quantidade)
.slice(0, 10);
}
4. 💰 Fluxo Financeiro Completo
async function calcularSaldoCompleto(participanteId, ligaId, temporada) {
const rodadas = await Rodada.find({
participante_id: participanteId,
liga_id: ligaId,
temporada
});
const saldoRodadas = rodadas.reduce((sum, r) => {
return sum + (r.ganho_rodada || 0);
}, 0);
const premiacoes = await Premiacao.find({
participante_id: participanteId,
liga_id: ligaId,
temporada
});
const saldoDisputas = premiacoes.reduce((sum, p) => {
return sum + (p.valor || 0);
}, 0);
const saldoAcertos = await calcularSaldoAcertos(
participanteId,
ligaId,
temporada
);
const saldoTotal = formatarValor(
saldoRodadas + saldoDisputas + saldoAcertos
);
return {
: (saldoRodadas),
: (saldoDisputas),
: (saldoAcertos),
saldoTotal,
: {
: rodadas.( ({
: r.,
: r.
})),
: premiacoes.( ({
: p.,
: p.
})),
: .({
: participanteId,
: ligaId,
temporada
}).()
}
};
}
5. 📋 Validações de Negócio
const VALIDACOES_NEGOCIO = {
async validarSomaZero(ligaId, temporada) {
const participantes = await Participante.find({ liga_id: ligaId, temporada });
const somaTotal = participantes.reduce((sum, p) => {
return sum + (p.saldo_temporada || 0);
}, 0);
const tolerance = 0.10;
if (Math.abs(somaTotal) > tolerance) {
console.error(`⚠️ Soma não é zero: R$ ${somaTotal.toFixed(2)}`);
return false;
}
return true;
},
async validarRodadas(ligaId, temporada) {
const config = await SystemConfig.findOne({ tipo: 'temporada' });
const rodadaAtual = config.rodada_atual;
( i = ; i < rodadaAtual; i++) {
count = .({
: ligaId,
temporada,
: i
});
(count === ) {
.();
;
}
}
;
},
() {
rodadas = .({
: ligaId,
temporada,
: rodada
});
posicoes = rodadas.( r.);
uniquePosicoes = (posicoes);
(posicoes. !== uniquePosicoes.) {
.();
;
}
;
}
};
STATUS: ⚖️ League Architect - LAWS ENFORCED
Versão: 2.0
Última atualização: 2026-01-17