[LED-31] Split active and raw transaction operations#187
Open
gorushkin wants to merge 6 commits into
Open
Conversation
…eleted operations in snapshots
Contributor
There was a problem hiding this comment.
Pull request overview
This PR implements the LED-31 domain distinction between active operations and raw/persisted operations within the Transaction aggregate, ensuring tombstoned operations remain part of the restored aggregate while client-facing accessors continue to hide them by default.
Changes:
- Restore and snapshot all operations (including tombstones) inside
Transaction, while keepinggetOperations()active-only and introducinggetAllOperations()for raw/persistence use. - Update
TransactionRepositoryto persist all known operations rather than only active operations. - Adjust repository/domain tests and add integration-test TODOs to lock in expected behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| apps/backend/src/interfaces/transactions/transaction.integration.test.ts | Adds TODO coverage targets to ensure tombstoned operations are not returned by transaction endpoints. |
| apps/backend/src/infrastructure/db/transaction/transaction.repository.ts | Persists all operations via getAllOperations() for create/update/softDelete flows. |
| apps/backend/src/infrastructure/db/transaction/transaction.repository.test.ts | Updates expectations to persist all operations and adds a TODO for active vs raw restoration behavior. |
| apps/backend/src/domain/transactions/transaction.entity.ts | Restores/snapshots all operations and adds getAllOperations() while keeping getOperations() active-only. |
| apps/backend/src/domain/transactions/transaction.entity.test.ts | Updates operation-deletion assertions to reflect “tombstones kept in snapshot, hidden from active operations”. |
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
apps/backend/src/infrastructure/db/transaction/transaction.repository.test.ts:292
- This test’s expectation for
mockOperationsRepository.saveis usingop.toSnapshot()values, butTransactionRepository.create()passes DB rows produced byOperationMapper.toDBRow(...)intooperationsRepository.save(). Update the expected argument to match the actualOperationDbRow[]payload (includingisTombstone).
const expectedSnapshots = transaction
.getAllOperations()
.map((op) => op.toSnapshot());
expect(mockOperationsRepository.save).toHaveBeenCalledWith(
user.id,
expectedSnapshots,
);
});
Comment on lines
+195
to
+205
| const retrievedOperations = retrievedTransaction?.getOperations() ?? []; | ||
|
|
||
| expect(retrievedTransaction?.getAllOperations()).length( | ||
| allOperationsCount, | ||
| ); | ||
|
|
||
| expect(retrievedOperations).length(allOperationsCount - acc); | ||
|
|
||
| retrievedOperations.forEach((operation) => { | ||
| expect(operation.isDeleted()).toBe(false); | ||
| }); |
|
|
||
| await testDB.insertTransaction({ | ||
| ...transaction.toSnapshot(), | ||
| isTombstone: true, |
Comment on lines
100
to
121
| const snapshot = await this.getTransactionSnapshot( | ||
| userId, | ||
| transaction.getId().valueOf(), | ||
| ); | ||
|
|
||
| const operationsSnapshots = new Map<UUID, OperationSnapshot>(); | ||
|
|
||
| snapshot?.operations.forEach((operationSnapshot) => { | ||
| operationsSnapshots.set(operationSnapshot.id, operationSnapshot); | ||
| }); | ||
|
|
||
| const operationsToSave = operations.filter((operation) => { | ||
| const operationSnapshot = operationsSnapshots.get(operation.id); | ||
|
|
||
| return !(operationSnapshot?.isTombstone && operation.isTombstone); | ||
| }); | ||
|
|
||
| await this.operationsRepository.save( | ||
| userId, | ||
| operations, | ||
| operationsToSave, | ||
| operationsSnapshots, | ||
| ); |
| it('should return 401 when not authorized', async () => { | ||
| const response = await server.inject({ | ||
| method: 'GET', | ||
| url: `${url}/some-transaction-id`, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Transactionaggregate, including tombstone operations.getOperations()as the active-only accessor.getAllOperations()for persistence/raw state.TransactionRepositoryto persist all known operations instead of active-only operations.Why
LED-31requires the domain model to clearly separate active operations from raw operations. Repository reads should restore the complete aggregate state, while domain/client-facing accessors should hide tombstone operations by default.Validation
pnpm --filter backend test -- src/domain/transactions/transaction.entity.test.ts src/infrastructure/db/transaction/transaction.repository.test.ts src/infrastructure/db/operations/operation.repository.test.tspnpm --filter backend ts-checkpnpm --filter backend lint