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.
// 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.
// 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 rowsCode 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