# BizNode Smart Bot — Technical Documentation

**Version:** 2.0
**Date:** 2026-03-08
**Scope:** Complete business logic and implementation reference for the person-aware AI business agent.

---

## Table of Contents

1. [Architecture Overview](#1-architecture-overview)
2. [Person Classification System](#2-person-classification-system)
3. [Greeting & Response Engine](#3-greeting--response-engine)
4. [Transaction System](#4-transaction-system)
5. [Payment System — Stripe](#5-payment-system--stripe)
6. [Payment System — Crypto (Polygon MATIC)](#6-payment-system--crypto-polygon-matic)
7. [Customer Engagement Engine](#7-customer-engagement-engine)
8. [Price Negotiation Workflow](#8-price-negotiation-workflow)
9. [Affiliate Links System](#9-affiliate-links-system)
10. [Group Advertisement Engine](#10-group-advertisement-engine)
11. [RAG Pipeline (AI Responses)](#11-rag-pipeline-ai-responses)
12. [Onboarding State Machine](#12-onboarding-state-machine)
13. [Bot Commands Reference](#13-bot-commands-reference)
14. [API Endpoints Reference](#14-api-endpoints-reference)
15. [Database Schema](#15-database-schema)
16. [Scheduler Jobs](#16-scheduler-jobs)
17. [Environment Variables](#17-environment-variables)
18. [File Map](#18-file-map)
19. [Deployment & Operations](#19-deployment--operations)

---

## 1. Architecture Overview

### System Components

```
+---------------------+         +-------------------+
|  Telegram Users     |         |  Website          |
|  (9 person types)   |         |  biznode.1bz.biz  |
+---------+-----------+         +-------------------+
          |
          v
+---------+-----------+
|  Telegram Bot       |   polling (10s intervals)
|  docker/bot/        |
|  run_bot.py         |
+---------+-----------+
          |  REST API calls
          v
+---------+-----------+         +-------------------+
|  Dashboard API      |<------->|  PostgreSQL DB     |
|  ui/server.py       |         |  30+ tables        |
|  FastAPI :7777      |         +-------------------+
+---------+-----------+
          |
   +------+-------+--------+--------+
   v      v       v        v        v
Ollama  Qdrant  SMTP/IMAP  Stripe  Polygon RPC
:11434  :6333   :587/:993   API     API
```

### Data Flow Principles

1. **Bot → Dashboard API → Database**: All state changes go through REST API. Bot never touches DB directly.
2. **Fast path / Slow path**: Greetings and menus are instant (pre-computed). Only free-text questions hit the LLM.
3. **Person-first**: Every interaction starts by identifying WHO is talking, then adapting behavior.

### Technology Stack

| Layer | Technology | Purpose |
|-------|-----------|---------|
| Bot | python-telegram-bot 21.x | Telegram polling + handlers |
| API | FastAPI + Uvicorn | REST endpoints, WebSocket |
| Database | PostgreSQL 16 | All persistent state |
| Vector DB | Qdrant | RAG knowledge base |
| LLM | Ollama (qwen3.5:4b) | AI text generation |
| Embeddings | Ollama (nomic-embed-text) | 768-dim vectors |
| Scheduler | APScheduler | Cron + interval jobs |
| Email | SMTP (port 587) + IMAP (port 993) | Outbound/inbound email |
| Payments | Stripe Checkout API | Card payments |
| Blockchain | Polygon RPC | MATIC wallet verification |

---

## 2. Person Classification System

### Business Logic

Every person interacting with the bot falls into one of 9 categories. The person type determines:
- **Greeting message** (warm, professional, data-driven, etc.)
- **Menu options** (role-specific buttons)
- **Transaction types** available
- **Email engagement content**
- **Information access level**

### Person Types

| Type | Constant | Description | Menu Items |
|------|----------|-------------|------------|
| `owner` | `PERSON_OWNER` | Business operator. Full admin. | Leads, Queries, Status, Customer Menu |
| `customer` | `PERSON_CUSTOMER` | Paying/potential client. | My Services, Request Price Quote, Ask Question |
| `bot` | `PERSON_BOT` | Another bot in group. | Service Inquiry, Affiliate Click |
| `service_provider` | `PERSON_SERVICE_PROVIDER` | Vendor/partner. | Partnership Info, Ask Question |
| `investor` | `PERSON_INVESTOR` | Financial stakeholder. | Business Overview, Growth Metrics |
| `visitor` | `PERSON_VISITOR` | Browsing, not yet committed. | Ask Question, About BizNode AI |
| `guest` | `PERSON_GUEST` | One-time visitor. | Ask Question, About BizNode AI |
| `government` | `PERSON_GOVERNMENT` | Regulatory/compliance. | Compliance Request |
| `financier` | `PERSON_FINANCIER` | Funding entity. | Financial Overview, Investment |

### Implementation

**Storage:** `bot_users.person_type` column (TEXT, default `'visitor'`)

**Detection flow:**
1. New user → default `visitor`
2. After OTP verification → set to `customer`
3. Immediately shown role picker (inline keyboard)
4. User selects their actual role → stored in DB
5. Owner detected by `OWNER_TELEGRAM_ID` env var (bypasses classification)

**Code location:** `docker/bot/run_bot.py`
- Constants: lines ~103-135 (`PERSON_OWNER`, `VALID_PERSON_TYPES`, `PERSON_TYPE_LABELS`)
- Role picker: `_role_selection_menu()` → returns `InlineKeyboardMarkup`
- Role change: `/role` command or "Change My Role" menu button
- Callback: `role:{type}` → `update_bot_user(user_id, person_type=new_role)`

**API:**
- `POST /api/bot-user/{id}/update` with `{"person_type": "investor"}`
- `GET /api/bot-user/{id}` returns full record including `person_type`

---

## 3. Greeting & Response Engine

### Business Logic

Every `/start` or initial contact should be:
1. **Instant** — no LLM delay for greetings
2. **Personal** — use name, recall last conversation topic
3. **Role-aware** — different tone per person type
4. **Menu-first** — always show actionable options

### Fast Path (Verified Users)

```
/start
  → get_bot_user(telegram_id)         # REST call, <100ms
  → check step == "verified"          # Already onboarded
  → _time_greeting()                  # "Good morning"
  → _person_type_greeting(type, name) # "Welcome back, John! Great to see you."
  → _last_topic(user_id)              # "Last we discussed: pricing for web dev"
  → _main_menu(person_type)           # Role-specific inline keyboard
  → reply_text(...)                   # INSTANT — no LLM call
```

**Total response time: <500ms** (DB lookup + Telegram API)

### Slow Path (Free-Text Questions)

```
User sends text message
  → "Thinking..." placeholder               # INSTANT
  → embed_text(query)                        # Ollama embedding, ~2s
  → search_memory(vector)                    # Qdrant search, ~200ms
  → query_llm(prompt, snippets, history)     # Ollama generate, 30-90s
  → edit_text(response)                      # Replace placeholder
```

**Total response time: 30-90 seconds** (LLM-dependent)

### Greeting Templates by Person Type

```python
PERSON_OWNER:            "Welcome back, Boss {name}!"
PERSON_CUSTOMER:         "Welcome back, {name}! Great to see you again."
PERSON_BOT:              "Hello {name} (bot). Ready to exchange data."
PERSON_SERVICE_PROVIDER: "Hello {name}! Thanks for partnering with us."
PERSON_INVESTOR:         "Welcome, {name}. Here's your business pulse."
PERSON_VISITOR:          "Hi {name}! Welcome — let me show you what we offer."
PERSON_GUEST:            "Hello {name}! Feel free to explore our services."
PERSON_GOVERNMENT:       "Welcome, {name}. How can we assist with compliance?"
PERSON_FINANCIER:        "Welcome, {name}. Let's talk growth and opportunity."
```

### Owner /start Response Structure

```
*Good morning, Shashi!*
_1BZ DZIT DAO LLC_ · AI Persona: Priya
_Last discussed: "how do I configure Stripe"_

⚡ *Needs attention:* 3 new leads · 7 queries today

📊 *Today*
  Queries: *7* from *3* users
  New leads: *3* · Total: *42*
  Verified customers: *12* / 18 total

*Commands*
  /report — Full activity report
  /leads — Recent leads
  /queries — Customer queries
  /status — Services status
  /menu — Quick panel
```

### Implementation Details

**Code:** `docker/bot/run_bot.py`
- `_time_greeting()` — hour-based greeting (lines ~139-150)
- `_last_topic(user_id)` — fetches last customer message from conversation API
- `_person_type_greeting(type, name)` — lookup table of greeting strings
- `_customer_start()` — fast path for verified users
- `_owner_start()` — owner-specific dashboard
- `_main_menu(person_type)` — builds inline keyboard with role-specific buttons

---

## 4. Transaction System

### Business Logic

Every business interaction that has a purpose (inquiry, purchase, negotiation) is tracked as a **transaction**. Transactions have:
- Unique reference number: `TXN-A1B2C3D4`
- Lifecycle: `initiated → pending → confirmed/paid → completed`
- Type determined by person type
- Metadata for context (service name, desired price, etc.)

### Transaction Types

| Type | Triggered By | Description |
|------|-------------|-------------|
| `service_inquiry` | visitor/guest asks about services | Informational, no payment |
| `service_purchase` | customer buys a service | Linked to payment |
| `price_negotiation` | customer requests price quote | Bot mediates with owner |
| `consultation` | any person books a session | Scheduled follow-up |
| `partnership` | service_provider proposes deal | Routed to owner |
| `investment` | investor expresses interest | Owner notified |
| `compliance_request` | government requests info | Audit-logged |
| `funding_proposal` | financier offers funding | Owner notified |
| `affiliate_click` | any clicks affiliate link | Click tracked |
| `crypto_payment` | customer pays with MATIC | Blockchain verified |
| `stripe_payment` | customer pays with card | Webhook confirmed |

### Person → Transaction Mapping

```python
PERSON_TRANSACTION_MAP = {
    "customer":         ["service_purchase", "price_negotiation", "consultation",
                         "crypto_payment", "stripe_payment"],
    "investor":         ["investment", "consultation"],
    "service_provider": ["partnership", "consultation", "service_inquiry"],
    "financier":        ["funding_proposal", "investment", "consultation"],
    "government":       ["compliance_request"],
    "visitor":          ["service_inquiry", "consultation", "affiliate_click"],
    "guest":            ["service_inquiry", "affiliate_click"],
}
```

### Implementation

**Service:** `services/transaction_service.py`
- `generate_reference()` → `TXN-{uuid4_hex[:8].upper()}`
- `create_transaction(...)` → inserts row, returns `{id, reference_no, status}`
- `get_transaction(ref)` → lookup by reference number
- `get_user_transactions(telegram_id)` → history for a user
- `update_status(ref, status, payment_ref)` → lifecycle transition
- `get_suggested_transactions(person_type)` → returns list of `{type, label}`

**Database table:** `transactions`
```sql
CREATE TABLE transactions (
    id              SERIAL PRIMARY KEY,
    reference_no    TEXT UNIQUE NOT NULL,     -- TXN-A1B2C3D4
    telegram_id     TEXT,
    person_type     TEXT DEFAULT 'customer',
    transaction_type TEXT NOT NULL,           -- from type list above
    title           TEXT NOT NULL,
    description     TEXT,
    amount          REAL DEFAULT 0,
    currency        TEXT DEFAULT 'USD',
    status          TEXT DEFAULT 'initiated', -- initiated/pending/confirmed/paid/completed/expired
    payment_method  TEXT,                     -- stripe/crypto/manual
    payment_ref     TEXT,                     -- Stripe payment_intent or tx hash
    metadata_json   TEXT DEFAULT '{}',
    created_at      TIMESTAMP DEFAULT NOW(),
    updated_at      TIMESTAMP DEFAULT NOW(),
    completed_at    TIMESTAMP
);
```

**Bot command:** `/transact`
- Shows inline keyboard of suggested transaction types for user's person_type
- "My Transactions" button shows history
- Selecting a type creates a transaction and guides user to next step

**API endpoints:**
- `GET /api/transactions` — list all (filterable by status, telegram_id)
- `POST /api/transactions` — create new
- `GET /api/transactions/{ref}` — get by reference
- `POST /api/transactions/{ref}/status` — update status
- `GET /api/transactions/suggested/{person_type}` — get suggested types

---

## 5. Payment System — Stripe

### Business Logic

Stripe Checkout handles card payments. The flow:

```
Customer → /pay → "Pay with Card" → Bot creates Checkout Session
                                         ↓
                              Stripe hosted payment page
                                         ↓
                              Customer pays with card
                                         ↓
                              Stripe sends webhook → /api/stripe/webhook
                                         ↓
                              Verify signature → Update transaction status
                                         ↓
                              Email owner + customer confirmation
```

### Implementation

**Service:** `services/stripe_service.py`

**Functions:**
- `is_configured()` → checks if `STRIPE_SECRET_KEY` is set
- `create_checkout_session(telegram_id, service_name, amount, currency, email, reference_no)`:
  - Creates Stripe Checkout Session via `stripe.checkout.Session.create()`
  - Sets `success_url` and `cancel_url` with reference_no param
  - Stores `telegram_id` and `reference_no` in session metadata
  - Returns `{ok, session_id, url, reference_no}`
- `verify_webhook_signature(payload, signature)`:
  - Uses `stripe.Webhook.construct_event()` if stripe package available
  - Falls back to manual HMAC-SHA256 verification
  - Returns `True/False`
- `handle_webhook_event(event_data)`:
  - `checkout.session.completed` → updates transaction to `paid`, extracts payment_intent
  - `checkout.session.expired` → updates transaction to `expired`
  - Returns action dict with reference_no, amount, email, etc.

**Webhook endpoint:** `POST /api/stripe/webhook`
1. Reads raw body + `stripe-signature` header
2. Calls `verify_webhook_signature()`
3. Calls `handle_webhook_event()`
4. If payment confirmed → emails owner via `EmailService`
5. Returns `{"ok": true}`

**Configuration required:**
```env
STRIPE_SECRET_KEY=sk_live_...        # From Stripe dashboard
STRIPE_WEBHOOK_SECRET=whsec_...      # From Stripe webhook settings
STRIPE_SUCCESS_URL=https://...       # Redirect after payment
STRIPE_CANCEL_URL=https://...        # Redirect on cancel
```

**Bot flow:**
1. `/pay` → shows "Pay with Card" / "Pay with Crypto" / "Payment History"
2. `/services` → lists services with "Buy" buttons
3. `buy:{service_id}` callback → shows payment method picker
4. Stripe creates checkout session → bot sends payment link (via URL button)

**Security:**
- Webhook signature verified using HMAC-SHA256
- Secret key never exposed to frontend
- All payment state changes go through verified webhook only

---

## 6. Payment System — Crypto (Polygon MATIC)

### Business Logic

Customers register their Polygon wallet, send a verification payment (0.01 MATIC), and once verified, all future transactions from that wallet are tracked.

```
Customer → /wallet 0xABC...  → Registers wallet in bot_users
                              → Bot shows BizNode wallet address
                              → Customer sends 0.01 MATIC on Polygon
Customer → /verify_wallet    → Bot checks (or owner confirms manually)
                              → wallet_verified = 1
                              → Future: auto-track incoming payments
```

### Implementation

**Service:** `services/crypto_service.py`

**Functions:**
- `is_valid_wallet(address)` → checks `0x` prefix, 42 chars, valid hex
- `register_wallet(telegram_id, wallet_address)`:
  - Validates address format
  - Stores in `bot_users.crypto_wallet`
  - Sets `wallet_verified = 0`
  - Returns BizNode wallet address + verification amount
- `get_wallet_info(telegram_id)` → returns registration status
- `verify_wallet_payment(telegram_id)`:
  - Checks Polygon RPC for BizNode wallet balance (MVP)
  - Full transaction verification requires Polygonscan API (future)
  - Returns `{ok, mode, message}`
  - If auto-verify unavailable → `mode: "manual"` (owner confirms)
- `confirm_wallet(telegram_id)`:
  - Owner manually marks wallet as verified
  - Sets `bot_users.wallet_verified = 1`
- `get_payment_instructions(telegram_id)` → formatted Markdown instructions

**Database columns** (on `bot_users`):
```sql
ALTER TABLE bot_users ADD COLUMN crypto_wallet TEXT DEFAULT '';
ALTER TABLE bot_users ADD COLUMN wallet_verified INTEGER DEFAULT 0;
```

**Bot commands:**
- `/wallet 0x...` → register wallet
- `/wallet` (no args) → show wallet status
- `/verify_wallet` → attempt verification

**API endpoints:**
- `POST /api/crypto/register-wallet` — register wallet
- `GET /api/crypto/wallet/{telegram_id}` — get wallet info
- `POST /api/crypto/verify-wallet` — attempt auto-verification
- `POST /api/crypto/confirm-wallet` — owner manual confirmation

**Configuration:**
```env
BIZNODE_WALLET_ADDRESS=0x...     # Business's Polygon wallet
POLYGON_RPC_URL=https://polygon-rpc.com
```

---

## 7. Customer Engagement Engine

### Business Logic

Every verified bot user receives a **daily personalized email** based on their person_type. The goal is to maintain warm contact, provide value, and drive engagement.

| Person Type | Email Content |
|-------------|--------------|
| `customer` | Service offers, price negotiation mention, 24/7 support reminder |
| `investor` | Business highlights, growth metrics, platform expansion |
| `service_provider` | Partnership opportunities, API integration, cross-promotion |
| `financier` | Revenue model, unit economics, growth projections |
| `government` | Compliance commitments, audit transparency |
| `visitor/guest` | AI benefits, BizNode platform intro, DZIT credits |

Every email also includes:
- Active **affiliate links** section
- BizNode/DZIT footer with registration links
- Professional HTML styling with gradient header

### Implementation

**Service:** `services/customer_engagement_service.py`

**Main function:** `run_daily_engagement(dashboard_url=None) → {sent, skipped, errors}`

**Algorithm:**
1. Fetch all verified bot users via `get_all_verified_bot_users()`
2. Fetch business profile (name, persona) from dashboard API
3. Fetch active affiliate links from DB
4. For each user:
   a. Skip if no email or invalid email
   b. Skip if already received `daily_email` engagement today (check `engagement_log`)
   c. Build personalized email using `_build_engagement_email(user, biz_name, persona, affiliates)`
   d. Send via `EmailService.send_email()`
   e. Log to `engagement_log` table

**Deduplication:** `get_last_engagement(telegram_id, "daily_email")` checks if today's date matches.

**Database table:** `engagement_log`
```sql
CREATE TABLE engagement_log (
    id              SERIAL PRIMARY KEY,
    telegram_id     TEXT,
    email           TEXT,
    person_type     TEXT,
    engagement_type TEXT NOT NULL,    -- daily_email, promo, welcome, etc.
    subject         TEXT,
    status          TEXT DEFAULT 'sent',  -- sent/failed
    created_at      TIMESTAMP DEFAULT NOW()
);
```

**Scheduler:** `ENGAGEMENT_CRON` (default `0 9 * * *` — 9 AM UTC daily)
- Registered in `automation/scheduler.py` as `biznode_engagement` job
- Calls `_run_engagement_job()` → `run_daily_engagement(dashboard_url="http://localhost:7777")`

**Manual trigger:** `POST /api/engagement/run`

---

## 8. Price Negotiation Workflow

### Business Logic

A customer can request a price negotiation. The bot acts as mediator between customer and owner.

```
Customer → /negotiate WebDev 500
                ↓
  Bot creates transaction (type: price_negotiation)
  Bot replies: "Negotiation started! Ref: TXN-ABCD1234"
                ↓
  Bot emails owner: "John wants WebDev at $500. Ref: TXN-ABCD1234"
                ↓
  Owner reviews in dashboard or email
  Owner responds (approve/counter/reject)
                ↓
  (Future) Bot notifies customer of outcome
```

### Implementation

**Bot command:** `/negotiate ServiceName YourPrice`
- Parses service name (all args except last) and price (last arg)
- Creates transaction via `POST /api/transactions`:
  ```json
  {
    "transaction_type": "price_negotiation",
    "title": "Price negotiation: WebDev",
    "description": "John requests $500.00 for WebDev",
    "amount": 500.0,
    "metadata": {"service_name": "WebDev", "desired_price": 500,
                 "customer_name": "John", "customer_email": "john@example.com"}
  }
  ```
- Sends email to `OWNER_EMAIL` with negotiation details
- Bot replies with reference number

**Also available via:** `_handle_info_callback` with `info:price_quote` → guides user to `/negotiate`

---

## 9. Affiliate Links System

### Business Logic

The bot publishes affiliate/partner links to customers in:
1. Chat responses (via `/affiliate` command)
2. Daily engagement emails (included in every email)
3. Menu-driven recommendations

Each click is tracked for commission and analytics.

### Implementation

**Service:** `services/affiliate_service.py`

**Functions:**
- `get_active_links(category=None)` → filtered list
- `track_click(link_id, telegram_id)` → increments `click_count`
- `format_links_for_telegram(links)` → Markdown-formatted link list
- `format_links_for_email(links)` → HTML-formatted for email inclusion
- `create_link(title, url, description, category, commission)` → CRUD
- `update_link(link_id, **fields)` → update
- `delete_link(link_id)` → delete

**Database table:** `affiliate_links`
```sql
CREATE TABLE affiliate_links (
    id          SERIAL PRIMARY KEY,
    title       TEXT NOT NULL,
    url         TEXT NOT NULL,
    description TEXT,
    category    TEXT DEFAULT 'general',   -- general, tech, business, etc.
    commission  TEXT,                      -- "10%" or "$5 per sale"
    is_active   INTEGER DEFAULT 1,
    click_count INTEGER DEFAULT 0,
    sort_order  INTEGER DEFAULT 0,
    created_at  TIMESTAMP DEFAULT NOW()
);
```

**Bot command:** `/affiliate` — shows active links as inline keyboard buttons (URL type)

**API endpoints:**
- `GET /api/affiliate-links` — list (filterable: active_only)
- `POST /api/affiliate-links` — create
- `PUT /api/affiliate-links/{id}` — update
- `DELETE /api/affiliate-links/{id}` — delete
- `POST /api/affiliate-links/{id}/click` — track click

---

## 10. Group Advertisement Engine

### Business Logic

Group advertisements are a **second income source** for the bot. Scheduled messages are sent to Telegram groups at configured intervals.

Ad types:
- `promotion` — general business promotion
- `affiliate` — partner/affiliate content
- `opportunity` — business opportunity alert
- `alert` — urgent notification

### Implementation

**Service:** `services/group_ad_service.py`

**Functions:**
- `get_pending_ads()` → active ads not yet sent today (daily cap)
- `send_ad_to_group(bot, group_id, ad)` → prepares formatted message
- `mark_ad_sent(ad_id)` → updates `last_sent` and increments `send_count`
- CRUD: `create_ad`, `update_ad`, `delete_ad`, `get_all_ads`, `get_active_ads`

**Database table:** `group_ads`
```sql
CREATE TABLE group_ads (
    id            SERIAL PRIMARY KEY,
    title         TEXT NOT NULL,
    message       TEXT NOT NULL,
    target_group  TEXT,                 -- specific group ID or empty for default
    ad_type       TEXT DEFAULT 'promotion',
    schedule_cron TEXT,                 -- future: per-ad scheduling
    is_active     INTEGER DEFAULT 1,
    last_sent     TIMESTAMP,
    send_count    INTEGER DEFAULT 0,
    created_at    TIMESTAMP DEFAULT NOW()
);
```

**Bot integration:** `_send_pending_group_ads(context)`
- Registered as a repeating job in bot's `job_queue` (every 6 hours)
- Fetches pending ads → sends up to 3 per cycle to `TELEGRAM_GROUP_ID`
- Marks each as sent after successful delivery
- Message prefixed based on ad_type (Announcement / Business Opportunity / etc.)

**Also runs via scheduler:** `_run_group_ads_job()` in `automation/scheduler.py` (every 6 hours)

**API endpoints:**
- `GET /api/group-ads` — list
- `POST /api/group-ads` — create
- `PUT /api/group-ads/{id}` — update
- `DELETE /api/group-ads/{id}` — delete

---

## 11. RAG Pipeline (AI Responses)

### Business Logic

When a user asks a free-text question, the bot uses Retrieval-Augmented Generation:

```
User message
    → embed_text(query)              [Ollama nomic-embed-text, 768-dim, ~2s]
    → search_memory(vector, top_k=5) [Qdrant cosine similarity, ~200ms]
    → query_llm(prompt, snippets,    [Ollama qwen3.5:4b, 30-90s]
                history, owner_mode)
    → add_message(user_id, ...)      [store conversation]
    → log_query(user_id, ...)        [store in query_logs]
```

### Owner vs Customer Mode

| Aspect | Owner (`owner_mode=True`) | Customer |
|--------|---------------------------|----------|
| System prompt | Direct, factual, no persona | Business persona + instruction.md |
| History | Saved for context recall | Full history in prompt |
| Vector store | Read only (no contamination) | Read + write |
| instruction.md | Excluded | Included as context |

### Rate Limiting

- 10 messages per 60 seconds per user
- Applied to all non-owner users
- Checked before any processing

---

## 12. Onboarding State Machine

### Business Logic

New users must verify their identity before accessing services.

```
new → awaiting_name → awaiting_business → awaiting_email → awaiting_otp → verified
```

### State Transitions

| State | User Input | Next State | Bot Action |
|-------|-----------|------------|------------|
| `new` | `/start` | `awaiting_name` | Show persona greeting, ask name |
| `awaiting_name` | "John" | `awaiting_business` | "Nice to meet you, John! What business?" |
| `awaiting_business` | "TechCorp" | `awaiting_email` | "Got it — TechCorp. Please share email." |
| `awaiting_email` | "john@tc.com" | `awaiting_otp` | Send OTP email, "Check your inbox." |
| `awaiting_otp` | "123456" | `verified` | Create lead, show role picker |
| `verified` | `/start` | stays `verified` | Fast greeting + menu |

### Post-Verification

After OTP success:
1. `person_type` set to `customer` (default)
2. Role selection keyboard shown immediately
3. User picks their actual role (investor, service_provider, etc.)
4. Personalized menu displayed

---

## 13. Bot Commands Reference

### All Users

| Command | Description | Response Time |
|---------|-------------|--------------|
| `/start` | Greeting + menu (verified) or onboarding (new) | Instant |
| `/menu` | Show role-specific action menu | Instant |
| `/role` | Change person type | Instant |
| `/help` | 4-step BizBrain business profile intake | Interactive |
| `/transact` | Start a transaction based on role | Instant |
| `/pay` | Choose payment method | Instant |
| `/wallet 0x...` | Register Polygon MATIC wallet | Instant |
| `/verify_wallet` | Verify crypto wallet after payment | ~5s |
| `/services` | Browse services with prices and Buy buttons | Instant |
| `/negotiate Svc Price` | Start price negotiation with owner | Instant |
| `/affiliate` | View partner links and recommendations | Instant |
| `/clear` | Clear conversation history | Instant |
| `/memory` | Show knowledge base entry count | ~2s |

### Owner Only

| Command | Description |
|---------|-------------|
| `/report` | Full activity report: leads, queries, payments |
| `/leads` | View recent leads (top 10) |
| `/queries` | View customer queries (top 10) |
| `/status` | Bot health: Ollama, Qdrant, Dashboard status |

### Inline Menu Callbacks

| Callback Data | Handler | Description |
|---------------|---------|-------------|
| `owner:leads` | `_owner_show_leads` | Show leads (owner) |
| `owner:queries` | `_owner_show_queries` | Show queries (owner) |
| `owner:status` | `_owner_show_status` | Show status (owner) |
| `owner:custmenu` | — | Preview customer menu |
| `role:{type}` | update bot_user | Change person type |
| `info:about_biznode` | Pre-written | BizNode AI + DZIT info |
| `info:my_services` | Pre-written | Customer service list |
| `info:price_quote` | Pre-written | Negotiation instructions |
| `info:biz_overview` | Pre-written | Business overview |
| `info:growth` | Live data | Growth metrics from report |
| `info:partnership` | Pre-written | Partnership opportunities |
| `info:finance` | Pre-written | Financial overview |
| `info:change_role` | Role picker | Show role selection |
| `txn:{type}` | Create transaction | Start transaction of type |
| `txn:history` | Show history | User's transaction history |
| `pay:stripe` | Payment info | Stripe payment instructions |
| `pay:crypto` | Payment info | Crypto wallet status/instructions |
| `pay:history` | Show payments | Payment transaction history |
| `buy:{service_id}` | Payment picker | Payment method for service |
| `task:__ask` | Prompt | "Type your question" |
| `task:{code}` | Workflow trigger | Start workflow |

---

## 14. API Endpoints Reference

### New Endpoints (added in v2.0)

**Transactions (5):**
- `GET /api/transactions` — query: `status`, `telegram_id`, `limit`
- `POST /api/transactions` — body: `{telegram_id, person_type, transaction_type, title, amount, ...}`
- `GET /api/transactions/{ref}` — by reference number
- `POST /api/transactions/{ref}/status` — body: `{status, payment_ref}`
- `GET /api/transactions/suggested/{person_type}` — returns `[{type, label}]`

**Stripe (3):**
- `POST /api/stripe/create-checkout` — body: `{telegram_id, service_name, amount, currency, email}`
- `POST /api/stripe/webhook` — Stripe event payload (signature verified)
- `GET /api/stripe/status` — returns `{configured: bool}`

**Crypto (4):**
- `POST /api/crypto/register-wallet` — body: `{telegram_id, wallet_address}`
- `GET /api/crypto/wallet/{telegram_id}` — returns `{registered, wallet, verified, biznode_wallet}`
- `POST /api/crypto/verify-wallet` — body: `{telegram_id}`
- `POST /api/crypto/confirm-wallet` — body: `{telegram_id}` (owner action)

**Affiliate Links (5):**
- `GET /api/affiliate-links` — query: `active_only`
- `POST /api/affiliate-links` — body: `{title, url, description, category, commission}`
- `PUT /api/affiliate-links/{id}` — body: fields to update
- `DELETE /api/affiliate-links/{id}`
- `POST /api/affiliate-links/{id}/click` — body: `{telegram_id}`

**Group Ads (4):**
- `GET /api/group-ads` — query: `active_only`
- `POST /api/group-ads` — body: `{title, message, target_group, ad_type, schedule_cron}`
- `PUT /api/group-ads/{id}` — body: fields to update
- `DELETE /api/group-ads/{id}`

**Engagement (2):**
- `GET /api/engagement-log` — query: `telegram_id`, `limit`
- `POST /api/engagement/run` — manually trigger daily engagement

**Total new endpoints: 23**

---

## 15. Database Schema

### New Tables (v2.0)

| Table | Columns | Purpose |
|-------|---------|---------|
| `transactions` | id, reference_no, telegram_id, person_type, transaction_type, title, description, amount, currency, status, payment_method, payment_ref, metadata_json, created_at, updated_at, completed_at | All business transactions |
| `affiliate_links` | id, title, url, description, category, commission, is_active, click_count, sort_order, created_at | Partner/affiliate links |
| `engagement_log` | id, telegram_id, email, person_type, engagement_type, subject, status, created_at | Email engagement tracking |
| `group_ads` | id, title, message, target_group, ad_type, schedule_cron, is_active, last_sent, send_count, created_at | Group advertisement management |

### Modified Tables

| Table | New Columns | Purpose |
|-------|-------------|---------|
| `bot_users` | `person_type TEXT DEFAULT 'visitor'` | Person classification |
| `bot_users` | `crypto_wallet TEXT DEFAULT ''` | Polygon wallet address |
| `bot_users` | `wallet_verified INTEGER DEFAULT 0` | Wallet verification flag |

---

## 16. Scheduler Jobs

| Job ID | Schedule | Function | Purpose |
|--------|----------|----------|---------|
| `biznode_backup` | `0 2 * * *` | `_run_backup_job` | Daily backup |
| `biznode_digest` | `0 22 * * *` | `_run_digest_job` | Daily digest email to owner |
| `biznode_imap` | Every 15 min | `_run_imap_check` | Poll IMAP for owner commands |
| `biznode_promo_email` | `0 8 * * *` | `_run_promo_email_job` | Promo emails to new leads |
| `biznode_engagement` | `0 9 * * *` | `_run_engagement_job` | **NEW** Daily personalized emails |
| `biznode_group_ads` | Every 6 hours | `_run_group_ads_job` | **NEW** Group ad delivery |
| `biznode_video_tasks` | Every 5 min | `_run_video_task_check` | Video task processing |
| `group_ads` (bot) | Every 6 hours | `_send_pending_group_ads` | **NEW** Bot-side ad sender |

---

## 17. Environment Variables

### New Variables (v2.0)

| Variable | Default | Required | Description |
|----------|---------|----------|-------------|
| `STRIPE_SECRET_KEY` | *(empty)* | For Stripe | Stripe API secret key (sk_...) |
| `STRIPE_PUBLISHABLE_KEY` | *(empty)* | For frontend | Stripe publishable key (pk_...) |
| `STRIPE_WEBHOOK_SECRET` | *(empty)* | For webhooks | Webhook signing secret (whsec_...) |
| `STRIPE_SUCCESS_URL` | `https://biznode.1bz.biz/payment-success` | No | Redirect after payment |
| `STRIPE_CANCEL_URL` | `https://biznode.1bz.biz/payment-cancel` | No | Redirect on cancel |
| `BIZNODE_WALLET_ADDRESS` | *(empty)* | For crypto | Polygon wallet for receiving payments |
| `POLYGON_RPC_URL` | `https://polygon-rpc.com` | No | Polygon network RPC endpoint |
| `ENGAGEMENT_CRON` | `0 9 * * *` | No | Daily engagement email schedule |

---

## 18. File Map

### New Files (v2.0)

| File | Lines | Purpose |
|------|-------|---------|
| `services/transaction_service.py` | ~130 | Transaction types, creation, lifecycle |
| `services/stripe_service.py` | ~180 | Stripe Checkout + webhook handling |
| `services/crypto_service.py` | ~150 | Polygon MATIC wallet management |
| `services/customer_engagement_service.py` | ~210 | Daily personalized emails |
| `services/affiliate_service.py` | ~100 | Affiliate link CRUD + formatting |
| `services/group_ad_service.py` | ~110 | Group ad management + delivery |

### Modified Files (v2.0)

| File | Changes |
|------|---------|
| `docker/bot/run_bot.py` | Person types, fast greeting, role system, 7 new commands, 5 callback handlers, group ad sender |
| `memory/database.py` | 4 new tables, 3 new columns on bot_users, ~15 new CRUD functions |
| `ui/server.py` | 23 new API endpoints, 8 new settings schema entries, expanded _BOT_PATHS |
| `automation/scheduler.py` | 2 new scheduled jobs (engagement, group ads) |

### Website Files

| File | Purpose |
|------|---------|
| `feature-smart-bot.php` | **NEW** — Full documentation page for Smart Bot features |
| `features.php` | Updated roadmap pills (6 new completed features) |

---

## 19. Deployment & Operations

### Starting the System

```bash
# From C:\nodesrunning\biznodemainnode
python run_dashboard.py   # Dashboard on :7777 (start first — runs DB migrations)
python bot_runner.py      # Bot with watchdog (auto-restart on crash)
```

### Verifying Health

```bash
# Dashboard API
curl http://localhost:7777/api/transactions        # Should return []
curl http://localhost:7777/api/stripe/status        # {configured: false/true}
curl http://localhost:7777/api/affiliate-links      # Should return []

# Bot log
tail -f logs/bot.log   # Should show getUpdates polling
```

### Adding Affiliate Links (via API)

```bash
curl -X POST http://localhost:7777/api/affiliate-links \
  -H "Content-Type: application/json" \
  -d '{"title":"Example Partner","url":"https://example.com","description":"Great service","commission":"10%"}'
```

### Creating a Group Ad (via API)

```bash
curl -X POST http://localhost:7777/api/group-ads \
  -H "Content-Type: application/json" \
  -d '{"title":"Weekly Promo","message":"Check out our new AI consulting packages!","ad_type":"promotion"}'
```

### Activating Stripe

1. Get API keys from https://dashboard.stripe.com/apikeys
2. Add to `.env`:
   ```
   STRIPE_SECRET_KEY=sk_live_...
   STRIPE_WEBHOOK_SECRET=whsec_...
   ```
3. Install stripe package: `pip install stripe`
4. Configure webhook in Stripe dashboard: `https://your-domain/api/stripe/webhook`
5. Restart dashboard

### Activating Crypto Payments

1. Create a Polygon wallet (MetaMask or similar)
2. Add to `.env`:
   ```
   BIZNODE_WALLET_ADDRESS=0xYourWalletAddress
   ```
3. Restart bot

---

## Appendix: Security Considerations

- **Stripe webhook** signatures are verified before processing any payment events
- **Crypto wallet** addresses are validated (0x prefix, 42 chars, valid hex)
- **Bot auth** middleware: `X-Bot-Secret` header for internal API calls
- **Rate limiting**: 10 messages/60s per user (prevents abuse)
- **Blocked customers**: checked on every interaction
- **Email SPF/DKIM**: verified on inbound IMAP emails
- **Dashboard auth**: session-based with `DASHBOARD_PASSWORD`
- **Sensitive data**: Stripe keys, DB passwords, SMTP passwords stored in `.env` only

---

*Document auto-generated and maintained. Last updated: 2026-03-08 v2.0*
