Add escrow transaction history service and /api/escrow/logs endpoints#2
Conversation
Reviewer's GuideIntroduces 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 creationsequenceDiagram
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 }
Entity relationship diagram for escrow_transaction_logs audit tableerDiagram
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
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The COUNT and SELECT queries in
listLogsduplicate 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_logstable uses a plainTEXTcolumn with a CHECK constraint forstatuswhiletransaction_typeuses a dedicated enum type; if you expectstatusvalues 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>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| } | ||
|
|
||
| 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') |
There was a problem hiding this comment.
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.
| 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' | |
| ) |
Motivation
Description
EscrowTransactionHistoryServicewith creation and listing APIs, schema validation, relation checks (contract/milestone/dispute/users), money-transaction validation, and access checks for participants/admins inlib/escrow/history.ts.POST /api/escrow/logsandGET /api/escrow/logsthat wire the service into the app and map domain errors to HTTP responses inapp/api/escrow/logs/route.ts.lib/db/migrations/004_escrow_transaction_logs.sqlthat creates theescrow_transaction_logstable, enum type, constraints for transaction-specific fields, and indexes for efficient queries.lib/escrow/index.tsso other modules can import the history service and types.Testing
npm run lint, which completed successfully with no lint errors for the new code.npm run build(Next.js production build), which completed successfully and discovered the new routes during route generation.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:
Enhancements: