# Genex Flutter 移动端开发指南

> Consumer App（消费者端）+ Merchant App（商户核销端）

---

## 1. 技术栈概览

| 技术 | 版本 | 用途 |
|------|------|------|
| **Flutter** | 3.x | 跨平台UI框架 |
| **Dart** | 3.x | 开发语言 |
| **Riverpod** | 2.x | 状态管理（Provider替代方案，编译安全） |
| **GoRouter** | 最新 | 声明式路由、深链接 |
| **Dio** | 5.x | HTTP客户端 |
| **Freezed** | 最新 | 不可变数据模型代码生成 |
| **Hive/Isar** | 最新 | 本地持久化 |
| **WebSocket** | 内置 | AI Agent实时通信、行情推送 |
| **flutter_localizations** | 内置 | 国际化 |

---

## 2. 项目架构：Clean Architecture + Riverpod

### 2.1 目录结构

```
genex_mobile/
├── lib/
│   ├── main.dart                    # 应用入口
│   ├── app/
│   │   ├── app.dart                 # MaterialApp配置
│   │   ├── router.dart              # GoRouter路由定义
│   │   └── theme/                   # 主题配置
│   ├── core/
│   │   ├── constants/               # 常量（API地址、术语映射表）
│   │   ├── network/                 # Dio配置、拦截器、错误处理
│   │   ├── storage/                 # 本地存储封装
│   │   ├── utils/                   # 工具类
│   │   └── extensions/              # Dart扩展方法
│   ├── features/                    # 按功能模块组织
│   │   ├── auth/                    # 注册/登录
│   │   │   ├── data/
│   │   │   │   ├── datasources/     # 远程/本地数据源
│   │   │   │   ├── models/          # DTO（Freezed生成）
│   │   │   │   └── repositories/    # Repository实现
│   │   │   ├── domain/
│   │   │   │   ├── entities/        # 领域实体
│   │   │   │   ├── repositories/    # Repository接口
│   │   │   │   └── usecases/        # 用例
│   │   │   └── presentation/
│   │   │       ├── providers/       # Riverpod Providers
│   │   │       ├── pages/           # 页面Widget
│   │   │       └── widgets/         # 模块专用组件
│   │   ├── coupons/                 # 券浏览/购买/持有
│   │   ├── trading/                 # 二级市场交易
│   │   ├── wallet/                  # 余额/资产/交易记录
│   │   ├── redeem/                  # 券使用/核销
│   │   ├── transfer/                # P2P转赠
│   │   ├── profile/                 # 个人中心/KYC
│   │   ├── ai_agent/                # AI Agent对话/建议
│   │   └── merchant/                # 商户端核销（共享模块）
│   ├── shared/
│   │   ├── widgets/                 # 全局共享组件
│   │   ├── providers/               # 全局Provider
│   │   └── models/                  # 共享数据模型
│   └── l10n/                        # 国际化资源
├── test/                            # 单元/Widget测试
├── integration_test/                # 集成测试
└── pubspec.yaml
```

### 2.2 Clean Architecture 分层

```
┌────────────────────────────────────────┐
│         Presentation Layer             │
│  Pages → Widgets → Riverpod Providers  │
├────────────────────────────────────────┤
│           Domain Layer                 │
│  Entities → UseCases → Repository(接口)│
├────────────────────────────────────────┤
│            Data Layer                  │
│  Models(DTO) → DataSources → Repo实现  │
└────────────────────────────────────────┘
```

**依赖方向**：Presentation → Domain ← Data（Domain层不依赖任何外层）

---

## 3. 核心模块实现

### 3.1 术语映射（全局执行）

> 所有面向用户的UI文本必须使用Web2术语，禁止出现区块链术语。

```dart
// lib/core/constants/terminology.dart
class Terminology {
  // 用户界面术语 → 底层技术术语
  static const Map<String, String> mapping = {
    '我的账户': '链上钱包地址',
    '我的券': 'ERC-721/1155 NFT资产',
    '我的余额': '链上稳定币(USDC)余额',
    '转赠给朋友': 'P2P链上转移',
    '购买': '链上原子交换',
    '核销/使用': '合约兑付(Redemption)',
    '订单号': '交易哈希(TX Hash)',
    '安全验证': '链上签名(MPC钱包后台执行)',
  };
}
```

### 3.2 认证模块

