Files
dev-procfile/REFACTORING-AUDIT.md
T

28 KiB
Raw Blame History

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

  1. api uses knadh/koanf/v2; auth and wallet still use kkyr/fig. The refactoring plan is correct on this point, while the root AGENTS.md current-state summary is stale.
  2. All three Go services expose global config.Cfg and read it throughout bootstrap, logging, transport, use-case, repository, and utility code.
  3. Every current ParseConfig calls (&sync.Once{}).Do(...). Because that creates a new sync.Once per invocation, configuration is not actually guarded by a process-wide once initializer.
  4. 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.
  5. auth application structs directly implement and embed generated public and internal gRPC server interfaces.
  6. wallet/core/{walletImp,marketImp,alertImp} directly implements generated servers and mixes protobuf mapping, configuration, business rules, repositories, cryptography, and Stellar operations.
  7. Repository interfaces live in top-level repository packages and use GORM-tagged structs from domain/db; domain and persistence representations are therefore conflated.
  8. AdminPanel has BetterProto/grpclib dependencies and a generator configuration, but no application gRPC client integration was found. Its generator reads the remote v2 proto branch rather than the local proto checkout.
  9. AdminPanel writes directly through MultiDBMixIn, specialized admin classes, and signals. The unmanaged coreLogic/models.py replicas are used for both reads and writes.
  10. CoreRouter.no_migartion is misspelled and is referenced by allow_migrate, confirming the planned router fix.
  11. 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.
  12. Automated test coverage is extremely limited: the audit found only wallet/repository/db/redis/lock_test.go among conventional Go/Python test filenames in the active repositories.

Generated-code boundaries

  • api, auth, and wallet generate Go protobuf code into domain/stub/go from the local root proto directory.
  • Their Buf generation configurations use clean: true; generation replaces output directories.
  • Generated Go stubs are marked DO NOT EDIT and must remain mechanically generated.
  • AdminPanel generates BetterProto Python code into src/stub, currently from a remote repository branch.
  • Root proto/buf.gen.yaml generates Go, documentation, gateway, and TypeScript artifacts under proto/stub; the root repository has no Makefile.
  • The existing untracked proto/buf-Linux-x86_64.bin is 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/ and repository/service/
  • Persistence models: GORM-tagged domain/db/
  • Generated contracts: domain/stub/go/

wallet

  • Multi-mode bootstrap: cmd/ and cmd/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

  1. Configuration loader migration and removal of globals must be separate tasks. First preserve parsing behavior, then inject configuration into progressively deeper dependencies.
  2. Current fixed connection lifetime and config reparse behavior are compatibility baselines, even if they appear unintended. Tests must capture them before an intentional correction.
  3. Package moves must proceed through vertical slices because existing test coverage cannot protect a repository-wide rename.
  4. AdminPanel mutation inventory and RPC gap analysis must happen before protobuf edits.
  5. 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 generate in a temporary clone: failed because protoc-gen-doc and protoc-gen-es are 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 intentional omitempty removal, 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 flock is implemented by the air-build target. .NOTPARALLEL only 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 intentional omitempty removal, 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:

  1. Add auth/infrastructure/config as the owner of config types and a pure Load(path) (*Config, error) function based on koanf/TOML.
  2. Preserve all existing TOML keys, types, durations, peer field capitalization, and actual reparse behavior.
  3. Keep auth/config temporarily as a compatibility facade so C001 does not also perform global dependency injection.
  4. Add synthetic loader tests that do not read or expose repository secrets.
  5. Remove fig and add the same pinned koanf packages already used by API.
  6. 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/config with config types and a pure, error-returning TOML loader.
  • Replaced fig tags/dependency with pinned koanf packages matching API.
  • Retained authorization/config as an explicitly temporary compatibility facade; its global API and effective reload-on-each-call behavior are preserved for C002.
  • 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 in logger/main.go and a discarded timeout cancel in usecase/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.go and passed explicitly into database, Redis, upstream-service, repository-system, use-case, gRPC-server, profiling, logger, and JWT utility boundaries.
  • JWT helpers receive the narrow JWTModel value rather than consulting process state.
  • PostgreSQL now uses its constructor argument for GORM log level instead of reading a global.
  • The legacy authorization/config facade and Cfg global were removed.
  • Source scans confirm no production config.Cfg, Cfg global, 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/config with pure TOML loading and retained wallet/config as a temporary compatibility facade for C004.
  • 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/config compatibility facade and its process-global Cfg; production source has no active global configuration reads or legacy config imports.
  • Full go test ./..., go test -race ./..., go vet ./..., and go build ./... pass with the isolated Go cache.
  • Wallet implementation was committed in reviewable slices from f507637 through 4d192a6, 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.Cfg singleton and legacy gateway/config package; source scans show no active global configuration reads or legacy imports.
  • API go test ./..., go test -race ./..., go vet ./..., and go 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 httptest test; the same verification passed with localhost access enabled.
  • GL implementation commits: 3f5fd86, b14c5e2, and d5c9b33; verification completed on 2026-08-30.

