Skip to content

Add escrow transaction history service and /api/escrow/logs endpoints#2

Merged
chiscookeke11 merged 1 commit into
issue-100from
codex/add-escrow-transaction-history-service
May 30, 2026
Merged

Add escrow transaction history service and /api/escrow/logs endpoints#2
chiscookeke11 merged 1 commit into
issue-100from
codex/add-escrow-transaction-history-service

Conversation

@chiscookeke11
Copy link
Copy Markdown
Owner

@chiscookeke11 chiscookeke11 commented May 30, 2026

Motivation

  • Provide a persistent, auditable backend for escrow transaction events (deposits, milestone releases, refunds, disputes) so projects and admins can inspect payment history and maintain accountability.
  • Support efficient pagination and filtering to handle large log volumes while enforcing access rules so only project participants or admins can view or create logs.

Description

  • Added a new service EscrowTransactionHistoryService with creation and listing APIs, schema validation, relation checks (contract/milestone/dispute/users), money-transaction validation, and access checks for participants/admins in lib/escrow/history.ts.
  • Implemented authenticated HTTP endpoints POST /api/escrow/logs and GET /api/escrow/logs that wire the service into the app and map domain errors to HTTP responses in app/api/escrow/logs/route.ts.
  • Added a DB migration lib/db/migrations/004_escrow_transaction_logs.sql that creates the escrow_transaction_logs table, enum type, constraints for transaction-specific fields, and indexes for efficient queries.
  • Exported the new service and DTO types from the escrow barrel in lib/escrow/index.ts so other modules can import the history service and types.

Testing

  • Ran npm run lint, which completed successfully with no lint errors for the new code.
  • Ran npm run build (Next.js production build), which completed successfully and discovered the new routes during route generation.
  • Ran npx tsc --noEmit, which reported failures, but the type errors are unrelated to the new history code (preexisting repository type issues in other modules); the new files do not introduce type errors reported by the build step.

Codex Task

Summary by Sourcery

Introduce persistent escrow transaction logging with authenticated APIs for creating and querying logs.

New Features:

  • Add EscrowTransactionHistoryService to create and list escrow transaction logs with access control and validation.
  • Expose authenticated REST endpoints POST /api/escrow/logs and GET /api/escrow/logs for managing escrow transaction history.
  • Create a database schema and migration for escrow_transaction_logs with enum-backed transaction types and supporting indexes.

Enhancements:

  • Export escrow transaction history service and DTO types from the escrow module barrel for reuse across the codebase.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 30, 2026

Reviewer's Guide

Introduces an escrow transaction history subsystem: a database-backed audit log with a dedicated service and authenticated REST endpoints for creating and listing escrow transaction logs, including validation, access control, and pagination, and exports the new APIs via the escrow module barrel.

Sequence diagram for POST /api/escrow/logs escrow transaction log creation

sequenceDiagram
  actor User
  participant API_EscrowLogs as API_escrow_logs_route
  participant Auth as withAuth
  participant HistoryService as EscrowTransactionHistoryService
  participant DB as sql

  User->>API_EscrowLogs: POST /api/escrow/logs
  API_EscrowLogs->>Auth: withAuth(POST handler)
  Auth->>HistoryService: createLog(body, auth.walletAddress)
  HistoryService->>DB: sql SELECT users WHERE wallet_address
  HistoryService->>DB: sql SELECT contracts WHERE id = contractId
  HistoryService->>DB: sql INSERT INTO escrow_transaction_logs
  HistoryService->>DB: sql SELECT escrow_transaction_logs JOIN contracts, projects, users
  HistoryService-->>Auth: EscrowTransactionLog
  Auth-->>API_EscrowLogs: EscrowTransactionLog
  API_EscrowLogs-->>User: 201 { log }
Loading

Entity relationship diagram for escrow_transaction_logs audit table

