Saltar a contenido

Anexo A — Estado técnico y alcance de la entrega

Naturaleza del documento: anexo contractual de entrega del sistema "Camarero IA". Describe el estado final cedido, el stack, la arquitectura, los prompts de IA (históricos y actuales), la infraestructura y la titularidad. Titular pendiente: BestWaiter S.L. (en constitución), representante Fabio Peral. Precio pactado: 6.000 €.


A.1 Stack tecnológico

Backend (backend/)

Capa Tecnología
Lenguaje Python 3.12
API FastAPI + uvicorn
ORM / migraciones SQLAlchemy 2.x async (asyncpg) + Alembic
Validación / settings Pydantic v2 + pydantic-settings
Auth JWT (python-jose / PyJWT), OAuth Google + Apple (RS256)
Tiempo real SSE (sse-starlette), bus de eventos de dominio
IA chat NVIDIA NIM (stepfun-ai/step-3.5-flash) vía NvidiaLlmClient en época histórica; proxy LLM local DeepSeek en híbrido. Cuenta NVIDIA solo de pruebas, no se transmite. Modelo LLM recomendado: DeepSeek Flash
Clasificador intents / recomendador sentence-transformers (paraphrase-multilingual-MiniLM-L12-v2) + numpy; singleton en app/shared/infrastructure/granite_embeddings.py
Fuzzy matching entidades rapidfuzz (diseño propuesto; ver arquitectura_hibrida_chatbot.md)
Rate limiting Redis/Valkey (redis>=5.0.0) con degradación a Postgres
Tests pytest + pytest-asyncio + httpx + testcontainers; contract-lock OpenAPI/SSE
Calidad make lint-arch (import-linter, ADR-004), make typecheck (mypy, no-bloqueante por baseline), black (línea 88), radon CC ≤ 10

Frontend (frontend/)

Capa Tecnología
Framework Next.js 16.2.9 + React 19.2.4
Estado cliente zustand
UI Tailwind CSS v4, radix-ui, shadcn, lucide-react, sonner, vaul
Editor de flujos @xyflow/react (editor visual de árboles de conversación)
Datos / charts recharts, date-fns, qrcode.react, react-markdown + remark-gfm, next-themes
Contrato tipado openapi-typescript generado desde backend/tests/contract/openapi_snapshot.json (npm run codegen)
Tests vitest + @playwright/test + @testing-library

Base de datos

  • PostgreSQL en local y producción (driver asyncpg). No SQLite en producción.
  • Migraciones Alembic (backend/alembic/versions/, formato YYYYMMDD_descripcion.py).
  • Precios siempre en céntimos (int). Campos i18n como dicts {"es": …, "en": …}.
  • Tablas clave: restaurants, rooms/tables, table_sessions, menus/categories/products, orders (Comanda) + order_lines, payments, conversations/chat_messages/chat_logs, conversation_trees, recommendation_artifacts, admin_users, audit_logs, manager_calls.
  • BD de tests: Postgres dedicado (podman camarero-test-db); en tests EMBEDDINGS_ENABLED=false.

A.2 Repositorios y SHAs finales cedidos

Superproyecto: /home/francisco/sandra-projects/camarero-ia

Repo Remoto SHA final cedido Descripción
Superproyecto HEAD de main a fecha de firma f9c9914 (+ limpieza 4815bcb) Docs unificadas MkDocs + llms.txt y fix del saludo en bucle; limpieza de docs obsoletas
backend git@github.com:N0-IDEA/camarero-ia-backend.git 4c2151e (merge de feature/new-arch 44048e5521b9e9c5212f9e6bf6558b0f9e1a4b37) Estado híbrido pre-entrega BestWaiter
frontend git@github.com:N0-IDEA/camarero-ia-frontend.git a202357 (merge de feature/backend-leveling 2cc5b83e5ad6d29d7842abbae8b12fcd75f3943c) Control de sala admin + tipos SSE manager + selected_options

Verificación: git -C backend log --oneline -1 44048e5 → fix(chat): saludo proactivo escribía en bucle + módulo manager + fixes preexistentes; git -C frontend log --oneline -1 2cc5b83 → feat(sala): control de sala admin + tipos SSE manager + selected_options.