Auth periodic identity validation extension

  • Added Identity.LastChecked for the biweekly phone/national-ID validation and Identity.LastBirthDateChecked for 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, and false are also accepted) disables the job. The nested periodic-identity-validation config 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 A002A008 package extraction.

A002 — Auth domain entities and repository ports

  • Added auth/domain/model with transport/persistence-independent User, Identity, Session, Permission, Role, RolePermission, and BankInfo entities.
  • Added validated NationalID, MobileNumber, and BirthDate value objects plus domain-level user status values.
  • Added stable domain error vocabulary independent of gRPC status codes.
  • Added auth/domain/ports repository and cache interfaces using only standard library types and domain models.
  • Focused value-object/domain tests and the full Auth test suite pass; commits 32f182b and d292822.
  • Existing domain/db remains the legacy persistence mapping until A003 introduces explicit infrastructure mappings.

A003 — Auth persistence migration checkpoint

  • Added auth/infrastructure/persistence with 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/db composition.
  • Added auth/infrastructure/postgres and auth/infrastructure/redis composition boundaries and switched cmd/serve.go to 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 in 7d9dd25.
  • 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.

A004 — OTP application checkpoint

  • Extracted OTP code generation and the default expiration into the transport-independent application/otp package while preserving the existing disabled-code and six-digit behavior; focused and full Auth tests pass in 0c92b14.
  • 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 in 133fcc3.
  • Added explicit OTP Store and Sender application contracts, isolating persistence and delivery concerns for the next adapter migration; full Auth tests pass in 8fbfcff.
  • 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/auth and kept JWT verification/error mapping behavior unchanged; focused and full Auth tests pass in 1d72faa.
  • Extracted refresh-token marker validation into application/auth while preserving refresh-flow behavior; full Auth tests pass in 4225332.
  • 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/auth with focused tests; integration into IAM/session retrieval remains for the next checkpoint (424741c).
  • Added a domain-session SessionStore contract, infrastructure adapter over the legacy cache/persistence composition, and runtime wiring for IAM retrieval; full Auth tests pass in d744ffc. 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 BySubject session 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 in 016d705. 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 in 9f97cec.
  • 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.CalcBuyAsset and WalletService.BuyAsset; API routes and existing request fields do not move.
  • MarketplaceSrv owns 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-publisher role 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.
  • GenerateBuyContract pins that maker-order ID in ICOAgreements, preventing confirmation from silently switching price or publisher.
  • BuyAsset delegates the pinned agreement to market. Market creates a taker/buy order owned by the buyer and calls the same synchronous settleOrder operation used by market matching.
  • Existing market confirmation keeps asynchronous behavior, while the ICO endpoint waits for settlement so BuyAssetRes.success reflects 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.