```dart
// lib/features/auth/domain/entities/user.dart
@freezed
class User with _$User {
  const factory User({
    required String id,
    required String phone,        // 或 email
    required KycLevel kycLevel,   // L0/L1/L2/L3
    required WalletMode walletMode, // standard/pro
    String? displayName,
    String? avatar,
  }) = _User;
}

enum KycLevel { L0, L1, L2, L3 }
enum WalletMode { standard, pro }
```

```dart
// lib/features/auth/domain/usecases/register_usecase.dart
class RegisterUseCase {
  final AuthRepository _repo;
  RegisterUseCase(this._repo);

  /// 注册：手机号/邮箱 → 后台自动创建MPC钱包，用户无感知
  Future<Either<Failure, User>> call(RegisterParams params) {
    return _repo.register(
      phone: params.phone,
      email: params.email,
      password: params.password,
    );
  }
}
```

### 3.3 券资产模块

```dart
// lib/features/coupons/domain/entities/coupon.dart
@freezed
class Coupon with _$Coupon {
  const factory Coupon({
    required String id,           // 券ID（链上唯一）
    required String issuerName,   // 发行方名称
    required double faceValue,    // 面值
    required double currentPrice, // 当前市场价
    required DateTime expiryDate, // 到期日期
    required CouponStatus status, // 可用/已使用/已过期
    required CouponType type,     // utility/security
    String? imageUrl,
    String? description,
    List<String>? usageConditions,
  }) = _Coupon;
}

enum CouponStatus { available, used, expired, listed }
enum CouponType { utility, security }
```

```dart
// lib/features/coupons/presentation/providers/coupon_providers.dart
final couponListProvider = FutureProvider.autoDispose<List<Coupon>>((ref) {
  final repo = ref.watch(couponRepositoryProvider);
  return repo.getMyCoupons();
});

final couponDetailProvider = FutureProvider.autoDispose.family<Coupon, String>(
  (ref, couponId) {
    final repo = ref.watch(couponRepositoryProvider);
    return repo.getCouponDetail(couponId);
  },
);
```

### 3.4 交易模块

```dart
// lib/features/trading/domain/entities/order.dart
@freezed
class TradeOrder with _$TradeOrder {
  const factory TradeOrder({
    required String orderId,      // 订单号（映射TX Hash）
    required String couponId,
    required OrderSide side,      // buy/sell
    required double price,
    required OrderStatus status,
    required DateTime createdAt,
  }) = _TradeOrder;
}

enum OrderSide { buy, sell }
enum OrderStatus { pending, matched, settled, cancelled }
```

**Utility Track价格校验（前端 + 后端双重验证）**：

```dart
// lib/features/trading/presentation/providers/sell_provider.dart
class SellNotifier extends StateNotifier<SellState> {
  // Utility Track券：卖出价 ≤ 面值
  bool validatePrice(double sellPrice, double faceValue, CouponType type) {
    if (type == CouponType.utility && sellPrice > faceValue) {
      return false; // 消费型券不允许溢价
    }
    return true;
  }
}
```

### 3.5 P2P转赠

```dart
// 转赠流程：输入朋友手机号 → 翻译层解析为链上地址 → 链上P2P转移
class TransferUseCase {
  final TransferRepository _repo;
  TransferUseCase(this._repo);

  Future<Either<Failure, TransferResult>> call({
    required String couponId,
    required String recipientPhone,  // 手机号（非链上地址）
  }) {
    return _repo.transferByPhone(
      couponId: couponId,
      recipientPhone: recipientPhone,
    );
    // 后端翻译层：手机号 → 链上地址 → Gas代付 → 链上P2P转移
  }
}
```

---

## 4. AI Agent 集成

### 4.1 架构

```
┌──────────────────────────────┐
│      AI Agent UI Layer       │
│  悬浮按钮 / 对话面板 / 建议条  │
├──────────────────────────────┤
│      AI Agent SDK            │
│  对话管理 / 上下文组装 / 流式  │
├──────────────────────────────┤
│      WebSocket连接            │
│  Agent Gateway API           │
└──────────────────────────────┘
```

### 4.2 悬浮入口按钮

