Add B2B reformista panel with Postgres/Drizzle data layer

Modela el funnel del lead en dos dimensiones (pipeline_stage técnico
de 7 pasos + estado comercial de 6 estados) y siembra 11 leads demo,
uno por cada momento del funnel, para analizar el siguiente paso.
Incluye panel /panel (lista + detalle RF-D-01/02) y wiring de deploy
(Dockerfile multi-stage + entrypoint migrate+seed).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Carlos Narro
2026-05-29 15:51:10 +02:00
parent 9020c24e68
commit f09024f753
20 changed files with 3630 additions and 2 deletions

29
mvp/b2c/src/db/index.ts Normal file
View File

@@ -0,0 +1,29 @@
import { drizzle, type PostgresJsDatabase } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';
// Cliente perezoso: solo se conecta en el primer acceso real a la DB.
// Evita que `next build` (que importa los módulos de ruta) falle si no hay
// DATABASE_URL en tiempo de build.
let _db: PostgresJsDatabase<typeof schema> | null = null;
function getDb(): PostgresJsDatabase<typeof schema> {
if (_db) return _db;
const connectionString = process.env.DATABASE_URL;
if (!connectionString) {
throw new Error('DATABASE_URL no está definida. Copia .env.example a .env.local y rellénala.');
}
const client = postgres(connectionString, { prepare: false });
_db = drizzle(client, { schema });
return _db;
}
export const db = new Proxy({} as PostgresJsDatabase<typeof schema>, {
get(_target, prop) {
const instance = getDb();
const value = instance[prop as keyof typeof instance];
return typeof value === 'function' ? value.bind(instance) : value;
},
});
export { schema };