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/, formatoYYYYMMDD_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 testsEMBEDDINGS_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 nodoclassifydel árbol puede sobreescribirlo con sumin_confidencepropio: 0.75 enhybrid_v1, 0.65 enhybrid_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 endocs/hexagonal.md; plan histórico en memoria del proyecto). - Sin imports cross-module: comunicación solo vía puertos / eventos de dominio;
make lint-archlo hace cumplir en CI. - Convenciones:
StrEnum+match/case, value objectsfrozen, excepciones de dominio (DomainException) conHTTPExceptionsolo eninterface/, use cases con métodoexecute, reposfind_by_id/create/update/save/delete,Moneyen céntimos,datetimesiempre timezone-aware, eventos publicados después del commit. - Contrato hacia el frontend protegido por tests contract-lock:
tests/contract/openapi_snapshot.json(solo crece) ytests/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(legacypor defecto |hybrid). Seam único:ModeDispatchingChatAiResponder(chat/infrastructure/external/mode_dispatcher.py), fail-open a legacy. Rollback instantáneo (volver el flag alegacy, sin despliegue). - Legacy congelado:
chat/infrastructure/ai/engine.pyno 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 recorreTreeInterpreter; siembra automática dedefault_trees/hybrid_v1.jsonal primer mensaje en modo hybrid; edición víaPOST /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 porcourse_typedeterminista); umbral por nodo (min_confidence); shadow mode escribeintent_predicted/intent_confidenceenchat_logsen 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-recsoPOST /api/v1/admin/recommendations/recompute). - Contrato SSE (igual que legacy + frame aditivo
recommendation):content/: thinking(keepalive) /recommendation(solo híbrido, antes dedone) /done(concart_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 enbackend/app/shared/infrastructure/granite_embeddings.pyentre el clasificador de intents y la capa 2 del recomendador. - Funcionamiento: el nodo
ClassifyNodedel árbol invoca al clasificador kNN sobre embeddings y bifurca por(intent, confidence); umbral globalintent_min_confidence = 0.65(sobrescribible por nodo víamin_confidenceen el JSON, p. ej.hybrid_v2.jsonusa 0.65). Intent únicopedir_producto(drink-vs-food porcourse_typedeterminista, no por el clasificador). - Calibración: shadow mode escribe
intent_predicted/intent_confidenceenchat_logsen ambos motores; el umbral se calibra con esos datos antes de promoverpedir_productoa 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 enapp/main.py. En tests siempreEMBEDDINGS_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. Verentrega/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
ClassifyNodemanteniendo el contrato(intent, confidence)→ bifurcación porbranches[intent]/fallback. - Puntos de inserción: el seam
ModeDispatchingChatAiResponder(chat/infrastructure/external/mode_dispatcher.py) y el nodoClassifyNode(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
f6ce7cfOLDKILL10):PromptBuildercon base común (reglas, propagación de alergias, contrato de state snapshot, personalidad por restaurante) + 4 prompts de fase (WELCOMEbebidas,MAINS,DESSERTS,CHECKOUT); protocolo XML<edit_cart>(opsadd/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 porfinish_reason=length); propuesta inicialSYSTEM_PROMPTcamarero (5 líneas) enarquitectura_hibrida_chatbot.md. Volcado íntegro:documentation/entrega/prompts-historicos-llm.md. - Actuales híbridos: nodos
llm_streamcon plantillas cortas (p. ej. cuenta, recomendación con{ctx.recs_resumen}, alergias con{ctx.plato.alergenos}); nodollm_actualconprompt_builder_por_fase+include_state_snapshot; apertura proactiva (saludo LLM + nudgeALLERGY"¿alguna alergia o intolerancia…? 🌾"); señales Fase 5 (KITCHEN STATUS,table_profile);thinkingdesactivado.
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.jsoncon 145 paths y 178 operaciones (74 GET, 57 POST, 10 PUT, 23 PATCH, 14 DELETE); inventario SSE enbackend/tests/contract/sse_events_inventory.md(bus con 19 tipos de evento másconnected/heartbeat/typing-replayenGET /sessions/{token}/events, más stream de 4 eventos en el POST de mensajes de chat). Réplica del OpenAPI servida enfrontend/public/openapi.json.
- Chat camarero virtual (
backend/app/modules/chat/, routers eninterface/). - 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íaai_service.stream_chat_response); modolegacypor defecto (chat_mode; fases WELCOME → MAINS → DESSERTS → CHECKOUT) y modohybrid(árbol determinista + LLM redactor:infrastructure/flows/interpreter.py,hybrid_responder.py,mode_dispatcher.py). - Admin:
admin_chat_router.py(GET /api/v1/admin/chat/conversations; páginaapp/admin/restaurants/[restaurantId]/chat/page.tsxcon thinking visible) yadmin_flows_router.py(GET /conversation-trees/active,POST /{tree_id}/activate,POST /{tree_id}/simulate; editor enflows/page.tsx+FlowEditorClient.tsx). - 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 enlib/openui/meal-library.tsx,menu-context.tsx),QuickReplies.tsx(+ lógica enlib/chat/quickReplies.ts),QuickActionBar.tsxfija 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. - 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). - Carta/Menú, knowledge y promociones (
backend/app/modules/menu/). - 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áginamenu/page.tsx+MenuEditorClient.tsx). - Knowledge (FAQs/eventos del restaurante):
admin_knowledge_router.py(GET/PUT /knowledge;knowledge/page.tsx+KnowledgeClient.tsx); alimenta tono y respuestas del chat. - Promociones:
admin_promotions_router.py(GET/POST,PATCH /{promotion_id}/toggle;promotions/page.tsx+PromotionsClient.tsx). - Cliente: vista de carta
app/menu/[restaurantId]/,lib/hooks/useMenu.ts(fetch por restaurante + idioma), tarjetasChatProductCard.tsxdentro del chat. - Sesiones QR y carrito (
backend/app/modules/session/,table/). - Sesión:
session/interface/sessions_router.py—POST /api/v1/sessions/peek,POST /api/v1/sessions/validate(tiene en cuenta nº de comensales, devuelveis_new_session),GET /api/v1/sessions/{session_token};TableSessioncon ventana de jornadaSESSION_TIMEOUT_MINUTES = 600(session/domain/constants.py); idioma y comensales por mesa. - 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. - 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áginaqr/page.tsx). - Llamadas al encargado:
admin_manager_calls_router.py(GET /manager-calls,POST /{call_id}/respond). - Frontend:
store/sessionStore.ts(guard anti-concurrencia),cartStore.ts,batchStore.ts(ciclo batch/comanda, bloqueo del carrito),tabStore.ts(cuenta y borradores de pases); hooksuseSessionSync.ts,useBatch.ts(qty<1→ DELETE para evitar 422),useOrder.ts; tarjetasOrderSummaryCard.tsx,BatchSummaryCard.tsx,BatchStatusBadge.tsx,OrderConfirmDrawer.tsx(bottom-sheet de confirmación). - Comanda, coursing y cocina (
backend/app/modules/comanda/). - 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 endomain/state_machine.py: DRAFT → AI_REVIEWING → PENDING_MANAGER → PENDING → IN_PROGRESS → READY → SERVED → CLOSED. - Validación IA + aprobación:
order_validation_router.py(POST /api/v1/orders/validate;ValidationResultCard.tsx,OrderRejectedCard.tsx) yadmin_order_batches_router.py(GET /kitchen-queue/{restaurant_id},POST /{comanda_id}/approve,POST /{comanda_id}/ready); cambios de estado desde admin enadmin_orders_router.py(PATCH /api/v1/admin/orders/{order_id}/status). - Coursing: plan de cursos y "marchar curso" (toasts de pases en
useChat.ts, borradores optimistas entabStore.ts); consulta de estado del pedido (ComandaStatusCard.tsxen vivo). - Cocina/kanban:
app/admin/restaurants/[restaurantId]/orders/page.tsx+OrdersKanbanClient.tsx(SSE en vivo); post-pedidoOrderConfirmedCard.tsx, cancelaciónOrderCanceledCard.tsx, cuentaOrderHistorySheet.tsx("Mi Cuenta", estética ticket térmico). - Pagos, propinas y facturación.
- Pagos simulados (flujo request/get/configure/pay con idempotencia, cobro siempre
successvíaFakePaymentGateway, sin PSP real); propinas configurables (%/redondeo/custom,tip_mode/tip_centsen cuenta); sin facturación (solo ticket informal, IVA 10 % fijo encheckout/page.tsx:32, sin número de factura ni TicketBAI/Verifactu). - Cableado:
backend/app/modules/payment/interface/router.py(POST/GET /sessions/{token}/bill,POST /sessions/{token}/bill/payments;domain/state_machine.py,services/) ystore/billStore.ts(idempotency keys, split parcial). - Sala y manager en tiempo real (
backend/app/modules/manager/;domain/lifecycle.py,profiling.py). - 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. - Dashboard (
sala/page.tsx+SalaClient.tsx, hookuseManagerSessionSync.ts): vista floor en tiempo real por SSE tipado; saturación de cocina y perfil de mesa que calibran el chat (Fase 5). - Mesas/salas unificadas:
tables/page.tsx+TablesClient.tsx(+ detalletables/[tableId]/page.tsx);rooms/page.tsxredirige a la vista unificada (routersrestaurant/interface/rooms_router.py,table/interface/admin_tables_router.py). - Recomendador (
backend/app/modules/recommendation/;domain/engine_v2.py,artifacts.py,services.py). - 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). - El motor decide (capas 0-2) y el LLM redacta; embeddings
paraphrase-multilingual-MiniLM-L12-v2(EMBEDDINGS_ENABLED=falseen tests/CI); tarjetas estructuradas (RecommendationCard.tsxcon motivo + añadir/ver, hookuseRecommendations.ts). - Clientes y reseñas (
backend/app/modules/customer/,review/). - Perfil:
customer/interface/router.py—GET/PATCH /api/v1/customers/me(preferencias, dieta; personalizan chat y recomendador); auth cliente enstore/authStore.ts. - 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}). - Admin multi-restaurante (
app/admin/restaurants/[restaurantId]/, 15 secciones; patrónpage.tsxserver-fetch +*Client.tsxinteractivo; shelllayout.tsxconMobileBottomNav,loading.tsx/error.tsx). - Carta:
menu/(MenuEditorClient.tsx). - Pedidos/kanban:
orders/(OrdersKanbanClient.tsx, SSE en vivo). - Salas/mesas:
tables/(TablesClient.tsx, detalletables/[tableId]/),sala/(SalaClient.tsx),qr/(QR por mesa);rooms/redirige a la vista unificada. - Usuarios/invitaciones:
users/(UsersClient.tsx,users/invite/page.tsx; routersadmin_user/interface/router.py—GET/POST /admin/users,PATCH /users/{user_id}/role— yrestaurants_router.py—POST /restaurants/{id}/staff/invite). - Analytics:
analytics/(AnalyticsClient.tsx, rango inicial 30 días;analytics_router.py:overview,orders,revenue; solo lectura). - Auditoría:
audit/(placeholder "próximamente";audit/interface/router.py: listar,export, detalle). - Knowledge:
knowledge/(KnowledgeClient.tsx). - Promociones:
promotions/(PromotionsClient.tsx). - Flujos/árboles:
flows/(FlowEditorClient.tsx, React Flow lazy ~150 KB) +chat/(historial admin con thinking). - Errores:
errors/interface/router.py(POST /api/v1/errors/logdesde frontend,GET /api/v1/errors/recent;ChatErrorBoundary.tsx). - Super-admin: roles
owner/super_admin(require_owner_or_super,require_super_admin), listado/creación multi-restaurante (GET/POST /api/v1/admin/restaurants); storesadminAuthStore.ts(separada de cliente),adminRestaurantStore.ts,adminUserStore.ts,adminUIStore.ts; hooksuseAdminError.ts,useBulkActions.ts,useDataTable.ts. - 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/callbackGoogle) + 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íascripts/setup_oauth.sh). - Multitenancy:
require_restaurant_accesspor restaurante; rate limiting; idempotencia en POST críticos (pagos, carrito); persistencia/rehidratación (useAuthPersistence.ts).
- Clientes:
- i18n (es/en/fr/de/pt/it/ca/gl/eu).
- Saludos por franja horaria y tono por restaurante (knowledge); carta servida por idioma
(
useMenu.tsrestaurante + idioma); selector en chat (LanguageSelectorModal.tsx,LANGUAGES).
- Saludos por franja horaria y tono por restaurante (knowledge); carta servida por idioma
(
- Transversal.
- Hexagonal por módulo (
domain/,application/,infrastructure/,interface/en los 16 módulos debackend/app/modules/); contrato OpenAPI/SSE como especificación exigible (cifras en cabecera); en frontendlib/{api,admin,chat,config,constants,errors,menu,openui,utils},utils.ts,scroll-animate.tsx,lib/hooks/(16 + barrel) ystore/index.ts; UI con shadcn/radix,uiStore.ts(modales/drawers/toasts),useIsMobile()(use-mobile.ts).
- Hexagonal por módulo (
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.