Skip to content

[LED-31] Split active and raw transaction operations#187

Open
gorushkin wants to merge 6 commits into
LED-27-transaction-refactoringfrom
LED-31-split-active-and-raw-operations
Open

[LED-31] Split active and raw transaction operations#187
gorushkin wants to merge 6 commits into
LED-27-transaction-refactoringfrom
LED-31-split-active-and-raw-operations

Conversation

@gorushkin
Copy link
Copy Markdown
Owner

What changed

  • Restore all operations into the Transaction aggregate, including tombstone operations.
  • Keep getOperations() as the active-only accessor.
  • Add getAllOperations() for persistence/raw state.
  • Update TransactionRepository to persist all known operations instead of active-only operations.
  • Update domain and repository tests to lock in the active/raw split.

Why

LED-31 requires 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.ts
  • pnpm --filter backend ts-check
  • pnpm --filter backend lint

@gorushkin gorushkin requested a review from Copilot May 20, 2026 18:15
@gorushkin gorushkin marked this pull request as ready for review May 20, 2026 18:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 keeping getOperations() active-only and introducing getAllOperations() for raw/persistence use.
  • Update TransactionRepository to 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”.

Comment thread apps/backend/src/domain/transactions/transaction.entity.ts
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Comment thread apps/backend/src/infrastructure/db/transaction/transaction.repository.test.ts Outdated
Comment thread apps/backend/src/interfaces/transactions/transaction.integration.test.ts Outdated
Comment thread apps/backend/src/interfaces/transactions/transaction.integration.test.ts Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.save is using op.toSnapshot() values, but TransactionRepository.create() passes DB rows produced by OperationMapper.toDBRow(...) into operationsRepository.save(). Update the expected argument to match the actual OperationDbRow[] payload (including isTombstone).
      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`,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants