Files
dev-procfile/REFACTORING-AUDIT.md
T

306 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.
- A004 remains in progress: template lookup, delivery, verification, and thin gRPC adapter extraction still use the legacy use-case/repository composition.
### `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.