174 lines
13 KiB
Markdown
174 lines
13 KiB
Markdown
# TradeMate (外贸小助手) — Agent Guide
|
||
|
||
## Chrome 浏览器扩展 🆕
|
||
|
||
- **目录**: `browser-extension/` — 完整 Chrome 插件
|
||
- **功能**: popup 面板调用 AI 翻译/回复/提取客户信息、网页右键菜单集成、自动填写报价单
|
||
- **兼容平台**: LinkedIn / Amazon / AliExpress 等外贸平台页面
|
||
- **安装**: 打开 `chrome://extensions` → 加载已解压的扩展 → 选择 `browser-extension/` 目录
|
||
- **API 客户端**: `browser-extension/api/client.js` — 封装后端 API 调用,支持 JWT 认证
|
||
|
||
## UX Design
|
||
|
||
- **PC 工作台**: 侧边栏 5 项精简导航 (首页/客户/业务/翻译/更多) + **CommandK 命令面板** (Ctrl+K)
|
||
- **移动端 H5**: 底部 4 Tab 导航 (首页/客户/业务/我的)
|
||
- **工作区合并**: Customers/Discovery/Followup → `WorkspaceCustomer`;Translate/Products/Quotations/Marketing → `WorkspaceBiz`
|
||
- **路由**: 旧页面保留隐藏路由,保证兼容性
|
||
|
||
## uni-app 移动端 H5 (改版后)
|
||
|
||
- **Tab Bar**: 4 项底部导航 — 首页 / 客户 / 业务 / 我的
|
||
- **主页** `pages/index/index.vue` — 简化仪表盘 (统计卡片 + 快捷入口矩阵 + 待办提醒)
|
||
- **客户工作台** `pages/workspace-customer/workspace-customer.vue` — **NEW** 3 个内联标签 (客户列表 / 挖掘新客 / 智能跟进)
|
||
- **业务工作台** `pages/workspace-biz/workspace-biz.vue` — **NEW** 4 个内联标签 (翻译 / 产品库 / 报价单 / 营销素材)
|
||
- **个人中心** `pages/profile/profile.vue` — 更新导航 (通知中心 / 数据分析 / 团队 / 升级会员 / 联系客服)
|
||
- **旧页面保留** (customers, discovery, followup, translate, product, quotation, marketing 等仍可通过 deep link 访问)
|
||
- **pages.json** — 标签栏从 5 项变为 4 项,新增 workspace-customer 和 workspace-biz 页面
|
||
- **config.js** — PAGES 配置新增 WORKSPACE_CUSTOMER / WORKSPACE_BIZ
|
||
- **部署路径**: `trade.yuzhiran.com/app/` — nginx SPA fallback `try_files $uri $uri/ /app/index.html`
|
||
|
||
## AI Assistant (Frontend AI Chatbot)
|
||
|
||
- **Components**: `user-frontend/src/components/AiAssistant.vue` + `admin-frontend/src/components/AiAssistant.vue`
|
||
- **Backend**: `backend/app/api/v1/ai_assistant.py` — `POST /api/v1/ai/chat`, `GET /api/v1/ai/quick-questions`
|
||
- **Action types** (configurable via `ACTION_INSTRUCTIONS`): create_customer, create_product, create_quotation, scan_followups, generate_marketing, discovery_search, navigate, search_users, update_user, update_config, review_certification, process_invoice
|
||
- **Frontend action dispatch**: `AiAssistant.vue` switch/case calls corresponding API from `@/api`
|
||
- **Layout integration**: `<AiAssistant />` in `UserLayout.vue` + `AdminLayout.vue`, floating button bottom-right
|
||
- **Quick questions**: configurable via `ai_assistant_quick_questions` `SystemConfig` key
|
||
- **System prompt**: configurable via `ai_assistant_prompt` `SystemConfig` key
|
||
|
||
## AI 数字员工 (Agent Orchestrator) 🆕
|
||
|
||
- **Dashboard**: `user-frontend/src/views/Agent.vue` — 全功能仪表盘,位于 `/agent` 路由
|
||
- **编排服务**: `backend/app/services/agent_orchestrator.py` — `AgentOrchestrator` 类
|
||
- `start_pipeline(user_id, product_name, product_description, target_market)` — 启动完整流程
|
||
- `get_pipeline(pipeline_id, user_id)` — 获取流水线详情
|
||
- `list_pipelines(user_id, page, size)` — 分页列表
|
||
- **数据模型**: `backend/app/models/agent_pipeline.py` — `AgentPipeline` (表: `agent_pipelines`)
|
||
- JSONB `pipeline_data` 存储 stages + leads + summary
|
||
- **API 端点**: `backend/app/api/v1/agent.py` — 3 个端点
|
||
- `POST /api/v1/agent/start` — 启动新任务 (timeout: 300s)
|
||
- `GET /api/v1/agent/pipelines` — 任务列表
|
||
- `GET /api/v1/agent/{pipeline_id}` — 任务详情
|
||
- **流程**: 用户输入产品+市场 → AgentOrchestrator 串接 DiscoveryService.search() → analyze() → outreach() → 自动保存高匹配客户
|
||
- **前端入口**: `user-frontend/src/views/Agent.vue` 已接入路由 `/workspace/agent` 与 `UserLayout.vue` 侧边栏 "AI数字员工" (MagicStick 图标);`/agent` 重定向到 `/workspace/agent`
|
||
- **迁移**: 需要运行 `alembic revision --autogenerate -m "add agent_pipelines"` 创建 `agent_pipelines` 表
|
||
|
||
## 收费方式(免费试用 / 私有化部署 / 买断源码)
|
||
|
||
- **页面**: `user-frontend/src/views/Upgrade.vue` + `UpgradeModal.vue`、`uni-app/src/pages/upgrade/upgrade.vue`、浏览器插件升级入口均改为三种方案:免费试用 / 私有化部署(年付授权)/ 买断源码(一次性)
|
||
- **企业线索**: 私有化部署与买断源码的 CTA 提交到 `POST /api/v1/leads`(模型 `EnterpriseLead`,表 `enterprise_leads`),无需登录;admin 可在 `enterprise_leads` 表查看
|
||
- **价格占位**: `Upgrade.vue` 中 `PRICING` 对象(¥39,800/年、¥98,000 一次性)为可配置展示值
|
||
- **说明**: 旧的按月订阅套餐(`/credits/subscribe`)仍存在于后端,但前端不再主推;如彻底下线订阅需同步清理 `credits.py` 订阅逻辑
|
||
|
||
## Architecture
|
||
|
||
- **Backend**: `backend/` — FastAPI + SQLAlchemy 1.4 async + asyncpg, single `app.main:app`
|
||
- **Frontends**: `uni-app/` (mobile H5/mini-program), `admin-frontend/` (PC admin), `user-frontend/` (PC workspace)
|
||
- **Config**: `backend/app/config.py` reads from `/.env` (project root) via pydantic BaseSettings
|
||
- **Auth**: JWT (python-jose). Default dep `get_current_user_id` in `backend/app/api/v1/deps.py`
|
||
- **AI Router**: `backend/app/ai/router.py` — singleton `AIRouter`, DB-driven providers + DB-driven routing rules. Routing reads `ai_routing` from `system_configs` table.
|
||
- **Database**: PostgreSQL via `asyncpg`, pool_size=20
|
||
|
||
## AI Providers
|
||
|
||
- **Active (seeded by `seed_from_env()`)**: Sensenova (商汤, if `SENSENOVA_API_KEY` set), NVIDIA (if `NVIDIA_API_KEY` set), 阿里翻译 alibaba-mt (always inserted) — at most 3 rows. Do NOT assume 5 providers exist.
|
||
- **Removed**: Claude, DeepL, Local, OpencodeGo, 讯飞 Spark — provider implementations were git rm'd; don't re-add them.
|
||
- **DB-driven**: `AIProvider` model + `admin_ai.py` API — manage providers at runtime. `router.seed_from_env()` loads from `.env` on startup
|
||
- **ECS RAM role**: 阿里翻译使用 ECS 实例 RAM 角色 `trademate-translate` 获取 STS 临时凭证
|
||
- **Provider type mapping** in `router.py._build_provider()`: sensenova, nvidia, alibaba-mt
|
||
|
||
## Security
|
||
|
||
- **CORS**: `middleware.py` — whitelist origins, restricted methods/headers
|
||
- **Rate Limit**: endpoint-specific — login 5/min, register 3/h, password 3/5min, payment 20/min, admin 30/min
|
||
- **CSRF**: `core/csrf.py` — double-submit cookie pattern. Required on auth/payment/profile. Webhooks skipped.
|
||
- **Login**: JSON `LoginRequest` model, not `OAuth2PasswordRequestForm`
|
||
|
||
## Customer Discovery
|
||
|
||
- `discovery.py` + `discovery_record.py` — Google Custom Search integration
|
||
- Contact extraction from company websites (email/phone/WhatsApp/WeChat)
|
||
|
||
## Dev Commands
|
||
|
||
```bash
|
||
# Backend (from project root — .env is there)
|
||
# Dev: matches Vite proxy (both frontends proxy /api → localhost:8000)
|
||
cd backend && source venv/bin/activate && uvicorn app.main:app --reload --port 8000
|
||
# Production: nginx proxies /api/ → localhost:8002
|
||
cd backend && source venv/bin/activate && uvicorn app.main:app --port 8002
|
||
|
||
# Mobile H5
|
||
cd uni-app && npm run dev:h5
|
||
|
||
# Admin frontend (PC management)
|
||
cd admin-frontend && npm run dev # port 5173, base: /admin/
|
||
|
||
# User workspace (PC workbench)
|
||
cd user-frontend && npm run dev # port 5174, base: /workspace/
|
||
|
||
# Tests (backend — needs PostgreSQL running with foreign_trade_test DB)
|
||
cd backend && venv/bin/pytest # all
|
||
venv/bin/pytest tests/test_auth_api.py # single file
|
||
venv/bin/pytest tests/ -k "test_login" # keyword filter
|
||
# pytest.ini: asyncio_mode=auto (no @pytest.mark.asyncio needed) and
|
||
# addopts adds --cov=app coverage automatically on every run.
|
||
|
||
# Builds
|
||
cd uni-app && npm run build:h5 # uni-app (mobile H5)
|
||
cd admin-frontend && npm run build # admin => /www/wwwroot/trade.yuzhiran.com/admin/
|
||
cd user-frontend && npm run build # workspace => /www/wwwroot/trade.yuzhiran.com/workspace/
|
||
|
||
# Alembic migrations
|
||
cd backend && alembic upgrade head
|
||
alembic revision --autogenerate -m "desc"
|
||
```
|
||
|
||
## Deployment
|
||
|
||
- **Landing page**: `trade.yuzhiran.com/` — static marketing HTML
|
||
- **SPA**: `trade.yuzhiran.com/app/` — uni-app build (mobile)
|
||
- **Admin**: `trade.yuzhiran.com/admin/` — Vue 3 + Element Plus (standalone)
|
||
- **Workspace**: `trade.yuzhiran.com/workspace/` — Vue 3 + Element Plus (standalone)
|
||
- **Nginx**: SPA fallbacks for `/app/`, `/admin/`, `/workspace/`
|
||
- **vite config**: each project has its own `base` path and dev port
|
||
- **API**: proxied via nginx `location /api/` to `127.0.0.1:8000`
|
||
- **Makefile `make deploy`** references `docker-compose.prod.yml` / `docker-compose.staging.yml`, which do **not** exist (only `docker-compose.yml` is present). Those targets are currently broken.
|
||
|
||
## Critical Quirks
|
||
|
||
- **Route ordering**: FastAPI matches top-down. Specific routes (`/{customer_id}/health`) must be registered **before** wildcard `/{customer_id}`.
|
||
- **AI `extract_info`**: Some models (e.g. deepseek-v4-flash) don't support `response_format={"type": "json_object"}`. `openai.py` catches the failure and retries without it.
|
||
- **Manual auth on some endpoints**: `keywords` and `competitor-analysis` endpoints use `authorization: str = Header(None)` instead of `Depends(get_current_user_id)`.
|
||
- **MarketingService fallback**: When no AI providers initialized, returns template content instead of crashing.
|
||
- **Onboarding service**: calls `mkt.generate(product_info={"name": ..., ...})`, not keyword args. Check `onboarding.py` for the exact dict shape.
|
||
- **CustomerHealthService**: `get_health_overview` endpoint must use `CustomerHealthService(db)` not `CustomerService(db)`.
|
||
- **CSRF**: Sensitive endpoints (auth/payment/profile) require `X-CSRF-Token` header. Token available via `csrf_token` cookie / `X-CSRF-Token` response header.
|
||
- **AI Router reload**: After modifying AI providers via admin API, call `POST /api/v1/admin/ai/reload` to refresh in-memory providers.
|
||
- **Payment**: Uses unified `pay-api` gateway (`UnifiedPayService`). NOT direct WeChat/Alipay integration. Credentials: `PAY_API_KEY`/`PAY_API_SECRET` from `.env`. HMAC-SHA256 auth. Webhook at `POST /api/v1/payment/webhook` skips CSRF.
|
||
- **Payment gateway config**: `PAY_API_KEY`, `PAY_API_SECRET`, `PAY_API_BASE_URL`, `PAY_WEBHOOK_URL` in `config.py`. `pay_type` param: `"alipay"` (returns `pay_url`) or `"wechat"` (returns `code_url`). `UnifiedPayService` normalizes legacy `native`/`jsapi`/`pc` to `wechat`/`alipay`.
|
||
- **Stripe**: `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET` in `.env`. `StripePaymentService` via Checkout Sessions. Selected when `pay_type` is `card`/`stripe`. Webhook `POST /api/v1/payment/stripe-webhook`.
|
||
- **PayPal**: `PAYPAL_CLIENT_ID`, `PAYPAL_CLIENT_SECRET`, `PAYPAL_WEBHOOK_ID`, `PAYPAL_SANDBOX=True` in `.env`. `PayPalPaymentService` via Orders v2 API. Selected when `pay_type` is `paypal`. Webhook `POST /api/v1/payment/paypal-webhook`.
|
||
- **Credit purchase**: `POST /api/v1/credits/stripe-purchase` with `gateway: "stripe"|"paypal"` for overseas payments (USD), returns `session_url` for redirect. Gateway-agnostic: `gateway` param selects the provider.
|
||
- **Agent Pipeline timeout**: `POST /api/v1/agent/start` may take 2-3 minutes to complete (it chains search → analyze → outreach synchronously). Frontend timeout set to 300s.
|
||
- **Agent auto-save**: High-scoring leads (>=70 match_score) are auto-saved as Customer records with `source='ai_agent:{pipeline_id}'`. Duplicate check by name+user_id.
|
||
- **Agent pipeline_data JSONB**: Contains stages progress, leads array (with outreach content), and summary stats. This is the source of truth for the frontend dashboard rendering.
|
||
|
||
## Project Conventions
|
||
|
||
- **Docs**: `README.md` (overview), `PROGRESS.md` (task status), `docs/` (API/schema/architecture). README references this file for dev norms.
|
||
- **Chinese UI** — mobile-first, for foreign-trade SOHOs/small teams
|
||
- **No comments in code** unless explicitly asked
|
||
- **Commit messages** focus on "why" not "what", in English
|
||
- **Services** instantiate `MarketingService()` (no db needed). For customer health: `CustomerHealthService(db)`. For agent: `AgentOrchestrator(db)`.
|
||
- **AI providers** in `backend/app/ai/providers/` — inherit from `OpenAIProvider` if compatible with OpenAI API format
|
||
- **Static assets** go in `uni-app/src/static/`
|
||
- **Test DB**: `foreign_trade_test` (uses credentials from `conftest.py`, not `.env`)
|
||
|
||
## Remember
|
||
|
||
- Write tests for new features
|
||
- Run `cd backend && venv/bin/pytest` before committing
|
||
- Keep context compact — avoid bloating the session with unnecessary file reads
|