Skip to content

Transactions Module

Records and maintains money movement with strict validation, wallet/category ownership checks, and OCR-assisted batch creation.

  • POST /api/v1/transaction
  • POST /api/v1/transaction/receipt
  • GET /api/v1/transaction
  • GET /api/v1/transaction/:id
  • PATCH /api/v1/transaction/:id
  • DELETE /api/v1/transaction/:id
  • Create: positive numeric amount, valid date string, supported currency, required walletId and categoryId.
  • Update: partial update allowed but at least one field required.
  • Receipt flow: multipart file receipt plus walletId and categoryId.
  • Receipt upload is parsed by Multer (receipt) in the presentation layer before invoking the OCR use case.
  • Schemas:
    • backend/src/Shared/Schemas/transactionSchema.ts
    • backend/src/Shared/Schemas/ocrSchema.ts
RouteControllerUse caseRepository / Service chainRoute file trace
POST /transactionTransactionController.createAddTransactionImplTransactionRepositoryImpl, WalletRepositoryImpl, CategoryRepositoryImpl, BudgetAllocationRepositoryImplbackend/src/Presentation/Routes/TransactionRoutes.ts
POST /transaction/receiptTransactionController.createFromReceiptTransactionOcrImpl -> AddTransactionImplOcrServiceImpl, repositories abovebackend/src/Presentation/Routes/TransactionRoutes.ts
GET /transactionTransactionController.listUserTransactionsListTransactionImplTransactionRepositoryImplbackend/src/Presentation/Routes/TransactionRoutes.ts
GET /transaction/:idTransactionController.getByIdGetTransactionImplTransactionRepositoryImplbackend/src/Presentation/Routes/TransactionRoutes.ts
PATCH /transaction/:idTransactionController.updateUpdateTransactionImplTransactionRepositoryImplbackend/src/Presentation/Routes/TransactionRoutes.ts
DELETE /transaction/:idTransactionController.deleteDeleteTransactionImplTransactionRepositoryImplbackend/src/Presentation/Routes/TransactionRoutes.ts

Controller: backend/src/Presentation/Controllers/TransactionController.ts.

  • INVALID_TRANSACTION_ID (400).
  • TRANSACTION_NOT_FOUND (404).
  • TRANSACTION_OWNER_MISMATCH (403).
  • WALLET_NOT_FOUND / INVALID_CATEGORY_EXIST_PARAMS (400/404 path dependent).
  • OCR_PARSE_FAILED / OCR_RESPONSE_FAILED (500) for receipt ingestion.
  • E2E file: backend/src/tests/e2e/transaction/transaction-crud.e2e.test.ts.
  • Unit file: backend/src/tests/unit/add-transaction-impl.test.ts.
Terminal window
curl -X POST "https://budgeti-backend.johandercampos.com/api/v1/transaction" \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"amount": 45.9,
"description": "Lunch",
"date": "2026-02-20T13:00:00.000Z",
"currency": "USD",
"walletId": "wlt_123",
"categoryId": "cat_123",
"type": "expense"
}'
{
"code": "TRANSACTION_CREATED",
"message": "Transaction created successfully",
"transaction": {
"id": "txn_123",
"amount": -45.9,
"description": "Lunch",
"date": "2026-02-20T13:00:00.000Z",
"currency": "USD",
"walletId": "wlt_123",
"categoryId": "cat_123"
}
}
{
"code": "INVALID_TRANSACTION_ID",
"message": "Invalid transaction identifier",
"error": "Invalid transaction identifier"
}
// TransactionController.create
const amount = req.body.type === 'expense'
? -Math.abs(Number(req.body.amount))
: Math.abs(Number(req.body.amount));
const transaction = await createTransactionImpl.execute(
{
amount,
date: parseIsoDateOrThrow(String(req.body.date), 'Invalid transaction date'),
walletId: req.body.walletId,
categoryId: req.body.categoryId,
},
req.userId!,
);