local dev setup + OPENAI_BASE_URL support + dashboard fix

- CLAUDE.md con arquitectura y comandos del proyecto
- env.example: agregar LIMIT_CONVERSATIONS, MAX_CHARS_PER_MESSAGE, OPENAI_BASE_URL
- docker-compose.override: puerto 3001, extra_hosts para modelo local en Linux
- OpenAI clients: soporte OPENAI_BASE_URL para apuntar a modelo local compatible
- stats.js: sync de órdenes en background, dashboard no bloquea al cargar
- package-lock: dbmate movido a prod dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lucas Tettamanti
2026-05-01 18:32:22 -03:00
parent b933db88df
commit 525679cf8b
8 changed files with 116 additions and 20 deletions

View File

@@ -5,10 +5,12 @@ import * as ordersRepo from "../../4-woo-orders/ordersRepo.js";
* Obtiene estadísticas de pedidos para el dashboard
*/
export async function handleGetOrderStats({ tenantId }) {
// 1. Sincronizar pedidos nuevos de Woo
const syncResult = await syncOrdersIncremental({ tenantId });
// 2. Obtener todas las estadísticas en paralelo
// Sync en background — no bloqueamos el request
const syncPromise = syncOrdersIncremental({ tenantId }).catch(err =>
console.error("[stats] sync error:", err)
);
// Respondemos con lo que hay en DB mientras sincroniza
const [monthlyStats, productStats, yoyStats, totals] = await Promise.all([
ordersRepo.getMonthlyStats({ tenantId }),
ordersRepo.getProductStats({ tenantId }),
@@ -36,8 +38,8 @@ export async function handleGetOrderStats({ tenantId }) {
// YoY
yoy: yoyStats,
// Info de sync
synced: syncResult.synced,
total_in_cache: syncResult.total,
// Info de sync (sincronizando en background)
synced: 0,
total_in_cache: totals.total_orders ?? 0,
};
}

View File

@@ -14,7 +14,8 @@ function getClient() {
throw new Error("OPENAI_API_KEY is not set");
}
if (!_client) {
_client = new OpenAI({ apiKey });
const baseURL = process.env.OPENAI_BASE_URL || undefined;
_client = new OpenAI({ apiKey, ...(baseURL ? { baseURL } : {}) });
}
return _client;
}

View File

@@ -17,7 +17,8 @@ function getClient() {
throw new Error("OPENAI_API_KEY is not set");
}
if (!_client) {
_client = new OpenAI({ apiKey });
const baseURL = process.env.OPENAI_BASE_URL || undefined;
_client = new OpenAI({ apiKey, ...(baseURL ? { baseURL } : {}) });
}
return _client;
}

View File

@@ -18,7 +18,8 @@ function getClient() {
}
if (_client && _clientKey === apiKey) return _client;
_clientKey = apiKey;
_client = new OpenAI({ apiKey });
const baseURL = process.env.OPENAI_BASE_URL || undefined;
_client = new OpenAI({ apiKey, ...(baseURL ? { baseURL } : {}) });
return _client;
}