```dart
// lib/features/ai_agent/presentation/widgets/ai_fab.dart
class AiAgentFab extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final unreadCount = ref.watch(aiUnreadCountProvider);
    return Positioned(
      right: 16,
      bottom: 80,
      child: GestureDetector(
        onTap: () => _showAgentPanel(context),
        onLongPress: () => _showQuickActions(context),
        child: Stack(
          children: [
            CircleAvatar(
              radius: 28,
              child: Icon(Icons.smart_toy_outlined),
            ),
            if (unreadCount > 0)
              Positioned(
                right: 0, top: 0,
                child: Badge(count: unreadCount),
              ),
          ],
        ),
      ),
    );
  }
}
```

### 4.3 对话面板（流式输出）

```dart
// lib/features/ai_agent/presentation/pages/agent_chat_panel.dart
class AgentChatPanel extends ConsumerStatefulWidget {
  @override
  _AgentChatPanelState createState() => _AgentChatPanelState();
}

class _AgentChatPanelState extends ConsumerState<AgentChatPanel> {
  final _channel = WebSocketChannel.connect(
    Uri.parse('wss://api.gogenex.com/agent/ws'),
  );

  void _sendMessage(String text) {
    final context = _buildContext(); // 组装上下文
    _channel.sink.add(jsonEncode({
      'type': 'chat',
      'message': text,
      'context': context,
    }));
  }

  Map<String, dynamic> _buildContext() {
    return {
      'user_profile': ref.read(userProfileProvider).toJson(),
      'current_page': GoRouter.of(context).location,
      'coupon_portfolio': ref.read(myCouponsProvider).toSummary(),
      'recent_actions': ref.read(recentActionsProvider),
    };
  }
}
```

### 4.4 消费者端AI场景

| 场景 | 实现方式 |
|------|---------|
| 智能选券推荐 | 首页Feed中插入AI推荐卡片 |
| 价格顾问 | 券详情页底部AI分析标签 |
| 到期管理 | 我的券列表AI排序+推送提醒 |
| 出售定价 | 出售页面AI建议价格+解释 |
| 自然语言搜索 | 对话面板返回筛选券卡片 |

---

## 5. 商户端核销模块

### 5.1 核销方式

| 方式 | 场景 | 技术 |
|------|------|------|
| 扫码核销 | 门店扫消费者券码 | Camera → QR解码 → API调用 |
| 输码核销 | 手动输入券码 | 文本输入 → API调用 |
| 离线核销 | 网络不可用 | 本地验证 → 队列缓存 → 联网同步 |

### 5.2 离线核销实现

```dart
// lib/features/merchant/data/services/offline_redeem_service.dart
class OfflineRedeemService {
  final _queue = HiveBox<PendingRedemption>('offline_queue');
  final _localValidator = LocalCouponValidator();

  /// 离线核销：本地验证 + 缓存 + 联网自动同步
  Future<RedeemResult> redeemOffline(String couponCode) async {
    // 1. 本地验证（预下载的有效券列表 + 签名验证）
    final isValid = await _localValidator.validate(couponCode);
    if (!isValid) return RedeemResult.invalid();

    // 2. 本地标记已核销，加入同步队列
    await _queue.add(PendingRedemption(
      couponCode: couponCode,
      timestamp: DateTime.now(),
      storeId: currentStoreId,
    ));

    return RedeemResult.pendingSync();
  }

  /// 联网后自动同步
  Future<void> syncPendingRedemptions() async {
    final pending = _queue.values.toList();
    for (final item in pending) {
      try {
        await _api.confirmRedemption(item);
        await _queue.delete(item.key);
      } catch (_) {
        // 重试逻辑
      }
    }
  }
}
```

---

## 6. 网络层

### 6.1 Dio配置

```dart
// lib/core/network/api_client.dart
class ApiClient {
  late final Dio _dio;

  ApiClient() {
    _dio = Dio(BaseOptions(
      baseUrl: 'https://api.gogenex.com/api/v1',
      connectTimeout: Duration(seconds: 10),
      receiveTimeout: Duration(seconds: 30),
    ));

    _dio.interceptors.addAll([
      AuthInterceptor(),      // JWT Token注入
      LoggingInterceptor(),   // 日志
      RetryInterceptor(),     // 重试策略
      ErrorInterceptor(),     // 统一错误处理
    ]);
  }
}
```

### 6.2 错误处理

```dart
// lib/core/network/failure.dart
@freezed
class Failure with _$Failure {
  const factory Failure.network({String? message}) = NetworkFailure;
  const factory Failure.server({required int code, String? message}) = ServerFailure;
  const factory Failure.auth({String? message}) = AuthFailure;
  const factory Failure.validation({required Map<String, String> errors}) = ValidationFailure;
}
```

---

## 7. 状态管理模式（Riverpod）

```dart
// 只读数据查询
final couponListProvider = FutureProvider.autoDispose<List<Coupon>>((ref) async {
  return ref.watch(couponRepoProvider).getAll();
});

// 可变状态管理
final cartProvider = StateNotifierProvider<CartNotifier, CartState>((ref) {
  return CartNotifier(ref.watch(orderRepoProvider));
});

// 异步操作
final purchaseProvider = FutureProvider.family<Order, PurchaseParams>((ref, params) {
  return ref.watch(orderRepoProvider).purchase(params);
});
```

---

## 8. 应用构建配置

### 8.1 多环境配置

```dart
// lib/core/config/env.dart
enum Environment { dev, staging, prod }

class AppConfig {
  static late Environment env;
  static String get apiBase => switch (env) {
    Environment.dev => 'https://dev-api.gogenex.com',
    Environment.staging => 'https://staging-api.gogenex.com',
    Environment.prod => 'https://api.gogenex.com',
  };
}
```

### 8.2 Flavor构建

```yaml
# Consumer App
flutter run --flavor consumer -t lib/main_consumer.dart

# Merchant App
flutter run --flavor merchant -t lib/main_merchant.dart
```

Consumer和Merchant共享核心模块（`core/`、`shared/`），通过不同入口和路由配置区分功能。

---

## 9. 测试策略

| 层级 | 工具 | 覆盖目标 |
|------|------|---------|
| 单元测试 | `flutter_test` + `mocktail` | UseCase、Repository、Provider |
| Widget测试 | `flutter_test` | 关键页面组件 |
| 集成测试 | `integration_test` | 购买流程、核销流程、转赠流程 |
| Golden测试 | `golden_toolkit` | UI快照回归 |

```dart
// test/features/trading/sell_notifier_test.dart
void main() {
  test('Utility券不允许溢价出售', () {
    final notifier = SellNotifier();
    expect(
      notifier.validatePrice(110.0, 100.0, CouponType.utility),
      false, // 110 > 面值100，拒绝
    );
    expect(
      notifier.validatePrice(85.0, 100.0, CouponType.utility),
      true, // 85 < 面值100，允许
    );
  });
}
```

---

## 10. 性能优化

| 策略 | 实现 |
|------|------|
| 图片懒加载 | `cached_network_image` + CDN |
| 列表虚拟化 | `ListView.builder` + 分页加载 |
| 离线缓存 | Hive本地数据库 + 增量同步 |
| 启动优化 | 延迟初始化非核心服务 |
| 包体积 | Tree-shaking + 延迟加载 |
| 内存管理 | `autoDispose` Provider自动释放 |

---

## 11. 安全规范

- JWT Token存储于Flutter Secure Storage（非SharedPreferences）
- 敏感操作（大额交易、转赠）需二次验证（PIN/生物识别）
- API通信全链路HTTPS，Certificate Pinning
- 本地数据加密存储（Hive加密Box）
- 禁止在日志中输出敏感信息（Token、用户手机号）
- ProGuard/R8混淆（Android）

---

## 12. 发布流程

```
开发 → 提交PR → CI自动测试 → Code Review → 合入main
                                              ↓
                                    自动构建（GitHub Actions / GitLab CI）
                                              ↓
                              ┌────────────────┼────────────────┐
                              ↓                ↓                ↓
                        Dev Build        Staging Build      Prod Build
                        (内部测试)       (TestFlight/Beta)   (App Store/Play Store)
```

---

## 13. Pro模式（加密原生用户）

### 13.1 Pro模式切换

```dart
// lib/features/profile/presentation/pages/pro_mode_settings.dart
class ProModeSettings extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final user = ref.watch(userProfileProvider);

    return Column(children: [
      // 风险提示确认
      RiskDisclosureCard(
        text: '切换至Pro模式后，您将自行管理钱包私钥。'
              '平台无法帮您恢复丢失的私钥或资产。',
      ),

      // 开启Pro模式
      SwitchListTile(
        title: Text('开启Pro模式'),
        value: user.walletMode == WalletMode.pro,
        onChanged: (enabled) async {
          if (enabled) {
            // 必须确认风险提示
            final confirmed = await showRiskConfirmDialog(context);
            if (confirmed) {
              await ref.read(walletProvider.notifier).switchToProMode();
            }
          } else {
            // Pro→标准：需将资产转回平台托管
            await ref.read(walletProvider.notifier).switchToStandard();
          }
        },
      ),

      if (user.walletMode == WalletMode.pro) ...[
        // 链上地址显示
        CopyableAddressField(address: user.chainAddress),
        // WalletConnect连接
        WalletConnectButton(),
        // MetaMask连接
        MetaMaskConnectButton(),
        // 交易哈希查看入口
        ListTile(
          title: Text('查看链上交易'),
          onTap: () => launchUrl(explorerUrl),
        ),
      ],
    ]);
  }
}
```

### 13.2 助记词备份与社交恢复

```dart
// lib/features/wallet/domain/usecases/backup_usecase.dart
class BackupSeedPhraseUseCase {
  /// Pro模式开启时强制提示备份助记词
  Future<Either<Failure, void>> call() async {
    final mnemonic = await _walletService.generateMnemonic();
    // 显示12词助记词，用户手动抄写
    // 验证确认（随机抽3个词验证）
    return _walletService.confirmBackup(mnemonic);
  }
}

// 社交恢复（Guardian机制）
class SocialRecoveryUseCase {
  /// 预设3-5个可信联系人，多数确认即可恢复
  Future<Either<Failure, void>> setupGuardians(List<String> guardianPhones) async {
    if (guardianPhones.length < 3 || guardianPhones.length > 5) {
      return Left(Failure.validation(errors: {'guardians': '需要3-5个守护人'}));
    }
    return _repo.setupSocialRecovery(guardianPhones);
  }

  /// 发起恢复（需>50%守护人确认）
  Future<Either<Failure, void>> initiateRecovery() async {
    return _repo.initiateRecovery();
  }
}

// AA钱包（ERC-4337）集成
class AAWalletService {
  /// 邮箱/手机号作为恢复入口
  Future<void> recoverViaEmail(String email) async {
    // ERC-4337 Account Abstraction恢复流程
  }
}
```

---

## 14. 提取到外部钱包

```dart
// lib/features/wallet/presentation/pages/extract_to_external.dart
class ExtractToExternalPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Column(children: [
      // KYC L2+才可提取
      KycGuard(requiredLevel: KycLevel.L2, child: Column(children: [
        // 输入外部钱包地址（EVM兼容）
        TextField(
          decoration: InputDecoration(labelText: '外部钱包地址（0x...）'),
          controller: _addressController,
        ),
        // 风险提示
        WarningCard(
          text: '提取后平台将不再托管该券。'
                '您需自行保管钱包私钥，平台无法冻结、恢复或干预该券。',
        ),
        // 选择要提取的券
        CouponSelector(onSelected: (coupons) => setState(() => _selected = coupons)),
        // 确认提取
        ElevatedButton(
          onPressed: () => _confirmExtract(ref),
          child: Text('确认提取'),
        ),
      ])),
    ]);
  }
}
```

---

## 15. 个人中心完整模块

### 15.1 转赠记录

```dart
// lib/features/transfer/presentation/pages/transfer_history.dart
class TransferHistoryPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final transfers = ref.watch(transferHistoryProvider);

    return transfers.when(
      data: (list) => ListView.builder(
        itemCount: list.length,
        itemBuilder: (_, i) => TransferHistoryCard(
          direction: list[i].direction, // sent / received
          recipientDisplay: list[i].recipientPhone ?? '外部钱包',
          couponName: list[i].couponName,
          timestamp: list[i].createdAt,
          status: list[i].status, // completed / pending
        ),
      ),
      loading: () => SkeletonList(),
      error: (e, _) => ErrorWidget(e),
    );
  }
}
```

### 15.2 我的余额/充值/提现