A.3 Evolución full-LLM → híbrido

Época Backend Frontend Modelo / clave Característica
Full-LLM (22 may 2026) ae4fc98 (rango 5666f40→ae4fc98, Feature/add confirm order (#20)) — stepfun-ai/step-3.5-flash vía NVIDIA NIM (NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1) 100 % LLM: cada turno envía historial completo + ChatContext inyectado; el modelo decide con tags XML
Full-LLM (23 may 2026) — f47c5e4 — Frontend parejo de la época full-LLM
Híbrido (13 jun 2026) 8f96944 — Mismo modelo + sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 Inicio arquitectura híbrida (HYBRID01): árbol DATA + clasificador kNN
Híbrido (14 jun 2026) 8c1d5c7 — id. Continuación híbrida
Híbrido (17 jun 2026) 44048e5 2cc5b83 id. + proxy LLM local DeepSeek (thinking off) Saludo proactivo sin bucle, módulo manager, control de sala
Cierre (8 jun 2026, en rama) f6ce7cf (OLDKILL10) — — Muerte del full-LLM: app.old.services.{ai_service,context_builder} movidos a chat/infrastructure/ai/engine.py + context_builder.py; ficheros legacy eliminados

Detalle de prompts históricos rescatados: ver documentation/entrega/prompts-historicos-llm.md (documento compañero de este anexo).

Configuración IA entonces y ahora

Histórico (ae4fc98:app/core/config.py, idéntico en espíritu al actual):

nvidia_api_key: str = ""   # NVIDIA NIM API key for Step 3.5 Flash
nvidia_model: str = "stepfun-ai/step-3.5-flash"
nvidia_base_url: str = "https://integrate.api.nvidia.com/v1"
stepfun_api_key: str = ""  # alias legacy
stepfun_model: str = "stepfun-ai/step-3.5-flash"

Actual (backend/app/core/config.py, líneas 95-147): lo anterior más

  • ai_stream_timeout_seconds = 60, max_ai_tokens_per_session = 200_000, apple_jwks_timeout_seconds = 5;
  • embeddings: embeddings_enabled, embeddings_model_name = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2", embeddings_cache_dir;
  • clasificador: intent_min_confidence = 0.65 (el nodo classify del árbol puede sobreescribirlo con su min_confidence propio: 0.75 en hybrid_v1, 0.65 en hybrid_v2);
  • resolver semántico: resolver_accept_threshold = 0.50, resolver_ambiguous_floor = 0.45, resolver_margin = 0.06;
  • intérprete: interpreter_max_steps = 50, interpreter_action_timeout_seconds = 5.

A.4 Arquitectura

A.4.1 Backend hexagonal / modular (ADR-004)

  • Módulos en app/modules/{m}/{domain,application,infrastructure,interface}/ (migración documentada en docs/hexagonal.md; plan histórico en memoria del proyecto).
  • Sin imports cross-module: comunicación solo vía puertos / eventos de dominio; make lint-arch lo hace cumplir en CI.
  • Convenciones: StrEnum + match/case, value objects frozen, excepciones de dominio (DomainException) con HTTPException solo en interface/, use cases con método execute, repos find_by_id/create/update/save/delete, Money en céntimos, datetime siempre timezone-aware, eventos publicados después del commit.
  • Contrato hacia el frontend protegido por tests contract-lock: tests/contract/openapi_snapshot.json (solo crece) y tests/contract/sse_events_inventory.md. Autorización del owner (2026-06-13): adiciones aditivas al contrato permitidas si en el mismo cambio se cablea el frontend; removals/renames con cuidado.

A.4.2 Chat híbrido (HYBRID01)

Fuente: documentation/architecture/chat-hibrido.md. Resumen:

  • Dos motores conmutados por restaurants.chat_mode (legacy por defecto | hybrid). Seam único: ModeDispatchingChatAiResponder (chat/infrastructure/external/mode_dispatcher.py), fail-open a legacy. Rollback instantáneo (volver el flag a legacy, sin despliegue).
  • Legacy congelado: chat/infrastructure/ai/engine.py no se refactoriza; el stack híbrido (chat/infrastructure/flows/ + chat/domain/flows/) es reescritura limpia.
  • El árbol es DATA: JSON en conversation_trees (un activo por restaurante); lo recorre TreeInterpreter; siembra automática de default_trees/hybrid_v1.json al primer mensaje en modo hybrid; edición vía POST /api/v1/admin/conversation-trees (editor React Flow). Nodos: Entry/StateCheck/PhaseSwitch/Classify/Condition/Action/ LlmStream/ExecuteTags/PhaseTransition/PublishEvent/SetState/End.
  • Clasificador de intents kNN sobre embeddings MiniLM; intent único pedir_producto (drink-vs-food por course_type determinista); umbral por nodo (min_confidence); shadow mode escribe intent_predicted/intent_confidence en chat_logs en ambos motores.
  • Recomendador: el motor decide (capas 0-2, artefactos en recommendation_artifacts), el LLM solo redacta la intro; recómputo fuera de proceso (python -m app.worker.runner recompute-recs o POST /api/v1/admin/recommendations/recompute).
  • Contrato SSE (igual que legacy + frame aditivo recommendation): content / : thinking (keepalive) / recommendation (solo híbrido, antes de done) / done (con cart_actions, course_actions, confirm_order, suggestions, …) / error. done.model="deterministic" en turnos sin LLM.
  • Fase 5 (control de sala en el prompt): kitchen_overloaded → sección ## KITCHEN STATUS (priorizar platos rápidos/fríos, avisar demoras con tacto); table_profile (executive_lunch | social_leisure) → tono directo o cálido. Best-effort: ante fallo de gateways, estado neutro sin romper el chat.
  • LLM: NvidiaLlmClient.stream (chat/infrastructure/flows/llm_client.py), thinking: {"type": "disabled"} top-level en todos los nodos (el árbol ya decidió; evita bloques <think> y latencia). Seams de test distintos a propósito: legacy → ChatService._stream_nvidia_completion; híbrido → NvidiaLlmClient.stream.

A.4.4 Embeddings y clasificador de intents (detalle)

  • Modelo: sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 (backend/app/core/config.py:128, embeddings_model_name; Apache-2.0 la librería, checkpoint con licencia propia permisiva). Singleton compartido en backend/app/shared/infrastructure/granite_embeddings.py entre el clasificador de intents y la capa 2 del recomendador.
  • Funcionamiento: el nodo ClassifyNode del árbol invoca al clasificador kNN sobre embeddings y bifurca por (intent, confidence); umbral global intent_min_confidence = 0.65 (sobrescribible por nodo vía min_confidence en el JSON, p. ej. hybrid_v2.json usa 0.65). Intent único pedir_producto (drink-vs-food por course_type determinista, no por el clasificador).
  • Calibración: shadow mode escribe intent_predicted/intent_confidence en chat_logs en ambos motores; el umbral se calibra con esos datos antes de promover pedir_producto a rama determinista dura (hoy va por fallback).
  • Coste operativo: descarga de ~390 MB en el primer arranque (cache en volumen camarero_ia_hf_cache); warmup fire-and-forget en app/main.py. En tests siempre EMBEDDINGS_ENABLED=false (tests/conftest.py).
  • Licencia: librería sentence-transformers >= 3.0.0 (Apache-2.0); descarga pública desde Hugging Face Hub sin cuenta. Ver entrega/licencias-servicios.md §3.

A.4.5 Vía de evolución: del intent-classifier a un modelo de decisiones

  • El enfoque actual intent-classifier (kNN sobre embeddings + árbol de decisión DATA en hybrid_v1.json) es sustituible por un modelo de decisiones tipo JEV o LAYA sin tocar el resto del sistema.
  • Contexto temporal: cuando se desarrolló este proyecto (abr–jun 2026), JEV aún no había sido anunciado; por eso se implementó el clasificador kNN propio. Modelos posteriores de esa familia (JEV, LAYA o equivalentes) pueden ocupar el lugar del ClassifyNode manteniendo el contrato (intent, confidence) → bifurcación por branches[intent] / fallback.
  • Puntos de inserción: el seam ModeDispatchingChatAiResponder (chat/infrastructure/external/mode_dispatcher.py) y el nodo ClassifyNode (chat/domain/flows/nodes.py + chat/infrastructure/flows/interpreter.py) aíslan la decisión del redactado (NvidiaLlmClient.stream, modelo recomendado: DeepSeek Flash). Cambiar el clasificador no afecta a comanda, pagos, sala, SSE ni admin.
  • Se documenta como vía de evolución informativa, sin compromiso de implementación.

A.4.3 Árboles de decisión incluidos

En backend/app/modules/chat/infrastructure/flows/default_trees/:

Fichero Versión Entrada Papel
hybrid_v1.json hybrid-1 check_pausa Árbol de siembra: pausa → clasificar (6 intents: pedir_cuenta, recomendacion, respuesta_alergias, consulta_alergeno, marchar_curso, consultar_pedido) → ramas deterministas + llm_actual (paridad por fase, tags edit_cart/add_to_cart/phase_transition/confirm_order/set_course_plan/fire_course)
hybrid_v2.json hybrid-2 check_pausa Árbol extendido (~50 nodos): añade resolución determinista de opciones/cantidades, pedir_producto, modificar_pedido, cancelar_item, confirmar_pedido, smalltalk/off-topic, consultas de plato/local/carta; min_confidence: 0.65
parity_v1.json paridad-1 check_pausa Paridad pura: ambas ramas de pausa van a llm_actual (prompt de fase completo + snapshot de estado); sirve de referencia conductual del legacy dentro del runner híbrido

A.5 Prompts de IA (resumen; volcado íntegro en documento compañero)

  • Históricos full-LLM (abr–22 may 2026, muertos en f6ce7cf OLDKILL10): PromptBuilder con base común (reglas, propagación de alergias, contrato de state snapshot, personalidad por restaurante) + 4 prompts de fase (WELCOME bebidas, MAINS, DESSERTS, CHECKOUT); protocolo XML <edit_cart> (ops add/set_quantity/remove, tope 100 uds), <add_to_cart> legacy, <recommendation> (2-3 tarjetas), <confirm_order/>, <phase_transition>; llamada streaming a NVIDIA (temperature 0.6, top_p 0.95, max_tokens 16000, auto-continuación por finish_reason=length); propuesta inicial SYSTEM_PROMPT camarero (5 líneas) en arquitectura_hibrida_chatbot.md. Volcado íntegro: documentation/entrega/prompts-historicos-llm.md.
  • Actuales híbridos: nodos llm_stream con plantillas cortas (p. ej. cuenta, recomendación con {ctx.recs_resumen}, alergias con {ctx.plato.alergenos}); nodo llm_actual con prompt_builder_por_fase + include_state_snapshot; apertura proactiva (saludo LLM + nudge ALLERGY "¿alguna alergia o intolerancia…? 🌾"); señales Fase 5 (KITCHEN STATUS, table_profile); thinking desactivado.

A.6 Infraestructura y despliegue

Pieza Detalle
VPS producción DADO DE BAJA — NO SE TRANSMITE. Histórico: 79.117.123.235 (tráfico HTTPS vía nginx, nginx/n0idea.app.conf: api.camarero-demo.n0idea.app → puerto 8000; redirección HTTP→HTTPS, TLS 1.2/1.3). Sin acceso al mismo; se entrega toda la información y scripts necesarios para un despliegue nuevo (Dockerfile, docker-compose.yml / .dev.yml, nginx/*.conf como referencia, scripts/deploy*.sh, guía en getting-started/instalacion-entrega.md)
Dominio demo camarero-demo.n0idea.app (histórico; ligado al VPS dado de baja, no se transmite)
Contenedores Dockerfile + docker-compose.yml / docker-compose.dev.yml en backend y raíz
Documentación MkDocs (mkdocs.yml, docs_dir: documentation, nav en líneas 131-179) + plugin llmstxt (llms-full.txt); no modificado mkdocs.yml en este paso
Diseño híbrido (propuesta) arquitectura_hibrida_chatbot.md (mayo 2026: intents, clasificador kNN umbral 0.75, handlers, DeepSeek V4-Flash, voz Web Speech API, migración en 4 fases, coste ~10x)

A.7 Titularidad

Activo Titular actual conocido Observaciones
Repos Github N0-IDEA/camarero-ia-backend, N0-IDEA/camarero-ia-frontend Organización N0-IDEA (Francisco Quintana Quiroga) Se transmiten a la Sociedad, que hará push a su propia organización; historial git completo incluido
VPS 79.117.123.235 y dominio *.n0idea.app Dado de baja, sin acceso No se transmite; la Sociedad deberá provisionar infraestructura propia con los scripts y configs entregados
Claves proveedor IA (NVIDIA NIM / StepFun) Solo pruebas, ninguna que transmitir La Sociedad crea su cuenta; modelo recomendado: DeepSeek Flash
Cuentas OAuth Google/Apple No se transmiten La Sociedad regenera credenciales con sus cuentas de empresa (Google Cloud Console + Apple Developer); el código y scripts/setup_oauth.sh están entregados para reconfigurar
Titular destino BestWaiter S.L. (en constitución), representante Fabio Peral Cesión vinculada a este anexo; precio 6.000 €

A.8 Documentos y diseños entregados

  • Este anexo (documentation/entrega/anexo-a.md).
  • documentation/entrega/prompts-historicos-llm.md (rescate de prompts históricos + descripción de actuales).
  • Documentación MkDocs (documentation/): visión general, getting-started, how-tos, arquitectura (hexagonal, SSE, sesiones/carrito, comanda, chat-híbrido, control-de-sala, recomendador, pagos, seguridad/multitenancy, menú, salas/mesas, clientes/reseñas, admin/roles, plataforma, frontend), referencia API/SSE/módulos/convenciones/configuración.
  • Propuesta de diseño arquitectura_hibrida_chatbot.md (raíz del superproyecto).
  • Contratos máquina: backend/tests/contract/openapi_snapshot.json, tests/contract/sse_events_inventory.md, documentation/reference/sse-events.md.

A.9 Lista informativa de funcionalidades

Informativa, sin valor de especificación cerrada. El comportamiento exigible es el fijado por el contrato OpenAPI/SSE y la conducta observable en el SHA cedido.

Cifras de contrato a fecha de redacción: backend/tests/contract/openapi_snapshot.json con 145 paths y 178 operaciones (74 GET, 57 POST, 10 PUT, 23 PATCH, 14 DELETE); inventario SSE en backend/tests/contract/sse_events_inventory.md (bus con 19 tipos de evento más connected/heartbeat/typing-replay en GET /sessions/{token}/events, más stream de 4 eventos en el POST de mensajes de chat). Réplica del OpenAPI servida en frontend/public/openapi.json.

  1. Chat camarero virtual (backend/app/modules/chat/, routers en interface/).
  2. Conversación cliente: conversations_router.py — POST /api/v1/chat/conversations, GET /api/v1/chat/conversations/by-session/{session_token}, POST /api/v1/chat/conversations/{conversation_id}/messages (respuesta en streaming SSE vía ai_service.stream_chat_response); modo legacy por defecto (chat_mode; fases WELCOME → MAINS → DESSERTS → CHECKOUT) y modo hybrid (árbol determinista + LLM redactor: infrastructure/flows/interpreter.py, hybrid_responder.py, mode_dispatcher.py).
  3. Admin: admin_chat_router.py (GET /api/v1/admin/chat/conversations; página app/admin/restaurants/[restaurantId]/chat/page.tsx con thinking visible) y admin_flows_router.py (GET /conversation-trees/active, POST /{tree_id}/activate, POST /{tree_id}/simulate; editor en flows/page.tsx + FlowEditorClient.tsx).
  4. Frontend (frontend/components/chat/, ~24 piezas): ChatWidget.tsx (flotante, entrada principal), ChatPanel.tsx, MessageList.tsx (burbujas + tarjetas inyectadas), MessageBubble.tsx (markdown, estilo por rol), OpenUIMessageRenderer.tsx (bloques openui; librería en lib/openui/meal-library.tsx, menu-context.tsx), QuickReplies.tsx (+ lógica en lib/chat/quickReplies.ts), QuickActionBar.tsx fija demo, LanguageSelectorModal.tsx, CallManagerButton.tsx / ManagerCallBanner.tsx (llamar al encargado pausa la sesión), ChatErrorBubble.tsx / ChatErrorBoundary.tsx, FullPageChat.tsx (app/menu/[restaurantId]/chat/), debug/ChatDebugPanel.tsx.
  5. Estado: store/chatStore.ts (el mayor, ~25 KB) + lib/hooks/useChat.ts (envío/stream, toasts de pases), useChatError.ts, useChatActionGuard.ts, useSuggestionTimer.ts (nudges temporizados).
  6. Carta/Menú, knowledge y promociones (backend/app/modules/menu/).
  7. Carta pública: public_menu_router.py — GET /api/v1/restaurants/{slug}/menu, GET /api/v1/products/{product_id}; gestión: admin_menu_router.py — GET/POST /products, GET /categories (página menu/page.tsx + MenuEditorClient.tsx).
  8. Knowledge (FAQs/eventos del restaurante): admin_knowledge_router.py (GET/PUT /knowledge; knowledge/page.tsx + KnowledgeClient.tsx); alimenta tono y respuestas del chat.
  9. Promociones: admin_promotions_router.py (GET/POST, PATCH /{promotion_id}/toggle; promotions/page.tsx + PromotionsClient.tsx).
  10. Cliente: vista de carta app/menu/[restaurantId]/, lib/hooks/useMenu.ts (fetch por restaurante + idioma), tarjetas ChatProductCard.tsx dentro del chat.
  11. Sesiones QR y carrito (backend/app/modules/session/, table/).
  12. Sesión: session/interface/sessions_router.py — POST /api/v1/sessions/peek, POST /api/v1/sessions/validate (tiene en cuenta nº de comensales, devuelve is_new_session), GET /api/v1/sessions/{session_token}; TableSession con ventana de jornada SESSION_TIMEOUT_MINUTES = 600 (session/domain/constants.py); idioma y comensales por mesa.
  13. Carrito: session/interface/cart_router.py — GET /{token}/cart, POST /{token}/cart/items (extras, comentarios), PATCH /{token}/cart/items/{item_id}; editable también desde el chat (tags <edit_cart>); nota de alergia propagada a cocina.
  14. Mesas/QR: table/interface/public_tables_router.py (GET /api/v1/tables/{qr_code}), admin_tables_router.py (GET /restaurant/{rid}, POST, PATCH /{table_id}), qr_router.py (POST /admin/qr/generate, POST /admin/qr/validate; página qr/page.tsx).
  15. Llamadas al encargado: admin_manager_calls_router.py (GET /manager-calls, POST /{call_id}/respond).
  16. Frontend: store/sessionStore.ts (guard anti-concurrencia), cartStore.ts, batchStore.ts (ciclo batch/comanda, bloqueo del carrito), tabStore.ts (cuenta y borradores de pases); hooks useSessionSync.ts, useBatch.ts (qty<1 → DELETE para evitar 422), useOrder.ts; tarjetas OrderSummaryCard.tsx, BatchSummaryCard.tsx, BatchStatusBadge.tsx, OrderConfirmDrawer.tsx (bottom-sheet de confirmación).
  17. Comanda, coursing y cocina (backend/app/modules/comanda/).
  18. Cliente: customer_router.py — POST /api/v1/sessions/{token}/lines (añadir línea), POST /api/v1/sessions/{token}/submit, GET /api/v1/sessions/{token}/ticket. Ciclo de vida en domain/state_machine.py: DRAFT → AI_REVIEWING → PENDING_MANAGER → PENDING → IN_PROGRESS → READY → SERVED → CLOSED.
  19. Validación IA + aprobación: order_validation_router.py (POST /api/v1/orders/validate; ValidationResultCard.tsx, OrderRejectedCard.tsx) y admin_order_batches_router.py (GET /kitchen-queue/{restaurant_id}, POST /{comanda_id}/approve, POST /{comanda_id}/ready); cambios de estado desde admin en admin_orders_router.py (PATCH /api/v1/admin/orders/{order_id}/status).
  20. Coursing: plan de cursos y "marchar curso" (toasts de pases en useChat.ts, borradores optimistas en tabStore.ts); consulta de estado del pedido (ComandaStatusCard.tsx en vivo).
  21. Cocina/kanban: app/admin/restaurants/[restaurantId]/orders/page.tsx + OrdersKanbanClient.tsx (SSE en vivo); post-pedido OrderConfirmedCard.tsx, cancelación OrderCanceledCard.tsx, cuenta OrderHistorySheet.tsx ("Mi Cuenta", estética ticket térmico).
  22. Pagos, propinas y facturación.
  23. Pagos simulados (flujo request/get/configure/pay con idempotencia, cobro siempre success vía FakePaymentGateway, sin PSP real); propinas configurables (%/redondeo/custom, tip_mode/tip_cents en cuenta); sin facturación (solo ticket informal, IVA 10 % fijo en checkout/page.tsx:32, sin número de factura ni TicketBAI/Verifactu).
  24. Cableado: backend/app/modules/payment/interface/router.py (POST/GET /sessions/{token}/bill, POST /sessions/{token}/bill/payments; domain/state_machine.py, services/) y store/billStore.ts (idempotency keys, split parcial).
  25. Sala y manager en tiempo real (backend/app/modules/manager/; domain/lifecycle.py, profiling.py).
  26. Operativa: admin_manager_router.py — GET /api/v1/admin/manager/restaurants/{id}/sessions, POST /api/v1/admin/manager/sessions/{token}/deliver, POST /api/v1/admin/manager/sessions/{token}/courtesy-round (ronda de cortesía), carga cocina.
  27. Dashboard (sala/page.tsx + SalaClient.tsx, hook useManagerSessionSync.ts): vista floor en tiempo real por SSE tipado; saturación de cocina y perfil de mesa que calibran el chat (Fase 5).
  28. Mesas/salas unificadas: tables/page.tsx + TablesClient.tsx (+ detalle tables/[tableId]/page.tsx); rooms/page.tsx redirige a la vista unificada (routers restaurant/interface/rooms_router.py, table/interface/admin_tables_router.py).
  29. Recomendador (backend/app/modules/recommendation/; domain/engine_v2.py, artifacts.py, services.py).
  30. API: interface/router.py — GET /api/v1/recommendations, GET /api/v1/recommendations/conversation/{id}, POST /api/v1/recommendations/{id}/action; admin: POST /api/v1/admin/recommendations/recompute (artefactos precalculados).
  31. El motor decide (capas 0-2) y el LLM redacta; embeddings paraphrase-multilingual-MiniLM-L12-v2 (EMBEDDINGS_ENABLED=false en tests/CI); tarjetas estructuradas (RecommendationCard.tsx con motivo + añadir/ver, hook useRecommendations.ts).
  32. Clientes y reseñas (backend/app/modules/customer/, review/).
  33. Perfil: customer/interface/router.py — GET/PATCH /api/v1/customers/me (preferencias, dieta; personalizan chat y recomendador); auth cliente en store/authStore.ts.
  34. Reseñas por sesión: review/interface/customer_router.py (POST /api/v1/sessions/{session_token}/review), review/interface/admin_router.py (GET /api/v1/admin/reviews/restaurant/{restaurant_id}).
  35. Admin multi-restaurante (app/admin/restaurants/[restaurantId]/, 15 secciones; patrón page.tsx server-fetch + *Client.tsx interactivo; shell layout.tsx con MobileBottomNav, loading.tsx/error.tsx).
  36. Carta: menu/ (MenuEditorClient.tsx).
  37. Pedidos/kanban: orders/ (OrdersKanbanClient.tsx, SSE en vivo).
  38. Salas/mesas: tables/ (TablesClient.tsx, detalle tables/[tableId]/), sala/ (SalaClient.tsx), qr/ (QR por mesa); rooms/ redirige a la vista unificada.
  39. Usuarios/invitaciones: users/ (UsersClient.tsx, users/invite/page.tsx; routers admin_user/interface/router.py — GET/POST /admin/users, PATCH /users/{user_id}/role — y restaurants_router.py — POST /restaurants/{id}/staff/invite).
  40. Analytics: analytics/ (AnalyticsClient.tsx, rango inicial 30 días; analytics_router.py: overview, orders, revenue; solo lectura).
  41. Auditoría: audit/ (placeholder "próximamente"; audit/interface/router.py: listar, export, detalle).
  42. Knowledge: knowledge/ (KnowledgeClient.tsx).
  43. Promociones: promotions/ (PromotionsClient.tsx).
  44. Flujos/árboles: flows/ (FlowEditorClient.tsx, React Flow lazy ~150 KB) + chat/ (historial admin con thinking).
  45. Errores: errors/interface/router.py (POST /api/v1/errors/log desde frontend, GET /api/v1/errors/recent; ChatErrorBoundary.tsx).
  46. Super-admin: roles owner/super_admin (require_owner_or_super, require_super_admin), listado/creación multi-restaurante (GET/POST /api/v1/admin/restaurants); stores adminAuthStore.ts (separada de cliente), adminRestaurantStore.ts, adminUserStore.ts, adminUIStore.ts; hooks useAdminError.ts, useBulkActions.ts, useDataTable.ts.
  47. Auth y multitenancy (backend/app/modules/auth/).
    • Clientes: customer_router.py (POST /api/v1/auth/register, POST /api/v1/auth/login, POST /api/v1/auth/oauth/callback Google) + sesión QR anónima por mesa.
    • Admin: admin_router.py (GET /api/v1/admin/auth/google, POST /api/v1/admin/auth/callback, GET /api/v1/admin/me; Google/Apple con JWT, reconfigurable vía scripts/setup_oauth.sh).
    • Multitenancy: require_restaurant_access por restaurante; rate limiting; idempotencia en POST críticos (pagos, carrito); persistencia/rehidratación (useAuthPersistence.ts).
  48. i18n (es/en/fr/de/pt/it/ca/gl/eu).
    • Saludos por franja horaria y tono por restaurante (knowledge); carta servida por idioma (useMenu.ts restaurante + idioma); selector en chat (LanguageSelectorModal.tsx, LANGUAGES).
  49. Transversal.
    • Hexagonal por módulo (domain/, application/, infrastructure/, interface/ en los 16 módulos de backend/app/modules/); contrato OpenAPI/SSE como especificación exigible (cifras en cabecera); en frontend lib/{api,admin,chat,config,constants,errors,menu,openui,utils}, utils.ts, scroll-animate.tsx, lib/hooks/ (16 + barrel) y store/index.ts; UI con shadcn/radix, uiStore.ts (modales/drawers/toasts), useIsMobile() (use-mobile.ts).

A.10 Componentes de terceros y licencias (resumen)

Resumen informativo. El detalle licencia-por-licencia lo elabora otro interviniente; este anexo no constituye dictamen de compatibilidad de licencias.

Componente Uso Licencia (orientativa)
FastAPI / uvicorn / pydantic / SQLAlchemy / Alembic / asyncpg Backend API y persistencia MIT / Apache-2.0 / BSD
openai (cliente HTTP), sse-starlette, redis, numpy Llamadas IA, streaming, caché, cómputo MIT / Apache-2.0 / BSD
sentence-transformers + modelo paraphrase-multilingual-MiniLM-L12-v2 Embeddings intents/recomendador Apache-2.0 (librería); modelo con licencia propia permisiva de uso
Next.js / React / Tailwind / radix-ui / shadcn / zustand / @xyflow/react / recharts Frontend MIT
Modelo stepfun-ai/step-3.5-flash vía NVIDIA NIM (histórico, cuenta solo de pruebas); DeepSeek vía proxy local Inferencia LLM Términos comerciales del proveedor; la Sociedad crea su cuenta. Recomendado: DeepSeek Flash
PostgreSQL, Redis/Valkey, nginx Datos, caché, proxy inverso PostgreSQL License / BSD / BSD-2

Fin del Anexo A.