Skip to content

wallet transfer implementation - #133

Open
raknay wants to merge 4 commits into
Robustrade:mainfrom
raknay:solution/rakesh
Open

wallet transfer implementation#133
raknay wants to merge 4 commits into
Robustrade:mainfrom
raknay:solution/rakesh

Conversation

@raknay

@raknay raknay commented Aug 17, 2026

Copy link
Copy Markdown

Summary

Wallet transfer implementation using Golang, Postgresql. Handled invalid state by transaction and row locking, duplicate processing using idempotency key, created db schema with correct constraints.

AI disclosure

Each line of the code is written from scratch and by author and no coding agent is used. However used Chatgpt and Google search for research purposes. More improvements can be done but due to time constraints was not possible to contribute but can be discussed if required.

Schema Design

  1. wallets:
Column Name Data Type Constraint
id VARCHAR(40) Primary Key
balance BIGINT
created_at TIMESTAMP
updated_at TIMESTAMP
  1. transfers:
Column Name Data Type Constraint
id VARCHAR(40) Primary Key
from_wallet_id VARCHAR(40) NOT NULL REFERENCES wallets(id)
to_wallet_id VARCHAR(40) NOT NULL REFERENCES wallets(id)
amount BIGINT NOT NULL CHECK (amount > 0)
status VARCHAR(20) NOT NULL CHECK(status IN ('PENDING', 'PROCESSED','FAILED'))
idempotency_key VARCHAR(255) NOT NULL UNIQUE
  1. ledger_entries:
Column Name Data Type Constraint
id VARCHAR(40) Primary Key
transfer_id VARCHAR(40) NOT NULL REFERENCES transfers(id)
wallet_id VARCHAR(40) NOT NULL REFERENCES wallets(id)
entry_type BIGINT NOT NULL CHECK (entry_type IN ('DEBIT', 'CREDIT'))
amount BIGINT NOT NULL CHECK (amount > 0)

Idempotency Strategy

  • Clients required to pass idempotency keys in request body else request will be rejected
  • Idempotency key should be unique for each new transfer request and if client passes the duplicate
    key due to retry or user behavior request will be served with already cached result and no duplicate processing will be done

Concurrency Strategy

  • Transfer between wallets are used using database transactions so the whole process is atomic by nature.
  • By using transactions, we would prevent inconsistent state of the wallet, ledger and transfer tables.
  • As SELECT statement doesn't lock row, FOR UPDATE clause is used while selecting wallets for update.

How to Run

  • make all

How to Test

  • make test

Tradeoffs / Assumptions

Checklist

  • Tests pass
  • Lint passes
  • Format check passes
  • README or notes updated
  • PR description explains schema, idempotency, and concurrency

Copilot AI lite review requested due to automatic review settings August 17, 2026 18:34
@raknay
raknay requested a review from amitlambakulu as a code owner August 17, 2026 18:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds an end-to-end wallet transfer feature backed by Postgres: schema migrations, DB/config wiring, repository/service layers, and an HTTP endpoint with basic tests.

Changes:

  • Introduces Postgres connection/config loading plus DB migrations for wallets, transfers, and ledger entries.
  • Implements transfer creation across handler → service → repository with transactions and idempotency checks.
  • Adds unit tests for the handler and service using gomock.

Reviewed changes

Copilot reviewed 19 out of 23 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
pkg/config/pg.go Adds env-based Postgres configuration loading.
db/conn.go Adds pgxpool connection helper with pooling settings.
db/migrations/*.sql Introduces wallet/transfers/ledger DB schema.
internal/wallet/domain/transfer.go Adds domain models and validation for transfer requests.
internal/wallet/repository/transfer.go Implements transactional CreateTransfer with idempotency and ledger entries.
internal/wallet/service/transfer.go Adds WalletService layer that validates and delegates to repository.
internal/wallet/service/service_test.go Adds service tests using a mocked repository.
internal/wallet/handler/http/wallet.go Adds POST /wallet/transfer handler and JSON response helper.
internal/wallet/handler/http/wallet_test.go Adds handler tests using a mocked service.
cmd/main.go / app/app.go Wires configuration + DB + routes and starts HTTP server.
go.mod / go.sum Adds module definition and dependency locks.
Makefile Adds build/run/test/mockgen/migrate targets.
README.md Documents stack, schema, idempotency, concurrency strategy.
.gitignore Ignores built binary output.
Files not reviewed (2)
  • internal/wallet/repository/mock/mock.go: Generated file
  • internal/wallet/service/mock/mock.go: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS transfers (
id VARCHAR(40) PRIMARY KEY,
from_wallet_id VARCHAR(40)NOT NULL REFERENCES wallets(id),
Comment thread internal/wallet/repository/transfer.go Outdated
Comment thread internal/wallet/repository/transfer.go Outdated
Comment on lines +88 to +90
if err != nil {
return domain.Transfer{}, fmt.Errorf("Couldn't create transfer entry")
}
Comment on lines +100 to +102
if err != nil {
return domain.Transfer{}, fmt.Errorf("Error while updating debit wallet balance")
}
Comment thread pkg/config/pg.go
Comment on lines +9 to +23
DB_URL = "DB_URL"
)

type PostgresConfig struct {
DbUrl string
}

func LoadPostgresConfig() (PostgresConfig, error) {
dbUrl, ok := os.LookupEnv(DB_URL)
if !ok {
return PostgresConfig{}, fmt.Errorf("Env Var %s not set", DB_URL)
}

return PostgresConfig{
DbUrl: dbUrl,
Comment on lines +41 to +45
func response(w http.ResponseWriter, status int, body any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(body)
}
Comment thread Makefile Outdated
)

func TestCreateTransfer_ValidationError(t *testing.T) {
ctrl := gomock.NewController(t)
Comment thread README.md
| id | VARCHAR(40)| Primary Key|
|transfer_id | VARCHAR(40) |NOT NULL REFERENCES transfers(id)|
|wallet_id | VARCHAR(40)|NOT NULL REFERENCES wallets(id)|
|entry_type |BIGINT| NOT NULL CHECK (entry_type IN ('DEBIT', 'CREDIT'))|
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