49 KiB
Darano Refactoring Audit
Audit date: 2026-08-14
Active repositories: api, auth, wallet, AdminPanel, proto.
Excluded and not audited: ui, docs, DevOps.
Repository safety
| Repository | Branch | Initial state | HEAD at audit |
|---|---|---|---|
api |
feat/refactor-v1 |
Clean | 37b72f8 |
auth |
feat/refactor-v1 |
Clean | 1d4cba4 |
wallet |
feat/refactor-v1 |
Clean | 53b6901 |
AdminPanel |
feat/refactor-v1 |
Clean | b4668d4 |
proto |
feat/refactor-v1 |
Existing untracked buf-Linux-x86_64.bin |
892ffc2 |
No nested AGENTS.md files were found in the active repositories. Root instructions therefore govern all active work.
Findings that correct the planning documents
apiusesknadh/koanf/v2;authandwalletstill usekkyr/fig. The refactoring plan is correct on this point, while the rootAGENTS.mdcurrent-state summary is stale.- All three Go services expose global
config.Cfgand read it throughout bootstrap, logging, transport, use-case, repository, and utility code. - Every current
ParseConfigcalls(&sync.Once{}).Do(...). Because that creates a newsync.Onceper invocation, configuration is not actually guarded by a process-wide once initializer. - API upstream connections are created through
grpc.NewClient, health-checked on first acquisition, and closed by a two-minute context timer. The timer is not reset on subsequent use, so current behavior is a fixed connection lifetime rather than a true two-minute inactivity timeout. authapplication structs directly implement and embed generated public and internal gRPC server interfaces.wallet/core/{walletImp,marketImp,alertImp}directly implements generated servers and mixes protobuf mapping, configuration, business rules, repositories, cryptography, and Stellar operations.- Repository interfaces live in top-level
repositorypackages and use GORM-tagged structs fromdomain/db; domain and persistence representations are therefore conflated. - AdminPanel has BetterProto/grpclib dependencies and a generator configuration, but no application gRPC client integration was found. Its generator reads the remote
v2proto branch rather than the localprotocheckout. - AdminPanel writes directly through
MultiDBMixIn, specialized admin classes, and signals. The unmanagedcoreLogic/models.pyreplicas are used for both reads and writes. CoreRouter.no_migartionis misspelled and is referenced byallow_migrate, confirming the planned router fix.- Existing internal wallet RPCs cover locking, commission operations, public-key lookup, and referral commission initialization. They do not currently expose general AdminPanel asset/wallet/market mutation operations.
- Automated test coverage is extremely limited: the audit found only
wallet/repository/db/redis/lock_test.goamong conventional Go/Python test filenames in the active repositories.
Generated-code boundaries
api,auth, andwalletgenerate Go protobuf code intodomain/stub/gofrom the local rootprotodirectory.- Their Buf generation configurations use
clean: true; generation replaces output directories. - Generated Go stubs are marked
DO NOT EDITand must remain mechanically generated. - AdminPanel generates BetterProto Python code into
src/stub, currently from a remote repository branch. - Root
proto/buf.gen.yamlgenerates Go, documentation, gateway, and TypeScript artifacts underproto/stub; the root repository has no Makefile. - The existing untracked
proto/buf-Linux-x86_64.binis user-owned baseline state and must not be removed or committed implicitly.
Current architecture map
api
- Bootstrap:
cmd/serve.go - Configuration:
config/config.go - HTTP adapters:
handler/ - Middleware:
middlewares/ - Upstream gRPC aggregation:
service/ - Generated contracts:
domain/stub/go/ - Notable compatibility constraints: middleware order, response envelopes, HTTP-to-gRPC metadata, reflection-based peer field lookup, connection lifetime behavior, Swagger environment mapping, profiling, metrics, WebSocket.
auth
- Bootstrap and gRPC registration:
cmd/serve.go - Configuration: fig-based
config/config.go - Business and gRPC implementation:
usecase/ - Repository ports and aggregate:
repository/ - PostgreSQL/Redis/service implementations:
repository/db/andrepository/service/ - Persistence models: GORM-tagged
domain/db/ - Generated contracts:
domain/stub/go/
wallet
- Multi-mode bootstrap:
cmd/andcmd/cmdServe/ - Configuration: fig-based
config/config.go - Business and gRPC implementation:
core/walletImp,core/marketImp,core/alertImp - Cron orchestration:
core/cronJobs - Repository ports and aggregate:
repository/ - PostgreSQL, Redis, queue, mailer, and service implementations:
repository/ - Stellar implementation:
port/stellar - Persistence models: GORM-tagged
domain/db/ - Generated contracts:
domain/stub/go/
AdminPanel
- Shared direct-write behavior:
src/utils/base_admin.py - Business rules and specialized writes:
src/coreLogic/admin/ - Additional write side effects:
src/coreLogic/signals.py - Database router:
src/adminpanel/db/routers.py - Legacy unmanaged models:
src/coreLogic/models.py - Generated Python target:
src/stub/
proto
- Source packages:
base/v1,errors/v1,auth/v1,wallet/v1,market/v1,alert/v1 - Buf lint policy: BASIC plus package/import rules; breaking policy: FILE
- Contract changes must remain backward-compatible and be justified by a proven service-layer gap.
Migration implications
- Configuration loader migration and removal of globals must be separate tasks. First preserve parsing behavior, then inject configuration into progressively deeper dependencies.
- Current fixed connection lifetime and config reparse behavior are compatibility baselines, even if they appear unintended. Tests must capture them before an intentional correction.
- Package moves must proceed through vertical slices because existing test coverage cannot protect a repository-wide rename.
- AdminPanel mutation inventory and RPC gap analysis must happen before protobuf edits.
- AdminPanel should eventually generate against the local proto checkout during coordinated changes, but switching its source is a separate, verified task.
Toolchain and dependency baseline
| Tool | Baseline |
|---|---|
| Go | go1.26.5-X:nodwarf5 linux/amd64; active modules declare Go 1.24; GOTOOLCHAIN=auto |
| Python | 3.14.6 |
| uv | 0.12.2 |
| Django | 5.2.14 |
| Buf | /usr/bin/buf, 1.72.0 |
| protoc | 35.1 |
| protoc-gen-go | 1.36.11 |
| protoc-gen-go-grpc | 1.6.2 |
| swag | 1.16.4 |
| air | 1.66.0 |
| BetterProto | 1.2.5 |
| grpclib | 0.4.9 |
The committed go.mod, go.sum, AdminPanel/pyproject.toml, and AdminPanel/uv.lock are the dependency baseline. No dependency was upgraded. Notable direct versions include API koanf 2.3.4, auth/wallet fig 0.5.0, API gRPC declaration 1.62.1, auth/wallet gRPC declaration 1.67.1, and the shared replacement of gRPC with 1.64.0 in all three modules.
The local untracked Buf file is mode 0644, size 54,050,978 bytes, SHA-256 8720830e26a733da55bb89bcd3cb44849c0965fc0c44fb5d691cccdc64dca5af; it is not executable. protoc-gen-doc and protoc-gen-es are absent, while protoc-gen-grpc-gateway is installed. Root proto generation therefore has known missing-tool preconditions.
A read-only go list -m all succeeded from the local cache for auth and wallet. API enumeration attempted to contact the configured private Go proxy and was sandbox-blocked; committed module files remain sufficient and authoritative for the no-upgrade baseline.
Baseline check results
proto
buf build: passed.buf lint: passed after redirecting Buf's cache to a writable temporary directory; the default cache location is read-only in the workspace sandbox.buf format --diff --exit-code: failed with existing formatting differences in alert, base, errors, market, and wallet proto files. No formatting changes were applied.- Exact root
buf generatein a temporary clone: failed becauseprotoc-gen-docandprotoc-gen-esare not installed. Other plugins were canceled after those failures. - The active proto working tree remained unchanged, and the pre-existing untracked Buf binary retained its original SHA-256.
auth
make build-proto: passed in a temporary clone and reproduced committed stubs with no diff.make test: passed; every package reports no test files.make build: passed and produced the service binary.- The active auth working tree remained unchanged.
wallet
make build-proto: passed and reproduced committed stubs, including the intentionalomitemptyremoval, with no diff.make test: passed; the Redis lock package test passed and all other packages report no test files.make build: passed, including generation, formatting/tidy, and binary creation, with no tracked diff afterward.- The active wallet working tree remained unchanged.
- Cross-process
flockis implemented by theair-buildtarget..NOTPARALLELonly serializes targets within one Make invocation, so refactor checks will continue to avoid concurrent standalone generation/build commands.
api
make build-proto: passed and reproduced committed stubs, including intentionalomitemptyremoval, with no diff.make test: passed; every package reports no test files.make build: passed, including go/swag formatting, tidy, protobuf generation, Swagger generation, and binary creation.- Generated protobuf and Swagger outputs are reproducible with the installed tools; the temporary clone remained clean after the build.
- The active API working tree remained unchanged.
AdminPanel
manage.py check: passed with no issues.manage.py check --deploy: exited successfully but reports six existing security warnings for HSTS, SSL redirect, weak/development secret key, secure session/CSRF cookies, and DEBUG.manage.py test --noinput: discovered zero tests and failed its system check because Django Debug Toolbar is enabled while Django forces DEBUG false for tests.makemigrations --check --dry-run: passed with no model migration drift.- Python bytecode compilation: passed.
- No database migrations were run, no application database was modified, and the active working tree remained clean.
First migration slice
The first code task is C001, limited to auth configuration ownership and parsing:
- Add
auth/infrastructure/configas the owner of config types and a pureLoad(path) (*Config, error)function based on koanf/TOML. - Preserve all existing TOML keys, types, durations, peer field capitalization, and actual reparse behavior.
- Keep
auth/configtemporarily as a compatibility facade soC001does not also perform global dependency injection. - Add synthetic loader tests that do not read or expose repository secrets.
- Remove fig and add the same pinned koanf packages already used by API.
- Run generation, tests, and build; require a clean generated diff and no behavior changes outside configuration parsing.
Global config removal remains the separate follow-up C002.
Implementation progress
C001 — auth configuration ownership and koanf loader
- Added
authorization/infrastructure/configwith config types and a pure, error-returning TOML loader. - Replaced fig tags/dependency with pinned koanf packages matching API.
- Retained
authorization/configas an explicitly temporary compatibility facade; its global API and effective reload-on-each-call behavior are preserved forC002. - Added synthetic tests for flags, durations, GORM level, uppercase peer keys, missing files, independent loads, and legacy facade reloads.
- Proto generation remained reproducible; full tests, targeted race tests, and binary build passed.
go vet ./...still reports the same two pre-existing findings as the untouched baseline: unreachable code inlogger/main.goand a discarded timeout cancel inusecase/identity.go.- Auth commit:
29b7e07 refactor(auth): move config loading to infrastructure.
C002 — auth configuration injection
- Auth configuration is now loaded once in
cmd/serve.goand passed explicitly into database, Redis, upstream-service, repository-system, use-case, gRPC-server, profiling, logger, and JWT utility boundaries. - JWT helpers receive the narrow
JWTModelvalue rather than consulting process state. - PostgreSQL now uses its constructor argument for GORM log level instead of reading a global.
- The legacy
authorization/configfacade andCfgglobal were removed. - Source scans confirm no production
config.Cfg,Cfgglobal, or legacy config import remains. - Full tests, full race tests, proto generation, module tidy, and binary build passed. Vet remains limited to the two confirmed baseline findings.
- Auth commit:
1bd5559 refactor(auth): inject service configuration.
C003 — wallet configuration ownership and koanf loader
- Added
wallet/infrastructure/configwith pure TOML loading and retainedwallet/configas a temporary compatibility facade forC004. - Reproduced measured fig defaults: page size 50, gRPC timeout 1s, Redis port/DB/mutex defaults, cron timings/retries, log level, nil SMTP without a section, and SMTP port/auth defaults with a section.
- Added tests for defaults, nested overrides, durations, uppercase peer keys, missing files, independent load state, legacy facade reloads, and all five committed service-mode config files.
- Removed fig and pinned the same koanf packages used by API/auth.
- Proto output remained reproducible; full tests, targeted race tests, module tidy, and full build passed.
- Wallet vet remains limited to three findings reproduced in the untouched baseline: logger unreachable code, alert timeout cancel, and protobuf lock copying in queue JSON marshaling.
- Wallet commit:
7958530 refactor(wallet): move config loading to infrastructure.
C004 — wallet configuration injection
- Configuration is loaded once by each Cobra command and carried explicitly through command context into repository setup, service constructors, gRPC listeners, profiling, availability monitoring, ledger and transaction-event workers, cron jobs, and Stellar initialization.
- Repository, domain/use-case, market, alert, wallet lifecycle, financial, SMS, logger, and Stellar dependencies now receive either the full configuration or narrow values at construction/call boundaries.
- Stellar transaction fees, network passphrase, gas policy, deterministic key material, and distributor secret are injected into the adapter; focused tests verify the initialized client retains every supplied value.
- Removed the temporary
wallet/configcompatibility facade and its process-globalCfg; production source has no active global configuration reads or legacy config imports. - Full
go test ./...,go test -race ./...,go vet ./..., andgo build ./...pass with the isolated Go cache. - Wallet implementation was committed in reviewable slices from
f507637through4d192a6, including final Stellar (53df96a), logger (1b3ffc8), and command-root (4d192a6) injection commits.
C005/C006 — API configuration ownership and injection
- Moved API configuration types and pure koanf/TOML loading into
api/infrastructure/config, preserving the default IPG callback and UI error URLs and file-overrides-default behavior. - The command boundary loads configuration once and passes it into logger, gRPC service composition, HTTP handlers, middleware, Swagger selection, profiling, and upstream clients.
- Removed the API
config.Cfgsingleton and legacygateway/configpackage; source scans show no active global configuration reads or legacy imports. - API
go test ./...,go test -race ./...,go vet ./..., andgo build ./...pass. Existing unrelated Swagger and module-file work remains uncommitted and preserved. - API commit:
44d56d3 refactor(api): move and inject configuration.
L009/L010 — GL reconciliation and recovery verification
- GL provides read-only reconciliation over sealed journals, detecting invalid journals and duplicate source transaction/version identities without mutating ledger state.
- External settlement evidence can be compared repeatedly against GL journals to report missing evidence, duplicate evidence, and blockchain network/hash mismatches.
- The read-only explorer reconstructs account and holder balances from immutable entries and exposes journal, transaction-hash, account, and balance reads for disaster recovery.
- Replay is bounded and idempotent; immutable journal validation, canonical payload hashes, transactional rollback, sealed-journal checks, and database uniqueness constraints prevent duplicate or partial postings.
- Conservation and concurrent transfer behavior are exercised by the fixed redistribution load scenario; GL full tests, race tests, vet, and build pass. The sandbox initially blocked localhost sockets for an existing
httptesttest; the same verification passed with localhost access enabled. - GL implementation commits:
3f5fd86,b14c5e2, andd5c9b33; verification completed on2026-08-30.
Auth periodic identity validation extension
- Added
Identity.LastCheckedfor the biweekly phone/national-ID validation andIdentity.LastBirthDateCheckedfor the monthly national-ID/birthdate validation; Auth's existing startup auto-migration adds the indexed columns. - Added a local-midnight scheduler job with configurable cron expression and independent validation intervals (defaults: 14 days and 30 days).
- The job retries failed people on a later run by updating timestamps only after successful validation and refresh; it reports checked, skipped, and failed counts without disabling or overwriting an identity on a failed provider check.
DISABLE_PRIODICAL_IDENTITY_VALIDATION=1(the requested spelling;0,true, andfalseare also accepted) disables the job. The nestedperiodic-identity-validationconfig section controls schedule, intervals, and the file-level disabled flag.- Auth full tests, race tests, vet, and build pass; implementation committed as
9bc9cca.
A001 — Auth RPC and dependency migration map
| RPC / operation | Current operation | Persistence / external dependencies | Target application boundary |
|---|---|---|---|
AuthorizationSrvHealth, InternalAuthorizationSrvHealth |
readiness check | PostgreSQL ping | health use case + gRPC adapter |
CheckIAM |
authenticate request identity and load roles/identity | User, Identity, Role, RolePermission, Redis cache | authorization use case |
SendLoginOTP, LoginWithOTP, GetAccessTokenByRefreshToken |
OTP issuance, login, refresh-token rotation | User, Session, OTP templates, Redis, Kavenegar, JWT keys | authentication/OTP use cases |
GetUserPermission, InitPermissionsForRoutes, InitAdminRole |
route/role/permission bootstrap and lookup | Permission, Role, RolePermission, User, Redis | permission use case |
GetIdentity, UpdateIdentity, GetUserIdentityBasic, GetUserIAM, GetUser |
identity read/update and IAM projection | User, Identity, Redis, Shahkar provider, Pecco/Zohal/Ehraz, Internal Wallet | identity use case |
GetBankInfoList, UpdateBankInfo, RemoveBankInfo |
IBAN verification and bank-info lifecycle | BankInfo, Identity, transaction boundary, Zohal | bank-information use case |
ProcessTFAReq, InitTFAReq, CheckTFACode |
TFA state/code lifecycle | Session, Redis, Kavenegar, OTP templates | TFA use case |
LookUpName |
resolve mobile/national ID/public key to recipient | direct SQL join of User/Identity | recipient lookup use case |
FetchBasicUserInfoList |
list basic user identities for internal consumers | User, Identity | internal user-query use case |
DeleteCache |
invalidate authorization/identity cache | Redis | cache management operation |
| periodic identity validation | scheduled phone/national-ID and national-ID/birthdate refresh | User, Identity, Shahkar/person providers | scheduled identity-validation use case |
The current composition root is cmd/serve.go; repository.System aggregates PostgreSQL, Redis, and upstream service ports, while usecase.useCase currently implements both generated gRPC server interfaces. External provider selection is configuration-driven (ShahkarProvider), and the Wallet/Notification clients are gRPC dependencies. This map is the baseline for A002–A008 package extraction.
A002 — Auth domain entities and repository ports
- Added
auth/domain/modelwith transport/persistence-independent User, Identity, Session, Permission, Role, RolePermission, and BankInfo entities. - Added validated
NationalID,MobileNumber, andBirthDatevalue objects plus domain-level user status values. - Added stable domain error vocabulary independent of gRPC status codes.
- Added
auth/domain/portsrepository and cache interfaces using only standard library types and domain models. - Focused value-object/domain tests and the full Auth test suite pass; commits
32f182bandd292822. - Existing
domain/dbremains the legacy persistence mapping until A003 introduces explicit infrastructure mappings.
A003 — Auth persistence migration checkpoint
- Added
auth/infrastructure/persistencewith explicit User and Identity mappings between legacy GORM records and the pure domain model. - Mapping validates domain value objects at the boundary and preserves timestamps, roles, public keys, identity validation timestamps, and birth-date representation.
- Focused mapping tests and the full Auth test suite pass; commit
58f6a43. - A003 remains in progress: PostgreSQL/Redis adapter ownership and use-case integration still need to move out of the legacy
repository/dbcomposition. - Added
auth/infrastructure/postgresandauth/infrastructure/rediscomposition boundaries and switchedcmd/serve.goto use them; the legacy adapters remain wrapped behind these boundaries pending per-repository port integration (8ce3727). - Added domain-port adapters for User, Identity, and Cache that translate legacy repository records at the infrastructure edge and satisfy
domain/ports; mapping, full tests, and infrastructure vet pass in7d9dd25. - Added mappings and domain-port adapters for Session, Permission, Role, RolePermission, BankInfo, and OTPTemplate, completing the explicit persistence boundary coverage; full Auth tests pass in
e6e8e34. - Relocated the concrete PostgreSQL and Redis implementations from
repository/db/*intoinfrastructure/postgresandinfrastructure/redis, removed the temporary forwarding wrappers and empty unreferenced Mongo placeholder, and confirmed no runtime imports of the legacy implementation paths remain. Full tests, race tests, vet, and build pass in1323aa4; A003 is complete.
A004 — OTP application checkpoint
- Extracted OTP code generation and the default expiration into the transport-independent
application/otppackage while preserving the existing disabled-code and six-digit behavior; focused and full Auth tests pass in0c92b14. - Extracted OTP template parameter decoding into the same application package and kept persistence JSON types at the infrastructure boundary; full Auth tests pass in
62fb1b1. - Extracted the three-attempt retry and already-used verification policy into
application/otp; the gRPC use-case retains compatible status/error mapping and full tests pass in133fcc3. - Added explicit OTP
StoreandSenderapplication contracts, isolating persistence and delivery concerns for the next adapter migration; full Auth tests pass in8fbfcff. - Added concrete infrastructure adapters for the Redis OTP store and Kavenegar sender while preserving existing key/TTL behavior; full Auth tests pass in
cde73ef. - Wired the OTP adapters into runtime composition and generation, delivery, verification, and deletion paths while retaining compatibility fallback; full Auth tests pass in
c951875. - Wired the OTP template repository port and adapter into runtime composition and TFA processing; legacy fallback remains for compatibility and full Auth tests pass in
741415b. - Added thin Auth and internal Auth gRPC registration adapters and routed server registration through them; full Auth tests pass in
b56d54c. A004 is complete; remaining legacy fallback removal is tracked under A008.
A005 — authentication/JWT checkpoint
- Extracted HTTP bearer-token normalization into
application/authand kept JWT verification/error mapping behavior unchanged; focused and full Auth tests pass in1d72faa. - Extracted refresh-token marker validation into
application/authwhile preserving refresh-flow behavior; full Auth tests pass in4225332. - Added access/refresh JWT verifier contracts and an infrastructure adapter delegating to the existing parser; full Auth tests pass in
ad6f5cc. Runtime injection into all auth flows remains. - Injected the verifier into IAM and refresh-token flows through runtime composition, retaining fallback for compatibility; full Auth tests pass in
6c5b8cc. - Extracted active/expiry session policy into
application/authwith focused tests; integration into IAM/session retrieval remains for the next checkpoint (424741c). - Added a domain-session
SessionStorecontract, infrastructure adapter over the legacy cache/persistence composition, and runtime wiring for IAM retrieval; full Auth tests pass ind744ffc. The adapter deliberately preserves existing Redis-expiry semantics without activating stricter status checks during the refactor. - Routed login and refresh-session persistence through the same application boundary with legacy fallback retained; full Auth tests and vet pass in
c15bcff. - Added a distinct persistent
BySubjectsession lookup and routed refresh-token rotation through it, deliberately keeping it separate from access-token Redis lookup so refresh validity is not capped by access expiry; full Auth tests and vet pass in016d705. A005 is complete; compatibility fallback removal remains under A008.
A006 — identity and permission checkpoint
- Extracted case-insensitive route/method evaluation and privileged-role detection into
application/permission, retaining development-mode bypass and existing gRPC error mapping; focused and full Auth tests pass in9f97cec. - Runtime-wired the permission repository adapter and routed permission initialization lookup/creation plus super-admin listing through the domain port, retaining legacy fallback; full Auth tests pass in
5b61adf. - Added an application role-permission reader and infrastructure adapter over the existing Redis/Postgres cache-aside path, then routed standard-user permission reads through it; full Auth tests pass in
24722cb. - Added an application identity store and infrastructure adapter over the existing identity cache/persistence composition, then routed identity reads/writes through pure domain mappings; full Auth tests pass in
113faef. - Extracted identity request normalization/validation into
application/identity, preserving Persian-digit conversion and existing validation behavior while leaving protobuf mutation at the interface boundary; full Auth tests pass in2d5ab3d. - Added identity ownership/person-verification application contracts and infrastructure adapters, runtime-wired both real and configured fake-provider paths, and preserved existing error mapping; full Auth tests and vet pass in
75c2e0d. A006 is complete.
A007 — explicit Auth composition
- Replaced the eleven-argument positional constructor with a typed
Dependenciesgraph assembled incmd/serve.go, making OTP, JWT/session, permission, and identity infrastructure wiring explicit at bootstrap. - The legacy two-argument constructor remains only as an A008 compatibility shim; full Auth tests and vet pass in
7d7871b. A007 is complete.
A008 — Auth compatibility cleanup
- Removed the legacy two-argument constructor and all nil-dependent fallback implementations superseded by the explicit OTP, JWT/session, permission, and identity dependency graph.
- The remaining legacy repository methods are still active consumers for Auth operations outside the extracted paths and are therefore not dead/superseded code; full tests, race tests, and vet pass in
a9b11a3. A008 and the Auth architecture phase are complete. - A006 remains in progress: permission repository wiring and identity application orchestration still need extraction.
- A005 remains in progress: JWT validation, session checks, refresh-token flow, and broader authentication orchestration still need application ports and adapters.
I001 — publisher-backed ICO purchase map
- Compatibility entrypoints remain
WalletService.CalcBuyAssetandWalletService.BuyAsset; API routes and existing request fields do not move. MarketplaceSrvowns order selection, pricing, taker creation, and settlement. Wallet delegates instead of retaining a second ICO transfer implementation.- A publisher creates the normal maker/sell order with an additive ICO designation. The designation is accepted only when IAM contains the
token-publisherrole key; normal orders retain their current authorization behavior. - Auth supplies additive IAM role keys because database role IDs are deployment-local and must not be hard-coded in wallet.
- An ICO quote selects an open, designated maker/sell order for the requested asset against IRT, validates remaining volume, and returns its order ID additively in
CalcBuyAssetRes. GenerateBuyContractpins that maker-order ID inICOAgreements, preventing confirmation from silently switching price or publisher.BuyAssetdelegates the pinned agreement to market. Market creates a taker/buy order owned by the buyer and calls the same synchronoussettleOrderoperation used by market matching.- Existing market confirmation keeps asynchronous behavior, while the ICO endpoint waits for settlement so
BuyAssetRes.successreflects the actual result and hashes can be returned when available. - Discounts are not applied to publisher orders: quote and settlement use the existing market-taker commission model, eliminating divergence between displayed and settled values.
W001 — Wallet process and dependency migration map
All six runtime modes currently call cmd/helper.SetupRepository*, which constructs PostgreSQL, Redis, internal/external service clients, the GL/Kuknos availability gate, the GL outbox dispatcher, the global Stellar client, and optional profiling. wallet, market, alert, and internal_wallet use safe/lazy peer connection; cron and stream use strict peer connection. This shared bootstrap is a primary W003/W010/W011 separation point.
| Process / operation family | Current implementation | Persistence and cache | Queue / async | Internal and external dependencies | Stellar / availability |
|---|---|---|---|---|---|
| Wallet reads: health, assets/prices/commissions, networks, wallets/balances, transactions, BNPL, redeem/referral lists | core/walletImp (health.go, asset.go, network.go, wallet.go, transaction.go, bnpl.go, redeem.go, commission.go) |
PostgreSQL Asset, Commission, Network, Wallet, Transaction, BNPL, Redeem, Federation, whitelist; repository cache helpers where invoked | None directly | Internal Authorization for identity/user data on selected operations | Availability gate for health; Stellar balance reads for synchronized wallet/balance operations |
| Wallet initialization and federation | UserInitWallet, GetOrInitWallet, SyncUserWalletBalance, UserCreateFederation, UserGetFederation, GetPublicKeyByNationalID |
PostgreSQL TX, Wallet, Asset, Federation, Transaction, whitelist | GL ledger outbox may be enqueued in transactional paths | Internal Authorization; system encryption/key derivation | Recover/generate keys, activate accounts, create trustlines, query balances; Kuknos/GL gate at RPC boundary |
| Wallet transfers and locking | InternalTransferAsset, ExternalTransferAsset, LockAsset, release helpers, transaction tracking |
PostgreSQL TX, Wallet, Transaction, LedgerOutbox | GL journals/events via transactional outbox | Authorization/InternalAuthorization for IAM/TFA/recipient resolution | Stellar balance, trustline checks, transfers, Horizon transaction tracking; availability interceptor |
| Asset buy and contracts | CalcBuyAsset, BuyAsset, GenerateBuyContract, DeclineBuyContract, discount helpers |
PostgreSQL TX, Asset, Wallet, Transaction, Contract, Discount, buy whitelist (legacy Sale references remain in code) | GL/transaction event outbox through transaction paths | Market RPC; Authorization for agreement/IAM checks | Settlement delegates to wallet/market transfer paths; availability interceptor |
| IRT/IPG/accounting | DepositIRT, withdrawal init/confirm, IPGGetToken, IPGConfirm, GetIPGLog |
PostgreSQL Accounting, WithdrawLog/IPGLog, Asset, Transaction, Wallet (legacy Sale references remain) | Notification calls are asynchronous at provider/RPC level; transaction/GL outboxes on financial paths | Authorization/InternalAuthorization, Notification, configured PSP (Mellat/Vandar), API gateway callback client |
Stellar server/user transfers for IRT settlement; availability interceptor |
| Redeem, commission, referral and BNPL mutations | Redeem calculation/settlement, commission collect/refund/claim, BNPL submit/update/cancel/payment generation | PostgreSQL TX, Redeem, Asset, Wallet, Transaction, Commission, Discount, BNPL; Redis distributed mutex for commission claims | GL/transaction event outbox where financial transaction helpers are used | Authorization/InternalAuthorization as required | Stellar transfers for redeem/commission settlement; availability interceptor |
| Transaction-event pipeline (wallet process only) | cmd/cmdServe/transaction_events.go, application/transactionevents |
PostgreSQL TransactionEventOutbox/Inbox/Deadbox and Transaction | Active RabbitMQ/Watermill publisher, subscriber, retry router, dispatcher; explicit startup/shutdown | Direct gRPC notifier to InternalAuthorization and Alert | Handler receives availability gate; financial event processing delegates to wallet service |
| Market reads and order lifecycle | core/marketImp/market.go: lists/details/history, calculate/new/cancel order |
PostgreSQL Market, Asset, Commission, Contract, Transaction, TX; Redis mutex for order settlement | No active legacy market AMQP consumer (commented out) | Authorization/InternalAuthorization, Wallet/InternalWallet, Notification | Key generation and two-leg Stellar asset/IRT settlement with refund path; availability interceptor |
| ICO marketplace and market contracts | core/marketImp/ico.go, contract.go, irt.go |
PostgreSQL Market, Contract, Asset | Uses wallet transaction/event mechanisms indirectly through internal RPCs | InternalAuthorization, Authorization, InternalWallet/Wallet | Settlement delegates to wallet and uses shared availability gate |
| Alert | core/alertImp.Emit |
No domain persistence | Per-request goroutine; email retry group and parallel SMS | SMTP mail adapter and Kavenegar SMS adapter | No Stellar/availability interceptor |
| Internal-wallet RPC | Same core/walletImp.walletSrv, registered as InternalWalletSrvServer |
Same PostgreSQL/Redis aggregates as invoked internal methods | Same GL/transaction outbox mechanisms | Primarily internal callers; Authorization/InternalAuthorization as operation requires | Same global Stellar client and availability interceptor |
| Cron | core/cronJobs: vacuum expired transactions and expire stale market orders, hourly at minute 1 with retry |
PostgreSQL Transaction and Market | robfig cron scheduler; no RabbitMQ | Strict initialization currently connects all peers even though jobs only require persistence/config | Shared setup unnecessarily starts availability monitor, GL dispatcher, and Stellar client; W010 must narrow this |
| Stream | port/stellar.StreamPayments |
Reads/writes through the full repository passed into streamer, including user/asset/transaction lookup paths | Horizon streaming callback loop; no RabbitMQ | Strict initialization currently connects all configured peers | Direct global Stellar/Horizon stream client; shared setup also starts availability/GL infrastructure |
Repository ownership map for migration:
- PostgreSQL adapters: Accounting/IPG/withdraw logs, Asset and buy/sell whitelists, Wallet, Federation, Transaction, TransactionEvent outbox/inbox/deadbox, LedgerOutbox, Discount, Commission, Contract/agreement, Redeem, BNPL, Network, Market, and transaction manager.
- Redis adapter: JSON cache primitives, key scan/delete, pub/sub (currently no active core consumer found), and distributed mutexes used by market and commission operations.
- Queue adapters: active RabbitMQ Watermill transaction-event bus plus PostgreSQL outbox/inbox/deadbox; the older market AMQP consumer is commented and must not be migrated as active behavior.
- Internal gRPC peers: Wallet, InternalWallet, Market, Authorization, InternalAuthorization, Notification, API gateway callback, and GL ledger/health clients.
- External adapters: SMTP, Kavenegar SMS, Mellat/Vandar PSP, Kuknos Horizon health, Horizon streaming, and Stellar account/trustline/balance/transfer operations.
- Cross-cutting bootstrap: configuration, logger/APM/Prometheus/reflection, system cryptography, profiling, availability gate, GL dispatcher, Stellar global initialization, and graceful shutdown.
Migration order implied by the map: isolate shared infrastructure constructors (W003), extract read-only wallet paths first (W004), then initialization/trustline (W005), financial transaction/event paths (W006), market/alert/internal RPCs (W007-W009), and finally give cron/stream minimal process-specific dependency graphs (W010) before the unified explicit composition cleanup (W011-W012).
W002 — Wallet domain foundation
- Added pure
domain/modelentities for Asset, Wallet, Federation, Network, Transaction, MarketOrder, Commission, Redeem, Accounting, and BNPL, using the existing exact fixed-pointmoney.Amountvalue object rather than protobuf numeric fields. - Added domain-owned status/side types, filters, AssetCode/TrackingCode normalization, wallet available-balance behavior, and focused tests.
- Added transport-independent domain errors and inward-facing repository, cache/lock, unit-of-work, blockchain, identity, notification, payment-gateway, and event-publisher ports.
- Verified the new packages contain no generated stub, GORM, repository, infrastructure, or database imports. Focused tests/vet and the full Wallet test suite pass in
ac649d2; W002 is complete.
W003 — infrastructure adapter migration checkpoint
- Relocated every Wallet PostgreSQL repository implementation and its tests from
repository/db/postgrestoinfrastructure/postgres, and every Redis implementation/test fromrepository/db/redistoinfrastructure/redis. - Updated
cmd/helperto construct the infrastructure-owned adapters; no runtime import of the old PostgreSQL/Redis implementation paths remains. Full Wallet tests pass ind2580cd. - RabbitMQ/Watermill was already under
infrastructure/eventbus; external service clients now live underinfrastructure/service(Darano, Kavenegar, Mellat, and Vandar), and Stellar/Horizon operations now live underinfrastructure/stellar. - Wallet, market, stream, and bootstrap call sites no longer import legacy implementation paths under
repository/db,repository/service, orport/stellar. Temporary/non-Go artifacts left under the old service directory are not runtime implementations. - Full Wallet tests, race tests, vet, and build pass after the migration (
d121fc9); W003 is complete.
W004 — read-only wallet application boundary checkpoint
- Added
application/walletread, with transport-independent catalog, commission, network, and balance reader ports and use-case methods. - gRPC methods for asset list/get, asset commissions, asset price, network list, health, balance, and check-balance now delegate through the application boundary; protobuf conversion and existing error mapping remain in
core/walletImp. - Transaction-list querying and blockchain balance reads now delegate through the application reader as well. Wallet listing consumes the application catalog; its database synchronization remains an explicit mutation in the service and is deferred to later wallet work. Full Wallet tests pass in
5b17c82; W004 is complete.
W005 — wallet initialization boundary checkpoint
- Added
application/walletinitfor the identity precondition and exact Stellar trustline-limit policy. UserInitWalletdelegates those rules and the key-recovery/trustline adapter while retaining the existing database transaction, wallet creation, transaction recording, and rollback behavior.- Wallet-code generation is also application-owned and tested. Full Wallet tests pass in
c09fdf8; orchestration extraction remains in progress. - Wallet draft construction (user, asset, federation, code, and timestamps) is application-owned and tested; repository lookup/insertion remains at the service boundary. Full Wallet tests pass in
28d0846; orchestration extraction remains in progress. - Repository-backed wallet/federation find-or-create orchestration is now application-owned with injected repositories and federation creation callback;
UserInitWalletdelegates it while retaining transaction scope. Full Wallet tests pass in63d4d52; transaction recording and rollback policy extraction remains. - Trustline transaction construction is now application-owned and tested; the service still performs the insert and rollback decisions at the transaction boundary. Full Wallet tests pass in
1999ec0; rollback policy extraction remains. UserInitWalletnow uses named-return transaction finalization: successful execution commits, while any returned error rolls back (including failures after key recovery or trustline submission). Full Wallet tests pass in4e4f2af; broader integration coverage remains before W005 completion.- Commit-on-success and rollback-on-error behavior is covered by focused application tests in addition to the service wiring. Full Wallet tests pass in
3bc9591; broader integration coverage remains before W005 completion. - Existing-wallet and federation-create wallet paths are covered with repository fakes, alongside transaction finalization tests. Full Wallet tests pass in
15200dc; broader integration coverage remains before W005 completion.
Federation removal investigation (A009 / W013)
- Federation is not currently safe to delete outright: wallet persistence links
wallet.federation_id, transaction records expose nullablefrom_federation_id/to_federation_id, generated wallet APIs expose federation messages, and wallet code still has federation lookup/creation paths. - Auth has no active federation implementation; its wallet federation client is commented/dead code. Auth’s identity service should remain the owner of identity and national-ID data.
- The proposed target is reasonable only after consumers are migrated:
user_id → identity_id → wallet_id, withwallet_idstill scoped toasset_idand Stellar key derivation/custody explicitly preserved. W013 must first identify whether federation addresses or transaction routing are actually supported in production, then remove or retain the model based on evidence and a data/API compatibility plan. - Per the requested migration, federation is fully removed from active Wallet/Auth/API code and the shared wallet protobuf: no federation creation/lookup, persistence adapter/model, wallet field, transaction field/filter, generated message, stale API route, or runtime reference remains. New wallet creation uses user/asset identity; wallet records remain asset-scoped. Wallet/Auth/API contracts were regenerated and all service tests pass. The database must be migrated separately to drop legacy federation columns/tables in deployed environments.
W006 — deposit/withdrawal/transaction boundary checkpoint
- Added
application/withdrawalwith the IRT amount reconciliation policy and focused tests for the one-unit balance threshold. WithdrawIRTInitcontinues to own the gRPC/payment flow but delegates amount policy through the application package; full Wallet tests pass in16ebd2d.- IPG Toman/Rial conversion, positivity, rounding, and exactness checks now live in
application/deposit; the gRPC/payment flow delegates through wrappers and remains response-compatible. Full Wallet tests pass ina565ce0. - Transfer display-to-raw amount conversion and positive/exactness validation now live in
application/transfer; the gRPC service retains protocol-specific error mapping. Full Wallet tests pass in1e5b977. - Settled IPG deposits now use
application/deposit.RawSettlementAmountfor Rial→Toman→raw conversion, retaining exactness checks before Stellar transfer. Full Wallet tests pass in08c2d7b. - Transaction status-update construction now lives in
application/transaction; Stellar polling remains at the infrastructure-facing service while persistence update shape is application-owned. Full Wallet tests pass in7941966. - Transaction-event type support is centralized in
application/transactionevents, removing the duplicate wallet-server policy. Full Wallet tests pass in4d03adb. - IPG payer-ID derivation is now application-owned with short/invalid input protection and deterministic tests; the gRPC service delegates through a compatibility wrapper. Full Wallet tests pass in
f12752d. - Pending IRT deposit and withdrawal transaction-record construction is now application-owned and tested; persistence insertion remains at the gRPC/service boundary. Full Wallet tests pass in
0efc199. - Pending internal and external transfer transaction-record construction is now application-owned and tested; repository insertion and transfer execution remain at the gRPC/service boundary. Full Wallet tests pass in
98753f7. - The active IRT deposit creation path now also uses the shared
application/transaction.PendingDepositpolicy; repository insertion and IPG orchestration remain at the service boundary. Focused Wallet tests pass inb009837. - Successful commission and referral-commission transaction records now use the shared
application/transaction.SuccessfulTransferpolicy; Stellar execution and repository insertion remain at the service boundary. Full Wallet tests pass ina4717d9. - IPG settlement success updates now use the shared
application/transaction.SettlementUpdatepolicy for hash, status, and settled amount; repository update and external transfer remain at the service boundary. Focused Wallet tests pass inf9b3c46. - IRT dev-mode completion updates now use the shared
application/transaction.HashStatusUpdatepolicy; insert-vs-update branching and repository persistence remain at the service boundary. Focused Wallet tests pass in926ea23. - IRT dev-mode successful-deposit creation now uses the shared
application/transaction.SuccessfulDepositpolicy; insert error handling and completion orchestration remain at the service boundary. Focused Wallet tests pass in89027b4. - Redeem transaction creation now uses the shared
application/transaction.PendingRedeempolicy; repository insertion and Stellar transfer orchestration remain at the service boundary. Focused Wallet tests pass ine8fa40d. - Redeem completion status/hash/error updates now use the shared
application/transaction.CompletionUpdatepolicy; repository update and transfer error orchestration remain at the service boundary. Focused Wallet tests pass inaf880c5. - Transaction-list balance-change classification now uses the shared
application/transaction.BalanceChangepolicy with focused coverage for increases, decreases, and non-balance transaction types. Full Wallet tests pass inca7ae43. - Internal transfer and sell insufficient-balance transitions now use the shared
application/transaction.FailureUpdatepolicy; atomic wallet/transaction persistence and rollback behavior remain unchanged. Focused Wallet tests pass ind10ff42. - Transaction persistence atomically enqueues ledger and transaction-event outbox records; deterministic idempotency keys, duplicate/conflict handling, retry claims, and dead-letter behavior are implemented and covered by infrastructure/application tests. Remaining W006 work is balance coordination and business-level failure/refund orchestration in deposit, withdrawal, transfer, and redeem flows.
W007 — market boundary checkpoint
- ICO agreement amount tolerance is now application-owned in
application/market.AgreementAmountMatches, using the existing fixed-point money type and preserving the 0.5-unit tolerance. The market gRPC package delegates through a compatibility wrapper; focused market tests pass in3d9e1af. - Pricing, order lifecycle, settlement, contract generation, and external adapter composition remain for subsequent W007 increments.
- ICO available-amount validation now uses
application/market.ValidateAvailableAmountwith application-level sentinel errors mapped to existing gRPC error codes by the market adapter. Focused market tests pass inbbb3443. - Market display-to-raw amount conversion now uses
application/market.RawAmount, preserving exact fixed-point conversion and positive-amount checks. Focused market tests pass ind217623. - Market pricing arithmetic now uses typed
application/market.CalculationInput/CalculationResult; the gRPC adapter maps commission persistence values and protobuf fields at the boundary. Existing maker/taker and base/asset side behavior is covered by focused market tests ine21ecf2.