From 353af841dd5c73be88ef3e68f70af83fdbd9982f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 16 Mar 2026 18:09:00 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20adiciona=20PLANO=5FSOE=5FCENTRAL=5Fv2.m?= =?UTF-8?q?d=20=E2=80=94=20plano=20revisado=20baseado=20no=20Replit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Análise profunda do MAPA_SOE_ARCADIA.md revelou que o SOE já tem: - SOE.tsx com 2.414 linhas funcionando - 60+ endpoints /api/soe/* já existindo - ArcadiaPlusClient e ArcadiaNextClient já implementados - Padrão motor/adaptador já operacional O plano v2 foca no que realmente falta: - SOE Rule Engine (middleware entre rota e adaptador) - Event Bus (lançamentos contábeis automáticos) - Ocultação de Plus/ERPNext do usuário final - Regras fiscais centralizadas no SOE https://claude.ai/code/session_01DinH3VcgbAv1d9MqnNxzdb --- PLANO_SOE_CENTRAL_v2.md | 666 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 666 insertions(+) create mode 100644 PLANO_SOE_CENTRAL_v2.md diff --git a/PLANO_SOE_CENTRAL_v2.md b/PLANO_SOE_CENTRAL_v2.md new file mode 100644 index 0000000..f5f9d40 --- /dev/null +++ b/PLANO_SOE_CENTRAL_v2.md @@ -0,0 +1,666 @@ +# PLANO SOE CENTRAL v2 — Análise Real + Evolução +## Baseado no MAPA_SOE_ARCADIA.md (Replit) + Auditoria do Código +### Versão 2.0 — Março 2026 + +--- + +## 1. DIAGNÓSTICO — O QUE JÁ EXISTE (e o plano v1 não sabia) + +O MAPA_SOE_ARCADIA.md do Replit revelou que **o SOE já é uma realidade arquitetural robusta**, não apenas um conceito. Antes de planejar qualquer coisa, é crítico entender o que já funciona. + +### 1.1 O que já está construído e funcionando + +| Componente | Status | Localização | +|---|---|---| +| `SOE.tsx` | ✅ 2.414 linhas — UI completa com 9 tabs | `client/src/pages/SOE.tsx` | +| `SoeMotorContext.tsx` | ✅ Seletor de motor (plus/erpnext) | `client/src/contexts/` | +| `ErpApiClient` (interface) | ✅ Interface unificada definida | `server/erp/index.ts` | +| `ArcadiaPlusClient` | ✅ Adaptador HTTP → Plus:8080 | `server/erp/index.ts` | +| `ArcadiaNextClient` | ✅ Adaptador HTTP → ERPNext API | `server/erp/index.ts` | +| `registerSoeRoutes()` | ✅ 60+ endpoints em /api/soe/* | `server/erp/routes.ts` | +| `server/plus/proxy.ts` | ✅ Proxy reverso para Plus | `server/plus/` | +| `server/plus/sso.ts` | ✅ SSO automático Plus ↔ Suite | `server/plus/` | +| `server/plus/launcher.ts` | ✅ Lança PHP artisan serve | `server/plus/` | +| Módulo de Pessoas unificado | ✅ `persons` + `person_roles` | Schema PostgreSQL | +| Módulo de Produtos | ✅ Com NCM, CST, CFOP, IMEI | Schema PostgreSQL | +| Módulo Financeiro | ✅ Contas a P/R + transações | Schema PostgreSQL | +| Motor Fisco (:8002) | ✅ NF-e/NFC-e via nfelib | `server/python/` | +| Motor Contábil (:8003) | ✅ DRE, Balanço, SPED | `server/python/` | +| Sistema de módulos por tenant | ✅ `tenants.features` (JSONB) | Schema PostgreSQL | +| Middleware de gating | ✅ `requireModule()` | `server/` | + +### 1.2 Bancos de Dados por Motor (detalhe crítico) + +``` +Arcádia Suite → PostgreSQL 16 (dados do SOE, pessoas, produtos, vendas...) +Arcádia Plus → MySQL 8.0 (dados do Laravel — vendas, estoque, NF-e...) +ERPNext → MariaDB (dados do Frappe — CRM, HR, projetos...) +Motor Fisco → sem banco (só processa, retorna resultado) +Motor Contábil → sem banco (só processa, retorna resultado) +``` + +**Implicação:** Não há sincronização automática entre esses bancos. Um pedido criado no SOE (PostgreSQL) não aparece no Plus (MySQL) automaticamente — e vice-versa. + +### 1.3 O padrão motor/adaptador atual + +``` +Request do usuário + │ + ▼ +/api/soe/sales-orders (POST) + │ + ▼ +Verifica motor ativo (localStorage: arcadia_soe_motor) + │ + ├── motor = "local" → INSERT direto no PostgreSQL + ├── motor = "plus" → POST → Plus:8080 → MySQL + └── motor = "erpnext" → POST → ERPNext API → MariaDB +``` + +--- + +## 2. O PROBLEMA REAL — Onde o SOE atual para + +O SOE atual é um **roteador inteligente**: recebe o request, decide para qual motor enviar, e despacha. Ele **não tem inteligência própria**. + +### 2.1 O que falta (lacuna real) + +``` +Situação atual: + +SOE.tsx → /api/soe/* ────────────────────────────► Plus/ERPNext + (sem regras, sem processamento) + Regras ficam DENTRO do Plus + Regras ficam DENTRO do ERPNext + +Situação desejada: + +SOE.tsx → /api/soe/* → [RULE ENGINE SOE] ──────► Plus/ERPNext + │ (só executa) + ├── Regras Fiscais + ├── Regras Contábeis + ├── Regras Financeiras + └── Regras de Negócio +``` + +### 2.2 Problemas concretos hoje + +| Problema | Impacto | +|---|---| +| Fiscal rules dentro do Plus | Se trocar de motor (Plus→ERPNext), perde todas as regras | +| Nenhum lançamento contábil automático | DRE fica vazio, contabilidade manual | +| Motor Contábil (:8003) existe mas nada alimenta ele | 0 lançamentos automáticos | +| Plus tem UI própria (/plus) | Usuário pode bypassar o SOE e ir direto ao Plus | +| Sem event bus entre motores | Uma NF-e emitida no Plus não dispara nada no SOE | +| 25 conectores ERP definidos, zero chamadas reais | Integração existe no papel, não funciona | + +### 2.3 O que o usuário vê hoje vs o que deveria ver + +``` +Hoje: + /soe → UI do SOE (tabs: dashboard, pessoas, produtos, vendas...) + /plus → UI do Plus (Laravel) — direto, sem passar pelo SOE + /erp → UI do ERP legado + (usuário VÊ o Plus se quiser) + +Desejado: + /soe → UI do SOE (mesma, mas com inteligência) + /plus → BLOQUEADO ou redirecionado para /soe + /erp → BLOQUEADO ou redirecionado para /soe + (Plus e ERPNext = invisíveis, executando em background) +``` + +--- + +## 3. ARQUITETURA EVOLUÍDA — SOE com Rule Engine + +### 3.1 O que muda (e o que fica igual) + +**NÃO MUDA:** +- `SOE.tsx` — a UI continua a mesma (só ganha funcionalidades) +- `SoeMotorContext.tsx` — seleção de motor continua existindo +- `ArcadiaPlusClient` / `ArcadiaNextClient` — adaptadores continuam +- Todas as rotas `/api/soe/*` — continuam funcionando +- Todos os bancos — PostgreSQL, MySQL, MariaDB — continuam separados + +**MUDA / ADICIONA:** +- Uma **camada de Rule Engine** entre as rotas e os adaptadores +- **Event Bus SOE** que dispara lançamentos contábeis automaticamente +- **Ocultação do Plus** — `/plus` passa a ser controlado pelo SOE +- **Regras fiscais** saem do Plus e entram no SOE + +### 3.2 Diagrama completo com Rule Engine + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ ARCÁDIA SUITE — CAMADA DE APRESENTAÇÃO │ +│ │ +│ SOE.tsx (2.414+ linhas) │ +│ Tabs: Dashboard | Pessoas | Produtos | Vendas | Compras │ +│ Financeiro | CRM | Sincronização | Config │ +│ │ +│ SoeMotorContext.tsx → motor = "plus" | "erpnext" | "local" │ +└───────────────────────────────┬─────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────┐ +│ /api/soe/* — CAMADA DE API (já existe) │ +│ registerSoeRoutes() em server/erp/routes.ts │ +│ requireAuth + requireModule middleware │ +└───────────────────────────────┬─────────────────────────────────────┘ + │ + ▼ ◄── INSERIR AQUI (novo) +┌─────────────────────────────────────────────────────────────────────┐ +│ SOE RULE ENGINE (NOVO) │ +│ server/soe/rule-engine/ │ +│ │ +│ Antes de despachar para o motor, o Rule Engine: │ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ 1. FISCAL RULES (server/soe/rule-engine/fiscal.ts) │ │ +│ │ • Resolve CFOP correto (intra/interestadual) │ │ +│ │ • Aplica tributação por regime (Simples/Presumido/Real) │ │ +│ │ • Valida NCM obrigatório │ │ +│ │ • Define CST/CSOSN automático │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ 2. BUSINESS RULES (server/soe/rule-engine/business.ts) │ │ +│ │ • Aprovação automática de pedidos < R$ X │ │ +│ │ • Reserva de estoque ao confirmar venda │ │ +│ │ • Trigger de NF-e ao faturar pedido │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ 3. ACCOUNTING RULES (server/soe/rule-engine/accounting.ts) │ │ +│ │ • Emitiu NF-e → lançamento automático D: Clientes │ │ +│ │ C: Receita │ │ +│ │ • Pagou conta → lançamento automático D: Fornecedor │ │ +│ │ C: Banco │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +└───────────────────────────────┬─────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────┐ +│ DESPACHADOR DE MOTOR (já existe, aprimorado) │ +│ createErpClient(connection) em server/erp/index.ts │ +│ │ +│ motor = "local" → INSERT PostgreSQL │ +│ motor = "plus" → ArcadiaPlusClient → Plus:8080 → MySQL │ +│ motor = "erpnext" → ArcadiaNextClient → ERPNext API → MariaDB │ +└───────────────────────────────┬─────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────┐ +│ SOE EVENT BUS (NOVO) │ +│ server/soe/event-bus.ts │ +│ │ +│ Depois que o motor executa, o Event Bus dispara: │ +│ │ +│ evento: "nfe_emitida" → Motor Contábil (lançamento auto) │ +│ evento: "venda_confirmada" → Reserva estoque + alerta WhatsApp │ +│ evento: "pagamento_feito" → Baixa C/P + lançamento contábil │ +│ evento: "recebimento" → Baixa C/R + lançamento contábil │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 4. O QUE CONSTRUIR — Detalhamento por Módulo + +### 4.1 SOE Rule Engine (PRIORIDADE MÁXIMA) + +**Localização:** `server/soe/rule-engine/` + +Este é o coração da evolução. É um middleware que intercepta as chamadas às rotas SOE **antes** de despachar para o motor. + +#### Como funciona na prática + +```typescript +// server/erp/routes.ts — modificação cirúrgica + +// ANTES (atual): +app.post("/api/soe/sales-orders", requireAuth, async (req, res) => { + const client = getActiveClient(req) // pega Plus ou ERPNext + const result = await client.createSalesOrder(req.body) // despacha direto + res.json(result) +}) + +// DEPOIS (com Rule Engine): +app.post("/api/soe/sales-orders", requireAuth, async (req, res) => { + // 1. Aplica regras ANTES de despachar + const enriched = await ruleEngine.apply('pre_sales_order', req.body, req.user) + + // 2. Despacha para o motor com dados enriquecidos + const client = getActiveClient(req) + const result = await client.createSalesOrder(enriched.payload) + + // 3. Dispara eventos DEPOIS da execução + await eventBus.emit('sales_order_created', { result, rules: enriched.appliedRules }) + + res.json(result) +}) +``` + +#### Estrutura do Rule Engine + +```typescript +// server/soe/rule-engine/index.ts + +interface SoeRule { + id: string + dominio: 'fiscal' | 'business' | 'accounting' | 'financial' + trigger: string // ex: 'pre_sales_order', 'post_nfe_emitida' + condicao: RuleCondition // quando esta regra se aplica + acao: RuleAction // o que ela faz ao payload + prioridade: number + ativo: boolean + empresaId?: number // null = regra global de todos os tenants +} + +class SoeRuleEngine { + async apply(trigger: string, payload: any, context: RuleContext): Promise { + // 1. Busca regras ativas para este trigger (do banco + defaults hardcoded) + const rules = await this.getActiveRules(trigger, context.tenantId) + + // 2. Filtra regras cuja condição se aplica ao payload + const applicable = rules.filter(r => this.avaliarCondicao(r.condicao, payload, context)) + + // 3. Aplica cada regra em ordem de prioridade + let enriched = { ...payload } + const applied: string[] = [] + for (const rule of applicable.sort((a, b) => a.prioridade - b.prioridade)) { + enriched = await this.aplicarAcao(rule.acao, enriched, context) + applied.push(rule.id) + } + + return { payload: enriched, appliedRules: applied } + } +} +``` + +### 4.2 Regras Fiscais no SOE + +Estas regras **hoje vivem dentro do Plus** (Laravel controllers). A ideia é trazê-las para o SOE. + +**Nota importante:** Não é mover o código PHP para TypeScript. É criar regras **declarativas** no SOE que enriquecem o payload **antes** de enviar ao Plus. O Plus ainda processa e emite — mas recebe o payload já correto. + +```typescript +// server/soe/rule-engine/fiscal-rules.ts + +export const FISCAL_RULES_PADRAO: SoeRule[] = [ + + // CFOP — resolve automaticamente por operação + { + id: 'CFOP_VENDA_DENTRO_ESTADO', + dominio: 'fiscal', + trigger: 'pre_sales_order', + condicao: { uf_emitente: '==', uf_destinatario: true, tipo_op: 'venda_produto' }, + acao: { set: { 'items[*].cfop': '5.102' } }, + prioridade: 10, ativo: true + }, + { + id: 'CFOP_VENDA_OUTRO_ESTADO', + dominio: 'fiscal', + trigger: 'pre_sales_order', + condicao: { uf_emitente: '!=', uf_destinatario: true, tipo_op: 'venda_produto' }, + acao: { set: { 'items[*].cfop': '6.102' } }, + prioridade: 10, ativo: true + }, + + // Tributação por Regime + { + id: 'CST_SIMPLES_NACIONAL', + dominio: 'fiscal', + trigger: 'pre_nfe_emissao', + condicao: { regime_tributario: 'simples_nacional' }, + acao: { + set: { 'items[*].cst_icms': '400', 'items[*].pis': null, 'items[*].cofins': null }, + // No Simples Nacional: CSOSN 400 = tributado, sem destaque PIS/COFINS + }, + prioridade: 5, ativo: true + }, + { + id: 'CST_LUCRO_PRESUMIDO', + dominio: 'fiscal', + trigger: 'pre_nfe_emissao', + condicao: { regime_tributario: 'lucro_presumido' }, + acao: { set: { 'items[*].cst_pis': '01', 'items[*].cst_cofins': '01' } }, + prioridade: 5, ativo: true + }, + + // Validações obrigatórias + { + id: 'VALIDAR_NCM_NFE', + dominio: 'fiscal', + trigger: 'pre_nfe_emissao', + condicao: { tipo_documento: ['nfe', 'nfce'] }, + acao: { validar: { campo: 'items[*].ncm', obrigatorio: true, formato: /^\d{8}$/ } }, + prioridade: 1, ativo: true + }, +] +``` + +### 4.3 SOE Event Bus — Lançamentos Contábeis Automáticos + +Este é o **maior salto de valor**. Hoje o Motor Contábil (:8003) existe mas nada o alimenta automaticamente. + +```typescript +// server/soe/event-bus.ts + +type SoeEvent = + | 'nfe_emitida' + | 'nfe_cancelada' + | 'venda_confirmada' + | 'compra_recebida' + | 'pagamento_realizado' + | 'recebimento_realizado' + | 'boleto_gerado' + +interface SoeEventPayload { + empresaId: number + tenantId: number + evento: SoeEvent + dados: Record + motorOrigem: 'plus' | 'erpnext' | 'local' +} + +class SoeEventBus { + async emit(evento: SoeEvent, payload: SoeEventPayload) { + // Registra no banco (audit trail) + await db.insert(soeEventos).values({ ...payload, createdAt: new Date() }) + + // Dispara handlers + await Promise.allSettled( + this.getHandlers(evento).map(h => h(payload)) + ) + } + + // Handlers por evento + private handlers: Record = { + 'nfe_emitida': [ + contabilHandler.lancamentoVenda, // D: Clientes / C: Receita Bruta + contabilHandler.lancamentoImpostos, // D: Impostos / C: ICMS/PIS/COFINS a Recolher + financialHandler.gerarRecebivel, // Cria C/R automaticamente + ], + 'pagamento_realizado': [ + contabilHandler.lancamentoPagamento, // D: Fornecedores / C: Banco + financialHandler.baixarContaPagar, // Baixa C/P + ], + 'recebimento_realizado': [ + contabilHandler.lancamentoRecebimento, // D: Banco / C: Clientes + financialHandler.baixarContaReceber, // Baixa C/R + ], + 'compra_recebida': [ + contabilHandler.lancamentoCompra, // D: Estoque / C: Fornecedores + ], + } +} +``` + +#### Lançamentos automáticos para cada evento + +``` +NF-e emitida (venda): + D: 1.1.3.01 — Clientes (valor total da nota) + C: 3.1.1.01 — Receita Bruta de Vendas + + D: 3.1.2.01 — Deduções (ICMS) + C: 2.1.2.01 — ICMS a Recolher + + D: 3.1.2.02 — Deduções (PIS) + C: 2.1.2.02 — PIS a Recolher + + D: 3.1.2.03 — Deduções (COFINS) + C: 2.1.2.03 — COFINS a Recolher + +Pagamento de fornecedor: + D: 2.1.1.{categoria} — Fornecedores + C: 1.1.1.01 — Banco (conta configurada) + +Recebimento de cliente: + D: 1.1.1.01 — Banco + C: 1.1.3.01 — Clientes + +Compra recebida (NF-e entrada): + D: 1.1.4.01 — Estoque / Mercadorias + C: 2.1.1.01 — Fornecedores +``` + +### 4.4 Ocultação do Plus e ERPNext + +O Plus tem página própria em `/plus` (client/src/pages/Plus.tsx). O usuário pode acessá-la diretamente. Precisamos de 3 mudanças: + +#### a) Redirecionar `/plus` para `/soe` + +```typescript +// client/src/App.tsx — modificação simples +// Trocar: +// Por: } /> +``` + +**Mas manter o proxy reverso Plus ativo** — o Plus continua funcionando em background, só não fica visível como página separada. + +#### b) Ocultar o seletor de motor do usuário final + +```typescript +// client/src/contexts/SoeMotorContext.tsx +// O seletor fica SOMENTE na tab Config do SOE, e somente para admins + +// A tab Config na SOE.tsx — adicionar role check: +{user?.role === 'admin' && Config} +``` + +#### c) Na tab Config (admin), o label muda + +``` +Antes: "Selecione o motor: Plus | ERPNext" +Depois: "Motor de execução: Plus | ERPNext | Local" +(invisível para usuário final, só admin de tenant vê) +``` + +--- + +## 5. TABELAS A CRIAR (complemento ao schema existente) + +As tabelas canônicas do SOE já existem. Precisamos adicionar apenas as tabelas do Rule Engine. + +```typescript +// shared/schema.ts — adicionar ao final + +// Regras do SOE — configuráveis por tenant +export const soeRegras = pgTable('soe_regras', { + id: uuid('id').primaryKey().defaultRandom(), + tenantId: integer('tenant_id'), // null = regra global (todas as empresas) + empresaId: integer('empresa_id'), // null = todas as empresas do tenant + dominio: varchar('dominio', { length: 50 }).notNull(), + trigger: varchar('trigger', { length: 100 }).notNull(), + nome: varchar('nome', { length: 200 }).notNull(), + condicao: jsonb('condicao').notNull(), + acao: jsonb('acao').notNull(), + prioridade: integer('prioridade').default(10), + ativo: boolean('ativo').default(true), + origemPadrao: boolean('origem_padrao').default(false), // true = regra default do sistema + createdAt: timestamp('created_at').defaultNow(), + updatedAt: timestamp('updated_at').defaultNow(), +}) + +// Log de todos os eventos SOE (audit trail completo) +export const soeEventos = pgTable('soe_eventos', { + id: uuid('id').primaryKey().defaultRandom(), + tenantId: integer('tenant_id').notNull(), + empresaId: integer('empresa_id'), + evento: varchar('evento', { length: 100 }).notNull(), + motorOrigem: varchar('motor_origem', { length: 50 }), // 'plus', 'erpnext', 'local' + regraIds: jsonb('regra_ids'), // regras aplicadas + payloadEntrada: jsonb('payload_entrada'), + payloadSaida: jsonb('payload_saida'), + status: varchar('status', { length: 50 }).notNull(), + duracaoMs: integer('duracao_ms'), + erro: text('erro'), + createdAt: timestamp('created_at').defaultNow(), +}) + +// Lançamentos contábeis automáticos do SOE +export const soeLancamentos = pgTable('soe_lancamentos', { + id: uuid('id').primaryKey().defaultRandom(), + tenantId: integer('tenant_id').notNull(), + empresaId: integer('empresa_id').notNull(), + data: date('data').notNull(), + contaDebito: varchar('conta_debito', { length: 30 }).notNull(), + contaCredito: varchar('conta_credito', { length: 30 }).notNull(), + valor: numeric('valor', { precision: 15, scale: 2 }).notNull(), + historico: text('historico').notNull(), + origemEvento: varchar('origem_evento', { length: 100 }), // 'nfe_emitida', etc. + origemEventoId: uuid('origem_evento_id'), // FK para soe_eventos + periodo: varchar('periodo', { length: 7 }), // '2026-03' + enviado8003: boolean('enviado_8003').default(false), // sincronizado com Motor Contábil + createdAt: timestamp('created_at').defaultNow(), +}) +``` + +--- + +## 6. ESTRUTURA DE PASTAS (Novo código a criar) + +``` +server/ +└── soe/ ← NOVA PASTA + ├── rule-engine/ + │ ├── index.ts ← SoeRuleEngine class + │ ├── fiscal-rules.ts ← Regras fiscais padrão + │ ├── business-rules.ts ← Regras de negócio + │ └── accounting-rules.ts ← Regras de lançamento contábil + │ + ├── event-bus.ts ← SoeEventBus class + │ + ├── handlers/ + │ ├── contabil-handler.ts ← Lançamentos automáticos + │ └── financial-handler.ts ← Automação financeira + │ + └── fiscal/ + └── cfop-resolver.ts ← Resolução de CFOP (lógica complexa) +``` + +**Modificações em arquivos existentes:** +``` +server/erp/routes.ts ← Inserir ruleEngine.apply() antes do dispatch +client/src/App.tsx ← Redirecionar /plus para /soe +client/src/pages/SOE.tsx ← Ocultar Config tab para não-admins +``` + +--- + +## 7. ROADMAP — Fases de Implementação + +### Fase 1 — Rule Engine Básico (1 semana) +``` +[ ] Criar server/soe/rule-engine/index.ts (SoeRuleEngine) +[ ] Criar tabelas soe_regras e soe_eventos (drizzle push) +[ ] Inserir ruleEngine.apply() em 3 rotas críticas: + - POST /api/soe/sales-orders + - POST /api/soe/sales-orders/:id/generate-nfe + - POST /api/soe/purchase-orders +[ ] Seed das regras fiscais padrão (CFOP, CST, validações NCM) +[ ] Testar: criar pedido → verificar que payload está sendo enriquecido +``` + +### Fase 2 — Event Bus + Contabilidade Automática (1 semana) +``` +[ ] Criar server/soe/event-bus.ts +[ ] Criar tabela soe_lancamentos (drizzle push) +[ ] Criar handlers: contabil-handler.ts + financial-handler.ts +[ ] Conectar: POST generate-nfe → emit('nfe_emitida') → lançamentos +[ ] Conectar: pagamento/recebimento → emit() → lançamentos +[ ] Criar endpoint: GET /api/soe/contabil/lancamentos?periodo=YYYY-MM +[ ] DRE: agora tem dados reais (via soe_lancamentos → Motor :8003) +``` + +### Fase 3 — Ocultar Plus/ERPNext (3 dias) +``` +[ ] client/src/App.tsx: /plus → redirect para /soe +[ ] client/src/pages/SOE.tsx: Config tab só para admins +[ ] Manter proxy Plus funcionando (invisível) +[ ] Testar: fluxo completo sem nenhum acesso direto ao Plus UI +``` + +### Fase 4 — Regras Configuráveis pelo Usuário (1 semana) +``` +[ ] UI na tab Config do SOE: "Regras de Negócio" +[ ] CRUD de regras via /api/soe/rules +[ ] Admin pode criar regras custom sem código +[ ] Exemplo: "Pedidos acima de R$10.000 requerem aprovação manual" +``` + +### Fase 5 — Financeiro Avançado (2 semanas) +``` +[ ] Auto-boleto ao confirmar venda (Asaas API) +[ ] Alertas de vencimento (Manus → WhatsApp) +[ ] Conciliação bancária OFX semi-automática +[ ] Previsão financeira (Motor BI :8004 + histórico soe_lancamentos) +``` + +### Fase 6 — Contábil Avançado (2 semanas) +``` +[ ] DRE automático mensal (100% alimentado pelo Event Bus) +[ ] Balanço Patrimonial automático +[ ] Fechamento contábil mensal +[ ] SPED ECD/ECF alimentado por soe_lancamentos +[ ] Exportação para escritório contábil (OFX, Excel, PDF) +``` + +--- + +## 8. COMPARAÇÃO: PLANO v1 vs PLANO v2 + +| Aspecto | Plano v1 (antes do Replit .md) | Plano v2 (com conhecimento real) | +|---|---|---| +| Adaptadores Plus/ERPNext | "Precisam ser criados" | Já existem — não tocar | +| SOE Routes | "Precisam ser criadas" | 60+ endpoints já existem | +| SOE.tsx | "Precisa ser construída" | 2.414 linhas — já funciona | +| Onde adicionar código | server/soe/ do zero | Middleware nas rotas existentes | +| Esforço estimado | Alto (refatoração total) | Médio (adição cirúrgica) | +| Risco de quebrar | Alto | Baixo (adição, não substituição) | +| Banco Plus | Ignorado | MySQL — separado, nunca tocar direto | + +--- + +## 9. PRINCÍPIO ORIENTADOR (REVISADO) + +> O SOE já é o roteador certo. Agora vamos torná-lo o **árbitro de regras**. +> +> O padrão motor/adaptador está perfeito. O que falta é a **inteligência entre a rota e o adaptador**. +> +> Plus e ERPNext continuam existindo e funcionando — só que o usuário final não sabe. +> Ele só vê a Central SOE. O restante é infraestrutura. + +--- + +## 10. RESUMO EXECUTIVO — O que fazer agora + +**1 ação que entrega valor imediato:** +``` +Criar o SoeRuleEngine e plugar nas rotas de venda/NF-e. +Resultado: Ao emitir uma NF-e, o CFOP correto é calculado +automaticamente pelo SOE — sem o usuário saber que o Plus está +sendo chamado por baixo. +``` + +**1 ação que entrega valor a médio prazo:** +``` +Criar o Event Bus com o handler de contabilidade. +Resultado: Cada NF-e emitida gera lançamentos contábeis +automaticamente. O DRE do mês é gerado sem entrada manual de dados. +``` + +**1 ação que fecha o conceito:** +``` +Redirecionar /plus → /soe. +Resultado: O usuário não tem mais acesso ao Plus diretamente. +Ele só vê o Arcádia. O Plus é infraestrutura invisível. +``` + +--- + +*PLANO_SOE_CENTRAL_v2.md — Arcádia Suite v3.0* +*Gerado em: 2026-03-16 — Baseado na análise real do MAPA_SOE_ARCADIA.md (Replit)*