| 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
-- ===========================
-- 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. 结算系统
// 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搜索
// 商家/服务索引,使用ik_max_word分词器
// 支持:全文搜索 + 地理位置排序 + 分类筛选 + 评分排序
// 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
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关键配置
# 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上线前完成 |
文档结束