docs: Initial approach and architecture for wallet transfer service - #105
Open
anilkumar2809 wants to merge 2 commits into
Open
docs: Initial approach and architecture for wallet transfer service#105anilkumar2809 wants to merge 2 commits into
anilkumar2809 wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds initial design and AI-usage documentation for the wallet transfer assignment, focusing on proposed architecture, database schema, idempotency, and concurrency approach.
Changes:
- Introduces
DESIGN.mdoutlining the intended layered architecture, schema, and locking/idempotency strategy. - Adds
AI_USAGE.mddocumenting how AI tools were used during the design phase.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| DESIGN.md | Documents proposed architecture, schema, and concurrency/idempotency approach for the wallet transfer service. |
| AI_USAGE.md | Records AI tooling usage and design discussion transcript. |
|
|
||
| I will rely on PostgreSQL's native ACID properties to handle distributed system edge cases: | ||
|
|
||
| * **Idempotency:** A `UNIQUE` constraint on `idempotency_records.idempotency_key`. If a concurrent retry hits the DB, the uncommitted lock will briefly block it, then safely reject it once the first transaction completes, allowing the API to return the processed response/status. |
|
|
||
| * **Idempotency:** A `UNIQUE` constraint on `idempotency_records.idempotency_key`. If a concurrent retry hits the DB, the uncommitted lock will briefly block it, then safely reject it once the first transaction completes, allowing the API to return the processed response/status. | ||
| * **Concurrency (Race Conditions):** The entire transfer lifecycle will be wrapped in a single database transaction. I will use pessimistic locking (`SELECT ... FOR UPDATE`) on the wallet rows to ensure sequential balance deductions. | ||
| * **Deadlock Prevention:** To prevent A $\rightarrow$ B and B $\rightarrow$ A deadlocks, the application will consistently sort the wallet UUIDs lexicographically(fromWalletId, then toWalletId) before acquiring the row locks. |
Comment on lines
+42
to
+46
| #### 6. Scaling(Not Going to implement but design constraints) | ||
| * Consider implementing patroni cluster for better node management | ||
| * consider Implementing DB wrapper such that underlying application interacts with the DB wrapper and need not be aware of the underlying DB, such that we can swap out for mySQL, Oracle DB if required later. | ||
| * Consider implementing the logic to maintain the connection pool. | ||
| * consider implementing additional services/crontabs and additiona of Queues to retry/clearn any dangling requests. No newline at end of file |
Comment on lines
+2
to
+3
| Additional Prompts used on Gemini to get clarity | ||
| PostgresSQL locking mechanisms including pessismistic locking and also different types of lock mechanisms. |
|
|
||
| How would you briefly address the "merchant contention" issue in the PR notes without actually over-engineering the code to solve it right now? | ||
|
|
||
| *Viewed [ASSIGNMENT.md](file:///Users/anilkumaryalla/Desktop/git_repo/wallet-transfer-assignment/ASSIGNMENT.md) * |
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
Describe your solution briefly.
1. Core Understanding
The goal is to build a highly reliable, concurrent wallet-to-wallet transfer Service.
The primary engineering challenges are guaranteeing exactly-once processing (idempotency), strictly maintaining a balanced double-entry ledger, and preventing race conditions/deadlocks during concurrent requests.
2. Proposed Architecture & Stack
3. Database Schema (PostgreSQL)
I will use 4 primary tables.
idempotency_records:idempotency_key(PRIMARY KEY),request_hash,response_status,response_body,created_at(TIMESTAMP with TIME ZONE DEFAULT CURRENT_TIMESTAMP).wallets:id,balance(with aCHECK balance >= 0constraint).transfers:id,idempotency_key(UNIQUE index),from_wallet_id,to_wallet_id,amount,status.ledger_entries:id,transfer_id,wallet_id,type(DEBIT/CREDIT),amount.(Note: To favor simplicity and prevent orphaned states in the event of an application crash, I am executing all the operations on the tables and handling everything within a single transaction).
4. Concurrency & Idempotency Strategy
I will rely on PostgreSQL's native ACID properties to handle distributed system edge cases:
UNIQUEconstraint onidempotency_records.idempotency_key. If a concurrent retry hits the DB, the uncommitted lock will briefly block it, then safely reject it once the first transaction completes, allowing the API to return the processed response/status.SELECT ... FOR UPDATE) on the wallet rows to ensure sequential balance deductions.5. Design Decisions & Trade-offs
Chosen Approach: Single Atomic Transaction
Pros: Simplicity. Zero possibility of orphaned states (such as writing an idempotency key as PENDING but crashing before money moves, locking the user out indefinitely). Relies directly on the maturity of PostgreSQL ACID mechanics.
Cons : Concurrent retries will briefly hang/block at the database level while waiting for the original transaction to commit, rather than immediately returning a 409 Conflict. Given a targeted REST API response time of$<50\text{ms}$ , this brief block is a preferred trade-off over implementing asynchronous sweepers and cleanup crons.
6. Scaling(Not Going to implement but design constraints)
AI disclosure
Detail how you used AI to help with your submission (including the tools you used, how
you used them and what your prompts were).
Include these points in detail
I have included it a sperate file as AI_USAGE.md
Schema Design
Describe the tables, constraints, and indexes you introduced.
Idempotency Strategy
Explain how duplicate requests are handled safely.
Concurrency Strategy
Explain how you prevent race conditions and double spending.
How to Run
How to Test
Tradeoffs / Assumptions
Checklist