Files
botino/CLAUDE.md
Lucas Tettamanti 6b7889ef4e Mono-tenant: resolver id una vez al boot, eliminar lookups por turno
El sistema nunca fue realmente multi-tenant en la práctica. El esquema
DB conserva las columnas tenant_id (queda lista para escalar más adelante
sin migración), pero la app ahora resuelve el tenant una sola vez al
arranque y todas las capas leen de un único punto.

- src/modules/shared/tenant.js: nuevo módulo. setTenant() en boot,
  getTenantId() lo lee desde cualquier lado.
- index.js: ensureTenant() → setTenant({ id, key }). Sin cambios externos.
- pipeline.resolveTenantId(): pasa de hacer 1-2 queries a DB por turno
  a un return sincrónico del id cacheado. Mantiene firma async para no
  romper callers.
- intake handlers (sim.js, evolution.js): usan getTenantId() directo,
  sin parsing de tenant_key del chat_id ni lookup por canal.
- wooWebhooks: ya no requiere ?tenant_key=... en la query string.
  El webhook va al único tenant configurado.
- repo.js: eliminados getTenantByKey() y getTenantIdByChannel() (no más
  callers).

Plumbing del parámetro tenantId en signatures de handlers/repos/machine
queda intacto — bajar eso es ruido de alto riesgo y no aporta hoy.
188 tests pasando.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 21:00:22 -03:00

105 lines
5.5 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Commands
```bash
# 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:
1. **Engage in conversation** — answer questions about products, prices, availability/stock; recommend; clarify.
2. **Take orders** — build a cart through natural dialogue (multi-product turns, quantities, units).
3. **Collect delivery data** — address, delivery vs pickup, payment method.
4. **Operate within store rules** — delivery zones, days/hours, pickup windows. These config tables (`delivery_zones`, store schedule in `tenant_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 **mono-tenant WhatsApp e-commerce chatbot** powered by Express.js. The store operator hooks the bot to a single WooCommerce shop; customers interact via WhatsApp to browse products, build carts, and place orders.
The DB schema retains `tenant_id` columns (it was originally multi-tenant) but the app boots with a single tenant resolved at startup. The single id is exposed via `src/modules/shared/tenant.js` (`getTenantId()`); webhook handlers and intake routes read from there instead of looking up tenants per-request.
### 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 a `db/` 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 in `tenant_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 by `USE_MODULAR_NLU` env flag. Two turn engine versions controlled by `TURN_ENGINE` env 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 via `pg`), 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_channels`
- `wa_identity_map` — WhatsApp ↔ WooCommerce customer mapping
- `wa_conversation_state` — FSM state + context per conversation
- `wa_messages` — Message history
- `woo_products_snapshot` — Cached product catalog
- `prompt_templates` — Versioned LLM prompts
- `human_takeovers`, `audit_log`, `conversation_runs`
### Feature flags (env vars)
- `TURN_ENGINE=v1|v2` — Which turn engine version to use
- `USE_MODULAR_NLU=1` — Use modular NLU (prompt templates from DB) vs. v3 hardcoded
- `EVOLUTION_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`.