# 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
- `createBatch` → `ApiResponse<GroupBatch>`
- `confirmBatch` → `ApiResponse<GroupBatch>`
- `requestBatch` → `ApiResponse<TransactionModel>` (reuses TransactionModel)
- `pollBatch` → `ApiResponse<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
