WalletManager is a backend service for managing users, wallets, balances, and transactions. The project is built using Clean Architecture / DDD-lite principles with a clear separation of domain logic, infrastructure, and application use cases.
-
๐ค User management (registration, login, blocking)
-
๐ Wallet management (creation, blocking, closing)
-
๐ฐ Balance management:
- regular (single currency)
- multi-currency (multiple assets per wallet)
-
๐ณ Transaction management:
- deposit
- withdrawal
- exchange
-
๐ญ Factory + Registry pattern for all domain entities
-
๐ Mapper layer (domain โ database)
-
๐ง Domain invariants (DomainInvariant)
-
๐ช Event signaling via blinker
-
๐ SQLAlchemy + PostgreSQL integration
-
๐ฆ Facade layer for use cases
The project is structured according to Clean Architecture principles.
Pure business logic. Does not depend on database, frameworks, or infrastructure.
UserBase,Client,Admin- domain invariants (email, name, password)
- user status handling
DebitWallet,CreditWallet- ownership relation
- blocking / closing logic
RegularBalanceโ single currencyForeignBalanceโ multiple currencies- stored internally as
dict[currency -> amount]
DepositTransactionWithdrawTransactionExchangeTransaction
๐ Domain layer contains:
- no ORM
- no SQL
- only business rules and invariants
Handles persistence and external dependencies.
UserTableWalletTableBalanceTableTransactionTable
Responsible for transforming:
Domain โ ORM (SQLAlchemy models)
UserMapperWalletMapperBalanceMapperTransactionMapper
๐ Important detail:
ForeignBalanceis stored as multiple rows in DB- and reconstructed via grouping
Split into:
commandsโ write operations (insert/update/delete)queriesโ read operations
Examples:
UserCommandsRepositoryWalletQueriesRepositoryBalanceCommandsRepository
Encapsulates business workflows.
CreateUserServiceLoginUserServiceBlockUserServiceCloseUserService
CreateWalletServiceBlockWalletServiceCloseWalletService
CreateBalanceServiceFreezeBalanceServiceShowBalanceService
CreateTransactionServiceShowTransactionServiceSortTransactionService
Provides a simplified interface:
UserServiceFacadeWalletServiceFacadeBalanceServiceFacadeTransactionServiceFacade
๐ Avoids direct interaction with multiple services
Each domain has:
- Factory โ creates instances
- Registry โ maps type โ class
Example:
BalanceTypesEnum.FOREIGN โ ForeignBalance
๐ Benefits:
- extensibility
- no hardcoded conditionals
- easy addition of new types
Shared components:
- ๐ข Enums (User, Wallet, Balance, Transaction)
โ ๏ธ DomainInvariant (validation rules)- ๐ช Signals (blinker)
- ๐งฐ utilities / decorators
- ๐ logging
Stored in DB as:
wallet_id | currency | amount
In domain:
{ "BTC": 2, "USDT": 3, "TON": 5 }
๐ Reconstructed using:
grouped[obj.balance_id]
Validation happens inside domain models:
DomainInvariant.no_empty(...)
DomainInvariant.is_instance(...)๐ Ensures consistent object state
On state change:
user_upgrade_signal.send(...)๐ Enables:
- logging
- auditing
- event-driven extensions
Clear separation:
Database model โ Domain model
๐ Prevents ORM leakage into business logic
- ๐ญ Factory Pattern
- ๐ Registry Pattern
- ๐ญ Facade Pattern
- ๐งฑ Mapper Pattern
- ๐ช Observer Pattern (via signals)
- ๐ง DDD-lite principles
- Unit of Work pattern
- CQRS (separate read/write models)
- Domain Events (instead of direct signals)
- Proper Alembic migration setup
- Async SQLAlchemy
- Redis (caching / locks)
- Integrate DI container (e.g. Dishka)
- FastAPI integration
- Pydantic DTOs for request/response
This project demonstrates:
- strong backend architecture design skills
- separation of concerns
- clean domain modeling
- practical usage of design patterns
- building scalable, production-ready systems