erDiagram
  escrow_transaction_logs {
    uuid id
    uuid contract_id
    uuid project_id
    uuid milestone_id
    uuid dispute_id
    uuid actor_user_id
    uuid counterparty_user_id
    escrow_transaction_type transaction_type
    numeric amount
    text status
    timestamptz created_at
  }

  contracts {
    uuid id
  }

  projects {
    uuid id
  }

  milestones {
    uuid id
  }

  disputes {
    uuid id
  }

  users {
    uuid id
  }

  contracts ||--o{ escrow_transaction_logs : contract_id
  projects ||--o{ escrow_transaction_logs : project_id
  milestones ||--o{ escrow_transaction_logs : milestone_id
  disputes ||--o{ escrow_transaction_logs : dispute_id
  users ||--o{ escrow_transaction_logs : actor_user_id
  users ||--o{ escrow_transaction_logs : counterparty_user_id
Loading

File-Level Changes

Change Details Files
Add EscrowTransactionHistoryService to create and list escrow transaction logs with validation, access control, and pagination.
  • Define transaction log types, DTOs, and pagination structures for escrow logs.
  • Implement zod-based payload validation, amount formatting rules, and semantic checks for required fields depending on transaction type.
  • Enforce actor/counterparty existence, contract/milestone/dispute relationship checks, and participant/admin-only access rules for log creation and retrieval.
  • Implement listLogs with limit/offset normalization, filtering by contract/project/transactionType, and access-scoped SQL queries that join contracts, projects, and users and map rows into domain models.
  • Add a private getLogById helper that reuses access scoping when returning a just-created log.
lib/escrow/history.ts
Expose the escrow transaction history service and related types via the escrow module barrel.
  • Export escrowTransactionHistoryService and EscrowTransactionHistoryService.
  • Export EscrowTransactionLog, EscrowTransactionLogPage, CreateEscrowTransactionLogInput, EscrowTransactionType, and EscrowTransactionStatus for external consumers.
lib/escrow/index.ts
Add authenticated HTTP API endpoints for creating and listing escrow transaction logs.
  • Implement POST /api/escrow/logs handler that parses JSON, invokes the history service createLog with the authenticated wallet, and maps domain errors to HTTP responses.
  • Implement GET /api/escrow/logs handler that forwards pagination and filter query params to listLogs, returning the paged result.
  • Use withAuth middleware and escrowErrorToHttpStatus, and add basic 400/500 error handling and logging for unexpected failures.
  • Mark the route as dynamic to avoid static optimization issues with authenticated access.
app/api/escrow/logs/route.ts
Introduce a database schema for escrow_transaction_logs with constraints and indexes to support auditing and efficient querying.
  • Create escrow_transaction_type enum if it does not already exist.
  • Create escrow_transaction_logs table with foreign keys to contracts, projects, milestones, disputes, and users, plus fields for amount, currency, transaction_hash, status, description, metadata, and created_at.
  • Add CHECK constraints to enforce positive amount and presence of milestoneId/disputeId for relevant transaction types and valid status values.
  • Create indexes on contract_id, project_id, actor_user_id, counterparty_user_id (partial), transaction_type, and transaction_hash (partial) for common access patterns.
lib/db/migrations/004_escrow_transaction_logs.sql

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The COUNT and SELECT queries in listLogs duplicate the same access and filter predicates; consider extracting the common WHERE into a reusable fragment (e.g., a CTE or helper) to reduce the risk of these drifting out of sync over time.
  • The escrow_transaction_logs table uses a plain TEXT column with a CHECK constraint for status while transaction_type uses a dedicated enum type; if you expect status values to be stable, aligning it to an enum as well would prevent invalid status values being inserted outside this service.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The COUNT and SELECT queries in `listLogs` duplicate the same access and filter predicates; consider extracting the common WHERE into a reusable fragment (e.g., a CTE or helper) to reduce the risk of these drifting out of sync over time.
- The `escrow_transaction_logs` table uses a plain `TEXT` column with a CHECK constraint for `status` while `transaction_type` uses a dedicated enum type; if you expect `status` values to be stable, aligning it to an enum as well would prevent invalid status values being inserted outside this service.

## Individual Comments

### Comment 1
<location path="lib/escrow/history.ts" line_range="63" />
<code_context>
+const amountSchema = z.string().regex(/^\d+(\.\d{1,6})?$/, 'amount must be a positive decimal string with up to 6 decimal places')
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Align amount validation semantics and error messaging for zero/negative values.

The regex permits `0` / `0.0` etc., but `assertPositiveAmount` rejects values `<= 0`, so the schema message (“must be a positive decimal string…”) is misleading for `0`. Either adjust the regex to exclude all-zero values, or relax the schema message (e.g. “non‑negative decimal string…”) and rely on `assertPositiveAmount` for strict positivity so validation is consistent.

```suggestion
const amountSchema = z
  .string()
  .regex(
    /^(?!0+(?:\.0+)?$)\d+(\.\d{1,6})?$/,
    'amount must be a positive decimal string with up to 6 decimal places'
  )
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread lib/escrow/history.ts
}

const uuidSchema = z.string().uuid()
const amountSchema = z.string().regex(/^\d+(\.\d{1,6})?$/, 'amount must be a positive decimal string with up to 6 decimal places')
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): Align amount validation semantics and error messaging for zero/negative values.

The regex permits 0 / 0.0 etc., but assertPositiveAmount rejects values <= 0, so the schema message (“must be a positive decimal string…”) is misleading for 0. Either adjust the regex to exclude all-zero values, or relax the schema message (e.g. “non‑negative decimal string…”) and rely on assertPositiveAmount for strict positivity so validation is consistent.

Suggested change
const amountSchema = z.string().regex(/^\d+(\.\d{1,6})?$/, 'amount must be a positive decimal string with up to 6 decimal places')
const amountSchema = z
.string()
.regex(
/^(?!0+(?:\.0+)?$)\d+(\.\d{1,6})?$/,
'amount must be a positive decimal string with up to 6 decimal places'
)

@chiscookeke11 chiscookeke11 merged commit cf6e776 into issue-100 May 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant