Files
velocity-pay-flutter/group-batches.md
2026-06-05 20:25:20 +02:00

4.6 KiB

Plan: Groups & Batches Feature

API Surface (from Postman)

Groups

  • GET /api/public/recipient-groups?userId={userId} — list groups
  • GET /api/public/recipient-groups/members?recipientGroupId={id} — list members
  • POST /api/public/recipient-groups — create group
    • Body: { name, description, userId, recipients: [{name, phoneNumber, latestProviderLabel, account}] }

Batches

  • GET /api/public/group-batches?recipientGroupId={id}&sort=createdAt,desc — list batches
  • GET /api/public/group-batches/items?groupBatchId={id}&sort=createdAt,desc — list batch items
  • POST /api/public/group-batches — create batch (recipientGroupId, userId, currency, amount, paymentProcessorLabel, paymentProcessorName, paymentProcessorImage, transactionTemplate)
  • POST /api/public/group-batches/{batchId}/confirm — confirm batch
  • POST /api/public/group-batches/{batchId}/request — request batch (payment)
  • POST /api/public/group-batches/{batchId}/poll — poll batch status

Files To Create

Phase 1: Models

  • lib/models/recipient_group_model.dart — RecipientGroup, RecipientMember, CreateGroupRequest
  • lib/models/group_batch_model.dart — GroupBatch, GroupBatchItem, CreateBatchRequest (transactionTemplate typed as TransactionModel from lib/screens/transactions/transaction_model.dart), BatchActionRequest. No separate TransactionTemplate class needed.

Phase 2: Controllers

  • lib/screens/groups/group_controller.dart — ChangeNotifier, list/create groups, list members
  • lib/screens/groups/batch_controller.dart — ChangeNotifier, list/create batches, list items, confirm/request/poll

Phase 3: Screens

  • lib/screens/groups/groups_screen.dart — list all groups
  • lib/screens/groups/group_create_screen.dart — create group form (name, description, multiline textarea: one recipient per line as name,account; phoneNumber defaults to account value)
  • lib/screens/groups/group_detail_screen.dart — tabbed view: Batches first (default), Members second; receives RecipientGroup via extra; FAB on Batches tab to create new batch
  • lib/screens/groups/batch_create_screen.dart — create batch form (provider, processor, amount, currency); on success navigate to BatchDetailScreen passing created batch via extra
  • lib/screens/groups/batch_detail_screen.dart — batch items list + Confirm/Request/Poll action buttons
  • lib/screens/groups/batch_item_screen.dart — single batch item detail view

Phase 4: Integration

  • lib/navbar.dart — add Groups as 3rd nav item (index 2)
  • lib/main.dart — add routes + GroupController + BatchController providers

Routes

  • /groups → GroupsScreen
  • /groups/create → GroupCreateScreen
  • /groups/:groupId → GroupDetailScreen
  • /groups/:groupId/batches/create → BatchCreateScreen
  • /groups/:groupId/batches/:batchId → BatchDetailScreen
  • /groups/:groupId/batches/:batchId/items/:itemId → BatchItemScreen

Action Return Types

  • createBatchApiResponse<GroupBatch>
  • confirmBatchApiResponse<GroupBatch>
  • requestBatchApiResponse<TransactionModel> (reuses TransactionModel)
  • pollBatchApiResponse<GroupBatch>
  • List endpoints → ApiResponse<PageableModel<T>>

BatchDetailScreen Auto-Poll Logic

After Request action:

  1. requestBatch() returns TransactionModel
  2. Check transaction.pollingStatus — if successful (e.g. SUCCESS, COMPLETE) → no poll needed, refresh batch
  3. Otherwise → auto-trigger pollBatch() immediately without user input
  4. If auto-poll fails (network error / non-terminal status) → show Poll button for manual retry
  5. Batch status from poll response drives UI state (show/hide action buttons)

Key Patterns

  • Controllers extend ChangeNotifier
  • Models use @JsonSerializable with generated .g.dart files
  • All network calls use ApiResponse<T> wrapping pattern (try/catch in controller)
  • Use ListenableBuilder in screens
  • Read userId/token from SharedPreferences
  • Pass extra data via GoRouter extra: parameter
  • idempotencyKey for batch actions generated as "batch-{batchId}-{action}-{timestamp}"
  • Navbar: add Groups at index 2, update _handleTap + _calculateSelectedIndex

Member Input Parsing (group_create_screen)

  • One recipient per line: name,account
  • phoneNumber defaults to account value
  • latestProviderLabel defaults to ""

Decisions

  • TransactionModel reused as-is for transactionTemplate field — no wrapper class
  • No pagination on groups/batches lists in this iteration
  • No edit/delete for groups or batches in scope
  • Poll button only shown as manual fallback after auto-poll failure