17 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.
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.