Foco: matar repetición y adaptar respuestas. Los handlers tenían ~30 strings hardcodeadas (3-7 lugares cada una). Aliases hacían substring exacto. - pg_trgm + GIN indexes en product_aliases / alias_product_mappings. Captura plurales, diminutivos, typos sin reglas. catalogRetrieval re-busca el snapshot con normalized_alias cuando el query original no rinde (vasio→vacio→Vacío). - reply_templates table + replyTemplates.js. 20 keys, 2-3 variantes c/u con DEFAULTS hardcodeados como fallback. pickVariant excluye las usadas en context.recent_replies (FIFO cap 8). Wired en idle/cart/cartHelpers/ shipping/payment/waiting. - failed_searches counter en context. count>=3 escala via humanFallback. Reset en cada add_to_cart exitoso. - storeContext.js: vars derivadas de getStoreConfig (delivery_zones, hours, zonas) listas para inyectar en templates cuando los datos se carguen. - replyRewriter.js: LLM call opcional (REPLY_REWRITER=1) que adapta el template al hilo conversacional. 1.5s timeout, fallback al template puro. Sólo activo en 8 slots semánticamente importantes. - 12 unit tests para replyTemplates (rotation, recency, FIFO, vars). 208 tests totales pasando. Plan completo: ~/.claude/plans/ok-creo-que-tiene-humming-sutton.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.2 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
# Development
npm run dev # Start with nodemon auto-reload
npm start # Production start
# Testing
npm test # Run all tests once (vitest run)
npm run test:watch # Watch mode
npm run test:coverage
# Run a single test file
npx vitest run src/modules/3-turn-engine/orderModel.test.js
# Database migrations (requires DATABASE_URL in .env)
npm run migrate:up
npm run migrate:down
npm run migrate:redo
npm run migrate:status
npm run seed # Seed a tenant via scripts/seed-tenant.mjs
No lint command is configured.
Product goal
The bot must be conversational and intelligent, not a menu-driven flow. Customers reach out via WhatsApp with intent to buy — the bot's job is to:
- Engage in conversation — answer questions about products, prices, availability/stock; recommend; clarify.
- Take orders — build a cart through natural dialogue (multi-product turns, quantities, units).
- Collect delivery data — address, delivery vs pickup, payment method.
- Operate within store rules — delivery zones, days/hours, pickup windows. These config tables (
delivery_zones, store schedule intenant_settings) will be populated later; the bot has to read and respect them when present.
Repetitive, hardcoded responses are a known quality problem and the focus of the active improvement plan (see ~/.claude/plans/ok-creo-que-tiene-humming-sutton.md). The system is not yet in production — refactors that change behavior are acceptable.
Architecture
This is a multi-tenant WhatsApp e-commerce chatbot powered by Express.js. Tenants are WooCommerce store operators; their customers interact via WhatsApp to browse products, build carts, and place orders. All database operations are isolated by tenant_id.
Request flow
WhatsApp → Evolution API webhook → /webhook/evolution
↓
1-intake: route & normalize message
↓
3-turn-engine: NLU → FSM → state handler
↓
Response persisted to DB + sent back via Evolution API
Module structure (numbered layers)
-
src/modules/0-UI/— Admin dashboard: REST controllers for products, conversations, settings, prompts, takeovers, recommendations, aliases. Each controller has adb/sub-layer for persistence. -
src/modules/1-intake/— Message ingestion. Routes:/simulator(dev UI),/webhook/evolution(WhatsApp). Normalizes incoming messages before passing to turn engine. -
src/modules/2-identity/— Tenant and user management. Maps WhatsApp numbers to WooCommerce customers. Stores encrypted WooCommerce credentials per tenant intenant_ecommerce_config. Routes WooCommerce webhooks. -
src/modules/3-turn-engine/— Core logic. NLU classifies intents; FSM transitions states (IDLE → CART → SHIPPING → PAYMENT → WAITING_WEBHOOKS). Two NLU versions controlled byUSE_MODULAR_NLUenv flag. Two turn engine versions controlled byTURN_ENGINEenv flag. State handlers map to FSM states. -
src/modules/4-woo-orders/— WooCommerce order sync. Fetches and caches customer order history for conversation context. -
src/modules/shared/— DB pool (PostgreSQL viapg), SSE for real-time admin UI updates, WooSnapshot (product catalog cache), debug utilities.
Key integrations
| System | Purpose | Config |
|---|---|---|
| OpenAI | NLU intent classification & response generation | OPENAI_API_KEY, OPENAI_MODEL |
| Evolution API | WhatsApp send/receive | EVOLUTION_API_URL, EVOLUTION_API_KEY, EVOLUTION_INSTANCE_NAME, EVOLUTION_SEND_ENABLED |
| WooCommerce REST API | Products, orders, customers | WOO_* env vars or per-tenant in DB |
| PostgreSQL | Primary database | DATABASE_URL |
Database
Migrations live in db/migrations/ as timestamped SQL files managed by dbmate. Key tables:
tenants,tenant_config,tenant_settings,tenant_ecommerce_config,tenant_channelswa_identity_map— WhatsApp ↔ WooCommerce customer mappingwa_conversation_state— FSM state + context per conversationwa_messages— Message historywoo_products_snapshot— Cached product catalogprompt_templates— Versioned LLM promptshuman_takeovers,audit_log,conversation_runs
Feature flags (env vars)
TURN_ENGINE=v1|v2— Which turn engine version to useUSE_MODULAR_NLU=1— Use modular NLU (prompt templates from DB) vs. v3 hardcodedEVOLUTION_SEND_ENABLED=1— Actually send messages to WhatsApp (disable in dev/test)DEBUG_PERF,DEBUG_WOO_HTTP,DEBUG_LLM,DEBUG_EVOLUTION— Granular debug logging
Local development
Copy env.example to .env and fill in values. Use docker-compose.override.yaml for local overrides. Run docker compose up to start app + Postgres + Redis. The Dockerfile runs migrations automatically on startup (migrate:up && seed && start).
Test files use Vitest with globals: true — no need to import describe, it, expect.