feat: release transfer service (Harish Algat)#116
Open
workharishalgat-lang wants to merge 1 commit into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a PostgreSQL-backed wallet-to-wallet transfer service with an idempotent POST /transfers API, transactional balance updates, and double-entry ledger recording, plus local/dev tooling and tests to validate concurrency and exactly-once behavior.
Changes:
- Added transfer service orchestration (idempotency, wallet row locking, state transitions) and HTTP handler wiring.
- Added Postgres persistence layer (repositories), domain models, and an authoritative SQL schema.
- Added local Postgres test environment scripts and unit + real-Postgres concurrency integration tests; expanded README documentation.
Reviewed changes
Copilot reviewed 19 out of 21 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
cmd/server/main.go |
Service entrypoint wiring (config, DB, handler, graceful shutdown). |
internal/api/handler.go |
HTTP POST /transfers endpoint and error mapping. |
internal/config/config.go |
Environment-based configuration loading/validation. |
internal/logging/logger.go |
Leveled logger utility used by service/runtime. |
internal/model/model.go |
Domain models, enums, and ID generator. |
internal/repository/repository.go |
Repository interfaces + shared error helpers. |
internal/repository/postgres/wallet.go |
Postgres wallet persistence (row locking + balance updates). |
internal/repository/postgres/transfer.go |
Postgres transfer persistence (create + state updates). |
internal/repository/postgres/ledger.go |
Postgres ledger entry persistence. |
internal/repository/postgres/idempotency.go |
Postgres idempotency record persistence. |
internal/service/transfer_service.go |
Core transfer workflow: idempotency, locking, balance moves, ledger writes. |
internal/service/transfer_service_test.go |
Unit tests for idempotency, snapshot semantics, and failure modes. |
migrations/schema.sql |
Authoritative SQL DDL for wallets/transfers/ledger/idempotency. |
test/integration/concurrency_test.go |
Real-Postgres concurrency/idempotency integration tests (gated by env). |
testenv/docker-compose.yml |
Local Postgres container for manual/integration runs. |
testenv/run-local.sh |
Script to start Postgres, wait for schema, seed wallets, run service. |
testenv/seed.sql |
Seed wallets for local endpoint checks. |
README.md |
Expanded documentation: architecture, schema, semantics, and how-to-run/test. |
go.mod |
Go module definition and dependencies. |
go.sum |
Dependency checksums. |
Comment on lines
+121
to
+127
| transfer := model.Transfer{ | ||
| TransferID: model.NewID(), | ||
| FromWalletID: request.FromWalletID, | ||
| ToWalletID: request.ToWalletID, | ||
| Amount: request.Amount, | ||
| State: model.TransferStatePending, | ||
| } |
| "strings" | ||
|
|
||
| "github.com/Robustrade/wallet-transfer-assignment/internal/model" | ||
| "github.com/jackc/pgconn" |
Comment on lines
+2
to
+3
| -- Run AFTER the service has started once, because the service creates the tables | ||
| -- via GORM AutoMigrate on startup. |
| set -euo pipefail | ||
| cd "$(dirname "$0")" | ||
|
|
||
| export DATABASE_URL="postgres://wallet:wallet@host.docker.internal:5432/wallet?sslmode=disable" |
Comment on lines
+35
to
+39
| var request TransferRequest | ||
| if err := json.NewDecoder(r.Body).Decode(&request); err != nil { | ||
| h.writeErrorStatus(w, http.StatusBadRequest, "invalid JSON payload") | ||
| return | ||
| } |
Comment on lines
+47
to
+54
| if err := db.AutoMigrate( | ||
| &model.Wallet{}, | ||
| &model.Transfer{}, | ||
| &model.LedgerEntry{}, | ||
| &model.IdempotencyRecord{}, | ||
| ); err != nil { | ||
| t.Fatalf("automigrate: %v", err) | ||
| } |
Comment on lines
+71
to
+73
| var buffer [16]byte | ||
| _, _ = rand.Read(buffer[:]) | ||
| return hex.EncodeToString(buffer[:]) |
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.
Summary
Implemented an idempotent wallet-to-wallet transfer service with atomic balance updates, durable transfer state, and double-entry ledger recording in PostgreSQL. The transfer flow is validated, transactionally executed, and safe under concurrent requests, including concurrent duplicate idempotency keys.
AI disclosure
I used AI as a development assistant for design review, implementation checks, and write-up drafting.
Schema Design
Tables introduced:
Key constraints:
Indexes:
Idempotency Strategy
Concurrency Strategy
How to Run
How to Test
Tradeoffs / Assumptions
Checklist