524 lines
16 KiB
Markdown
524 lines
16 KiB
Markdown
---
|
||
slug: tech-v2-0-full-architecture
|
||
---
|
||
|
||
# 「伴享」技术方案 V2.0 — 完整架构
|
||
|
||
**版本**: V2.0
|
||
**对应PRD**: PRD-V2.0-完整产品
|
||
**更新日期**: 2026-02-16
|
||
|
||
---
|
||
|
||
## 1. 架构演进
|
||
|
||
V2.0标志着产品从MVP走向完整商业化。核心变更:**商家后台Web端**、**完整9大服务板块**、**积分/优惠券/拼团**、**Elasticsearch搜索**。
|
||
|
||
### 1.1 完整架构图
|
||
|
||
```
|
||
┌───────────────────────────────────────────────────────────┐
|
||
│ 客户端层 │
|
||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────┐ │
|
||
│ │Flutter │ │子女端 │ │商家后台 │ │管理后台 │ │
|
||
│ │APP │ │小程序 │ │Web │ │Web(内部) │ │
|
||
│ └────┬────┘ └────┬────┘ └────┬────┘ └──────┬──────┘ │
|
||
└───────┼────────────┼────────────┼───────────────┼─────────┘
|
||
│ │ │ │
|
||
┌───────▼────────────▼────────────▼───────────────▼─────────┐
|
||
│ Nginx API网关 │
|
||
│ /api/v1/* → APP /api/merchant/* → 商家 │
|
||
│ /api/child/* → 子女 /api/admin/* → 管理 │
|
||
└────────────────────────┬──────────────────────────────────┘
|
||
│
|
||
┌────────────────────────▼──────────────────────────────────┐
|
||
│ 业务服务层 (Node.js) │
|
||
│ 用户│活动│AI管家│医疗│支付│通知│队长│会员│健康│子女│社区 │
|
||
│ 商家│积分│优惠券│拼团│家政│配送│候鸟│文教│法律│设备│课程 │
|
||
└────────────────────────┬──────────────────────────────────┘
|
||
│
|
||
┌────────────────────────▼──────────────────────────────────┐
|
||
│ Worker层 │
|
||
│ 健康同步│预警检测│队长等级│结算│积分过期│排行榜│会员到期 │
|
||
└────────────────────────┬──────────────────────────────────┘
|
||
│
|
||
┌────────────────────────▼──────────────────────────────────┐
|
||
│ 数据层 │
|
||
│ PostgreSQL │ Redis │ OSS │ Elasticsearch │
|
||
└───────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 1.2 新增技术组件
|
||
|
||
| 组件 | 用途 | 版本 |
|
||
|------|------|------|
|
||
| Elasticsearch | 全文搜索+日志 | 8.x |
|
||
| React + Ant Design Pro | 商家后台 | React 18 |
|
||
| Bull | 任务队列 | 4.x |
|
||
|
||
---
|
||
|
||
## 2. 商家后台架构
|
||
|
||
### 2.1 技术选型
|
||
|
||
- **前端**: React 18 + Ant Design Pro + ECharts + Vite
|
||
- **状态管理**: Zustand
|
||
- **部署**: Nginx静态托管 + CDN
|
||
|
||
### 2.2 项目结构
|
||
|
||
```
|
||
banxiang-merchant-web/
|
||
├── src/
|
||
│ ├── pages/
|
||
│ │ ├── login/ # 登录
|
||
│ │ ├── register/ # 注册+资质
|
||
│ │ ├── dashboard/ # 数据看板
|
||
│ │ ├── services/ # 服务管理
|
||
│ │ ├── orders/ # 订单管理
|
||
│ │ ├── finance/ # 财务结算
|
||
│ │ ├── reviews/ # 评价管理
|
||
│ │ └── settings/ # 店铺设置
|
||
│ ├── components/
|
||
│ ├── services/api.ts
|
||
│ └── stores/
|
||
└── package.json
|
||
```
|
||
|
||
### 2.3 增量DDL
|
||
|
||
```sql
|
||
-- ===========================
|
||
-- V2.0 增量DDL
|
||
-- ===========================
|
||
|
||
-- 1. 商家
|
||
CREATE TABLE merchants (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
company_name VARCHAR(200) NOT NULL,
|
||
credit_code VARCHAR(18) UNIQUE,
|
||
category VARCHAR(50) NOT NULL,
|
||
store_name VARCHAR(100),
|
||
store_description TEXT,
|
||
store_logo_url TEXT,
|
||
contact_name VARCHAR(50),
|
||
contact_phone VARCHAR(11),
|
||
contact_email VARCHAR(100),
|
||
business_license_url TEXT,
|
||
industry_license_url TEXT,
|
||
other_licenses TEXT[],
|
||
address TEXT,
|
||
lat DECIMAL(10,7),
|
||
lng DECIMAL(10,7),
|
||
service_area TEXT[],
|
||
business_hours JSONB,
|
||
annual_fee DECIMAL(10,2) DEFAULT 0,
|
||
commission_rate DECIMAL(4,2),
|
||
level VARCHAR(20) DEFAULT 'normal'
|
||
CHECK (level IN ('normal', 'certified', 'strategic')),
|
||
rating DECIMAL(2,1) DEFAULT 5.0,
|
||
total_orders INTEGER DEFAULT 0,
|
||
total_revenue DECIMAL(12,2) DEFAULT 0,
|
||
status VARCHAR(20) DEFAULT 'pending',
|
||
approved_at TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE merchant_accounts (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
merchant_id BIGINT REFERENCES merchants(id),
|
||
phone VARCHAR(11) UNIQUE NOT NULL,
|
||
password_hash VARCHAR(100),
|
||
role VARCHAR(20) DEFAULT 'owner',
|
||
last_login_at TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE merchant_services (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
merchant_id BIGINT REFERENCES merchants(id),
|
||
title VARCHAR(200) NOT NULL,
|
||
category VARCHAR(50),
|
||
subcategory VARCHAR(50),
|
||
description TEXT,
|
||
images TEXT[],
|
||
price DECIMAL(10,2),
|
||
original_price DECIMAL(10,2),
|
||
price_unit VARCHAR(20),
|
||
stock INTEGER,
|
||
service_duration VARCHAR(50),
|
||
is_online BOOLEAN DEFAULT TRUE,
|
||
sales_count INTEGER DEFAULT 0,
|
||
rating DECIMAL(2,1) DEFAULT 5.0,
|
||
status VARCHAR(20) DEFAULT 'active',
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE merchant_settlements (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
merchant_id BIGINT REFERENCES merchants(id),
|
||
period_start DATE,
|
||
period_end DATE,
|
||
total_orders INTEGER,
|
||
gross_amount DECIMAL(12,2),
|
||
commission_amount DECIMAL(12,2),
|
||
net_amount DECIMAL(12,2),
|
||
bank_account_encrypted JSONB,
|
||
status VARCHAR(20) DEFAULT 'pending',
|
||
paid_at TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE merchant_daily_stats (
|
||
merchant_id BIGINT REFERENCES merchants(id),
|
||
stat_date DATE,
|
||
page_views INTEGER DEFAULT 0,
|
||
order_count INTEGER DEFAULT 0,
|
||
revenue DECIMAL(10,2) DEFAULT 0,
|
||
avg_rating DECIMAL(2,1),
|
||
PRIMARY KEY(merchant_id, stat_date)
|
||
);
|
||
|
||
-- 2. 积分
|
||
CREATE TABLE point_accounts (
|
||
user_id BIGINT PRIMARY KEY REFERENCES users(id),
|
||
total_points INTEGER DEFAULT 0,
|
||
available_points INTEGER DEFAULT 0,
|
||
used_points INTEGER DEFAULT 0,
|
||
expired_points INTEGER DEFAULT 0,
|
||
updated_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE point_transactions (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
user_id BIGINT REFERENCES users(id),
|
||
type VARCHAR(20),
|
||
action VARCHAR(50),
|
||
points INTEGER,
|
||
balance INTEGER,
|
||
reference_id VARCHAR(50),
|
||
description TEXT,
|
||
expires_at TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE point_products (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
title VARCHAR(100),
|
||
description TEXT,
|
||
image_url TEXT,
|
||
points_required INTEGER,
|
||
stock INTEGER,
|
||
category VARCHAR(20),
|
||
status VARCHAR(20) DEFAULT 'active',
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- 3. 优惠券
|
||
CREATE TABLE coupon_templates (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
title VARCHAR(100),
|
||
type VARCHAR(20),
|
||
value DECIMAL(10,2),
|
||
min_amount DECIMAL(10,2),
|
||
applicable_categories TEXT[],
|
||
merchant_id BIGINT REFERENCES merchants(id),
|
||
total_count INTEGER,
|
||
issued_count INTEGER DEFAULT 0,
|
||
valid_days INTEGER,
|
||
status VARCHAR(20) DEFAULT 'active',
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE user_coupons (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
user_id BIGINT REFERENCES users(id),
|
||
template_id BIGINT REFERENCES coupon_templates(id),
|
||
status VARCHAR(20) DEFAULT 'available',
|
||
used_order_no VARCHAR(20),
|
||
expires_at TIMESTAMP,
|
||
used_at TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- 4. 拼团
|
||
CREATE TABLE group_buy_campaigns (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
service_id BIGINT REFERENCES merchant_services(id),
|
||
original_price DECIMAL(10,2),
|
||
group_price DECIMAL(10,2),
|
||
min_members INTEGER DEFAULT 3,
|
||
valid_hours INTEGER DEFAULT 24,
|
||
status VARCHAR(20) DEFAULT 'active',
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE group_buy_orders (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
campaign_id BIGINT REFERENCES group_buy_campaigns(id),
|
||
initiator_id BIGINT REFERENCES users(id),
|
||
current_members INTEGER DEFAULT 1,
|
||
status VARCHAR(20) DEFAULT 'pending',
|
||
expires_at TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE group_buy_members (
|
||
group_order_id BIGINT REFERENCES group_buy_orders(id),
|
||
user_id BIGINT REFERENCES users(id),
|
||
order_no VARCHAR(20),
|
||
joined_at TIMESTAMP DEFAULT NOW(),
|
||
PRIMARY KEY(group_order_id, user_id)
|
||
);
|
||
|
||
-- 5. 课程
|
||
CREATE TABLE courses (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
title VARCHAR(200),
|
||
category VARCHAR(50),
|
||
instructor_name VARCHAR(50),
|
||
description TEXT,
|
||
cover_image TEXT,
|
||
type VARCHAR(20),
|
||
video_url TEXT,
|
||
live_room_id VARCHAR(50),
|
||
scheduled_at TIMESTAMP,
|
||
duration_minutes INTEGER,
|
||
price DECIMAL(10,2) DEFAULT 0,
|
||
enrollment_count INTEGER DEFAULT 0,
|
||
rating DECIMAL(2,1) DEFAULT 5.0,
|
||
status VARCHAR(20) DEFAULT 'active',
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE course_enrollments (
|
||
course_id BIGINT REFERENCES courses(id),
|
||
user_id BIGINT REFERENCES users(id),
|
||
progress DECIMAL(5,2) DEFAULT 0,
|
||
completed BOOLEAN DEFAULT FALSE,
|
||
enrolled_at TIMESTAMP DEFAULT NOW(),
|
||
PRIMARY KEY(course_id, user_id)
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 商家API端点
|
||
|
||
| 方法 | 路径 | 描述 |
|
||
|------|------|------|
|
||
| POST | /merchant/register | 商家注册 |
|
||
| POST | /merchant/auth/login | 登录 |
|
||
| GET | /merchant/dashboard | 看板 |
|
||
| GET/POST/PUT/DELETE | /merchant/services/* | 服务CRUD |
|
||
| GET/POST | /merchant/orders/* | 订单管理 |
|
||
| GET/POST | /merchant/settlements/* | 结算管理 |
|
||
| GET | /merchant/stats/* | 数据统计 |
|
||
| GET/POST | /merchant/reviews/* | 评价管理 |
|
||
| PUT | /merchant/settings | 店铺设置 |
|
||
| POST | /merchant/coupons | 创建优惠券 |
|
||
|
||
---
|
||
|
||
## 4. 结算系统
|
||
|
||
```javascript
|
||
// workers/settlement.js - 每月1日凌晨生成结算单
|
||
cron.schedule('0 2 1 * *', async () => {
|
||
const merchants = await db.query('SELECT * FROM merchants WHERE status = $1', ['active']);
|
||
const lastMonth = moment().subtract(1, 'month');
|
||
|
||
for (const m of merchants.rows) {
|
||
const stats = await db.query(`
|
||
SELECT COUNT(*) as cnt, COALESCE(SUM(amount), 0) as gross
|
||
FROM orders o
|
||
JOIN merchant_services ms ON o.detail->>'serviceId' = ms.id::text
|
||
WHERE ms.merchant_id = $1 AND o.status = 'completed'
|
||
AND o.completed_at BETWEEN $2 AND $3
|
||
`, [m.id, lastMonth.startOf('month').toDate(), lastMonth.endOf('month').toDate()]);
|
||
|
||
const gross = parseFloat(stats.rows[0].gross);
|
||
const commission = gross * m.commission_rate / 100;
|
||
|
||
await db.query(`
|
||
INSERT INTO merchant_settlements
|
||
(merchant_id, period_start, period_end, total_orders, gross_amount, commission_amount, net_amount)
|
||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||
`, [m.id, lastMonth.startOf('month').format('YYYY-MM-DD'),
|
||
lastMonth.endOf('month').format('YYYY-MM-DD'),
|
||
stats.rows[0].cnt, gross, commission, gross - commission]);
|
||
}
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Elasticsearch搜索
|
||
|
||
```json
|
||
// 商家/服务索引,使用ik_max_word分词器
|
||
// 支持:全文搜索 + 地理位置排序 + 分类筛选 + 评分排序
|
||
```
|
||
|
||
```javascript
|
||
// GET /api/v1/search?q=保洁&category=housekeeping&lat=30.57&lng=104.07
|
||
router.get('/search', async (req, res) => {
|
||
const { q, category, lat, lng, page = 1, size = 20 } = req.query;
|
||
const result = await esClient.search({
|
||
index: 'banxiang_services',
|
||
body: {
|
||
query: {
|
||
bool: {
|
||
must: [{ multi_match: { query: q, fields: ['title^2', 'description'] } }],
|
||
filter: category ? [{ term: { category } }] : []
|
||
}
|
||
},
|
||
sort: lat ? [{ _geo_distance: { location: { lat, lon: lng }, order: 'asc' } }] : [{ salesCount: 'desc' }],
|
||
from: (page - 1) * size, size
|
||
}
|
||
});
|
||
res.json({ success: true, data: result.hits });
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 完整部署方案
|
||
|
||
### 6.1 服务器配置
|
||
|
||
| 服务 | 配置 | 月费 |
|
||
|------|------|------|
|
||
| 应用服务器 | ECS 4核8G × 2 | ¥800 |
|
||
| 数据库 | RDS PG 4核8G(主从) | ¥600 |
|
||
| Redis | 2G | ¥150 |
|
||
| Elasticsearch | 2核4G | ¥300 |
|
||
| OSS + CDN | 按量 | ¥200 |
|
||
| **月合计** | | **¥2050** |
|
||
|
||
### 6.2 Docker Compose
|
||
|
||
```yaml
|
||
version: '3.8'
|
||
services:
|
||
app:
|
||
build: .
|
||
ports: ["3000:3000"]
|
||
deploy: { replicas: 2 }
|
||
depends_on: [db, redis, es]
|
||
restart: always
|
||
worker:
|
||
build: .
|
||
command: node workers/index.js
|
||
depends_on: [db, redis]
|
||
restart: always
|
||
db:
|
||
image: postgres:15
|
||
volumes: [pgdata:/var/lib/postgresql/data]
|
||
restart: always
|
||
redis:
|
||
image: redis:7-alpine
|
||
volumes: [redisdata:/data]
|
||
restart: always
|
||
es:
|
||
image: elasticsearch:8.12.0
|
||
environment:
|
||
- discovery.type=single-node
|
||
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
|
||
volumes: [esdata:/usr/share/elasticsearch/data]
|
||
restart: always
|
||
nginx:
|
||
image: nginx:alpine
|
||
ports: ["80:80", "443:443"]
|
||
volumes:
|
||
- ./nginx.conf:/etc/nginx/nginx.conf
|
||
- ./merchant-web/dist:/var/www/merchant
|
||
depends_on: [app]
|
||
restart: always
|
||
volumes:
|
||
pgdata:
|
||
redisdata:
|
||
esdata:
|
||
```
|
||
|
||
### 6.3 Nginx关键配置
|
||
|
||
```nginx
|
||
# APP API + SSE支持
|
||
server {
|
||
listen 443 ssl;
|
||
server_name api.banxiang.com;
|
||
location /api/ { proxy_pass http://app:3000; }
|
||
location /api/v1/ai/chat {
|
||
proxy_pass http://app:3000;
|
||
proxy_buffering off;
|
||
proxy_http_version 1.1;
|
||
}
|
||
}
|
||
# 商家后台SPA
|
||
server {
|
||
listen 443 ssl;
|
||
server_name merchant.banxiang.com;
|
||
root /var/www/merchant;
|
||
location / { try_files $uri /index.html; }
|
||
location /api/merchant/ { proxy_pass http://app:3000; }
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 数据库表总览(全版本49张表)
|
||
|
||
| 版本 | 表数 | 核心表 |
|
||
|------|------|--------|
|
||
| V1.0 | 17张 | users, activities, ai_conversations, orders, hospitals等 |
|
||
| V1.1 | 9张 | captains, memberships, service_providers, products等 |
|
||
| V1.2 | 11张 | health_records, child_users, posts, service_products等 |
|
||
| V2.0 | 12张 | merchants, point_accounts, coupon_templates, courses等 |
|
||
| **合计** | **49张** | |
|
||
|
||
---
|
||
|
||
## 8. 向微服务演进路线
|
||
|
||
```
|
||
V2.0 (当前): 模块化单体
|
||
→ 代码按服务边界分离,共享数据库
|
||
|
||
V3.0 (计划): 拆分核心服务
|
||
→ 用户服务(独立DB)
|
||
→ 活动服务(独立DB)
|
||
→ AI管家服务(独立,GPU资源)
|
||
→ 其余保持单体
|
||
|
||
V4.0 (远期): 完整微服务
|
||
→ 所有服务独立
|
||
→ API Gateway统一入口
|
||
→ 服务间gRPC通信
|
||
→ K8s编排
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 安全合规清单
|
||
|
||
| 项目 | 状态 | 说明 |
|
||
|------|------|------|
|
||
| 《个人信息保护法》合规 | ✅ | 最小收集、明确告知、分项授权 |
|
||
| 数据加密 | ✅ | TLS 1.3 + AES-256 |
|
||
| 健康数据隔离 | ✅ | 单独加密存储 |
|
||
| 医疗免责声明 | ✅ | 所有页面标注 |
|
||
| 金融合规 | ✅ | 仅信息展示,不销售 |
|
||
| 老年人权益 | ✅ | 无自动续费、大额二次确认 |
|
||
| RBAC权限 | ✅ | 用户/商家/管理员角色分离 |
|
||
| 审计日志 | ✅ | 全操作记录 |
|
||
| 数据备份 | ✅ | 每日自动+跨区域 |
|
||
| 安全渗透测试 | 📋 | V2.0上线前完成 |
|
||
|
||
---
|
||
|
||
**文档结束**
|