Saltar a contenido

Base de datos

Motor, migraciones, seed y datos de prueba de Camarero IA. Sin secretos: las credenciales que aparecen son los defaults locales de desarrollo, no credenciales reales.

Alcance de entrega: se entregan todas las migraciones Alembic (backend/alembic/versions/) y el seed (scripts/seed_amici.py); con eso basta para recrear la base desde cero. No se entrega dump de datos de producción ni se necesita nada más.

Motor y conexión

  • PostgreSQL 15 (postgres:15-alpine) tanto en local como en producción. No usar sqlite3 para inspeccionar datos.
  • Driver asyncpg: la URL debe usar el esquema postgresql+asyncpg:// (SQLAlchemy 2.x async).
  • Conexión por defecto en local (backend/.env.example):
DATABASE_URL=postgresql+asyncpg://camarero_user:camarero_password@localhost:5432/camarero_db
Parte Default local
Usuario camarero_user
Contraseña camarero_password (default de desarrollo, cambiar en producción)
Host / puerto localhost:5432 (backend manual) o camarero_ia_db:5432 (dentro de Compose)
Base de datos camarero_db
  • BD de tests: contenedor Podman dedicado camarero-test-db con las mismas credenciales por defecto. Los e2e trabajan con PostgreSQL real sobre esquema limpio (DROP/CREATE en la fixture engine de backend/tests/e2e/conftest.py). Nunca EMBEDDINGS_ENABLED=true en tests (ver Ejecutar tests).

Esquema y tablas principales

Modelos en backend/app/modules/*/infrastructure/models/ (legacy residual en backend/app/old/models/ durante la migración hexagonal). Grupos:

Dominio Tablas
Restaurante y sala restaurants, restaurant_knowledge, rooms, tables, table_sessions
Menú y catálogo menus, categories, products, product_extras, product_option_groups, product_options, product_promotions
Pedido orders (entidad Comanda), order_lines (entidad ComandaLine)
Chat conversations, chat_messages, chat_logs, conversation_trees
Carrito y llamadas cart_items (PK UUID str, excepción documentada), manager_calls, idempotency_keys
Pagos y promo payments, recommendation_artifacts
Admin y auditoría admin_users, audit_logs
Recomendador recommendation_artifacts (artefactos precalculados capas 0-2)

Convenciones (ver backend/AGENTS.md): PK id: Mapped[int]; precios en céntimos (int); name/description como JSON {"es": ..., "en": ...}; timestamps timezone-aware (created_at/updated_at vía TimestampMixin); enums como String(N) con .value; FK {entidad}_id con ondelete explícito; SoftDeleteMixin (is_deleted + deleted_at) en entidades con audit trail.

Migraciones (Alembic)

Las migraciones viven en backend/alembic/versions/ con nombre YYYYMMDD_descripcion_breve.py, con upgrade() y downgrade() completos e inversos. Guía de autoría (crear, validar, errores comunes) en Migraciones de BD.

Aplicar desde cero

Desde backend/ con el venv y la BD levantada:

venv/bin/alembic upgrade head

Comprobaciones de estado:

venv/bin/alembic current   # revisión aplicada en la BD
venv/bin/alembic heads     # debe devolver UNA sola revisión
venv/bin/alembic history   # historial completo

Bootstrap de BD vacía

Sobre una base de datos vacía, alembic/env.py no reproduce toda la cadena: crea el esquema canónico actual con Base.metadata.create_all() y hace stamp a head. Las BD ya existentes siguen el camino incremental (alembic upgrade).

Merge heads históricos

Dos migraciones de merge consolidaron ramas paralelas; solo hacen merge (upgrade()/downgrade() vacíos), no cambian esquema:

Revisión Qué unifica Ramas (down_revision)
20260604_merge_heads Ramas safety01 + soft-delete 20260603_safety01, 20260604_soft_delete
20260605_merge_rd_heads Cinco ramas RD (RD02–RD07) para que alembic upgrade head corra limpio 20260604_add_flagged_allergens_to_order_lines, 20260604_payment_module, 20260604_comanda_course_plan, 20260604_rd04_order_approval_mode, 20260604_rd07_reviews

La regla sigue vigente: un solo head. Si alembic heads devuelve más de una revisión, hay que rebasar (down_revision) antes de mergear.

Seed (Amici, restaurante demo)

scripts/seed_amici.py carga una instancia completa del restaurante Amici: restaurante, menú, categorías, productos (con enriquecimiento IA por nombre: cost_price, ai_description, selling_points, flavor_profile), extras, grupos/opciones de producto, promociones, salas, mesas y base de conocimiento (restaurant_knowledge, incluye horarios, terraza, wifi, parking).

Características:

  • Idempotente: borra el restaurant_id elegido (y sus datos de carrito/pedido asociados) antes de resembrar; sincroniza las secuencias SERIAL con MAX(id) al final.
  • Multi-instancia con flags:
# Amici Madrid en id=1 (por defecto)
DATABASE_URL=postgresql://usuario:[REDACTED]@localhost:5432/bd \
  python3 scripts/seed_amici.py

# Segunda instancia
DATABASE_URL=postgresql://usuario:[REDACTED]@localhost:5432/bd \
  python3 scripts/seed_amici.py --restaurant-id 5 --name "Amici Bilbao" [--slug amici-bilbao]
Flag Efecto
--restaurant-id restaurants.id destino (default 1)
--name Nombre visible (default Amici …)
--slug Slug URL; si se omite, se deriva de --name (Amici Bilbao → amici-bilbao)
  • Lee DATABASE_URL del entorno (acepta con o sin +asyncpg; la normaliza para asyncpg directo).

El seed borra datos del restaurante destino

Solo ejecutarlo contra BDs de desarrollo/demo, nunca contra producción: elimina el restaurante indicado y todo lo ligado a él antes de resembrar.

Datos de prueba

Tras migraciones + seed, la BD contiene:

  • 1 restaurante (Amici, id configurable) con slug, features (terraza, salas privadas, wifi, reservas) y web de ejemplo.
  • Menú completo: categorías con course_type (APPETIZER/MAIN/SIDE/DESSERT/DRINK; el chat-validador y el filtro por fases dependen de este campo), productos con precios en céntimos, alérgenos (códigos AllergenType), imágenes y enriquecimiento IA.
  • Salas y mesas con qr_code para abrir sesiones cliente.
  • Base de conocimiento del restaurante para el chat híbrido.
  • Sin usuarios ni pedidos: el superadmin se crea vía ADMIN_SUPER_EMAIL en el primer arranque (ver Variables de entorno); las sesiones, comandas y pagos se generan al operar la app.

Páginas relacionadas