Skip to content

Implement Go wallet transfer service#112

Open
vardaanmittal09 wants to merge 3 commits into
Robustrade:mainfrom
vardaanmittal09:solution/vardaan-mittal
Open

Implement Go wallet transfer service#112
vardaanmittal09 wants to merge 3 commits into
Robustrade:mainfrom
vardaanmittal09:solution/vardaan-mittal

Conversation

@vardaanmittal09

@vardaanmittal09 vardaanmittal09 commented Jul 9, 2026

Copy link
Copy Markdown

Summary

Implemented a Go wallet transfer service with GORM-backed SQLite persistence, layered architecture, idempotent transfer creation, stored wallet balances, double-entry ledger entries, and behavioral tests for core transfer scenarios.

AI disclosure

Tool used: OpenAI Codex in the Codex desktop app.

How I used it: I used Codex as a pair-programming assistant to inspect the assignment, create the solution branch, scaffold the Go service, implement the layered design, write tests, and prepare documentation. I reviewed the generated implementation decisions and kept the scope focused on idempotency, ledger consistency, and concurrency control.

Prompts used:

  1. connect with my github
  2. we will do this in go make branch as Wallet Transfer Assignment Repository ... Your PR branch should be named: solution/<your-name> (e.g., solution/jane-doe).
  3. do again

Transcript note: The full interactive transcript is available in the Codex desktop thread. I also added AI_USAGE.md with the tool, usage summary, and prompts.

Schema Design

The SQLite schema is defined through GORM repository models and AutoMigrate. It introduces:

  • wallets: wallet id, stored integer balance, timestamps, and CHECK (balance >= 0).
  • transfers: transfer id, idempotency key, source/destination wallet ids, amount, state, failure reason, timestamps, and state/amount checks.
  • ledger_entries: one debit and one credit row per processed transfer, with type and amount checks, foreign keys to wallets/transfers, and UNIQUE (transfer_id, type).
  • idempotency_records: unique idempotency key, canonical request hash, original transfer id, and a foreign key back to transfers.

Indexes were added for ledger lookup by transfer and wallet.

Idempotency Strategy

POST /transfers requires an idempotencyKey. The service stores the key and a SHA-256 hash of the canonical request payload inside the same database transaction as the transfer.

  • Same key and same payload returns the original transfer result with replay: true.
  • Same key and different payload returns 409 Conflict.
  • Duplicate requests do not create additional transfers, ledger entries, or wallet balance updates.

Concurrency Strategy

Each transfer runs in a serializable SQLite transaction. The store uses one open database connection plus SQLite busy timeout, so writes are serialized for this small service. The debit operation also uses a guarded update:

UPDATE wallets
SET balance = balance - ?
WHERE id = ? AND balance >= ?

That guarded update prevents overspending even when multiple transfers target the same source wallet. Terminal state updates also require state = 'PENDING', making retries safe.

How to Run

  • Install Go 1.24 and CGO build support for github.com/mattn/go-sqlite3.
  • Run go run ./cmd/server.
  • Optional env vars: HTTP_ADDR=:9090 DB_PATH=/tmp/wallets.db go run ./cmd/server.
  • Create a transfer with POST /transfers.
  • Inspect data with GET /wallets/{id} and GET /transfers/{id}.

How to Test

  • Run go test ./....
  • CI runs go vet ./..., gofmt check, and go test ./....

Tradeoffs / Assumptions

  • SQLite with GORM was chosen over PostgreSQL to keep the assignment self-contained and easy to run while still using explicit persistence models.
  • Amounts are integer minor units; no floating point money.
  • Failed business transfers are durable records and do not write ledger entries.
  • The local Codex environment did not have go on PATH, so I could not run the Go test suite locally before pushing. The tests and CI workflow are included for verification in an environment with Go installed.

Checklist

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

@vardaanmittal09
vardaanmittal09 marked this pull request as ready for review July 9, 2026 15:31
Copilot AI review requested due to automatic review settings July 9, 2026 15:31

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

Implements a Go-based wallet transfer HTTP service backed by GORM + SQLite, aiming to provide idempotent transfer creation, stored wallet balances, and double-entry ledger entries with basic concurrency safety.

Changes:

  • Added transfer creation/read APIs with layered handler/service/store design.
  • Implemented SQLite persistence (AutoMigrate schema + transactional debit/credit + ledger writes) and behavioral tests for core scenarios including concurrent debits.
  • Updated CI workflow to run go vet, gofmt check, and go test, and expanded repository documentation/design notes.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
README.md Adds run/test instructions and implementation notes for the Go service.
internal/service/transfer.go Core transfer orchestration: validation, idempotency handling, transactional balance + ledger updates.
internal/service/transfer_test.go Behavioral tests for processing, idempotency, failures, and concurrent overspend prevention.
internal/repository/sqlite/store.go GORM store/transaction wrapper + wallet/transfer/ledger/idempotency persistence operations.
internal/repository/sqlite/models.go SQLite schema models and domain mappers (tables + constraints).
internal/port/transfer.go Defines store/transaction interfaces used by the service layer.
internal/handler/http.go HTTP routing and JSON error/status mapping for transfer/wallet endpoints.
internal/domain/models.go Domain models and state/ledger enums.
internal/domain/errors.go Domain error definitions used across layers.
go.mod Introduces Go module + GORM/SQLite dependencies.
docs/DESIGN.md Documents API contract, persistence approach, idempotency, and concurrency strategy.
cmd/server/main.go Wires up DB, migrations, seeding, and HTTP server startup.
AI_USAGE.md Records AI tool usage disclosure for the work.
.github/workflows/ci.yml Updates CI to install gcc, enable CGO, and run vet/format/tests with Go.

Comment thread internal/repository/sqlite/models.go
Comment thread internal/repository/sqlite/models.go
Comment thread go.mod
Comment on lines +1 to +8
module github.com/vardaanmittal09/wallet-transfer-assignment

go 1.24

require (
gorm.io/driver/sqlite v1.6.0
gorm.io/gorm v1.30.0
)
Comment on lines +243 to +248
func newID(prefix string) string {
var bytes [16]byte
if _, err := rand.Read(bytes[:]); err != nil {
panic(fmt.Sprintf("generate id: %v", err))
}
return prefix + "_" + hex.EncodeToString(bytes[:])
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
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