{"id":50798370,"url":"https://github.com/ovpn-dev/digital-wallet","last_synced_at":"2026-06-12T16:35:16.301Z","repository":{"id":337836422,"uuid":"1155453564","full_name":"ovpn-dev/digital-wallet","owner":"ovpn-dev","description":null,"archived":false,"fork":false,"pushed_at":"2026-02-11T14:36:18.000Z","size":31,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-11T22:37:15.860Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ovpn-dev.png","metadata":{"files":{"readme":"README.md","changelog":"history-service/Cargo.toml","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-11T14:32:07.000Z","updated_at":"2026-02-11T14:36:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ovpn-dev/digital-wallet","commit_stats":null,"previous_names":["ovpn-dev/digital-wallet"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ovpn-dev/digital-wallet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ovpn-dev%2Fdigital-wallet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ovpn-dev%2Fdigital-wallet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ovpn-dev%2Fdigital-wallet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ovpn-dev%2Fdigital-wallet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ovpn-dev","download_url":"https://codeload.github.com/ovpn-dev/digital-wallet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ovpn-dev%2Fdigital-wallet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34253937,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-12T02:00:06.859Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-12T16:35:14.393Z","updated_at":"2026-06-12T16:35:16.295Z","avatar_url":"https://github.com/ovpn-dev.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Digital Wallet Transaction System\n\nA distributed digital wallet system built with Rust, PostgreSQL, and Kafka demonstrating:\n- Event-driven architecture\n- ACID transactions with optimistic locking\n- Event sourcing and eventual consistency\n- Kafka producer/consumer patterns\n\n## Architecture\n\n```\n┌─────────────────┐         ┌──────────────┐         ┌─────────────────┐\n│ Wallet Service  │────────▶│    Kafka     │────────▶│ History Service │\n│   (Port 3000)   │ publish │wallet-events │ consume │   (Port 3001)   │\n└────────┬────────┘         └──────────────┘         └────────┬────────┘\n         │                                                     │\n         │                 ┌──────────────────────┐           │\n         └────────────────▶│    PostgreSQL        │◀──────────┘\n                           │  (Shared Database)   │\n                           └──────────────────────┘\n```\n\n## Services\n\n### Wallet Service (Port 3000)\n- Create wallets for users\n- Fund wallets with money\n- Transfer money between wallets\n- Publishes events to Kafka\n- **Tech:** Axum, SQLx, Rust, PostgreSQL\n\n### History Service (Port 3001)\n- Consumes wallet events from Kafka\n- Stores event-sourced transaction history\n- Provides query APIs for transaction history\n- Handles duplicate events (idempotent)\n- **Tech:** Axum, SQLx, rdkafka, PostgreSQL\n\n## Tech Stack\n\n- **Language:** Rust (Edition 2021)\n- **Web Framework:** Axum 0.7\n- **Database:** PostgreSQL 16\n- **Message Broker:** Apache Kafka\n- **Async Runtime:** Tokio\n- **Money Handling:** rust_decimal (no floats!)\n\n## Quick Start\n\n### Prerequisites\n\n- Rust 1.75+\n- PostgreSQL 16+\n- Apache Kafka + Zookeeper\n- Java 17+ (for running Kafka)\n\n### Setup\n\n```bash\n# Clone the repository\ngit clone \u003cyour-repo-url\u003e\ncd digital-wallet\n\n# Setup infrastructure\ncd scripts\n./setup-postgres.sh\n./setup-kafka.sh\n\n# Start Kafka (PostgreSQL auto-starts)\n./start-kafka.sh\n\n# Terminal 1: Run wallet service\ncd ../wallet-service\ncargo run\n\n# Terminal 2: Run history service\ncd ../history-service\ncargo run\n```\n\n### Test It\n\n```bash\n# Create a wallet\ncurl -X POST http://localhost:3000/wallets \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"user_id\": \"alice\"}'\n\n# Fund the wallet\ncurl -X POST http://localhost:3000/wallets/{WALLET_ID}/fund \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"amount\": \"100.00\"}'\n\n# Check history (wait 1-2 seconds for event processing)\ncurl http://localhost:3001/wallets/{WALLET_ID}/history\n```\n\n## Project Structure\n\n```\ndigital-wallet/\n├── .gitignore\n├── README.md                 # This file\n├── docker-compose.yml        # Optional: Docker setup\n├── scripts/                  # Setup scripts\n│   ├── setup-postgres.sh\n│   ├── setup-kafka.sh\n│   ├── start-kafka.sh\n│   └── stop-kafka.sh\n├── wallet-service/           # Main transaction service\n│   ├── src/\n│   │   ├── main.rs\n│   │   ├── models.rs\n│   │   ├── repository.rs    # Database operations\n│   │   ├── handlers.rs      # HTTP endpoints\n│   │   ├── kafka.rs         # Event publishing\n│   │   └── errors.rs\n│   ├── migrations/           # Database migrations\n│   ├── Cargo.toml\n│   ├── .env.example\n│   └── README.md\n└── history-service/          # Event consumer \u0026 query service\n    ├── src/\n    │   ├── main.rs\n    │   ├── models.rs\n    │   ├── repository.rs\n    │   ├── handlers.rs\n    │   ├── consumer.rs      # Kafka consumer\n    │   └── errors.rs\n    ├── migrations/\n    ├── Cargo.toml\n    ├── .env.example\n    └── README.md\n```\n\n## Key Features\n\n### 1. Optimistic Locking\nPrevents lost updates during concurrent operations:\n```rust\nUPDATE wallets \nSET balance = new_balance, version = version + 1\nWHERE id = wallet_id AND version = current_version;\n```\n\n### 2. Deadlock Prevention\nTransfers always lock wallets in consistent order:\n```rust\nlet (first, second) = if wallet_a \u003c wallet_b {\n    (wallet_a, wallet_b)\n} else {\n    (wallet_b, wallet_a)\n};\n```\n\n### 3. Event Sourcing\nComplete audit trail of all operations:\n```sql\nSELECT * FROM transaction_events \nWHERE wallet_id = 'abc-123' \nORDER BY created_at DESC;\n```\n\n### 4. Idempotent Event Processing\nHandles Kafka's at-least-once delivery:\n```rust\nif already_processed(transaction_id) {\n    return; // Skip duplicate\n}\n```\n\n### 5. Decimal Precision\nNever use floats for money:\n```rust\nuse rust_decimal::Decimal; // Exact precision\nlet amount: Decimal = dec!(100.00);\n```\n\n## API Documentation\n\n### Wallet Service (Port 3000)\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| POST | `/wallets` | Create a new wallet |\n| GET | `/wallets/:id` | Get wallet details |\n| GET | `/users/:id/wallets` | List user's wallets |\n| POST | `/wallets/:id/fund` | Add money to wallet |\n| POST | `/wallets/:id/transfer` | Transfer between wallets |\n| GET | `/health` | Health check |\n\n### History Service (Port 3001)\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/wallets/:id/history` | Get transaction history |\n| GET | `/users/:id/activity` | Get user activity |\n| GET | `/health` | Health check |\n\n## Database Schema\n\n### Wallets Table\n```sql\nCREATE TABLE wallets (\n    id VARCHAR(36) PRIMARY KEY,\n    user_id VARCHAR(100) NOT NULL,\n    balance DECIMAL(19,4) NOT NULL DEFAULT 0,\n    version BIGINT NOT NULL DEFAULT 0,\n    created_at TIMESTAMP,\n    updated_at TIMESTAMP\n);\n```\n\n### Transaction Events Table\n```sql\nCREATE TABLE transaction_events (\n    id VARCHAR(36) PRIMARY KEY,\n    wallet_id VARCHAR(36) NOT NULL,\n    user_id VARCHAR(100) NOT NULL,\n    amount DECIMAL(19,4) NOT NULL,\n    event_type VARCHAR(30) NOT NULL,\n    transaction_id VARCHAR(36),\n    created_at TIMESTAMP,\n    event_data JSONB NOT NULL\n);\n```\n\n## Configuration\n\nBoth services use `.env` files (create from `.env.example`):\n\n```bash\n# Wallet Service (.env)\nDATABASE_URL=postgres://wallet_user:wallet_pass@localhost:5432/wallet_db\nKAFKA_BROKERS=localhost:9092\nKAFKA_TOPIC=wallet-events\nPORT=3000\n\n# History Service (.env)\nDATABASE_URL=postgres://wallet_user:wallet_pass@localhost:5432/wallet_db\nKAFKA_BROKERS=localhost:9092\nKAFKA_TOPIC=wallet-events\nKAFKA_GROUP_ID=history-service-group\nPORT=3001\n```\n\n## Development\n\n### Running Tests\n\n```bash\n# Wallet service tests\ncd wallet-service\ncargo test\n\n# History service tests\ncd history-service\ncargo test\n```\n\n### Building for Production\n\n```bash\n# Build optimized binaries\ncargo build --release\n\n# Binaries will be in:\n# wallet-service/target/release/wallet-service\n# history-service/target/release/history-service\n```\n\n### Database Migrations\n\n```bash\n# Run migrations manually\ncd wallet-service\nsqlx migrate run\n\ncd history-service\nsqlx migrate run\n```\n\n## Monitoring\n\n### Check Kafka Consumer Lag\n\n```bash\n~/kafka/bin/kafka-consumer-groups.sh \\\n  --bootstrap-server localhost:9092 \\\n  --describe \\\n  --group history-service-group\n```\n\n### Database Consistency Check\n\n```sql\n-- Verify wallet balances match transaction sums\nSELECT \n  w.balance as current,\n  COALESCE(SUM(\n    CASE \n      WHEN wt.type = 'FUND' THEN wt.amount\n      WHEN wt.type = 'TRANSFER_IN' THEN wt.amount\n      WHEN wt.type = 'TRANSFER_OUT' THEN -wt.amount\n    END\n  ), 0) as calculated\nFROM wallets w\nLEFT JOIN wallet_transactions wt ON w.id = wt.wallet_id\nGROUP BY w.id, w.balance;\n```\n\n## Known Limitations\n\n### Dual-Write Problem\nIf database commit succeeds but Kafka publish fails:\n- Wallet state updated ✅\n- Event not published ❌\n- History won't be updated\n\n**Solution for production:** Implement outbox pattern or use CDC (Debezium).\n\n### Eventual Consistency\nHistory updates are **eventually consistent**:\n- Wallet balance: Immediate\n- History: Usually \u003c 1 second lag\n\nThis is by design! See documentation for details.\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## Learning Resources\n\n- [Rust Async Book](https://rust-lang.github.io/async-book/)\n- [SQLx Documentation](https://github.com/launchbadge/sqlx)\n- [Kafka Documentation](https://kafka.apache.org/documentation/)\n- [Designing Data-Intensive Applications](https://dataintensive.net/)\n\n## License\n\nMIT License - Feel free to use this for learning!\n\n## Acknowledgments\n\nBuilt as a learning project to understand:\n- Distributed systems patterns\n- Event-driven architecture\n- Rust async programming\n- Database transactions and consistency\n\n---","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fovpn-dev%2Fdigital-wallet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fovpn-dev%2Fdigital-wallet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fovpn-dev%2Fdigital-wallet/lists"}