--- slug: tech-v1-0-mvp-architecture --- # 「伴享」技术方案 V1.0 — MVP架构 **版本**: V1.0 **对应PRD**: PRD-V1.0-MVP核心功能 **更新日期**: 2026-02-16 --- ## 1. 技术架构总览 ### 1.1 系统架构图 ``` ┌────────────────────────────────────────────────────┐ │ 客户端层 │ │ ┌──────────────────┐ ┌───────────────────────┐ │ │ │ Flutter APP │ │ 子女端(V1.2预留) │ │ │ │ iOS + Android │ │ 微信小程序 │ │ │ └────────┬─────────┘ └───────────────────────┘ │ └───────────┼────────────────────────────────────────┘ │ HTTPS + WebSocket ┌───────────▼────────────────────────────────────────┐ │ API网关层(Nginx) │ │ SSL终止 │ 限流 │ 日志 │ 路由 │ CORS │ 压缩 │ └───────────┬────────────────────────────────────────┘ │ ┌───────────▼────────────────────────────────────────┐ │ 业务服务层(Node.js + Express) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 用户服务 │ │ 活动服务 │ │ AI管家 │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 医疗服务 │ │ 支付服务 │ │ 通知服务 │ │ │ └──────────┘ └──────────┘ └──────────┘ │ └───────────┬────────────────────────────────────────┘ │ ┌───────────▼────────────────────────────────────────┐ │ 数据层 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │PostgreSQL│ │ Redis │ │ 阿里云OSS │ │ │ └──────────┘ └──────────┘ └──────────┘ │ └────────────────────────────────────────────────────┘ ``` ### 1.2 技术选型 | 层级 | 技术 | 版本 | 选型理由 | |------|------|------|----------| | 前端 | Flutter | 3.x | 跨平台、性能好、适老化组件丰富 | | 后端 | Node.js + Express | 22 + 4.x | 生态成熟、AI集成方便 | | 数据库 | PostgreSQL | 15+ | JSON支持好、地理空间查询 | | 缓存 | Redis | 7.x | 会话管理、限流、缓存 | | 文件存储 | 阿里云OSS | - | 图片/语音文件 | | AI模型 | 通义千问 | qwen-max | 国产、函数调用支持好 | | 语音 | 讯飞ASR/TTS | - | 中文识别准确率高 | | 地图 | 高德地图 | - | 国内POI数据全 | | 支付 | 微信支付V3 | - | 银发群体使用率高 | | 推送 | JPush | - | 全平台推送 | | 部署 | Docker Compose | - | MVP阶段够用 | --- ## 2. 数据库设计 ### 2.1 ER关系概览 ``` users ──< activity_participants >── activities users ──< ai_conversations users ──< orders users ──< appointments >── doctors >── departments >── hospitals users ──< consultations >── doctors users ──< family_links users ──< notifications users ── ai_user_preferences ``` ### 2.2 完整DDL ```sql -- =========================== -- 伴享 V1.0 DDL -- PostgreSQL 15+ -- =========================== CREATE EXTENSION IF NOT EXISTS earthdistance CASCADE; CREATE EXTENSION IF NOT EXISTS pgcrypto; -- 1. 用户表 CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, phone VARCHAR(11) UNIQUE NOT NULL, nickname VARCHAR(50), avatar_url TEXT, birth_year INTEGER, birth_month INTEGER, gender VARCHAR(10) CHECK (gender IN ('male', 'female', 'other')), city VARCHAR(50) DEFAULT '成都', district VARCHAR(50), interests TEXT[] DEFAULT '{}', real_name VARCHAR(50), id_card_hash VARCHAR(64), id_card_encrypted TEXT, verified BOOLEAN DEFAULT FALSE, emergency_contact_name VARCHAR(50), emergency_contact_phone VARCHAR(11), font_size VARCHAR(10) DEFAULT 'medium', speech_speed VARCHAR(10) DEFAULT 'normal', auto_voice BOOLEAN DEFAULT TRUE, last_login_at TIMESTAMP, login_count INTEGER DEFAULT 0, status VARCHAR(20) DEFAULT 'active', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_users_phone ON users(phone); CREATE INDEX idx_users_city ON users(city); CREATE INDEX idx_users_interests ON users USING GIN(interests); -- 2. 短信验证码 CREATE TABLE sms_codes ( id BIGSERIAL PRIMARY KEY, phone VARCHAR(11) NOT NULL, code VARCHAR(6) NOT NULL, purpose VARCHAR(20) DEFAULT 'login', used BOOLEAN DEFAULT FALSE, expires_at TIMESTAMP NOT NULL, created_at TIMESTAMP DEFAULT NOW() ); -- 3. 家庭关联 CREATE TABLE family_links ( id BIGSERIAL PRIMARY KEY, parent_user_id BIGINT REFERENCES users(id), child_user_id BIGINT, invite_code VARCHAR(6), status VARCHAR(20) DEFAULT 'active', linked_at TIMESTAMP DEFAULT NOW(), UNIQUE(parent_user_id, child_user_id) ); CREATE TABLE invite_codes ( id BIGSERIAL PRIMARY KEY, user_id BIGINT REFERENCES users(id), code VARCHAR(6) UNIQUE NOT NULL, used BOOLEAN DEFAULT FALSE, expires_at TIMESTAMP NOT NULL, created_at TIMESTAMP DEFAULT NOW() ); -- 4. 活动表 CREATE TABLE activities ( id BIGSERIAL PRIMARY KEY, creator_id BIGINT REFERENCES users(id) NOT NULL, title VARCHAR(100) NOT NULL, category VARCHAR(50) NOT NULL, description TEXT, cover_image_url TEXT, location_lat DECIMAL(10,7) NOT NULL, location_lng DECIMAL(10,7) NOT NULL, location_address TEXT NOT NULL, location_name VARCHAR(100), start_time TIMESTAMP NOT NULL, end_time TIMESTAMP, max_participants INTEGER DEFAULT 10 CHECK (max_participants BETWEEN 5 AND 15), current_participants INTEGER DEFAULT 0, status VARCHAR(20) DEFAULT 'upcoming', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_activities_status_time ON activities(status, start_time); CREATE INDEX idx_activities_category ON activities(category); -- 5. 活动报名 CREATE TABLE activity_participants ( id BIGSERIAL PRIMARY KEY, activity_id BIGINT REFERENCES activities(id), user_id BIGINT REFERENCES users(id), status VARCHAR(20) DEFAULT 'registered', signed_in_at TIMESTAMP, signed_in_lat DECIMAL(10,7), signed_in_lng DECIMAL(10,7), rating INTEGER CHECK (rating BETWEEN 1 AND 5), review TEXT, joined_at TIMESTAMP DEFAULT NOW(), cancelled_at TIMESTAMP, UNIQUE(activity_id, user_id) ); -- 6. AI对话 CREATE TABLE ai_conversations ( id BIGSERIAL PRIMARY KEY, user_id BIGINT REFERENCES users(id), session_id VARCHAR(36) NOT NULL, role VARCHAR(20) NOT NULL, content TEXT NOT NULL, content_type VARCHAR(20) DEFAULT 'text', voice_url TEXT, intent VARCHAR(50), metadata JSONB, created_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_ai_conv_user ON ai_conversations(user_id, session_id); CREATE TABLE ai_user_preferences ( user_id BIGINT PRIMARY KEY REFERENCES users(id), preferred_hospital VARCHAR(100), preferred_doctor VARCHAR(100), home_address TEXT, common_destinations JSONB, dietary_restrictions TEXT[], updated_at TIMESTAMP DEFAULT NOW() ); -- 7. 医院/科室/医生/排班 CREATE TABLE hospitals ( id BIGSERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, address TEXT, lat DECIMAL(10,7), lng DECIMAL(10,7), phone VARCHAR(20), logo_url TEXT, level VARCHAR(20), status VARCHAR(20) DEFAULT 'active', created_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE departments ( id BIGSERIAL PRIMARY KEY, hospital_id BIGINT REFERENCES hospitals(id), name VARCHAR(50) NOT NULL, description TEXT, sort_order INTEGER DEFAULT 0 ); CREATE TABLE doctors ( id BIGSERIAL PRIMARY KEY, hospital_id BIGINT REFERENCES hospitals(id), department_id BIGINT REFERENCES departments(id), name VARCHAR(50) NOT NULL, title VARCHAR(50), avatar_url TEXT, specialty TEXT, rating DECIMAL(2,1) DEFAULT 5.0, rating_count INTEGER DEFAULT 0, status VARCHAR(20) DEFAULT 'active' ); CREATE TABLE doctor_schedules ( id BIGSERIAL PRIMARY KEY, doctor_id BIGINT REFERENCES doctors(id), schedule_date DATE NOT NULL, start_time TIME NOT NULL, end_time TIME NOT NULL, max_patients INTEGER DEFAULT 30, current_patients INTEGER DEFAULT 0, fee DECIMAL(10,2), status VARCHAR(20) DEFAULT 'available' ); -- 8. 预约/问诊 CREATE TABLE appointments ( id BIGSERIAL PRIMARY KEY, order_no VARCHAR(20) UNIQUE NOT NULL, user_id BIGINT REFERENCES users(id), hospital_id BIGINT REFERENCES hospitals(id), department_id BIGINT REFERENCES departments(id), doctor_id BIGINT REFERENCES doctors(id), schedule_id BIGINT REFERENCES doctor_schedules(id), patient_name VARCHAR(50), patient_phone VARCHAR(11), appointment_date DATE, appointment_time TIME, fee DECIMAL(10,2), status VARCHAR(20) DEFAULT 'pending', paid_at TIMESTAMP, cancelled_at TIMESTAMP, cancel_reason TEXT, created_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE consultations ( id BIGSERIAL PRIMARY KEY, order_no VARCHAR(20) UNIQUE NOT NULL, user_id BIGINT REFERENCES users(id), doctor_id BIGINT REFERENCES doctors(id), symptom_description TEXT, images TEXT[], doctor_reply TEXT, fee DECIMAL(10,2) DEFAULT 19.90, status VARCHAR(20) DEFAULT 'pending', replied_at TIMESTAMP, created_at TIMESTAMP DEFAULT NOW() ); -- 9. 订单 CREATE TABLE orders ( id BIGSERIAL PRIMARY KEY, order_no VARCHAR(20) UNIQUE NOT NULL, user_id BIGINT REFERENCES users(id), order_type VARCHAR(50) NOT NULL, amount DECIMAL(10,2) NOT NULL, status VARCHAR(20) DEFAULT 'pending', detail JSONB, wx_transaction_id VARCHAR(50), paid_at TIMESTAMP, completed_at TIMESTAMP, cancelled_at TIMESTAMP, refund_amount DECIMAL(10,2), refund_at TIMESTAMP, refund_reason TEXT, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_orders_user ON orders(user_id, created_at DESC); -- 10. 通知 CREATE TABLE notifications ( id BIGSERIAL PRIMARY KEY, user_id BIGINT REFERENCES users(id), type VARCHAR(50) NOT NULL, title VARCHAR(100), content TEXT, data JSONB, is_read BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_notif_user ON notifications(user_id, is_read, created_at DESC); -- 11. 审计日志 CREATE TABLE audit_logs ( id BIGSERIAL PRIMARY KEY, user_id BIGINT, action VARCHAR(50), resource_type VARCHAR(50), resource_id BIGINT, detail JSONB, ip_address INET, created_at TIMESTAMP DEFAULT NOW() ); ``` --- ## 3. API文档 ### 3.1 规范 - **Base URL**: `https://api.banxiang.com/api/v1` - **认证**: `Authorization: Bearer ` - **响应格式**: `{ "success": true, "data": {...} }` / `{ "success": false, "error": {"code":"...", "message":"..."} }` ### 3.2 完整接口清单 | 模块 | 方法 | 路径 | 描述 | |------|------|------|------| | 认证 | POST | /auth/send-code | 发送验证码 | | 认证 | POST | /auth/login | 登录/注册 | | 认证 | POST | /auth/refresh | 刷新Token | | 用户 | GET | /users/me | 获取当前用户 | | 用户 | PUT | /users/profile | 更新资料 | | 用户 | POST | /users/verify | 实名认证 | | 用户 | PUT | /users/emergency-contact | 紧急联系人 | | 用户 | PUT | /users/settings | 更新设置 | | 家庭 | POST | /family/generate-code | 生成邀请码 | | 家庭 | POST | /family/link | 绑定子女 | | 家庭 | GET | /family/members | 家人列表 | | 活动 | GET | /activities | 活动列表 | | 活动 | GET | /activities/:id | 活动详情 | | 活动 | POST | /activities | 创建活动 | | 活动 | PUT | /activities/:id | 修改活动 | | 活动 | DELETE | /activities/:id | 取消活动 | | 活动 | POST | /activities/:id/join | 报名 | | 活动 | POST | /activities/:id/cancel | 取消报名 | | 活动 | POST | /activities/:id/sign-in | 签到 | | 活动 | POST | /activities/:id/review | 评价 | | 活动 | GET | /users/me/activities | 我的活动 | | AI | POST | /ai/chat | 文字对话(SSE) | | AI | POST | /ai/voice | 语音对话 | | AI | GET | /ai/history | 对话历史 | | 医疗 | GET | /medical/hospitals | 医院列表 | | 医疗 | GET | /medical/hospitals/:id/departments | 科室 | | 医疗 | GET | /medical/doctors | 医生列表 | | 医疗 | GET | /medical/doctors/:id/schedules | 排班 | | 医疗 | POST | /medical/appointments | 创建预约 | | 医疗 | POST | /medical/appointments/:id/cancel | 取消 | | 医疗 | POST | /medical/consultations | 创建问诊 | | 订单 | POST | /orders/create | 创建订单 | | 订单 | GET | /orders | 订单列表 | | 订单 | GET | /orders/:orderNo | 订单详情 | | 订单 | POST | /orders/:orderNo/refund | 退款 | | 通知 | GET | /notifications | 通知列表 | | 通知 | PUT | /notifications/:id/read | 标记已读 | | 上传 | POST | /upload/image | 上传图片 | | 上传 | POST | /upload/voice | 上传语音 | --- ## 4. Flutter组件架构 ### 4.1 项目结构 ``` banxiang_app/ ├── lib/ │ ├── main.dart │ ├── app.dart │ ├── config/ │ │ ├── theme.dart # 适老化主题 │ │ ├── routes.dart │ │ └── constants.dart │ ├── core/ │ │ ├── api/ │ │ │ ├── api_client.dart # Dio封装 │ │ │ └── endpoints.dart │ │ ├── models/ # 数据模型 │ │ ├── providers/ # Riverpod状态管理 │ │ ├── services/ # 业务服务 │ │ └── utils/ │ ├── features/ │ │ ├── auth/ │ │ ├── home/ │ │ ├── activity/ │ │ ├── ai_butler/ │ │ ├── medical/ │ │ ├── profile/ │ │ └── notification/ │ └── shared/ │ ├── widgets/ # BX适老化组件库 │ └── layouts/ ├── assets/ │ ├── images/ │ ├── fonts/ │ └── animations/ ├── test/ └── pubspec.yaml ``` ### 4.2 适老化组件库(BX Design System) ```dart /// BX适老化按钮 class BxButton extends StatelessWidget { final String text; final VoidCallback onPressed; final BxButtonStyle style; // primary / secondary / danger final bool loading; // 最小高度48dp,字号18sp,圆角12dp // 点击区域≥48x48dp // loading状态显示转圈+文字 } /// BX适老化输入框 class BxInput extends StatelessWidget { final String label; final String hint; final TextInputType keyboardType; final bool voiceEnabled; // 右侧语音输入按钮 // 高度56dp,字号18sp // label在输入框上方 // 错误提示在下方,红色16sp } /// BX确认弹窗(防误操作) class BxConfirmDialog extends StatelessWidget { final String title; final String message; final String confirmText; final String cancelText; // 标题22sp,正文18sp // 按钮大且间隔远 // 危险操作confirmText用红色 } /// BX活动卡片 class BxActivityCard extends StatelessWidget { final Activity activity; final double distance; // 大标题18sp,时间地点16sp // 报名按钮在右侧 // 已满员显示灰色 } ``` ### 4.3 核心代码示例 #### API客户端 ```dart // core/api/api_client.dart class ApiClient { late final Dio _dio; ApiClient() { _dio = Dio(BaseOptions( baseUrl: 'https://api.banxiang.com/api/v1', connectTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 30), )); _dio.interceptors.addAll([ AuthInterceptor(), // 自动附加JWT LogInterceptor(), ErrorInterceptor(), // 统一错误处理 ]); } Future get(String path, {Map? params}) async { final response = await _dio.get(path, queryParameters: params); return response.data['data'] as T; } Future post(String path, {dynamic data}) async { final response = await _dio.post(path, data: data); return response.data['data'] as T; } } ``` #### AI管家对话页面 ```dart // features/ai_butler/chat_page.dart class AiChatPage extends ConsumerStatefulWidget { @override ConsumerState createState() => _AiChatPageState(); } class _AiChatPageState extends ConsumerState { final _controller = TextEditingController(); bool _isRecording = false; @override Widget build(BuildContext context) { final messages = ref.watch(aiChatProvider); return Scaffold( appBar: AppBar(title: Text('🤖 小伴 · AI管家')), body: Column( children: [ // 消息列表 Expanded( child: ListView.builder( reverse: true, itemCount: messages.length, itemBuilder: (ctx, i) => ChatBubble( message: messages[i], fontSize: ref.watch(fontSizeProvider), ), ), ), // 快捷指令栏 QuickActions( actions: ['附近活动', '挂号', '买菜', '天气'], onTap: (action) => _sendMessage(action), ), // 输入栏 ChatInputBar( controller: _controller, onSend: () => _sendMessage(_controller.text), onVoiceStart: _startRecording, onVoiceEnd: _stopRecording, isRecording: _isRecording, ), ], ), ); } void _sendMessage(String text) { ref.read(aiChatProvider.notifier).sendMessage(text); _controller.clear(); } } ``` #### 活动推荐算法 ```dart // core/services/recommendation_service.dart double calculateRecommendScore(User user, Activity activity, double distanceKm) { // 兴趣匹配度 (0-1) final commonInterests = user.interests .where((i) => i == activity.category) .length; final interestScore = commonInterests > 0 ? 1.0 : 0.0; // 距离分 (0-1), 10km内线性衰减 final distanceScore = 1 - (distanceKm / 10).clamp(0, 1); // 时间分 (0-1), 168小时(一周)内线性衰减 final hoursDiff = activity.startTime.difference(DateTime.now()).inHours; final timeScore = 1 - (hoursDiff / 168).clamp(0, 1); // 热度分 (0-1) final hotScore = activity.currentParticipants / activity.maxParticipants; return interestScore * 0.4 + distanceScore * 0.3 + timeScore * 0.2 + hotScore * 0.1; } ``` --- ## 5. AI管家技术方案 ### 5.1 架构 ``` 用户输入(文字/语音) ↓ ┌─────────────┐ │ 语音处理 │ ← 讯飞ASR(语音→文字) └──────┬──────┘ ↓ ┌─────────────┐ │ 意图识别 │ ← 通义千问 Function Calling └──────┬──────┘ ↓ ┌─────────────────────────────┐ │ 任务路由 │ │ ├── 活动查询 → 调用活动API │ │ ├── 挂号预约 → 调用医疗API │ │ ├── 生鲜购买 → 调用商品API │ │ └── 闲聊/咨询 → 直接对话 │ └──────┬──────────────────────┘ ↓ ┌─────────────┐ │ 响应生成 │ ← 通义千问生成回复 └──────┬──────┘ ↓ ┌─────────────┐ │ 语音合成 │ ← 讯飞TTS(文字→语音) └──────┬──────┘ ↓ 返回用户(文字+语音+操作按钮) ``` ### 5.2 Function Calling定义 ```javascript // AI工具定义 const tools = [ { type: 'function', function: { name: 'search_activities', description: '搜索附近的活动', parameters: { type: 'object', properties: { category: { type: 'string', description: '活动类型' }, timeRange: { type: 'string', enum: ['today', 'tomorrow', 'week'] }, lat: { type: 'number' }, lng: { type: 'number' } } } } }, { type: 'function', function: { name: 'book_appointment', description: '预约挂号', parameters: { type: 'object', properties: { hospitalName: { type: 'string' }, departmentName: { type: 'string' }, doctorName: { type: 'string' }, date: { type: 'string' }, time: { type: 'string' } } } } }, { type: 'function', function: { name: 'order_grocery', description: '生鲜配送下单', parameters: { type: 'object', properties: { items: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, quantity: { type: 'number' } } } }, deliveryAddress: { type: 'string' } } } } } ]; ``` ### 5.3 System Prompt ``` 你是「小伴」,「伴享」APP的AI智能管家。你服务的是50-70岁的银发群体。 规则: 1. 说话简洁、亲切、温暖,像家人一样 2. 每次回复不超过100字 3. 称呼用户为"X阿姨"或"X叔叔"(根据性别和姓氏) 4. 不使用网络用语、不说英文 5. 涉及医疗健康的建议必须加"仅供参考,建议咨询医生" 6. 涉及支付前必须明确告知金额并确认 7. 不确定的信息不要编造,说"我帮您查查" 8. 提供操作选项时,用简短的按钮文字 用户信息: - 姓名:{userName} - 城市:{city} - 兴趣:{interests} - 常去医院:{preferredHospital} - 家庭住址:{homeAddress} ``` --- ## 6. 部署方案 ### 6.1 服务器配置(MVP阶段) | 服务 | 配置 | 月费用 | |------|------|--------| | 应用服务器 | 阿里云ECS 2核4G | ¥200/月 | | 数据库 | 阿里云RDS PostgreSQL 2核4G | ¥300/月 | | Redis | 阿里云Redis 1G | ¥100/月 | | OSS | 按量计费 | ¥50/月 | | CDN | 按量计费 | ¥50/月 | | **合计** | | **¥700/月** | ### 6.2 Docker Compose ```yaml version: '3.8' services: app: build: . ports: - "3000:3000" environment: - NODE_ENV=production - DATABASE_URL=postgres://banxiang:xxx@db:5432/banxiang - REDIS_URL=redis://redis:6379 - QWEN_API_KEY=${QWEN_API_KEY} - XUNFEI_APP_ID=${XUNFEI_APP_ID} - WX_PAY_MCH_ID=${WX_PAY_MCH_ID} depends_on: - db - redis restart: always db: image: postgres:15 volumes: - pgdata:/var/lib/postgresql/data - ./init.sql:/docker-entrypoint-initdb.d/init.sql environment: - POSTGRES_DB=banxiang - POSTGRES_USER=banxiang - POSTGRES_PASSWORD=${DB_PASSWORD} restart: always redis: image: redis:7-alpine volumes: - redisdata:/data restart: always nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./ssl:/etc/nginx/ssl depends_on: - app restart: always volumes: pgdata: redisdata: ``` ### 6.3 CI/CD流程 ``` 代码推送 → GitHub Actions ├── 运行测试 ├── 构建Docker镜像 ├── 推送到阿里云容器镜像 └── SSH到服务器执行 docker compose pull && docker compose up -d ``` ### 6.4 监控方案 | 维度 | 工具 | 说明 | |------|------|------| | 应用监控 | PM2 + 阿里云ARMS | 错误率、响应时间 | | 服务器监控 | 阿里云云监控 | CPU/内存/磁盘 | | 日志 | Winston + 阿里云SLS | 结构化日志 | | 报警 | 钉钉/飞书Webhook | 异常自动通知 | --- ## 7. 安全方案 ### 7.1 数据安全 | 层面 | 措施 | |------|------| | 传输 | HTTPS + TLS 1.3 | | 存储 | 敏感字段AES-256加密 | | 身份证 | 哈希索引 + 加密存储,不存明文 | | JWT | HS256签名,7天有效期 | | 密钥管理 | 环境变量,不入代码库 | ### 7.2 接口安全 | 措施 | 配置 | |------|------| | 全局限流 | 100次/分钟/IP | | 登录限流 | 5次/分钟/手机号 | | 验证码限流 | 3次/5分钟/手机号 | | SQL注入防护 | 参数化查询 | | XSS防护 | 输出转义 + CSP头 | | CORS | 白名单域名 | --- **文档结束**