Volver a notas técnicas
9 min

Nota técnica

ERP multi-país sin duplicar codebase

Cómo servir Argentina y Colombia desde un ERP legacy PHP durante 16 meses — config por mercado, −35% carga en conciliaciones y 20+ features sin fork.

En números

2

Mercados

16

Meses

−35%

Tiempo carga

20+

Features

Un producto, dos regulaciones

ConsorcioAbierto (AR) y Properix (CO) comparten plataforma pero difieren en regulaciones fiscales, monedas, flujos de expensas y conciliaciones bancarias. Duplicar repos multiplicaba deuda. La regla: config por mercado en backend, componentes condicionados por contexto en Vue 3 — nunca fork de codebase.

Config-driven rules

Separé lo que varía por país (validaciones, labels, reglas fiscales) de lo core (modelo de consorcio, fondos, conciliaciones). Un servicio Laravel expone reglas por tenant; Vue consume un MarketContext que determina qué campos renderizar.

PHP · Laravel
// app/Services/MarketRules.php
class MarketRules
{
    public function getExpenseValidation(string $market): array
    {
        return match ($market) {
            'AR' => ['currency' => 'ARS', 'iva_required' => true, ...],
            'CO' => ['currency' => 'COP', 'iva_required' => false, ...],
        };
    }
}

// Vue 3 — composable
const { market, rules } = useMarketContext();
const schema = computed(() => buildFormSchema(rules.value));

Performance: medir antes de optimizar

Módulos de conciliaciones y fondos manejan alto volumen. Antes de tocar código, usamos slow query log: el 80% del tiempo estaba en 3 queries con N+1. Solución: eager loading, índices compuestos en columnas de filtro frecuente, paginación server-side. Resultado: −~35% tiempo de carga en conciliaciones.

PHP · Eloquent
// Antes — N+1 en conciliaciones
$movements = Movement::where('fund_id', $id)->get();
// Cada movement->fund, movement->account → query extra

// Después — eager loading + paginación
$movements = Movement::with(['fund', 'account', 'reconciliation'])
    ->where('fund_id', $id)
    ->orderByDesc('date')
    ->paginate(50); // server-side, no cargar 10k rows

Code review reforzado en finanzas

En módulos financieros: PR obligatorio de 2 reviewers, tests en cálculos de expensas y conciliaciones, y QA manual en escenarios cross-border antes de release por mercado. Releases incrementales: feature flag por país → deploy AR → validar → deploy CO.

16 meses, 20+ features

El balance estabilidad/velocidad: no big-bang refactors. Optimización incremental en módulos con tráfico real, features deployables por mercado, y coordinación con QA en escenarios AR+CO. 20+ features full stack (Laravel/Symfony + Vue 3) sin duplicar repos.

Takeaways

  • Config por mercado en backend — nunca fork de codebase
  • Slow query log antes de optimizar — el 80/20 aplica en SQL
  • −35% carga en conciliaciones con eager loading + índices + paginación
  • Code review doble en módulos financieros
  • Releases por mercado con feature flags — AR y CO independientes
ERPLaravelVue 3Multi-tenantPHP