```dart
// lib/features/wallet/domain/entities/balance.dart
@freezed
class WalletBalance with _$WalletBalance {
  const factory WalletBalance({
    required double totalBalance,       // 总余额（链上+链下聚合，美元显示）
    required double availableBalance,   // 可用余额
    required double frozenBalance,      // 冻结金额（挂单中/待结算）
    required double withdrawable,       // 可提现
  }) = _WalletBalance;
}

// 充值/提现流程
class DepositUseCase {
  Future<Either<Failure, DepositResult>> call(DepositParams params) {
    // 银行卡/信用卡/Apple Pay → 法币入金 → 后台转换USDC
    return _repo.deposit(params);
  }
}

class WithdrawUseCase {
  Future<Either<Failure, WithdrawResult>> call(WithdrawParams params) {
    // USDC → 法币 → 银行卡（T+1到账）
    return _repo.withdraw(params);
  }
}
```

### 15.3 我的订单

```dart
// lib/features/trading/presentation/pages/order_history.dart
class OrderHistoryPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final orders = ref.watch(orderHistoryProvider);
    return DefaultTabController(
      length: 3,
      child: Column(children: [
        TabBar(tabs: [
          Tab(text: '全部'),
          Tab(text: '买入'),
          Tab(text: '卖出'),
        ]),
        Expanded(child: TabBarView(children: [
          OrderList(orders: orders),
          OrderList(orders: orders.where((o) => o.side == OrderSide.buy)),
          OrderList(orders: orders.where((o) => o.side == OrderSide.sell)),
        ])),
      ]),
    );
  }
}
```

### 15.4 换手机号

```dart
// lib/features/profile/domain/usecases/change_phone.dart
class ChangePhoneUseCase {
  /// 换手机号：KYC身份验证（人脸+证件）后迁移账户
  Future<Either<Failure, void>> call(ChangePhoneParams params) async {
    // 1. 验证新手机号未注册
    // 2. KYC身份验证（人脸识别 + 证件对比）
    // 3. 旧手机号验证码确认
    // 4. 更新映射表（旧手机→新手机，链上地址不变）
    return _repo.changePhone(params);
  }
}
```

---

## 16. 离线核销增强

```dart
// lib/features/merchant/data/services/offline_redeem_service.dart
// 补充：离线核销限额与冲突处理

class OfflineRedeemConfig {
  static const maxSingleAmount = 500.0;  // 单笔离线核销限额$500
  static const maxDailyAmount = 5000.0;  // 单日离线核销限额$5,000
  static const maxDailyCount = 50;       // 单日离线核销笔数限制
}

class OfflineConflictResolver {
  /// 冲突处理：同一张券被两个门店离线核销
  /// 以先上链者为准，后者自动退回并通知
  Future<void> resolveConflict(PendingRedemption local, ChainRedemption chain) async {
    if (chain.redeemedBy != local.storeId) {
      // 该券已被其他门店核销，本地核销无效
      await _notifyStore(local.storeId, '券${local.couponCode}已被其他门店核销');
      await _queue.delete(local.key);
    }
  }
}
```

---

## 17. 争议与投诉

```dart
// lib/features/support/domain/entities/ticket.dart
@freezed
class SupportTicket with _$SupportTicket {
  const factory SupportTicket({
    required String id,
    required TicketCategory category,  // transaction/account/coupon
    required String description,
    required TicketStatus status,
    String? orderId,                   // 关联订单号
    List<String>? attachments,
  }) = _SupportTicket;
}

enum TicketCategory { transaction, account, coupon, compliance, other }
enum TicketStatus { open, inProgress, waitingUser, resolved, closed }
```

---

## 18. 消息通知

```dart
// lib/features/notification/domain/entities/notification.dart
@freezed
class AppNotification with _$AppNotification {
  const factory AppNotification({
    required String id,
    required NotificationType type,
    required String title,
    required String body,
    required DateTime createdAt,
    required bool isRead,
    String? deepLink,              // 点击跳转（如券详情、订单详情）
  }) = _AppNotification;
}

enum NotificationType {
  tradeComplete,        // 交易完成
  couponExpiringSoon,   // 券即将过期
  priceAlert,           // 价格变动
  transferReceived,     // 收到转赠
  systemAnnouncement,   // 系统公告
  issuerNotice,         // 发行方公告
}
```

---

*文档版本: v2.0*
*基于: Genex 券交易平台 - 软件需求规格说明书 v4.1*
*技术栈: Flutter 3.x + Riverpod + Clean Architecture*
*更新: 补充Pro模式/助记词/社交恢复/AA钱包/外部钱包提取/转赠记录/余额/订单/换手机号/离线核销增强/争议投诉/消息通知*
