Commit 72606a7
authored
feat(current-account): add Account Control Operations (UpCR and CoCR) (#424)
* feat(current-account): add proto definitions for UpdateCurrentAccount and ControlCurrentAccount
Implement BIAN Control Record operations for account lifecycle management:
- UpdateCurrentAccountRequest/Response (UpCR) for modifying overdraft settings and status
- ControlCurrentAccountRequest/Response (CoCR) for state transitions (freeze/unfreeze/close)
- ControlAction enum with FREEZE, UNFREEZE, CLOSE actions
- Validation rules: account_id required, overdraft_rate range 0-100
- HTTP annotations: PUT /v1/current-accounts/{account_id} and POST /v1/current-accounts/{account_id}/control
* feat: implement account state machine with strict validation
Add robust state machine enforcement to CurrentAccount domain model:
- Freeze(reason) now requires 10+ char reason, only from ACTIVE status
- Unfreeze() transitions FROZEN -> ACTIVE and clears freeze reason
- Close() validates zero balance (lien check is service-layer concern)
- UpdateOverdraftSettings() validates rate >= 0 before delegation
- StatusChange struct and statusHistory for audit trail tracking
- CLOSED is terminal - no transitions permitted from closed state
State transition diagram documented in code:
ACTIVE <-> FROZEN -> CLOSED (terminal)
Includes 30+ comprehensive unit tests covering:
- Valid/invalid state transitions for all methods
- Freeze reason validation (empty, short, exact 10 chars)
- Close with non-zero/negative balance validation
- Status history immutability and audit trail
- Builder methods for freeze reason and status history
* feat(current-account): implement UpdateCurrentAccount and ControlCurrentAccount service handlers
Add BIAN Control Record operations for account lifecycle management:
UpdateCurrentAccount (UpCR):
- Updates overdraft settings (limit, rate, enabled status)
- Uses optimistic locking to prevent concurrent modification conflicts
- Returns InvalidArgument for currency mismatch or invalid rates
- Returns FailedPrecondition if account is closed
ControlCurrentAccount (CoCR):
- Implements FREEZE action with required reason (min 10 characters)
- Implements UNFREEZE to restore frozen accounts to active
- Implements CLOSE with validation for zero balance and no active liens
- All transitions use domain layer state machine for consistency
- Returns Aborted on version conflicts for retry
Also adds CountActiveByAccountID to LienRepository to support lien
checking during account close operations.
Note: Kafka event emission and webhook notifications are documented as
TODOs for future implementation (requires Kafka producer integration).
* feat: add status_history audit trail for BIAN Control Record operations
Add database migration and repository support for tracking account status
changes (ACTIVE -> FROZEN -> CLOSED) with full audit trail in JSONB column.
Changes:
- Add migration for status_history JSONB column and freeze_reason
- Add indexes on status (operational queries) and status_history (audit queries)
- Update CurrentAccountEntity with StatusHistoryJSON GORM type
- Enhance repository to persist status_history on state transitions
- Add comprehensive integration tests for lifecycle, concurrent ops, and auditing
- Fix TestExecuteWithdrawal_AccountClosed to comply with zero-balance close rule
The status_history stores each transition with from_status, to_status, reason,
timestamp, and changed_by for regulatory compliance and audit purposes.
* fix: Move Deprecated notice to separate paragraph for gocritic
The gocritic linter requires Deprecated notices to be in a dedicated
paragraph, separated from the rest of the documentation.
* feat: Address CodeRabbit feedback on status audit trail
- Add ChangedBy field to domain.StatusChange struct to preserve audit info
- Update toDomain() to populate ChangedBy from persistence layer
- Change Close() to accept reason parameter for audit trail
- Update all call sites to pass reason (grpc_service, tests)
- Add test for default reason behavior when empty string passed
* docs: Address minor review feedback with documentation clarifications
- Add TODO for Activate() deprecation removal in next major version
- Document time.Now() usage and clock injection consideration
- Clarify ChangedBy field is populated by persistence layer from context
---------
Co-authored-by: Ben Coombs <bjcoombs@users.noreply.github.com>1 parent a236ca7 commit 72606a7
12 files changed
Lines changed: 1575 additions & 56 deletions
File tree
- api/proto/meridian/current_account/v1
- services/current-account
- adapters/persistence
- domain
- migrations
- service
Lines changed: 117 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
90 | 106 | | |
91 | 107 | | |
92 | 108 | | |
| |||
693 | 709 | | |
694 | 710 | | |
695 | 711 | | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
696 | 785 | | |
697 | 786 | | |
698 | 787 | | |
| |||
828 | 917 | | |
829 | 918 | | |
830 | 919 | | |
| 920 | + | |
| 921 | + | |
| 922 | + | |
| 923 | + | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
| 930 | + | |
| 931 | + | |
| 932 | + | |
| 933 | + | |
| 934 | + | |
| 935 | + | |
| 936 | + | |
| 937 | + | |
| 938 | + | |
| 939 | + | |
| 940 | + | |
| 941 | + | |
| 942 | + | |
| 943 | + | |
| 944 | + | |
| 945 | + | |
| 946 | + | |
| 947 | + | |
831 | 948 | | |
Lines changed: 52 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
5 | 9 | | |
6 | 10 | | |
7 | 11 | | |
8 | 12 | | |
9 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
10 | 17 | | |
11 | 18 | | |
12 | 19 | | |
| |||
28 | 35 | | |
29 | 36 | | |
30 | 37 | | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
31 | 43 | | |
32 | 44 | | |
33 | 45 | | |
| |||
45 | 57 | | |
46 | 58 | | |
47 | 59 | | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
Lines changed: 21 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
190 | 190 | | |
191 | 191 | | |
192 | 192 | | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
193 | 214 | | |
194 | 215 | | |
195 | 216 | | |
| |||
Lines changed: 47 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
159 | 159 | | |
160 | 160 | | |
161 | 161 | | |
| 162 | + | |
| 163 | + | |
162 | 164 | | |
163 | 165 | | |
164 | 166 | | |
| |||
402 | 404 | | |
403 | 405 | | |
404 | 406 | | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
405 | 427 | | |
406 | 428 | | |
407 | 429 | | |
| |||
417 | 439 | | |
418 | 440 | | |
419 | 441 | | |
| 442 | + | |
| 443 | + | |
420 | 444 | | |
421 | 445 | | |
422 | 446 | | |
| |||
453 | 477 | | |
454 | 478 | | |
455 | 479 | | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
456 | 501 | | |
457 | 502 | | |
458 | 503 | | |
| |||
462 | 507 | | |
463 | 508 | | |
464 | 509 | | |
| 510 | + | |
| 511 | + | |
465 | 512 | | |
466 | 513 | | |
467 | 514 | | |
| |||
0 commit comments