Restaurar funcionalidades desde stash + setup de despliegue Coolify

- Recupera el trabajo revertido (doble propuesta, retainer, niveles, API Python) desde el stash de GitHub Desktop
- Dockerfile multi-stage para Next.js (migraciones automáticas al arrancar, seed opcional via RUN_SEED)
- docker-compose.coolify.yml: postgres + web + api con healthchecks y SERVICE_FQDN_*
- Endpoint público /api/health (verifica BD) para healthchecks
- seed.ts parametrizado: conexión DB_* y credenciales SEED_* por entorno (sin passwords hardcodeadas)
- .env.example, .dockerignore, uvicorn con --proxy-headers
- Limpieza: .xlsx y __pycache__ fuera del repo

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
2026-06-10 02:21:18 -06:00
co-authored by Claude Fable 5
parent c3f4449296
commit 69c74faabb
43 changed files with 3536 additions and 1139 deletions
+14 -11
View File
@@ -47,6 +47,7 @@ def _row_to_response(row, categoria_row=None) -> ServicioCatalogoResponse:
entregablesDefault=entregables,
categoriaId=row["categoriaId"],
variante=row["variante"],
nivel=row["nivel"],
activo=row["activo"],
orden=row["orden"],
createdAt=row["createdAt"],
@@ -99,16 +100,16 @@ async def list_catalogo(
*params,
)
result: list[ServicioCatalogoResponse] = []
for r in rows:
cat_row = None
if r["categoriaId"]:
cat_row = await db.fetchrow(
'SELECT * FROM "Categoria" WHERE id = $1', r["categoriaId"]
)
result.append(_row_to_response(r, cat_row))
# Una sola query para todas las categorías referenciadas (evita N+1).
cat_ids = list({r["categoriaId"] for r in rows if r["categoriaId"]})
cat_map: dict = {}
if cat_ids:
cat_rows = await db.fetch(
'SELECT * FROM "Categoria" WHERE id = ANY($1::text[])', cat_ids
)
cat_map = {c["id"]: c for c in cat_rows}
return result
return [_row_to_response(r, cat_map.get(r["categoriaId"])) for r in rows]
@router.post(
@@ -134,8 +135,8 @@ async def create_catalogo(
row = await db.fetchrow(
'INSERT INTO "ServicioCatalogo" '
'(nombre, descripcion, fase, "tipoPago", "precioBase", "tiempoEntrega", '
'"entregablesDefault", "categoriaId", variante, activo, orden) '
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, true, $10) RETURNING *",
'"entregablesDefault", "categoriaId", variante, nivel, activo, orden) '
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, true, $11) RETURNING *",
body.nombre,
body.descripcion,
body.fase,
@@ -145,6 +146,7 @@ async def create_catalogo(
entregables_json,
body.categoriaId,
body.variante,
body.nivel,
body.orden,
)
@@ -218,6 +220,7 @@ async def update_catalogo(
"entregablesDefault": '"entregablesDefault"',
"categoriaId": '"categoriaId"',
"variante": "variante",
"nivel": "nivel",
"activo": "activo",
"orden": "orden",
}