89 lines
5.4 KiB
Markdown
89 lines
5.4 KiB
Markdown
# Roadmap
|
||
|
||
Not a generic TODO list — this captures the **intended architecture progression** and *why* each phase is sequenced that way.
|
||
|
||
## Phase 1 — Telegram AI Foundation ✅ (current)
|
||
|
||
TypeScript + grammY, Docker dev mode with hot reload, webhook + long-polling,
|
||
`/start` `/help`, normalized message contract, LLM via LiteLLM, conversation
|
||
persistence in Postgres, one controlled n8n path, tests + docs.
|
||
|
||
**Why this order**: prove the transport (Telegram webhook) and the AI loop end-to-end
|
||
before investing in durable context, RAG, or a second channel.
|
||
|
||
## Phase 2 — Durable Context + Business Tools
|
||
|
||
**Progress (2026-08-30):**
|
||
- ✅ **Product catalog awareness** — `CatalogRetriever` (`src/ai/retrieval/catalog.ts`)
|
||
replaces `NoopRetriever`: SKU-token + name/category keyword lookup over the
|
||
generated `src/data/catalog.ts` (259 entries, built by `gen_catalog.py` from
|
||
`catalog_sku.csv`; no prices, no storage paths). Hits are injected into the
|
||
prompt as "Product facts" with product-page links
|
||
(`https://www.digikedai.com/products/<sku>/`); free items (SKU prefix FREE —
|
||
FREECXM04 = FREE + original paid SKU CXM04, the trial twin) are flagged and routed to
|
||
`/free/`. Keyword search chosen over pgvector
|
||
at this scale (eval criteria below).
|
||
- ✅ **Passive human-handoff** in `system.ts` — admin contact (Telegram
|
||
@MrFullStackDev only, no WhatsApp/phone) is offered only when the customer
|
||
asks for a human or the bot cannot solve the issue; repeat questions are
|
||
re-answered with one ask-line (deterministic `isRepeatQuery` on top of
|
||
memory last_queries); URLs must stand alone on their own line; reply
|
||
language mirrors the customer (language_code mapped to friendly names).
|
||
- ✅ **Purchase flow: multi-way state machine + inline buttons** (第1–3批, 2026-08-31)
|
||
— deterministic `pendingPurchase` state machine (mirrors the free-trial
|
||
`pendingTrials` pattern) replaces the single admin deep link. Purchase intent
|
||
is intercepted in `message:text` via `PURCHASE_INTENT_RE` (zh/en/ms, SKU-aware;
|
||
FREE-prefixed trial SKUs are never intercepted) → a two-row inline keyboard:
|
||
① 网店下单 (online store / marketplace — neutral words, preferred, row on top)
|
||
→ neutral guidance + 联系 admin / 返回 buttons; ② 找 admin 购买 → admin deep
|
||
link issued DIRECTLY (fallback, fast). 「返回」re-shows the menu; every
|
||
callback branch ends with `answerCallbackQuery()` (Telegram retry idempotency).
|
||
Deep-link prefill is a free-text sentence in the customer's language built by
|
||
`buildAdminPurchaseLink({sku?, paymentPreference?, username?, lang?})` —
|
||
whatever was collected (SKU / payment preference / labelled username), nothing
|
||
forced; no SKU → generic product message. The URL is `encodeURIComponent`'d
|
||
exactly ONCE in code; the prompt carries two static pre-encoded samples
|
||
(with/without username) and the model only swaps alphanumeric SKU/username —
|
||
this killed the double-nesting bug (第1批 f27bbb4). **中性词纪律**: no
|
||
Shopee/Lazada/Add-On/TnG/bank-in anywhere in bot copy until the marketplace
|
||
is live (test-asserted). Full plan: `docs/PURCHASE_FLOW_REDESIGN.md`.
|
||
- ✅ **Free-trial flow button-ified** (第3批, 2026-08-31) — `startSku` /
|
||
`confirmReuse` replies now carry inline buttons (✅ 确认并开通 / ✏️ 提供新
|
||
username / ♻️ 加到现有账号) dispatched into the `pendingTrials` state machine;
|
||
the legacy text path (同意 / 新账号 xxx / 用户名:…) still works unchanged.
|
||
|
||
Remaining items:
|
||
|
||
- Enrich user profile & conversation memory (`src/ai/memory`).
|
||
- Explicit tool schemas (product lookup, order lookup, status, free-account) with validation before n8n execution.
|
||
- Admin/user authorization + rate limiting; allowlist enforced in production.
|
||
- Logging, correlation IDs, observability.
|
||
- Formalize Channel/Core contracts so Shopee/Lazada adapters drop in without touching the AI core.
|
||
|
||
**Why now**: only once Phase 1 shows what the customers actually ask.
|
||
|
||
## Phase 3 — RAG + Multi-Channel
|
||
|
||
- Enable `pgvector` in the existing `pgvector/pgvector:pg17` Postgres (already provisioned) when keyword lookup becomes insufficient.
|
||
- Ingestion pipeline for docs/FAQs/products/policies.
|
||
- Retrieval evaluation + source attribution/citation.
|
||
- Shopee adapter (merchant/chat API), then Lazada adapter.
|
||
- Channel-specific personas/prompts while keeping shared product/customer context.
|
||
- Consider a separate vector DB **only** if pgvector becomes a real bottleneck.
|
||
|
||
**Why pgvector before Qdrant**: vectors live alongside ordinary Postgres data;
|
||
exact + ANN search; keeps the architecture smaller until scale demands separation.
|
||
|
||
## Criteria for adding new infrastructure
|
||
|
||
Before introducing any new service, explain operational cost and confirm the existing
|
||
stack (Postgres, n8n, Traefik, LiteLLM) can't already meet the need. Non-goals to
|
||
protect: no Qdrant/vector DB without a concrete requirement, no multi-agent swarm,
|
||
no model fine-tuning, no Dify unless it earns its place.
|
||
|
||
## Risks / open items
|
||
|
||
- **LiteLLM shared key**: bot currently uses the mem0 LiteLLM master key. Phase 2 should mint a dedicated virtual key (rate-limit + revoke isolation). See `docs/DECISIONS.md`.
|
||
- **Webhook auth**: `TELEGRAM_WEBHOOK_SECRET` guards the URL path; keep it strong in production.
|
||
- **Free-account workflow**: the exact n8n workflow path/schema is still a placeholder — confirm with the actual workflow before wiring it to the LLM as a tool.
|