Compare commits

..

3 Commits

Author SHA1 Message Date
nfel 8bff15a0ad docs: use SSH for workspace handoff 2026-08-28 15:13:18 +03:30
nfel 3d5f8e68f9 docs: add workspace clone commands 2026-08-28 14:59:42 +03:30
nfel 01d3780a77 docs: centralize refactoring coordination files 2026-08-28 14:49:42 +03:30
7 changed files with 1807 additions and 0 deletions
+221
View File
@@ -0,0 +1,221 @@
# AGENTS.md
This file provides guidance for agents working in the Darano monorepo.
## Repository Structure
Multi-service monorepo for the Darano financial/crypto platform. Each subdirectory is its own independent git repository:
| Directory | Language | Role |
|-----------|----------|------|
| `api/` | Go (Gin) | HTTP REST gateway — the only public-facing service |
| `auth/` | Go (gRPC) | Authorization — OTP, JWT, permissions, identity |
| `wallet/` | Go (gRPC) | Wallet — assets, transactions, Stellar blockchain, market |
| `ui/` | TypeScript/Next.js | Customer-facing frontend |
| `AdminPanel/` | Python/Django | Internal admin panel (bypasses api, hits Postgres directly) |
| `proto/` | Protobuf | Central schema definitions shared by all services |
| `DevOps/` | Docker Compose | Infrastructure — Postgres, Redis, RabbitMQ, MinIO, Traefik |
| `docs/` | MkDocs | Documentation site |
**Root-level**: `Procfile` (deployment), `CLAUDE.md` (Claude Code config) — these are the monorepo's coordination files, not service-level.
## Service Communication Architecture
```
Browser/Client → api (REST/HTTP) → auth, wallet/market/alert (gRPC)
AdminPanel ──────────────────────→ Postgres directly (bypasses api)
```
The `api` gateway is the **only** HTTP-facing service. All inter-service communication is gRPC.
### API Gateway (api/)
- **Entry**: `api/main.go``cmd.Execute()` (Cobra) → `cmd/serve.go` sets up Gin router
- **Service layer**: `api/service/main.go``DaranoService` interface composes all upstream gRPC clients. Each service gets a persistent gRPC connection created lazily, with automatic reconnection after a **2-minute timeout**. URL lookup uses **reflection** on the `Peer` struct via `ServicesEnum` — field names must match `ServicesEnum` values exactly.
- **Handlers**: `api/handler/` — one file per domain. All handlers embed `service.DaranoService`.
- **Routing**: `api/handler/routing.go` — routes grouped into `/v1/public/`, `/v1/client/`, `/v1/admin/`. The `/v1/internal/` routes are commented out (placeholder).
- **Middleware chain** (order matters): APM → Profiling → Prometheus → CORS → JSON → I18n → Error → optional Logger
- **Endpoints**: `GET /` (health), `GET /metrics` (Prometheus), `GET /swagger/*any`, `GET /ws` (WebSocket)
- **Profiling**: `net/http/pprof` is imported (blank import `_`); runs on a separate port when `Profiling.Enabled` in config
### Wallet Binary (wallet/)
Single binary hosts multiple sub-services via Cobra subcommands: `wallet`, `market`, `alert`, `internal_wallet`, `stream`. These are spawned concurrently via `errgroup` in `cmd/cmdServe/main.go`.
**Concurrent build safety**: The Makefile uses `flock` on `./.build/air-build.lock` to serialize protobuf generation and binary writes when multiple air instances run simultaneously (`make dev-wallet`, `make dev-market`, etc. all trigger `make build`).
### Config
- **Go services** use `knadh/koanf` (not `fig` as older docs may suggest) to parse TOML config files
- **Global singleton**: `config.Cfg` — a `sync.Once` ensures it's initialized exactly once
- **Defaults baked into code**: `config.go` in `api/` sets default `ipg_callback_url` and `ui_server_error_status_url` before loading the TOML file (TOML overrides defaults)
- **Struct tags**: use `koanf:"field-name"` (not env vars)
### Config files reference
| Service | Config file |
|---------|------------|
| API | `./cfg.toml` (or `--conf ./config.cfg`) |
| Wallet sub-services | `./wallet.cfg.toml`, `./market.cfg.toml`, `./alert.cfg.toml`, `./stream.cfg.toml` |
| Internal wallet | `./wallet.internal.cfg.toml` |
## Commands
### Go services (`api/`, `auth/`)
```bash
cd api/ # or cd auth/
make dep # install buf, protoc plugins, swag, air
make build # fmt + proto gen + binary → ./build/main
make dev # build + hot reload via air
make test # go test ./...
./build/main serve --conf ./cfg.toml
```
### Wallet service (`wallet/`)
```bash
cd wallet/
make build # proto gen + binary
make dev-wallet # hot reload wallet sub-service (.wallet.air.toml)
make dev-market # hot reload market sub-service (.market.air.toml)
make dev-stream # hot reload stream sub-service (.stream.air.toml)
make run-wallet # ./build/main serve wallet -c ./wallet.cfg.toml
make run-market # ./build/main serve market -c ./market.cfg.toml
make run-internal # ./build/main serve internal_wallet -c ./wallet.internal.cfg.toml
make run-alert # ./build/main serve alert -c ./alert.cfg.toml
make run-stream # ./build/main stream -c ./stream.cfg.toml
make grpc-ui-wallet # open grpcui on port 7210 (localhost:8200)
make grpc-ui-market # open grpcui on port 7300 (localhost:8300)
make grpc-ui-alert # open grpcui on port 7400 (127.0.0.1:8400)
```
**Important**: When running multiple sub-services concurrently via `make run` or multiple `make dev-*` instances, the Makefile uses `flock` to prevent concurrent protobuf generation or binary overwrites. Don't parallelize make (`-j`) without `flock` — it will corrupt stub files.
### AdminPanel (`AdminPanel/`)
```bash
cd AdminPanel/
# DB setup (uv virtual env)
uv run python src/manage.py makemigrations
uv run python src/manage.py migrate
make run # runserver on 0.0.0.0:8080
make dev # watch mode using funzzy
make proto # buf generate → proto stubs via betterproto
make build-msg # compile Django messages (i18n)
```
### UI (`ui/`)
```bash
cd ui/
yarn build-proto # generate TS types from protos (buf generate)
yarn dev # Next.js dev server (also runs buf generate)
make dev # same, bound to 0.0.0.0:3000
yarn lint # ESLint
yarn lint:fix # ESLint with auto-fix
yarn build # production build (also runs buf generate)
```
## Protobuf Code Generation
All services depend on generated code. **Always run `make build-proto` (or `yarn build-proto` for UI) before building any service.**
Proto definitions live in `proto/` with subdirectories: `base/`, `auth/`, `wallet/`, `market/`, `alert/`, `errors/`. Each service has its own `buf.gen.yaml` controlling code generation output into `domain/stub/go/` (Go) or `src/types/stub/` (TypeScript).
**Gotcha**: The Go Makefiles **strip `omitempty`** from all JSON struct tags in `.pb.go` files after generation. This is intentional — protobuf JSON serialization needs consistent field presence. Do not re-add `omitempty` manually.
## Go Service Layer Pattern
Both `auth` and `wallet` follow a layered architecture:
- **`config/`** — TOML config via koanf. `config.Cfg` global singleton, `sync.Once` initialized.
- **`domain/stub/go/`** — Generated protobuf Go code. **Never edit manually.**
- **`cmd/`** — Cobra CLI entry points. Subcommands map to serve modes.
- **`repository/`** — Data access. Aggregates `IPostgres`, `IRedis`, `IService`, and `IQueue` (wallet only) interfaces.
- **`core/`** (wallet) / **`usecase/`** (auth) — Business logic. Implements gRPC server interfaces from proto.
- **`util/`** — Shared helpers; no business logic.
In `auth`, `usecase.UseCase` interface directly embeds the generated gRPC server interfaces (`authv1.AuthorizationServiceServer`, `authv1.InternalAuthorizationServiceServer`).
In `wallet`, `core/` contains sub-packages: `walletImp/`, `marketImp/`, `alertImp/`, `cronJobs/`.
## API Gateway Patterns
### Request/Response Flow
```
HTTP request → middleware chain → routing.go → handler/*.go → DaranoService.gRPC → backend service
```
- **Response helpers**: `handler/response.go``JSON()` and `JSONList[X]()` wrap responses in `transport.Response{Meta, Data}`. `JSONList` has a known issue: pointer-to-empty-slice marshals as `null` instead of `[]`, fixed via `EmptyList{make([]string, 0)}` sentinel.
- **HTTP-to-gRPC context**: `handler/contextWithMetadata()` converts HTTP headers to gRPC metadata using `util.ConvertHTTPHeaderToGRPCMetadata()`.
- **Handler interface**: Each handler file defines a `handle` interface; `handler/main.go` defines `Server` struct embedding `service.DaranoService`.
### Route conventions
- Public routes: `/v1/public/{domain}/{action}` — no JWT needed
- Client routes: `/v1/client/{domain}/{action}` — JWT required (validated by `AuthorizationMiddleware`)
- Admin routes: `/v1/admin/{domain}/{action}` — JWT required (mostly placeholder currently)
## UI Architecture
- **Next.js App Router** under `src/app/`. Notable route groups: `dashboard/` (auth-protected), `auth/login/`, `blog/` (MDX content), `projects/`, `receipt/`.
- **Auth**: `src/middleware.ts` uses next-auth to protect `/dashboard/:path*`. Exports default from `next-auth/middleware`.
- **Services**: `src/services/` — plain functions wrapping axios calls to the api gateway, typed with generated protobuf types.
- **State**: `src/stores/` — Zustand stores.
- **Hooks**: `src/hooks/` — TanStack Query hooks on top of service functions.
- **Components**: HeroUI + Tailwind CSS with RTL support (Persian/Farsi UI).
- **Forms**: Formik + Yup (older), react-hook-form (newer).
- **Date picker**: `@amir04lm26/react-modern-calendar-date-picker` (Jalali calendar).
- **MDX**: Blog content uses `.mdx` files with remark/rehype plugins.
- **Path alias**: `@/*` maps to `./src/*`.
- **Output**: `standalone` mode for Docker. Image domains hardcoded in `next.config.mjs` remote patterns.
## Infrastructure
Dev infrastructure: `DevOps/dev/compose.yml` — PostgreSQL 16, Redis, RabbitMQ, MinIO. Each Go service has its own DB name.
All Go services instrumented with Elastic APM and Prometheus metrics. Traefik handles TLS/routing in production.
## Gotchas and Non-Obvious Details
1. **Config library**: Services use `knadh/koanf` with TOML parser, not `fig`. Tags are `koanf:"field-name"`.
2. **gRPC connection lifecycle**: Connections are lazy — created on first call, not at startup. A background goroutine closes and nils connections after 2 minutes of inactivity, triggering reconnection.
3. **Enum codegen**: `api/service/servicesenum_enumer.go` is auto-generated via `//go:generate go run github.com/alvaroloes/enumer`. Adding enum values requires `go generate`.
4. **Swagger docs**: Generated by `swag init` and served via gin-swagger. URL adapts per environment (prod → `api.darano.ir`, dev → `dev.api.darano.ir`, local → `localhost:<port>`).
5. **Multi-service wallet**: The wallet binary serves 5 sub-services. `make run` kills existing processes matching the service name pattern via `pgrep | xargs kill` before starting.
6. **Concurrent dev**: Running multiple `make dev-*` targets simultaneously requires the `flock` serialization in the Makefile. Using `make -j` without flock will corrupt the build.
7. **Proto stubs excluded from watchers**: `.air.toml` excludes `domain/stub/` from file watching. Air also excludes `swagger/` and `testdata/`.
8. **API testing requests**: `api/req/` contains JS files for API request testing (axios-based) — not part of the app, useful for manual testing.
9. **Django Admin**: Uses `unfold` theme (AdminPanel admin customizations in `sites.py` and `unfoldconf.py`).
10. **Proto generation for AdminPanel**: Generates into root directories (`base/`, `wallet/`, etc.) then deletes them with `rm -rf`. The betterproto generator outputs Python classes directly.
## AdminPanel Deep Dive
- **Architecture**: Django admin panel that bypasses all Go backend services. Connects directly to `core_db` (same Postgres as Go services) for read/write. Uses Django DB routers in `src/adminpanel/db/routers.py` to route `coreLogic` models to `core_db` and other apps to `default`.
- **Models**: `src/coreLogic/models.py` contains `managed = False` Django models — manual replicas of Go GORM models generated via `inspectdb`. **Not auto-generated from protos.** `make proto` generates betterproto Python stubs separately but Django models are maintained by hand. **Never edit models.py manually** — it drifts from Go services.
- **Admin classes**: `src/coreLogic/admin/` — 17 admin files (`asset.py`, `wallets.py`, `market.py`, etc.). All inherit from `MultiDBModelAdmin` in `src/utils/base_admin.py` which handles: multi-database writes (`using="core_db"`), soft deletes via `deleted_at`, asset-level permission filtering, and Jalali date widgets.
- **Permission system**: `src/usermapper/user_perm.py` + `src/coreLogic/acl.py` — admin users get asset-level access control. `save_model` checks `user_perm.can_access_asset()` before allowing writes.
- **Key gotchas**:
- `check_token_policy()` in `admin/asset.py:161` duplicates validation from wallet service. Changes to asset validation must be made in **both** places.
- `GENERIC_ASSET_META_VALUE` in `admin/asset.py:31` is a hardcoded JSON blob — if the wallet service changes asset metadata structure, this must be updated too.
- The router has a typo: `no_migartion` → should be `no_migration`.
- All `coreLogic` models are read via `core_db` directly. **Any admin write bypasses Go services** — no trustline updates, no blockchain operations, no validation from wallet/market services.
## Ongoing Refactoring: DDD / Clean Architecture
This repository is being migrated to a unified Domain-Driven Design / Clean Architecture. See [`REFACTORING-PLAN.md`](REFACTORING-PLAN.md) for the full plan.
**Go services current state**: `api/` uses koanf, `auth/` uses fig with `usecase/`, `wallet/` uses fig with `core/walletImp/` mixing gRPC server and business logic. Config libraries differ. Domain entities and persistence models are conflated.
**AdminPanel current state**: Direct DB access to `core_db` with no gRPC layer. Business logic duplicated in Django admin classes (`check_token_policy`, `auto_gen` instead of delegating to Go services). `managed = False` models drift from Go GORM models.
**Target**: All Go services follow `domain/``application/``infrastructure/``interface/` with inward dependencies. AdminPanel routes writes through gRPC to Go services while keeping reads from DB for performance.
**Migration phases** (see plan for details): Config standardization → auth/ restructure → wallet/ restructure → api/ restructure → AdminPanel service layer → shared domain types. Parallel workstreams: Go services restructure can run alongside AdminPanel gRPC client creation.
+420
View File
@@ -0,0 +1,420 @@
# Wallet, Authentication, and API Refactoring Guide
This document records the current architectural and correctness risks in Darano's wallet, authentication, and API services, and proposes a safe sequence for refactoring them.
The recommended approach is an evolutionary refactor rather than a simultaneous rewrite. First stabilize financial and authentication flows, then establish explicit contracts and an append-only ledger, and finally migrate individual operations behind the new boundaries.
The existing [Spring 1404 technical report](docs/docs/%DA%AF%D8%B2%D8%A7%D8%B1%D8%B4%20%D9%87%D8%A7/%DA%AF%D8%B2%D8%A7%D8%B1%D8%B4-%D8%A8%D9%87%D8%A7%D8%B1-%DB%B1%DB%B4%DB%B0%DB%B4.md) is directionally correct about introducing an internal ledger. Its proposed schema should be extended with accounting invariants, reservations, idempotency, reversals, and reconciliation before implementation.
## Executive recommendation
Do not split the system into more independently deployed services yet. Keep the wallet as a modular service while the financial invariants are established. Prematurely separating ledger, market, settlement, and blockchain concerns would introduce more distributed failure modes without fixing the current consistency problems.
The first architectural decision must be the authoritative source of balances:
1. **Recommended:** an internal double-entry ledger is authoritative for available and reserved balances; Stellar is the custody and settlement layer.
2. **Alternative:** Stellar remains authoritative and PostgreSQL is a read-only projection.
The current system mixes both approaches: wallet reads retrieve Stellar balances and write them back to PostgreSQL, while other flows mutate PostgreSQL balances directly. This ambiguity must be removed.
## Highest-risk findings
### 1. Financial operations are not safely repeatable
- Asset purchase returns success before execution completes. Work runs in an in-process goroutine, so a restart can lose the operation. The accepted-agreement condition also does not reject a normally accepted agreement: [`wallet/core/walletImp/buy.go`](wallet/core/walletImp/buy.go#L390).
- The payment callback has no atomic terminal-state transition. A replay can repeat settlement and potentially initiate another on-chain credit, depending on provider behavior: [`wallet/core/walletImp/ipg.go`](wallet/core/walletImp/ipg.go#L131).
- Transfer confirmation loads a transaction using a caller-supplied ID without validating its owner, original asset, amount, recipient, type, or current state: [`wallet/core/walletImp/transfer.go`](wallet/core/walletImp/transfer.go#L208).
- IRT withdrawal confirmation has the same ownership and state-binding problem: [`wallet/core/walletImp/irt.go`](wallet/core/walletImp/irt.go#L110).
- `DepositIRT` creates a pending transaction and then calls another function that creates a second transaction: [`wallet/core/walletImp/irt.go`](wallet/core/walletImp/irt.go#L192).
Every financial command must accept an idempotency key, bind approval or MFA to the exact immutable transaction intent, and use a compare-and-set state transition.
### 2. The blockchain streamer has broken duplicate handling
The normal `record not found` result returns before inserting a deposit. That return also occurs before the mutex unlock is deferred, leaving the lock held until its TTL expires: [`wallet/port/stellar/stream.go`](wallet/port/stellar/stream.go#L91).
The streamer also needs a persistent blockchain cursor, a unique constraint on the external operation identity, replay-safe ingestion, and reconciliation against missed operations.
### 3. Database errors can be silently converted into success
The transaction helper wraps the named `err`, which is still nil, rather than `result.Error`: [`wallet/repository/db/postgres/tx.go`](wallet/repository/db/postgres/tx.go#L10).
Similar mistakes exist in transaction processing, including wallet fetch and commit failures: [`wallet/core/walletImp/transaction.go`](wallet/core/walletImp/transaction.go#L172).
Errors from `Begin`, `Commit`, `Rollback`, row-count checks, Redis, queues, and provider calls must never be ignored. Financial state transitions should fail closed.
### 4. Balance authority is ambiguous
Wallet reads query Stellar, merge blockchain and database state, calculate locks, and then update database balances as a side effect of reading: [`wallet/core/walletImp/wallet.go`](wallet/core/walletImp/wallet.go#L335).
Other paths directly mutate database balances. A refactor must define one authority, make projections explicitly disposable and rebuildable, and continuously reconcile the authority against custody and settlement systems.
### 5. Financial amounts use binary floating point
PostgreSQL `NUMERIC` values are represented as Go `float64` for wallet balances and transaction amounts:
- [`wallet/domain/db/wallet.go`](wallet/domain/db/wallet.go#L19)
- [`wallet/domain/db/transaction.go`](wallet/domain/db/transaction.go#L35)
Use integer minor units where the asset permits it, or an exact decimal type with an explicit scale per asset. Rounding rules must be named, centralized, and tested at every external boundary.
### 6. Concurrency protection is insufficient
- Balance reads inside database transactions do not lock rows using `SELECT ... FOR UPDATE` or an equivalent atomic update.
- The custom Redis lock is a non-atomic GET followed by SET, ignores Redis failures, and has no ownership token: [`wallet/repository/lock.go`](wallet/repository/lock.go#L13).
- Stellar sequence-number locking is commented out: [`wallet/port/stellar/transfer.go`](wallet/port/stellar/transfer.go#L130).
- Important uniqueness constraints are absent, including one wallet per `(user_id, asset_id)` and one accounting record per user.
Prefer database invariants and atomic conditional updates over distributed locks. When a distributed lock is unavoidable, it must use an owner token, safe release, bounded lease renewal, and fencing where applicable.
### 7. Migration and database transport policies are unsafe
Auth and wallet run GORM `AutoMigrate` during service startup. Wallet also disables PostgreSQL TLS and GORM's default transaction behavior: [`wallet/repository/db/postgres/main.go`](wallet/repository/db/postgres/main.go#L21).
Replace runtime migration with reviewed, versioned migrations. Use expand/contract deployments, migration tests, explicit rollback or forward-fix procedures, and TLS outside local development.
### 8. Internal gRPC trusts caller-supplied identity
Wallet RPC messages contain `InternalIAM`, but the wallet gRPC server does not install an authentication or authorization interceptor: [`wallet/cmd/cmdServe/wallet.go`](wallet/cmd/cmdServe/wallet.go#L74).
Service clients use plaintext `grpc.WithInsecure()`: [`api/service/main.go`](api/service/main.go#L107).
Any peer able to reach the gRPC ports may be able to forge an IAM payload. Internal communication should use:
- mTLS with service identities;
- per-RPC service authorization;
- a signed, short-lived user principal in metadata;
- network policies that make internal RPCs unreachable from the public edge;
- server-side derivation of identity instead of trusting protobuf body fields.
### 9. Authentication sessions and OTP need redesign
- OTP generation uses `math/rand`; development mode uses a fixed code: [`auth/usecase/tfa.go`](auth/usecase/tfa.go#L51).
- Failed OTP attempts rewrite the Redis entry with a 24-hour TTL: [`auth/repository/otp.go`](auth/repository/otp.go#L54).
- No per-mobile, IP, device, ASN, or system-wide OTP rate limiting is visible.
- Refresh-token rotation is not atomic. Concurrent reuse can mint multiple valid access tokens: [`auth/usecase/authorization.go`](auth/usecase/authorization.go#L221).
- JWT verification validates audience but does not explicitly constrain issuer and permitted algorithms. Signing keys are reread for each request, and no `kid`/JWKS rotation model exists: [`auth/util/auth.go`](auth/util/auth.go#L18).
- Permission checks are bypassed outside production. API routes are converted into permissions at startup, and newly created system roles are assigned to every user: [`auth/usecase/permission.go`](auth/usecase/permission.go#L57).
- Login synchronously calls wallet to provision a public key, coupling auth availability to wallet availability: [`auth/usecase/authorization.go`](auth/usecase/authorization.go#L166).
Auth should implement refresh-token families with hashed tokens, atomic rotation and replay detection, logout and revoke-all, device metadata, key rotation, secure OTP generation, abuse controls, and static deny-by-default policy definitions.
Wallet provisioning should be lazy or triggered by a durable `UserKYCVerified` event instead of blocking login.
### 10. API edge protections are incomplete
- Request and response logging can capture OTPs, access tokens, refresh tokens, banking data, and other PII: [`api/middlewares/logger.go`](api/middlewares/logger.go#L13).
- APM attaches national ID and mobile to traces.
- Gin uses its default HTTP server without explicit read, write, header, idle, and shutdown timeouts or request body limits: [`api/cmd/serve.go`](api/cmd/serve.go#L82).
- Metrics, Swagger, and WebSocket endpoints are registered on the public router without visible endpoint-specific protection.
- Multiple CORS origins are joined into one invalid response header: [`api/middlewares/cors.go`](api/middlewares/cors.go#L11).
- gRPC connections are deliberately closed after two minutes while generated clients keep references to the closed connection: [`api/service/main.go`](api/service/main.go#L128).
The API gateway should enforce request size and time limits, rate limits, security headers, redaction, idempotency, strict validation, bounded downstream deadlines, and a consistent public error model.
### 11. Key custody has a large compromise radius
The wallet configuration contains the master key and server secret keys, and user private keys are derived inside the wallet process from the master key and national ID:
- [`wallet/config/config.go`](wallet/config/config.go#L74)
- [`wallet/port/stellar/recoverKey.go`](wallet/port/stellar/recoverKey.go#L36)
Compromise of the wallet process or its configuration can therefore expose every derived user key. Define a custody model using an HSM, KMS, or isolated signing service; key versioning and rotation; hot/cold separation; quorum or maker-checker rules for high-value operations; backup and recovery; and an incident response procedure.
### 12. AdminPanel is a hidden wallet and auth consumer
AdminPanel reads unmanaged wallet and auth tables and directly modifies transaction status from a Django signal: [`AdminPanel/src/coreLogic/signals.py`](AdminPanel/src/coreLogic/signals.py#L14).
Schema and state-machine changes cannot safely proceed until AdminPanel is included in the migration plan. Prefer an authenticated internal command API for mutations and a dedicated read model for reporting.
### 13. Protobuf contracts and builds are not reproducible
API and auth generate protobufs from a moving `v2` branch, while wallet references an absolute path from another development machine:
- [`api/buf.gen.yaml`](api/buf.gen.yaml#L18)
- [`auth/buf.gen.yaml`](auth/buf.gen.yaml#L18)
- [`wallet/buf.gen.yaml`](wallet/buf.gen.yaml#L18)
Use one versioned protobuf module pinned to an immutable commit or release. Add Buf lint and breaking-change checks on every pull request, generate all clients from the same contract version, and publish deprecation metadata.
### 14. Test and CI coverage is effectively absent
The only Go test found is empty: [`wallet/repository/db/redis/lock_test.go`](wallet/repository/db/redis/lock_test.go#L9).
The service CI workflows build and deploy images without explicit unit tests, integration tests, race detection, vet, lint, migration checks, or contract compatibility checks: [`api/.gitea/workflows/ci.yaml`](api/.gitea/workflows/ci.yaml#L27).
The test strategy must be built before changing financial behavior.
## Recommended target boundaries
| Component | Responsibility |
| --- | --- |
| API gateway | HTTP validation, rate limits, idempotency, principal propagation, error mapping, and API compatibility. It should contain no financial logic or permission migrations. |
| Auth | Users, KYC, OTP/MFA, sessions, token issuance and revocation, and static policies. |
| Wallet core | Wallet commands, double-entry ledger, reservations, transaction state machines, and balance queries. |
| Payment orchestration | PSP callbacks, settlement, refunds, reversals, and reconciliation. |
| Chain adapter | Stellar-specific signing, submission, sequence management, confirmation, and chain reconciliation. |
| Workers | Durable processing of outbox records, callbacks, notifications, and retryable external work. |
| Admin | Authenticated internal command APIs and read-only reporting projections; no direct writes to core tables. |
Inside wallet, start with explicit modules rather than new services:
```text
wallet/
ledger/ append-only journals, entries, balances, holds
application/ commands and transaction state machines
payments/ IPG and bank orchestration
settlement/ chain intents and confirmation
chain/stellar/ Stellar adapter and signing client
reconciliation/ PSP, custody, supply, and ledger comparisons
projections/ user and admin read models
```
## Ledger requirements
The ledger must be append-only. Completed financial records should never be rewritten to represent a correction; use explicit reversal transactions.
At minimum, model:
- accounts scoped by owner, asset, purpose, and custody location;
- journals with a unique business operation and idempotency key;
- entries using exact amounts and explicit debit/credit direction;
- reservations or holds with purpose, status, and expiration;
- transaction state history;
- external settlement attempts and provider identifiers;
- outbox events committed in the same PostgreSQL transaction;
- optional materialized balance projections rebuildable from entries.
Required database invariants include:
- entries for each completed journal balance to zero per asset;
- every account has one asset and one defined scale;
- business and provider idempotency keys are unique;
- external blockchain hashes and PSP references are unique when present;
- state transitions use compare-and-set semantics;
- available balance cannot be overspent;
- immutable journal and entry rows cannot be updated or deleted by application roles.
## Transaction state machines
External operations cannot be made atomic with PostgreSQL. Model them as durable state machines or sagas.
An example withdrawal lifecycle is:
```text
requested
-> authorized
-> funds_reserved
-> signing
-> submitted
-> confirmed
-> completed
```
It must also support explicit failure states:
```text
expired
rejected
submission_unknown
failed
reversal_pending
reversed
manual_review
```
Each transition must record who or what initiated it, its timestamp, the previous state, an idempotency key, external references, and an auditable reason. Retries must resume from persisted state rather than restart the operation.
MFA approval should be bound to a hash of the exact intent, including user, operation type, asset, amount, recipient, fee, expiry, and nonce. An OTP tied only to a generic reason or record ID is insufficient.
## Refactoring sequence
### Phase 0: Stabilize and measure
- Freeze nonessential changes to financial flows.
- Patch the buy, callback, transfer, withdrawal, streamer, and transaction-error issues.
- Stop logging secrets and PII.
- Add missing uniqueness and positive-amount constraints after checking production data.
- Add correlation and idempotency IDs.
- Record metrics for transaction states, duplicates, balance drift, callback replay, OTP abuse, and chain lag.
### Phase 1: Add characterization tests
Before changing behavior, cover:
- OTP issuance, retry, expiry, and rate limiting;
- login, refresh rotation, concurrent refresh, logout, and revocation;
- internal and external transfers;
- IRT deposit, callback replay, settlement failure, and withdrawal;
- buy retries, compensation, and service restart;
- streamer restart, duplicate operations, cursor recovery, and missed events;
- wallet creation concurrency;
- AdminPanel mutations that currently affect wallet and auth state.
Add property tests for ledger invariants and concurrency tests for overspending and duplicate callbacks.
### Phase 2: Make contracts reproducible
- Pin protobuf inputs and generator versions.
- Add Buf lint and breaking checks.
- Define one structured error model using gRPC status details and a stable HTTP mapping.
- Add schema-level validation rules.
- Define pagination, filtering, public IDs, idempotency headers, and API deprecation rules.
- Generate and test UI clients from the same release.
### Phase 3: Secure service boundaries
- Add mTLS and service identities.
- Add gRPC authentication, authorization, deadline, recovery, metrics, and tracing interceptors.
- Remove caller-controlled IAM bodies.
- Restrict internal services using network policies.
- Replace manual connection expiry with normal long-lived gRPC connections and backoff.
- Move keys and provider credentials to managed secret storage.
### Phase 4: Refactor auth independently
- Introduce refresh-token families and store only token hashes.
- Rotate refresh tokens atomically and detect reuse.
- Support logout, revoke-all, device sessions, and administrative revocation.
- Validate issuer, audience, token type, timestamps, and permitted algorithms.
- Support `kid`-based signing-key rotation and JWKS distribution.
- Use cryptographically secure OTP generation and store OTP hashes.
- Add mobile, IP, device, and global abuse controls.
- Move permissions to reviewed, static, deny-by-default policy definitions.
- Remove wallet provisioning from the synchronous login path.
### Phase 5: Introduce the ledger
- Create versioned ledger migrations and invariants.
- Backfill opening balances with a documented source and timestamp.
- Build balance and statement projections.
- Introduce reservations for orders, withdrawals, purchases, BNPL, and redeem operations.
- Add transactional outbox publishing.
- Run old and new balance calculations in parallel and compare them continuously.
### Phase 6: Convert external flows
Migrate one flow at a time:
1. IRT deposit and payment callback.
2. IRT withdrawal.
3. Internal token transfer.
4. External token transfer.
5. Primary asset purchase.
6. Redeem and commission.
7. Market order reservation and settlement.
For each flow, require idempotency, durable state, compensation, reconciliation, and operational recovery procedures before cutover.
### Phase 7: Remove direct database consumers
- Route AdminPanel mutations through internal APIs.
- Move reporting to projections or a read replica.
- Remove old mutable balance code after parallel reconciliation reaches an agreed threshold.
- Separate ledger, settlement, or market into independent deployments only if scaling, ownership, or isolation requirements justify it.
## Missing considerations checklist
### Financial integrity
- [ ] Exact amount representation and asset-specific scale
- [ ] Double-entry and zero-sum enforcement
- [ ] Reservations, expirations, releases, and partial capture
- [ ] Reversal instead of mutation or deletion
- [ ] Unique business, provider, and blockchain idempotency keys
- [ ] Atomic compare-and-set state transitions
- [ ] Daily fiat, token-supply, PSP, and custody reconciliation
- [ ] Opening balance and migration reconciliation
- [ ] Negative balance and rounding policies
- [ ] Fee, tax, discount, and commission accounting
### Authentication and authorization
- [ ] Refresh-token family rotation and replay detection
- [ ] Logout, revoke-all, session expiry, and device management
- [ ] JWT key versioning, rotation, and emergency revocation
- [ ] Secure OTP generation, hashing, TTL, attempt limits, and abuse controls
- [ ] MFA bound to exact financial intent
- [ ] Static deny-by-default permissions
- [ ] Service-to-service identities and per-RPC authorization
- [ ] High-value transaction step-up policy
### Blockchain and custody
- [ ] HSM, KMS, or isolated signing service
- [ ] Master-key versioning and rotation
- [ ] Hot/cold wallet and treasury policy
- [ ] Sequence-number concurrency management
- [ ] Submission-unknown recovery
- [ ] Confirmation/finality definition
- [ ] Persistent stream cursor and replay procedure
- [ ] Gas and fee accounting
- [ ] Supply and custody reconciliation
- [ ] Key backup, restore drills, and compromise response
### Payments and messaging
- [ ] Webhook signature validation, timestamp, nonce, and replay protection
- [ ] Provider-specific idempotency and reference uniqueness
- [ ] Settlement, reversal, and refund state machines
- [ ] Transactional outbox and consumer inbox
- [ ] Durable queues and persistent messages
- [ ] Publisher confirms and mandatory routing
- [ ] Retry limits, exponential backoff, DLQ, and manual replay
- [ ] Event schema versioning and compatibility
### API and privacy
- [ ] Request body limits and HTTP server timeouts
- [ ] Per-route and per-identity rate limits
- [ ] Strict request validation and unknown-field handling
- [ ] Stable public error codes and status mapping
- [ ] Idempotency-key semantics and retention
- [ ] API versioning, deprecation, and consumer inventory
- [ ] Correct CORS and security headers
- [ ] Protected metrics, profiling, Swagger, and WebSocket endpoints
- [ ] PII encryption, redaction, retention, and deletion policy
- [ ] Immutable security and administrative audit trail
### Compliance and operations
- [ ] AML and suspicious-activity hooks
- [ ] User, asset, daily, and velocity limits
- [ ] Sanctions and risk screening integration points
- [ ] Maker-checker approval for administrative financial actions
- [ ] RPO, RTO, backup, restore, and disaster-recovery testing
- [ ] Incident response and key-compromise procedures
- [ ] Stuck-transaction and reconciliation-drift alerts
- [ ] Queue lag, chain lag, provider latency, and error budgets
- [ ] Capacity and load testing for high-volume events
### Delivery and testing
- [ ] Versioned database migrations and rollback/forward-fix policy
- [ ] Unit, integration, contract, concurrency, and property tests
- [ ] Deterministic Stellar, Redis, RabbitMQ, PostgreSQL, and PSP test environments
- [ ] Callback replay and service-restart tests
- [ ] Failure injection and reconciliation tests
- [ ] `go test`, race detector, vet, lint, and vulnerability scanning in CI
- [ ] Buf lint and breaking checks in CI
- [ ] Deployment health checks, readiness, graceful shutdown, and rollback gates
## Migration acceptance criteria
A flow should move to the new implementation only when:
- all monetary values use exact representation;
- repeat requests and callbacks produce one economic result;
- concurrent requests cannot overspend;
- every external action can be resumed after process restart;
- every state transition is auditable;
- ledger, PSP, and chain reconciliation is automated;
- old and new calculations agree within an explicitly approved tolerance;
- operational procedures exist for stuck, failed, unknown, and reversed operations;
- compatibility tests cover API, UI, AdminPanel, and protobuf consumers.
## Current verification status
This assessment is based on static inspection of the API, auth, wallet, protobuf, UI, AdminPanel, documentation, and CI configuration.
An attempt was made to run `go test ./...` for API, auth, and wallet. The configured internal Go module proxy timed out during dependency download, so the current compile status could not be independently verified. No source files were changed as part of that verification attempt.
+41
View File
@@ -28,6 +28,47 @@ Multi-service monorepo for the Darano financial/crypto platform.
- [overmind](https://github.com/DarthSim/overmind) or [foreman](https://github.com/ddollar/foreman) — Procfile runner - [overmind](https://github.com/DarthSim/overmind) or [foreman](https://github.com/ddollar/foreman) — Procfile runner
- PostgreSQL 16, Redis, RabbitMQ running locally (or via Docker) - PostgreSQL 16, Redis, RabbitMQ running locally (or via Docker)
## Clone the Workspace
The Darano workspace is an aggregate of independent Git repositories. These
commands reproduce the current directory layout and select the branches used by
this refactor. They expect the local branches to have been pushed first and
require SSH access to `git.darano.ir`.
```bash
mkdir darano
cd darano
git clone --branch feat/refactor-v1 git@git.darano.ir:Kahroba/AdminPanel.git AdminPanel
git clone --branch m2 git@git.darano.ir:Kahroba/DevOps.git DevOps
git clone --branch dev git@git.darano.ir:Kahroba/GL.git GL
git clone --branch main git@git.darano.ir:KuknosNode/Scripts.git Kuknos-Node-scripts
git clone --branch dev git@git.darano.ir:Kahroba/alert.git alert
git clone --branch main git@git.darano.ir:Kahroba/api.git api
git clone --branch feat/refactor-v1 git@git.darano.ir:Kahroba/auth.git auth
git clone --branch main git@git.darano.ir:Kahroba/dev-procfile.git dev-procfile
git clone --branch dev git@git.darano.ir:Kahroba/docs.git docs
git clone --branch feat/refactor-v1 git@git.darano.ir:Kahroba/proto.git proto
git clone --branch fix/contact-us git@git.darano.ir:Kahroba/ui.git ui
git clone --branch feat/refactor-v1 git@git.darano.ir:Kahroba/wallet.git wallet
```
`private-chain/` is not included because the current local repository has no
`origin` remote configured.
Recreate the root documentation links after cloning:
```bash
ln -s dev-procfile/AGENTS.md AGENTS.md
ln -s dev-procfile/CLAUDE.md CLAUDE.md
ln -s dev-procfile/README-REFACTORING.md README-REFACTORING.md
ln -s dev-procfile/README.md README.md
ln -s dev-procfile/REFACTORING-AUDIT.md REFACTORING-AUDIT.md
ln -s dev-procfile/REFACTORING-PLAN.md REFACTORING-PLAN.md
ln -s dev-procfile/REFACTORING-TODO.md REFACTORING-TODO.md
ln -s dev-procfile/گزارش-زیرساخت-توکنسازی-دارانو.md گزارش-زیرساخت-توکنسازی-دارانو.md
```
## Infrastructure ## Infrastructure
Start the shared infrastructure (Postgres, Redis, RabbitMQ, MinIO): Start the shared infrastructure (Postgres, Redis, RabbitMQ, MinIO):
+222
View File
@@ -0,0 +1,222 @@
# 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`.
### `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.
+301
View File
@@ -0,0 +1,301 @@
# Darano Monorepo — DDD / Clean Architecture Refactoring Plan
## Executive Summary
The five codebases (`api/`, `auth/`, `wallet/`, `AdminPanel/`, and `proto/`) share the same general idea of layering but diverge in naming, directory structure, config libraries, where business logic lives, and — critically for AdminPanel — **how they access data**. AdminPanel bypasses all Go backend services and writes directly to the core database, making it a parallel implementation of business logic. This plan defines a unified target architecture and a phased migration that preserves functionality at every step.
---
## 1. Current State Analysis
### 1.1 Naming & Structure Inconsistencies
| Concern | `api/` | `auth/` | `wallet/` |
|---|---|---|---|
| Business logic layer | `handler/` (HTTP-only) | `usecase/` | `core/walletImp/` |
| Business logic layer (2nd) | `service/` (gRPC client) | (same as above) | `core/marketImp/`, `core/alertImp/` |
| Data access | No repo (gateway only) | `repository/` | `repository/` |
| Domain models | `domain/stub/` only | `domain/db/` + `domain/dto/` | `domain/db/` |
| Config library | `knadh/koanf` | `kkyr/fig` | `kkyr/fig` |
| Config global | `config.Cfg` | `config.Cfg` | `config.Cfg` |
| gRPC server impl | N/A (HTTP-only) | `usecase/*` implements gRPC server | `core/*Imp/*` implements gRPC server |
**Key observation**: `auth/` has the cleanest pattern (`usecase/` for business logic), `wallet/` is the most messy (`core/` mixes gRPC server with business logic), and `api/` is fine as an HTTP gateway.
### 1.2 AdminPanel Architecture — Direct DB Access, No Abstraction
AdminPanel has a fundamentally different problem: it **bypasses all Go backend services** and connects directly to the core database.
```
AdminPanel ──direct Postgres──→ core_db (same DB as Go services)
──→ default_db (Django's own tables)
──→ lite_db (SQLite, fallback)
```
**Key problems**:
1. **`managed = False` GORM models copied manually**: Every model in `src/coreLogic/models.py` has `managed = False` and `db_table = "..."` — they are **manual replicas** of the Go services' GORM models. Generated via `inspectdb`, never kept in sync. `make proto` generates betterproto stubs, but Django models are **not auto-generated** from those.
2. **No service layer**: The entire AdminPanel is a thin layer of Django admin widgets on top of raw SQL tables. Business logic is scattered across:
- `src/coreLogic/admin/asset.py` — inline validation (`check_token_policy`, `auto_gen`) duplicating Go-side rules
- `src/coreLogic/acl.py` — permission rules
- `src/usermapper/user_perm.py` — asset access control
- Inline admin methods (`save_model`) that bypass Go services' validation entirely
3. **No gRPC integration**: The AdminPanel reads/writes directly to `core_db`. No gRPC call to Go services. Means:
- Admin edits to `Assets` bypass trustline updates
- Admin edits to `Transactions` don't trigger blockchain operations
- Admin edits to `Wallets` don't update Stellar balances
- Race conditions between admin edits and Go service operations
4. **Hardcoded business rules in Django**: `check_token_policy` duplicates validation that should live in the wallet service. `auto_gen` generates metadata that should be produced by the wallet service.
5. **Multi-database with fragile router**: `src/adminpanel/db/routers.py` routes `coreLogic` models to `core_db`. If a new model is added to Go services but forgotten in Django admin, it silently fails.
6. **Inline business logic in Django admin**: `MultiDBModelAdmin.save_model` has asset-level access control. `delete_model` does soft deletes. Mixed with admin layer, not separated.
### 1.3 Config Library Mismatch
- `api/` uses `knadh/koanf/v2` with TOML parser. Tags are `koanf:"field-name"`.
- `auth/` and `wallet/` use `kkyr/fig`. Tags are `fig:"field-name"`.
- All three use a **global singleton** `config.Cfg`.
- `api/` hardcodes defaults in `ParseConfig`; `auth/` and `wallet/` rely on struct defaults.
- AdminPanel uses `django-environ` (`.env` files). Different language/framework entirely.
### 1.4 Where Business Logic Lives
- **auth/ `usecase/`** — Decent separation, but gRPC interfaces embedded directly in the struct. Validation, business rules, and gRPC response building mixed in the same methods.
- **wallet/ `core/walletImp/`** — Problematic: 19 files implementing `WalletServiceServer` with business logic, validation, DB calls, and Stellar blockchain calls all in one method. Example: `UserInitWallet` does validation, DB transactions, key generation, trustline creation, and status response — all in one method.
- **api/ `handler/`** — Acceptable: handlers call `DaranoService` (gRPC client). No business logic here. But `service/` is a gRPC client aggregator with reflection-based URL lookup, not a traditional service layer.
- **AdminPanel `admin/`** — Wrong layer: business validation, metadata generation, and policy checks live in Django admin classes, not in a service layer.
### 1.5 Domain Model vs Persistence Model Confusion
All Go services use GORM models (`domain/db/`) directly as domain objects. No separation between **domain entities** (rich business objects with behavior) and **persistence models** (plain structs with GORM tags).
AdminPanel uses Django models with `managed = False` — the same conflation, but in Python.
---
## 2. Target Architecture
### 2.1 Go Services — Unified Directory Structure
Each Go service should follow:
```
service/
├── cmd/ # CLI entry points (Cobra)
├── domain/ # Innermost layer — pure business logic
│ ├── entity/ # Domain entities (rich, no persistence tags)
│ ├── valueobject/ # Immutable value objects (Money, AssetID, etc.)
│ ├── service/ # Domain services (orchestrate entities)
│ ├── repository/ # Repository INTERFACES only (ports)
│ ├── error/ # Domain-specific errors
│ ├── event/ # Domain events
│ ├── dto/ # Data transfer objects (gRPC/HTTP)
│ └── stub/ # Generated protobuf code (never edit)
├── application/ # Application layer — use cases
│ ├── usecase/ # Business logic / use cases
│ └── service/ # Application services
├── infrastructure/ # Infrastructure layer
│ ├── repository/ # Repository implementations (DB, Redis, Queue)
│ │ ├── db/ # PostgreSQL, etc.
│ │ ├── redis/ # Redis
│ │ └── queue/ # RabbitMQ
│ ├── config/ # Configuration loading
│ ├── grpc/ # gRPC server setup & registration
│ ├── logger/ # Logger initialization
│ └── crypto/ # Cryptography utilities
├── interface/ # Interface/Adapter layer
│ ├── http/ # HTTP handlers (api gateway only)
│ ├── grpc/ # gRPC server implementations
│ └── ws/ # WebSocket handlers
├── util/ # Cross-cutting utilities
├── go.mod
└── main.go
```
**Dependency flow** (points inward):
```
interface/ → application/ → domain/ ← infrastructure/
```
### 2.2 AdminPanel — Thin Admin Wrapper Around Go Services
AdminPanel needs a Django-native approach (no forced DDD naming), but the architectural principles are the same:
```
AdminPanel/src/
├── adminpanel/ # Django project config
├── coreLogic/
│ ├── domain/ # NEW: extracted business logic
│ │ ├── services/ # Validation, metadata generation (moved from admin/)
│ │ └── repositories/# Interfaces to backend
│ ├── application/ # NEW: use cases that delegate to gRPC
│ │ ├── asset_uc.py
│ │ ├── wallet_uc.py
│ │ └── market_uc.py
│ ├── infrastructure/ # NEW: gRPC client to Go services
│ │ └── grpc_client.py
│ ├── admin/ # Keep — now thin UI adapters only
│ ├── models.py # Keep as legacy (read-only ORM, managed=False)
│ └── enums.py # Keep
├── usermapper/ # Admin user management (keep as-is)
├── alerts/ # Notification system (keep as-is)
├── accounts/ # SMS accounts (keep as-is)
└── utils/ # Cross-cutting utilities
```
**Key principle**: AdminPanel should be a **thin admin wrapper** around the Go services, not a parallel implementation. Go services own all business logic. AdminPanel provides a human-friendly interface to view and (with validation) modify state.
### 2.3 AdminPanel Data Access Pattern
```
Read path: AdminPanel ──SQL──→ core_db (fast, direct, for list/detail views)
Write path: AdminPanel ──gRPC──→ Go services (validate + execute business logic)
```
### 2.4 Config Standardization
All Go services → `knadh/koanf/v2` with TOML. No global singletons — config passed via constructor injection.
---
## 3. Migration Plan — Phased Approach
### Phase 0: Preparation (1 day)
No code changes. Document test coverage, verify all services build, create tracking doc.
### Phase 1: Standardize Go Config (2-3 days)
Replace `fig``koanf` in `auth/` and `wallet/`. Move config to `infrastructure/config/config.go`. Remove global `config.Cfg`.
**Risk**: Low. Config struct fields stay the same; only the loader changes.
### Phase 2: Reorganize `auth/` (3-4 days)
Rename layers, move interfaces to `domain/`, move GORM models to `infrastructure/`. `auth/` already has the cleanest pattern — this validates the approach.
**Risk**: Low. Structure change, minimal logic changes.
### Phase 3: Reorganize `wallet/` (1-2 weeks)
Rename `core/``application/`. Split `walletImp/`, `marketImp/`, `alertImp/` into `application/usecase/`. Move GORM models and interfaces. Split gRPC server registration from use cases. Move `port/stellar/``infrastructure/`.
**Risk**: Medium. Incremental: rename first, then split gRPC, then add entities.
### Phase 4: Restructure `api/` (3-4 days)
Rename `handler/``interface/http/`, `service/``infrastructure/grpcclient/`, move `middlewares/``interface/http/middleware/`.
**Risk**: Medium. Gateway pattern is different from auth/wallet.
### Phase 5: AdminPanel Service Layer (2-3 weeks)
1. Create `infrastructure/grpc_client.py` — reusable gRPC client to Go services
2. Extract business logic from admin classes to `coreLogic/domain/services/`
3. Create use case layer `coreLogic/application/`
4. Refactor admin classes to thin adapters (delegate to use cases)
5. Fix router typo (`no_migartion``no_migration`)
6. Add gRPC write hooks for `save_model`
**Risk**: Medium. Test every admin page after migration.
### Phase 6: Shared Domain Types (3-5 days)
Extract `WalletID`, `UserID`, `AssetID`, `Balance` value objects into monorepo root `shared/domain/`. Import via each service's `go.mod`.
**Risk**: Medium. Affects all services on change.
### Phase 7: Domain Events (2-3 days, optional)
Add `domain/event/` to Go services for cross-domain communication.
---
## 4. Migration Order
```
Phase 0: Preparation
Phase 1: Go config standardization
Phase 2: Reorganize auth/ ──┐
├──→ Phase 5: AdminPanel (parallel with 2-4)
Phase 3: Reorganize wallet/ ─┘
Phase 4: Restructure api/
Phase 6: Shared domain types
Phase 7: Domain events (optional)
```
---
## 5. Before/After: AdminPanel Asset Management
**Before** — business logic in Django admin:
```python
# src/coreLogic/admin/asset.py
@admin.register(Assets, site=admin_site)
class AssetAdmin(MultiDBModelAdmin):
def save_model(self, request, obj, form, change):
if user_perm.can_access_asset(request.user, obj):
return super().save_model(request, obj, form, change)
# Direct DB write — bypasses wallet service!
def check_token_policy(self, request, obj: Assets) -> bool:
# Validation duplicated from wallet service
if obj.can_buy:
p = AssetPrices.objects.filter(asset=obj).last()
if not p or p.ico_price <= 0:
errors.append("ico price must be > 0")
```
**After** — thin admin delegating to Go service:
```python
# src/coreLogic/application/asset_uc.py
class AssetUseCase:
def __init__(self, grpc_client: GRPCClient):
self.grpc_client = grpc_client
def update_asset(self, admin_user, asset_id, changes: dict) -> StatusRes:
"""Delegates all mutations to wallet service."""
return self.grpc_client.wallet_service.InternalWalletUpdateAsset(
AssetUpdateReq(id=asset_id, changes=changes)
)
# src/coreLogic/admin/asset.py
@admin.register(Assets, site=admin_site)
class AssetAdmin(MultiDBModelAdmin):
list_display = [...]
# ... UI config only
def save_model(self, request, obj, form, change):
uc = AssetUseCase(self.grpc_client)
uc.update_asset(request.user, obj.id, form.cleaned_data)
```
---
## 6. Risk Mitigation
| Risk | Mitigation |
|---|---|
| Breaking CI/CD | Keep `make build` and `make run` working at every phase |
| Lost functionality during rename | Use `git mv` + `sed` for mass renames; commit each file move separately |
| gRPC contract breaks | Proto definitions are in `proto/`. We only change Go implementation |
| Config migration issues | Keep old config format identical; only change the loader |
| AdminPanel write conflicts | gRPC write path ensures Go services own all mutations |
| Django model drift | Document which models are read-only ORM vs which need gRPC sync |
| Multiple air instances conflict | The `flock` mechanism in wallet Makefile handles this |
## 7. Non-Goals
- Changing protobuf definitions — `.proto` files stay as-is
- Adding new frameworks — no ORM replacement
- Rewriting the UI
- Complete test suite rewrite
+275
View File
@@ -0,0 +1,275 @@
# Darano Refactoring Task Tracker
This is the authoritative execution tracker for the refactor. Work is performed sequentially, with no more than one task marked `STARTED` at a time.
## Status rules
| Status | Meaning |
|---|---|
| `TODO` | Ready or waiting on an earlier task. |
| `STARTED` | The single task currently being executed. |
| `DONE` | Implemented and verified against its acceptance checks. |
| `FAILED` | Attempted but not completed; failure evidence and a follow-up task must be recorded. |
| `CHANGED` | The task or scope changed after it was recorded; the reason must be retained. |
## Scope
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| S001 | `DONE` | Read root `AGENTS.md`, `REFACTORING-PLAN.md`, and RTK instructions. | Governing instructions incorporated into the tracker. |
| S002 | `CHANGED` | Refactor every repository originally listed in the plan. | Scope changed: `ui`, `docs`, and `DevOps` are excluded; new `GL` is included by user request. |
| S003 | `CHANGED` | Define active repositories. | Active scope changed to `api`, `auth`, `wallet`, `AdminPanel`, `proto`, and `GL`. |
| S004 | `DONE` | Create `feat/refactor-v1` in every active repository. | Branch exists and is checked out in all six active repositories. |
| S005 | `DONE` | Restore excluded repositories after the scope change. | `ui` is on `stage`, `docs` is on `dev`, and `DevOps` is on `m2`; their temporary refactor branches were removed without changing their files. |
## Phase 0 — Baseline and safety
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| B001 | `DONE` | Audit active repositories and reconcile plan claims with actual code. | Findings recorded in `REFACTORING-AUDIT.md`, including corrected config and connection-lifecycle claims. |
| B002 | `DONE` | Record toolchain and dependency baselines. | Versions and committed dependency sources recorded in `REFACTORING-AUDIT.md`; no upgrades performed. |
| B003 | `DONE` | Run `proto` baseline checks. | Build/lint pass; existing format differences and missing generation plugins recorded; active tree and binary preserved. |
| B004 | `DONE` | Run `auth` baseline checks. | Generation, tests, and build pass in a clean temporary clone; generated stubs are reproducible. |
| B005 | `DONE` | Run `wallet` baseline checks. | Generation is reproducible; Redis lock test and build pass serially with no diff. |
| B006 | `DONE` | Run `api` baseline checks. | Proto/Swagger outputs are reproducible; tests and full build pass with no diff. |
| B007 | `DONE` | Run `AdminPanel` baseline checks. | System/compile/migration checks pass; zero-test Debug Toolbar failure and deploy warnings recorded. |
| B008 | `DONE` | Produce the baseline report and lock the first migration slice. | Baseline and exact `C001` compatibility-facade migration are documented in `REFACTORING-AUDIT.md`. |
## Phase 1 — Configuration standardization
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| C001 | `DONE` | Refactor `auth` config loading into `infrastructure/config`. | Koanf loader/facade tests, race tests, generation, full tests, and build pass; committed as `29b7e07`. |
| C002 | `DONE` | Replace `auth` global config reads with constructor injection. | No global/legacy reads remain; tests, race tests, generation, tidy, and build pass; committed as `1bd5559`. |
| C003 | `DONE` | Refactor `wallet` config loading into `infrastructure/config`. | Fig defaults and all five configs verified; tests/race/build pass; committed as `7958530`. |
| C004 | `CHANGED` | Replace `wallet` global config reads with constructor injection. | Priority changed by the GL requirement after dependency inventory; resume as a new tracked task after the ledger adapter boundary stabilizes. |
| C005 | `TODO` | Move `api` config loading into `infrastructure/config`. | Koanf behavior and baked-in defaults remain compatible. |
| C006 | `TODO` | Replace `api` global config reads with constructor injection. | Server, middleware, Swagger, profiling, and clients receive explicit config. |
## Priority workstream — General Ledger (`GL`)
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| L001 | `DONE` | Define GL invariants, transaction mapping, failure semantics, and service boundary. | `GL/DESIGN.md` defines the append-only double-entry model, mappings, outbox delivery, controlled failover modes, and gRPC ownership; committed as `1863de1`. |
| L002 | `DONE` | Add backward-compatible internal GL protobuf contracts. | Added isolated `ledger.v1` append, event, query, balance, health, and replay contracts; Buf format/lint/build pass; committed as `b4bb506`. |
| L003 | `DONE` | Scaffold `GL` as an independent Go gRPC service. | Added generated consumers, explicit composition, pure koanf config, health RPC, bounded graceful shutdown, and tests; generation/test/race/vet/build pass; committed as `b1e0b01`. |
| L004 | `DONE` | Implement GL PostgreSQL persistence and migrations. | Exact fixed-point domain values, transactional idempotent append, per-asset seal checks, immutable tables/triggers, migrations, and repository tests pass; committed as `0b3eaa0`. |
| L005 | `DONE` | Implement GL application use cases and gRPC adapters. | Append/event/query/balance/replay RPCs, canonical hashes, exact reversals, status mapping, persistence queries, and tests pass; committed as `76905ab`. |
| L006 | `DONE` | Add a wallet-owned ledger port and GL gRPC adapter. | Wallet owns transport-neutral journal/event types; adapter maps them to generated GL messages with deadlines/TLS options and tests; committed as `9d91f8f`. |
| L007 | `DONE` | Add a durable wallet outbox for ledger delivery. | Transactional enqueue, locked claiming, stale recovery, retry/backoff, quarantine/replay, dispatcher, and commit/rollback tests pass; committed as `379dbc2`. |
| L008 | `CHANGED` | Integrate ledger recording into every wallet transaction path. | Scope split after implementation: all Wallet-owned deposit, withdrawal, transfer, buy, redeem, commission, market, IPG, stream, lock/release, and lifecycle paths are mapped and dispatched (`ff31c87`, `d1aa339`); AdminPanel direct writes remain under `P006`/`P008`. |
| L009 | `TODO` | Implement reconciliation and disaster-read tooling. | Missing/duplicate/mismatched blockchain records are detectable; ledger can reconstruct account/asset balances deterministically. |
| L010 | `TODO` | Run outage, replay, ordering, concurrency, and recovery verification. | No committed wallet transaction is lost; duplicates do not double-post; unbalanced journals never commit. |
## Priority workstream — Publisher-backed ICO purchases
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| I001 | `DONE` | Map the current `CalcBuyAsset`, `BuyAsset`, role/permission, market-order, and settlement paths. | Compatibility boundary and exact market-owned implementation are recorded in `REFACTORING-AUDIT.md`. |
| I002 | `DONE` | Add the `token-publisher` auth role and expose stable role keys in IAM. | Additive proto committed as `2d7d3ff`; idempotent custom-role bootstrap and stable role-key tests committed as `7c3b3b6`; auth tests/race/build pass. |
| I003 | `DONE` | Add a backward-compatible publisher ICO order contract and persistence linkage. | Additive proto committed as `286b8e5`; role-gated ICO sell-order designation and agreement maker linkage committed as `25d0f03`. |
| I004 | `DONE` | Refactor `CalcBuyAsset` to quote against the publisher's live sell order. | Market selects the best live publisher order, verifies the publisher role and remaining volume, calculates taker pricing, and wallet delegates; committed as `5a0f3d7`. |
| I005 | `DONE` | Refactor `BuyAsset` to create the user taker side and invoke the market settlement path. | Claim-once agreement, taker creation, maker-wide serialization, fresh-state checks, shared `settleOrder`, and synchronous hashes committed as `ef2e4ae`. |
| I006 | `DONE` | Verify publisher-backed ICO authorization, limits, quoting, settlement, ledger, and regressions. | Publisher/order/volume and claim tests pass; proto lint/build, reproducible generation, full auth/wallet/api tests, race tests, and builds pass; verification is `3555a5f`, with deterministic best-price selection corrected in `0d7c820`. |
## Priority workstream — Transaction event pipeline
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| E001 | `DONE` | Map every transaction write, existing RabbitMQ code, GL outbox, transaction consumer, and alert boundary. | All transaction inserts/updates converge in the PostgreSQL transaction repository; direct AMQP publishing is legacy and inactive; the durable DB outbox is the required publication boundary. |
| E002 | `DONE` | Define transaction event identity, per-type topics, durable outbox, inbox, and deadbox persistence. | All 17 enum values have unique topics; transaction ID is the event identity; atomic outbox, inbox claim states, and deadbox models/repositories are tested and committed as `5dfb223`. |
| E003 | `DONE` | Replace the legacy AMQP channel wrapper with Watermill publisher/subscriber adapters. | Application code depends only on transport-neutral ports; AMQP connection ownership is centralized and can be replaced by another Watermill backend; full Wallet tests pass in `25fdb37`. |
| E004 | `DONE` | Add per-transaction-type handlers with idempotent inbox processing. | Every declared transaction type has a channel; duplicate delivery cannot repeat processing; pending executable transactions use the existing transaction processor; tests/race tests pass in `951cd02`. |
| E005 | `DONE` | Add retry, success notification, and deadbox routing. | Handler errors retry with bounded backoff; successful handling notifies alert; exhausted messages enter a persistent deadbox with transaction/event/error metadata; tests/race tests pass in `c9a9101`. |
| E006 | `DONE` | Integrate dispatcher/router lifecycle and verify the full event pipeline. | Wallet-mode-only startup/shutdown is bounded; outbox recovery, duplicate delivery, all 17 per-type routes, retry, deadbox, Alert success, generation, tests, race tests, vet, and build pass in `b5784b7`. |
## Priority workstream — Go 1.26 toolchain
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| T001 | `DONE` | Inventory active Go modules, builders, and version pins while excluding docs, DevOps, and UI. | Four Go modules found; API/Auth/Wallet builders already use the official Go 1.26 Bookworm image; GL has no Dockerfile. |
| T002 | `DONE` | Upgrade API module metadata to Go 1.26 and verify its existing Docker builder. | Generation, tests, vet, and native build pass in `fb6ad38`; Docker proxy default changed in `ed8da2f`; Dockerfile check passes. |
| T003 | `DONE` | Upgrade Auth module metadata to Go 1.26 and verify its existing Docker builder. | Generation, tests, vet, and native build pass in `b2d6686`; Docker proxy default changed in `736a716`; Dockerfile check passes. |
| T004 | `DONE` | Upgrade Wallet module metadata to Go 1.26 and verify its existing Docker builder. | Generation, tests, full race tests, vet, and native build pass in `f5243a8`; Docker proxy default changed in `fc96120`; Dockerfile check passes. |
| T005 | `DONE` | Upgrade GL module metadata to Go 1.26 and add its missing Go 1.26 Dockerfile. | Scoped upgrade and new multi-stage image committed in `ce5f8b4`; Dockerfile check passes. Current-tree build validation changed because separate uncommitted GL explorer work is missing generated components. |
| T006 | `DONE` | Perform cross-repository version and clean-tree audit. | All four active Go modules and builders declare Go 1.26; all six active repositories use `feat/refactor-v1`; unrelated GL work and the known proto binary remain preserved. |
| T007 | `DONE` | Standardize in-scope Go Docker builders on the Darano Go proxy. | All four builders default to `https://go.reg.darano.ir`; Dockerfile checks pass. A cold API image build was stopped after repeated delayed proxy 404s for historical transitive metadata; no public fallback was added. |
| T008 | `DONE` | Execute full Docker image builds for every in-scope Go service. | GL passes and produced image `sha256:717c75dfa91f843acdb8d56b4dd111224e5ee45d060dcd4731e5d472ff2c8f69`; API, Auth, and Wallet are blocked in `go mod download` by repeated 300-second `504 Gateway Timeout` responses from `go.reg.darano.ir` for `google.golang.org/api` metadata. |
| T009 | `DONE` | Add Gitea CI/CD configuration to GL. | Seven action/workflow YAML files parse successfully; the exact buildx action produced both GL OCI tags using the mandated proxy; committed as `675def5`. |
| T010 | `DONE` | Commit outstanding workspace work and centralize root Markdown files in `dev-procfile` with root symlinks. | Pending work committed in DevOps (`665fd6b`), docs (`2c49a92`), Kuknos Node scripts (`c114c13`), and proto (`c778fda`); all eight root Markdown paths resolve through relative symlinks to tracked files in `dev-procfile`. |
| T011 | `DONE` | Document commands for cloning the complete Darano workspace on another machine. | `README.md` now has copy-paste commands for all 12 repositories with configured origins, pins the current branches, recreates all eight root Markdown symlinks, and identifies `private-chain` as lacking a clone URL. |
| T012 | `DONE` | Push every committed project branch required for cross-machine continuation. | All 12 top-level repositories with configured origins are synchronized; AdminPanel, Auth, and Proto refactor branches now have upstreams; `dev-procfile` uses SSH for non-interactive access; `private-chain` remains local because it has no remote. |
## Phase 2 — `auth` architecture
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| A001 | `TODO` | Map every auth RPC to business operations and dependencies. | Method-level migration map exists before package moves. |
| A002 | `TODO` | Introduce auth domain entities, value objects, errors, and repository ports. | Domain packages contain no gRPC, GORM, Redis, or framework imports. |
| A003 | `TODO` | Move auth persistence and Redis implementations into infrastructure. | Explicit persistence/domain mappings exist and repository tests pass. |
| A004 | `TODO` | Extract OTP application use cases and thin gRPC adapters. | OTP behavior and status mapping remain compatible. |
| A005 | `TODO` | Extract authentication/JWT application use cases and adapters. | Token behavior, validation, and status mapping remain compatible. |
| A006 | `TODO` | Extract identity and permission use cases and adapters. | Public and internal authorization services pass tests. |
| A007 | `TODO` | Replace auth bootstrap with explicit dependency composition. | Dependency direction is enforced and the service builds. |
| A008 | `TODO` | Remove superseded auth packages and compatibility shims. | No dead imports or duplicate implementations remain. |
## Phase 3 — `wallet` architecture
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| W001 | `TODO` | Map wallet, market, alert, internal-wallet, cron, stream, DB, Redis, queue, and Stellar dependencies. | Method/process-level migration map exists. |
| W002 | `TODO` | Introduce wallet domain entities, value objects, errors, and repository ports. | Domain packages have no transport or infrastructure dependencies. |
| W003 | `TODO` | Move PostgreSQL, Redis, RabbitMQ, external client, and Stellar adapters into infrastructure. | Existing behavior remains available behind inward-facing ports. |
| W004 | `TODO` | Extract read-only wallet use cases and gRPC adapters. | Responses and error mapping remain compatible. |
| W005 | `TODO` | Extract wallet initialization and asset/trustline use cases. | Transactions, key generation, trustlines, and rollback behavior are tested. |
| W006 | `TODO` | Extract deposit, withdrawal, and transaction use cases. | Idempotency, balances, queues, and failure behavior are tested. |
| W007 | `TODO` | Extract market use cases and adapters. | Pricing and market operations remain compatible. |
| W008 | `TODO` | Extract alert use cases and adapters. | Alert persistence, delivery, and error behavior remain compatible. |
| W009 | `TODO` | Extract internal-wallet use cases and adapters. | Internal RPC contracts remain compatible. |
| W010 | `TODO` | Separate cron and stream bootstrap from business operations. | Both modes start and stop correctly through explicit dependencies. |
| W011 | `TODO` | Replace wallet bootstrap with explicit dependency composition. | All five sub-services work independently and together. |
| W012 | `TODO` | Remove superseded `core/*Imp` packages and shims. | No duplicate business implementations remain. |
## Phase 4 — `api` architecture
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| G001 | `TODO` | Inventory routes, middleware, response contracts, WebSocket, Swagger, metrics, profiling, and gRPC clients. | Compatibility matrix exists before package moves. |
| G002 | `TODO` | Move upstream clients into `infrastructure/grpcclient`. | Lazy connection and two-minute idle-close behavior remain intact. |
| G003 | `TODO` | Move middleware into `interface/http/middleware`. | Existing middleware order is unchanged and tested. |
| G004 | `TODO` | Move public HTTP handlers and routes into `interface/http`. | Public endpoints retain paths, status codes, and envelopes. |
| G005 | `TODO` | Move authenticated client/admin handlers and routes. | JWT, metadata forwarding, errors, and route behavior remain compatible. |
| G006 | `TODO` | Move WebSocket and auxiliary endpoints into interface adapters. | WebSocket, health, metrics, Swagger, and profiling still work. |
| G007 | `TODO` | Replace API bootstrap with explicit dependency composition. | Gateway builds and all contract tests pass. |
| G008 | `TODO` | Remove superseded API packages and shims. | No duplicate handlers or clients remain. |
## Phase 5 — AdminPanel write service layer
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| P001 | `TODO` | Inventory every direct AdminPanel write, delete, inline, bulk action, validation, and side effect. | Each mutation is mapped to an owning Go service or explicitly classified. |
| P002 | `TODO` | Compare required AdminPanel mutations with existing internal RPCs. | Every missing contract is documented before any proto change. |
| P003 | `TODO` | Add reusable authenticated, deadline-aware gRPC client infrastructure. | Unit tests cover success, timeout, unavailable service, and status translation. |
| P004 | `TODO` | Add asset application use cases and route asset writes through wallet RPCs. | Direct asset writes stop; access checks and user-visible errors remain correct. |
| P005 | `TODO` | Move token-policy validation and metadata generation to Go-owned operations. | Django no longer owns duplicate wallet business rules. |
| P006 | `TODO` | Add wallet and transaction use cases and migrate writes. | Direct writes stop and failure/partial-write behavior is tested. |
| P007 | `TODO` | Add market and remaining mutable aggregate use cases. | All classified mutations use their owning service. |
| P008 | `TODO` | Make legacy unmanaged ORM models explicitly read-only. | List/detail reads remain fast; migrated writes cannot bypass services. |
| P009 | `TODO` | Fix `no_migartion` to `no_migration` with router tests. | Correct router setting is covered without unintended migrations. |
| P010 | `TODO` | Verify every affected admin page and permission tier. | Create/update/delete/inline/bulk/failure paths pass. |
## Phase 6 — Protobuf contracts
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| R001 | `TODO` | Decide whether existing internal RPCs cover all required AdminPanel writes. | Decision is evidence-based; no speculative contract changes. |
| R002 | `TODO` | Add backward-compatible internal RPCs only for proven gaps. | Buf lint/breaking checks pass; existing field numbers and contracts are preserved. |
| R003 | `TODO` | Regenerate only active Go and Python consumers. | Generated files are reproducible and Go JSON tags retain required field presence. |
## Phase 7 — Shared types and final verification
| ID | Status | Task | Acceptance check / note |
|---|---|---|---|
| F001 | `TODO` | Evaluate shared ID and monetary types after service boundaries stabilize. | Only genuinely identical cross-context semantics are shared. |
| F002 | `TODO` | Introduce approved shared types incrementally, if justified. | Versioned dependency and explicit boundary conversions are used. |
| F003 | `TODO` | Run final generation, tests, builds, and architecture checks. | Results meet or exceed the recorded baseline. |
| F004 | `TODO` | Review every active repository diff for generated/manual/unrelated changes. | Only scoped changes remain and user-owned work is preserved. |
| F005 | `TODO` | Prepare reviewable per-repository commits and final migration report. | Every commit has one purpose and leaves its repository buildable. |
## Execution log
Append one row whenever a task changes status. Existing rows are never rewritten, so failed or changed work remains visible.
| Time | Task | From | To | Evidence / reason |
|---|---|---|---|---|
| 2026-08-14 | S001 | `TODO` | `DONE` | Read and incorporated repository instructions and refactoring plan. |
| 2026-08-14 | S002 | `TODO` | `CHANGED` | User excluded `docs`, `DevOps`, then `ui`. |
| 2026-08-14 | S003 | `TODO` | `DONE` | Active scope reduced to five repositories. |
| 2026-08-14 | S004 | `TODO` | `DONE` | Created and checked out `feat/refactor-v1` in all active repositories. |
| 2026-08-14 | S005 | `TODO` | `DONE` | Restored excluded repositories and removed temporary branches. |
| 2026-08-14 | B001 | `TODO` | `STARTED` | Began code-backed architecture and repository audit. |
| 2026-08-14 | B001 | `STARTED` | `DONE` | Recorded repository state, actual config libraries/globals, architecture boundaries, AdminPanel writes, proto gaps, generated outputs, and plan discrepancies in `REFACTORING-AUDIT.md`. |
| 2026-08-14 | B002 | `TODO` | `STARTED` | Began read-only toolchain and dependency baseline capture. |
| 2026-08-14 | B002 | `STARTED` | `DONE` | Recorded Go, Python, uv, Django, Buf, protoc/plugin, generator, and committed dependency baselines; noted missing root proto plugins and sandbox-blocked API module metadata lookup. |
| 2026-08-14 | B003 | `TODO` | `STARTED` | Began proto lint/build/generation baseline checks with existing untracked binary protected. |
| 2026-08-14 | B003 | `STARTED` | `DONE` | Buf build/lint passed; format drift and missing root generation plugins recorded from non-mutating checks and a temporary clone. |
| 2026-08-14 | B004 | `TODO` | `STARTED` | Began auth generation, test, and build baseline. |
| 2026-08-14 | B004 | `STARTED` | `DONE` | Auth generation reproduced committed stubs; tests and build passed in a temporary clone. |
| 2026-08-14 | B005 | `TODO` | `STARTED` | Began serialized wallet generation, test, and build baseline. |
| 2026-08-14 | B005 | `STARTED` | `DONE` | Wallet generation reproduced committed stubs; tests and full build passed with no tracked diff. |
| 2026-08-14 | B006 | `TODO` | `STARTED` | Began API generation, test, Swagger, and build baseline. |
| 2026-08-14 | B006 | `STARTED` | `DONE` | API generation, tests, Swagger generation, and full build passed with reproducible outputs. |
| 2026-08-14 | B007 | `TODO` | `STARTED` | Began non-database-mutating AdminPanel system and test baseline checks. |
| 2026-08-14 | B007 | `STARTED` | `DONE` | System, compile, and migration-drift checks passed; deploy warnings and zero-test Debug Toolbar failure recorded. |
| 2026-08-14 | B008 | `TODO` | `STARTED` | Consolidated baseline results and selected the smallest compatibility-preserving first migration slice. |
| 2026-08-14 | B008 | `STARTED` | `DONE` | Locked C001 to pure koanf loader ownership plus a temporary legacy facade and synthetic tests. |
| 2026-08-14 | C001 | `TODO` | `STARTED` | Began auth config loader migration without global injection changes. |
| 2026-08-14 | C001 | `STARTED` | `DONE` | Added infrastructure-owned koanf loader, compatibility facade, and tests; generation/tests/race/build pass; committed as `29b7e07`. |
| 2026-08-14 | C002 | `TODO` | `STARTED` | Began auth global-config dependency inventory and constructor-injection migration. |
| 2026-08-14 | C002 | `STARTED` | `DONE` | Removed global config and legacy facade; injected config through auth boundaries; full verification passed; committed as `1bd5559`. |
| 2026-08-14 | C003 | `TODO` | `STARTED` | Began wallet config default/key/serve-mode compatibility inventory. |
| 2026-08-14 | C003 | `STARTED` | `DONE` | Reproduced measured fig defaults, validated all service configs, and passed generation/tests/race/build; committed as `7958530`. |
| 2026-08-14 | C004 | `TODO` | `STARTED` | Began wallet global-config dependency inventory across five modes, repositories, use cases, and Stellar adapters. |
| 2026-08-14 | C004 | `STARTED` | `CHANGED` | User prioritized a new disaster-recovery general-ledger service and wallet adapter; config injection will resume after its boundary is established. |
| 2026-08-14 | S003 | `DONE` | `CHANGED` | Added `GL` to active scope; excluded repositories remain unchanged. |
| 2026-08-14 | S004 | `DONE` | `DONE` | Created and checked out `GL/feat/refactor-v1`; all six active repositories now use the requested branch. |
| 2026-08-14 | L001 | `TODO` | `STARTED` | Began evidence-backed GL design from existing wallet transaction and Stellar paths. |
| 2026-08-14 | L001 | `STARTED` | `DONE` | Defined immutable double-entry invariants, mappings, transactional outbox delivery, controlled outage modes, and service ownership; committed in GL as `1863de1`. |
| 2026-08-14 | L002 | `TODO` | `STARTED` | Began the internal `ledger/v1` protobuf contract from the accepted GL boundary. |
| 2026-08-14 | L002 | `STARTED` | `DONE` | Added a new package without changing existing contracts; isolated-cache Buf format/lint/build checks pass; committed in proto as `b4bb506`. |
| 2026-08-14 | L003 | `TODO` | `STARTED` | Began the independent Go service scaffold and generated-consumer setup. |
| 2026-08-14 | L003 | `STARTED` | `DONE` | Scaffold generation is reproducible and tests/race/vet/build pass; committed in GL as `b1e0b01`. |
| 2026-08-14 | L004 | `TODO` | `STARTED` | Began the immutable PostgreSQL schema, decimal domain values, and transactional repository. |
| 2026-08-14 | L004 | `STARTED` | `DONE` | Domain and PostgreSQL enforce exact, balanced, sealed, immutable, idempotent journal storage; tests/race/vet/build pass; committed in GL as `0b3eaa0`. |
| 2026-08-14 | L005 | `TODO` | `STARTED` | Began application commands, persistence queries/events, reversal validation, and complete gRPC method adapters. |
| 2026-08-14 | L005 | `STARTED` | `DONE` | Added complete application/gRPC operations, exact reversal and canonical idempotency behavior, queries, error mapping, and tests; committed in GL as `76905ab`. |
| 2026-08-14 | L006 | `TODO` | `STARTED` | Began the wallet-owned ledger port, transaction mapper, generated client, and gRPC adapter. |
| 2026-08-14 | L006 | `STARTED` | `DONE` | Added the Wallet-owned ledger boundary, config, generated client, and tested gRPC adapter; full tests/race/build pass; committed in wallet as `9d91f8f`. |
| 2026-08-14 | L007 | `TODO` | `STARTED` | Began the wallet-local transactional outbox, claim/retry semantics, and dispatcher. |
| 2026-08-14 | L007 | `STARTED` | `DONE` | Added atomic enqueue, safe claiming, retry/backoff, quarantine/replay, dispatcher, and rollback/commit tests; committed in wallet as `379dbc2`. |
| 2026-08-14 | L008 | `TODO` | `STARTED` | Began per-call-site transaction-effect mapping and outbox integration. |
| 2026-08-14 | L008 | `STARTED` | `STARTED` | Checkpoint: lifecycle events now commit atomically with every transaction repository insert/update; full tests/race/build pass; committed in wallet as `ff31c87`; monetary journals remain. |
| 2026-08-14 | L008 | `STARTED` | `CHANGED` | Completed and tested all Wallet-owned financial/lifecycle paths plus dispatcher bootstrap in `d1aa339`; split AdminPanel's direct-write bypass into the already tracked `P006`/`P008` scope instead of treating it as a Wallet adapter path. |
| 2026-08-14 | I001 | `TODO` | `STARTED` | Began mapping the public buy-asset compatibility endpoints to auth publisher permissions and the existing market settlement transaction. |
| 2026-08-14 | I001 | `STARTED` | `DONE` | Recorded the additive contract, IAM role-key, publisher-order, pinned-agreement, and shared-settlement migration boundary in `REFACTORING-AUDIT.md`. |
| 2026-08-14 | I002 | `TODO` | `STARTED` | Began idempotent token-publisher bootstrap and stable IAM role-key propagation. |
| 2026-08-14 | I002 | `STARTED` | `DONE` | Added additive IAM role keys (`2d7d3ff`) and idempotent token-publisher bootstrap with focused tests (`7c3b3b6`); auth tests, race tests, and build pass. |
| 2026-08-14 | I003 | `TODO` | `STARTED` | Began additive ICO order designation, quote/settlement service contracts, and agreement-to-maker persistence linkage. |
| 2026-08-14 | I003 | `STARTED` | `DONE` | Added additive ICO order/quote/settlement fields and RPCs (`286b8e5`), role-gated hidden maker/sell orders, filtering, and agreement-to-maker persistence (`25d0f03`). |
| 2026-08-14 | I004 | `TODO` | `STARTED` | Began market-owned live publisher-order selection and BuyAsset quote delegation. |
| 2026-08-14 | I004 | `STARTED` | `DONE` | Delegated wallet quotes to market; live ICO selection verifies role, status, side, IRT pair, price, and remaining volume; agreement generation pins the maker; committed as `5a0f3d7`. |
| 2026-08-14 | I005 | `TODO` | `STARTED` | Began claim-once ICO confirmation, taker creation, and shared synchronous order settlement. |
| 2026-08-14 | I005 | `STARTED` | `DONE` | Removed the legacy direct ICO transfers; added claim-once agreement handling, taker orders, maker-wide locking/fresh reads, shared synchronous `settleOrder`, response hashes, and claim tests; committed as `ef2e4ae`. |
| 2026-08-14 | I006 | `TODO` | `STARTED` | Began focused authorization/order/claim tests, consumer regeneration, full test/race/build verification, and clean-tree review. |
| 2026-08-14 | I006 | `STARTED` | `DONE` | Verified high-volume role-gated publisher orders, IRT/side/participant constraints, overfill prevention, claim idempotency, and shared settlement; Buf checks, consumer generation, full auth/wallet/api tests, race tests, and builds pass; generated consumers committed as `a06c736`/`d2660f5`, wallet verification as `3555a5f`. |
| 2026-08-14 | I006 | `DONE` | `DONE` | Final review found the generic query's default newest-first order preceding ICO price order; replaced it with a dedicated best-price/oldest-order query and reverified tests/race/build in `0d7c820`. |
| 2026-08-14 | E001 | `TODO` | `STARTED` | Began mapping all transaction writes and the existing RabbitMQ, GL outbox, consumer, and alert paths. |
| 2026-08-14 | E001 | `STARTED` | `DONE` | Confirmed every active transaction insert/update converges in `repository/db/postgres/transaction.go`, which already atomically enqueues GL records; legacy direct AMQP publication is inactive and unsuitable for loss-free delivery. |
| 2026-08-14 | E002 | `TODO` | `STARTED` | Began the transport-neutral event envelope, per-type topic registry, transaction outbox/inbox/deadbox schema, and repository ports. |
| 2026-08-14 | E002 | `STARTED` | `DONE` | Added one stable event per transaction ID, unique topics for every transaction enum, atomic outbox enqueue, reclaimable inbox, persistent deadbox, migrations, and rollback/idempotency tests in `5dfb223`. |
| 2026-08-14 | E003 | `TODO` | `STARTED` | Began replacing the direct streadway AMQP channel with Watermill publisher/subscriber ownership and transport-neutral application ports. |
| 2026-08-14 | E003 | `STARTED` | `DONE` | Replaced the unused streadway wrapper with a shared Watermill AMQP connection, publisher/subscriber adapters, delivery confirmations, durable queues, and a retrying outbox dispatcher; full Wallet tests pass in `25fdb37`. |
| 2026-08-14 | E004 | `TODO` | `STARTED` | Began the transport-neutral transaction loader/processor boundary and idempotent inbox-backed event handler for all per-type channels. |
| 2026-08-14 | E004 | `STARTED` | `DONE` | Added topic/type validation, persisted inbox claims, duplicate-safe processing, existing processor delegation, final-status verification, claim-loss checks, and focused race coverage in `951cd02`. |
| 2026-08-14 | E005 | `TODO` | `STARTED` | Began bounded Watermill retry composition, persistent handler deadbox routing, and successful-transaction alert notification. |
| 2026-08-14 | E005 | `STARTED` | `DONE` | Added one Watermill handler per transaction topic, bounded retry/recovery, persistent deadbox-before-ack behavior, and Alert success notification without repeating completed financial effects in `c9a9101`. |
| 2026-08-14 | E006 | `TODO` | `STARTED` | Began wallet-mode-only Watermill dispatcher/router lifecycle integration, configuration defaults, graceful shutdown, and end-to-end verification. |
| 2026-08-14 | E006 | `STARTED` | `DONE` | Wired Wallet-only startup after all 17 durable subscriptions are ready, bounded handler/startup/shutdown timeouts, lazy Alert/Auth gRPC connections, graceful closure, and an in-memory dispatcher-to-router duplicate test; proto generation, full tests/race tests, vet, and build pass in `b5784b7`. |
| 2026-08-14 | T001 | `TODO` | `DONE` | Confirmed Go 1.26 is released, the official `golang:1.26-bookworm` tag exists, four active Go modules still declare 1.24, three existing Go builders already use 1.26, and GL lacks a Dockerfile. |
| 2026-08-14 | T002 | `TODO` | `STARTED` | Began the API module directive upgrade and isolated Go 1.26 verification. |
| 2026-08-14 | T002 | `STARTED` | `DONE` | Upgraded API to Go 1.26, removed behaviorally unreachable logger code exposed by vet, and passed generation, tests, vet, and build with the existing Go 1.26 Docker builder in `fb6ad38`. |
| 2026-08-14 | T003 | `TODO` | `STARTED` | Began the Auth module directive upgrade and isolated Go 1.26 verification. |
| 2026-08-14 | T003 | `STARTED` | `DONE` | Upgraded Auth to Go 1.26, removed behaviorally unreachable logger code, fixed the newsletter timeout lifecycle exposed by vet, and passed generation, tests, vet, and build in `b2d6686`. |
| 2026-08-14 | T004 | `TODO` | `STARTED` | Began the Wallet module directive upgrade and isolated Go 1.26 verification. |
| 2026-08-14 | T004 | `STARTED` | `DONE` | Upgraded Wallet to Go 1.26; module tidy and generation produced no extra drift; full tests, race tests, vet, and binary build pass in `f5243a8`. |
| 2026-08-14 | T005 | `TODO` | `STARTED` | Began the GL module upgrade and creation of its missing Go 1.26 multi-stage Dockerfile. |
| 2026-08-14 | T005 | `STARTED` | `CHANGED` | Separate GL explorer/web changes appeared during verification; preserved them and isolated the Go directive/Dockerfile commit from that work. |
| 2026-08-14 | T007 | `TODO` | `STARTED` | User required `HTTP_PROXY` and `HTTPS_PROXY` unset for `go get` and selected `https://go.reg.darano.ir` as the Go proxy. |
| 2026-08-14 | T007 | `STARTED` | `DONE` | Updated all four Go Docker proxy defaults in per-repository commits and passed Dockerfile checks; cold API build exposed delayed 404 coverage gaps in the selected proxy, so no fallback was introduced. |
| 2026-08-14 | T005 | `CHANGED` | `DONE` | Committed the isolated GL Go 1.26 directive and new multi-stage Dockerfile as `ce5f8b4`; current working directive remains 1.26 while unrelated explorer/dependency changes stay uncommitted. |
| 2026-08-14 | T006 | `TODO` | `STARTED` | Began final branch, module directive, Docker builder, proxy, and worktree audit across active repositories. |
| 2026-08-14 | T006 | `STARTED` | `DONE` | Confirmed all Go modules/builders use 1.26, all Go builders use the Darano proxy, all active branches are correct, and user-owned proto/GL work remains untouched. |
| 2026-08-14 | T008 | `TODO` | `STARTED` | Began sequential full image builds for API, Auth, Wallet, and GL using the configured Darano Go proxy. |
| 2026-08-15 | T008 | `STARTED` | `DONE` | GL built successfully as `darano-gl:go1.26`; API/Auth/Wallet independently reproduced Darano registry gateway timeouts before compilation, with no proxy fallback or source changes introduced. |
| 2026-08-15 | T009 | `TODO` | `STARTED` | Began adapting the established Go-service Gitea actions and three environment workflows for GL. |
| 2026-08-15 | T009 | `STARTED` | `DONE` | Added local build/login/deploy/notify actions plus main/dev/stage workflows; YAML parsing and the exact cached buildx command pass; committed in GL as `675def5`. |
@@ -0,0 +1,327 @@
# گزارش فنی زیرساخت سامانه توکن‌سازی دارانو
**تهیه‌کننده:** شرکت توسعه راه‌کارهای نامتمرکز سنا
**تاریخ انتشار:** مرداد ۱۴۰۴
**نسخه:** ۱.۰
---
## ۱. معرفی پروژه
### ۱.۱ درباره شرکت
شرکت **توسعه راه‌کارهای نامتمرکز سنا** فعال در حوزه فناوری بلاکچین و توکن‌سازی دارایی‌های واقعی (RWA — Real World Assets) است. مأموریت اصلی این شرکت، ایجاد زیرساخت‌های لازم برای تبدیل دارایی‌های فیزیکی و حقوقی به توکن‌های قابل معامله در بازارهای دیجیتال، با رعایت کامل الزامات رگولاتوری و قوانین بانک مرکزی جمهوری اسلامی ایران است.
### ۱.۲ معرفی سامانه دارانو
سامانه **دارانو** پلتفرمی برای **توکن‌سازی دارایی‌های واقعی** است. این سامانه دارایی‌های فیزیکی (مانند املاک و مستغلات) را پس از طی فرآیندهای احراز مالکیت، ارزیابی و تکمیل تشریفات حقوقی، به توکن‌های دیجیتال تبدیل می‌کند. هر توکن نماینده بخشی از مالکیت دارایی پایه بوده و امکان خرید، فروش و معامله در بازار اولیه و ثانویه را فراهم می‌سازد.
در فاز پایلوت، تمرکز سامانه بر روی **املاک** است و یک واحد ملکی با نام **«مژگان»** به‌عنوان نمونه اولیه توکن‌سازی انتخاب شده است.
### ۱.۳ اصول حاکم بر سامانه
| اصل | توضیح |
|-----|--------|
| **رعایت رگولاتوری** | کلیه فرآیندها منطبق بر قوانین بانک مرکزی و مقررات مرتبط طراحی شده‌اند |
| **بلاکچین به عنوان Source of Truth** | مالکیت توکن‌ها فقط و فقط روی شبکه ققنوس ثبت می‌شود |
| **تفکیک نقش‌ها** | ناشر، میزبان، سرمایه‌گذار، بازارگردان و ناظر هر کدام نقش مشخصی دارند |
| **امنیت چندلایه** | لایه‌های امنیتی از Cloudflare تا مدیریت کلیدها |
| **شفافیت کامل** | تمامی تراکنش‌ها و وضعیت دارایی‌ها شفاف و قابل ردیابی است |
---
## ۲. شرح پروژه
### ۲.۱ فرآیند توکن‌سازی
فرآیند توکن‌سازی در دارانو شامل مراحل زیر است:
```mermaid
flowchart LR
A[۱. شناسایی و ارزیابی دارایی] --> B[۲. بررسی حقوقی و مالکیت]
B --> C[۳. قرارداد میزبانی و امانت]
C --> D[۴. انتشار توکن روی ققنوس]
D --> E[۵. عرضه در بازار اولیه]
E --> F[۶. معامله در بازار ثانویه]
F --> G[۷. توزیع درآمد دوره‌ای]
```
### ۲.۲ جریان درآمدی دارایی
درآمدهای حاصل از دارایی پایه (مانند اجاره‌بها) از طریق مکانیزم‌های مختلف میان دارندگان توکن توزیع می‌شود:
- **توزیع مستقیم ریالی:** محاسبه ضریب توزیع بر اساس نسبت توکن‌های فروخته‌شده به کل توکن‌ها
- **بازخرید توکن از طریق بازارگردان:** ایجاد فشار خرید و رشد قیمت توکن
- **سبدگردانی و اثر مرکب:** امکان سرمایه‌گذاری مجدد سود برای دارندگان توکن
---
## ۳. کاربران هدف
سیستم دارانو شامل نقش‌های زیر می‌باشد:
| نقش | شرح | دسترسی |
|-----|-----|--------|
| **سرمایه‌گذار (خریدار)** | کاربران عادی که توکن‌ها را خریداری و نگهداری می‌کنند | خرید توکن، معامله در بازار ثانویه، مشاهده پورتفولیو |
| **ناشر** | مالک اصلی دارایی (یا صاحب سببی مانند صلح‌نامه/وکالت‌نامه) | ایجاد پروژه توکن‌سازی، ثبت اطلاعات دارایی |
| **میزبان (امین دارایی)** | نهاد مسئول نگهداری فیزیکی و حقوقی دارایی | تأیید وضعیت دارایی، همکاری حقوقی |
| **تیم بازارگردان** | یک یا چند نفر مسئول تنظیم و مدیریت بازار ثانویه | مدیریت نقدینگی، تسهیل معاملات |
| **پلتفرم (ادمین)** | تیم سنا مستقر در سامانه — شامل تیم فنی، پشتیبانی و مدیر سامانه | مدیریت کاربران، صدور توکن، پیکربندی سیستم |
| **بازرس بانکی** | کارشناس منتخب بانک برای نظارت امنیتی و بازرسی دفتری | مشاهده تراکنش‌ها، تیک امنیتی، نظارت بر حساب‌وکتاب |
> **نکته:** سامانه اپراتور عمومی ندارد و تنها چند ادمین اصلی با دسترسی‌های مجزا فعالیت می‌کنند. مدیر سامانه دسترسی به ایجاد توکن جدید و تغییرات سایت دارد. تیم توسعه به کدها و اجرای آن‌ها روی سرور تست و سندباکس دسترسی دارد، اما استقرار در محیط عملیاتی (Production) نیازمند تأیید مدیر سامانه و کمیته اجرایی است.
---
## ۴. ارتباط سامانه با بیرون
### ۴.۱ معماری ارتباطی
```mermaid
flowchart LR
subgraph External
CDN[CDN / Cloudflare]
Firewall[فایروال لینوکس]
end
subgraph Darano
Traefik[Traefik<br/>Reverse Proxy]
API[API Gateway]
Services[سرویس‌های داخلی]
end
Internet[(اینترنت)] --> CDN --> Firewall --> Traefik --> API --> Services
style CDN fill:#e1f5fe
style Firewall fill:#fff3e0
style Traefik fill:#e8f5e9
```
- **لایه CDN:** ترافیک ورودی ابتدا از CDN عبور می‌کند (پشتیبانی از DDoS Protection و TLS/SSL)
- **فایروال:** در حال حاضر از فایروال لینوکس (Firewalld) استفاده می‌شود؛ در آینده قرار است سرورها پشت CDN اصلی قرار گیرند
- **Traefik:** نقش Reverse Proxy و مدیریت ترافیک داخلی
- **API Gateway:** نقطه ورود واحد برای تمام درخواست‌های API
### ۴.۲ ارتباط با شبکه ققنوس
سامانه برای ثبت تراکنش‌های توکنی از **شبکه ققنوس** (بر پایه استلار) استفاده می‌کند. بانک ملت نیز یکی از میزبان‌های این شبکه است. ارتباط از طریق Horizon API انجام شده و یک سرویس **Wallet Streamer** به‌صورت مداوم تراکنش‌های شبکه را رصد و با سیستم داخلی همگام‌سازی می‌کند.
---
## ۵. دیاگرام موارد استفاده (Use Case Diagram)
```mermaid
graph TB
Investor[سرمایه‌گذار]
Issuer[ناشر]
Custodian[میزبان/امین دارایی]
MarketMaker[بازارگردان]
PlatformAdmin[ادمین پلتفرم]
BankInspector[بازرس بانکی]
Investor --> UC1[ثبت‌نام و ورود]
Investor --> UC2[احراز هویت KYC]
Investor --> UC3[خرید توکن در بازار اولیه]
Investor --> UC4[معامله در بازار ثانویه]
Investor --> UC5[مشاهده پورتفولیو و تاریخچه]
Investor --> UC6[واریز و برداشت ریال]
Investor --> UC7[واریز و برداشت توکن]
Issuer --> UC8[ایجاد پروژه توکن‌سازی]
Issuer --> UC9[ثبت اطلاعات دارایی]
Custodian --> UC10[تأیید وضعیت دارایی]
Custodian --> UC11[همکاری حقوقی]
MarketMaker --> UC12[مدیریت نقدینگی بازار]
MarketMaker --> UC13[سفارش‌گذاری در بازار ثانویه]
PlatformAdmin --> UC14[مدیریت کاربران]
PlatformAdmin --> UC15[صدور و مدیریت توکن]
PlatformAdmin --> UC16[مدیریت سفارش‌ها و بازار]
PlatformAdmin --> UC17[مدیریت بازخرید]
PlatformAdmin --> UC18[پیکربندی و پایش سامانه]
BankInspector --> UC19[مشاهده تراکنش‌ها]
BankInspector --> UC20[تیک امنیتی و نظارت]
style Investor fill:#e3f2fd
style Issuer fill:#f3e5f5
style Custodian fill:#e8f5e9
style MarketMaker fill:#fff3e0
style PlatformAdmin fill:#fce4ec
style BankInspector fill:#efebe9
```
---
## ۶. سرویس‌های شخص ثالث (3rd Party)
### ۶.۱ خدمات احراز هویت و بانکی
| سرویس | نقش | توضیح |
|-------|------|--------|
| **سامانه شاهکار** | احراز مالکیت سیم‌کارت و مطابقت کدملی با شماره تماس | استعلام از پایگاه داده پست |
| **سامانه احراز هویت** | تأیید اطلاعات هویتی (کدملی، تاریخ تولد، تصویر) | سرویس‌های شخص ثالث مشابه (مانند زحل، احراز، جیبیت) |
| **استعلامات بانکی** | تأیید مالکیت حساب بانکی و شماره شبا | سرویس‌های مشابه |
### ۶.۲ خدمات ارتباطی
| سرویس | نقش | توضیح |
|-------|------|--------|
| **پنل ایمیل سازمانی** | ارسال ایمیل‌های خدماتی (خوش‌آمدگویی، تأیید تراکنش و …) | سرویس‌هایی مشابه لیموهاست |
| **پنل پیامک** | ارسال OTP و پیام‌های خدماتی | سرویس‌هایی مشابه کاوه‌نگار |
### ۶.۳ زیرساخت و مانیتورینگ
| سرویس | نقش | توضیح |
|-------|------|--------|
| **Prometheus** | جمع‌آوری متریک‌ها | استاندارد CNCF |
| **Grafana** | داشبورد و تجسم داده‌ها | استاندارد CNCF |
| **OpenTelemetry** | Observability یکپارچه | استاندارد CNCF |
| **Node Exporter / cAdvisor** | مانیتورینگ سیستم‌عامل و کانتینرها | استاندارد CNCF |
| **S3 / Object Storage** | ذخیره‌سازی فایل‌ها و بک‌آپ | سرویس ابری |
| **Traefik** | Reverse Proxy و Load Balancer | استاندارد CNCF |
| **مرورگر شبکه (Stellar Horizon)** | ارتباط با شبکه ققنوس | سرویس بلاکچین |
---
## ۷. زیرساخت پلتفرم
### ۷.۱ زیرساخت فعلی
```mermaid
flowchart TB
subgraph InternetLayer
CDN[CDN / Cloudflare]
Firewall[Firewalld]
end
subgraph VPSLayer["زیرساخت ابری مورد تایید بانک"]
Docker[Docker + Docker Compose]
subgraph Services
Traefik[Traefik<br/>Reverse Proxy]
UI[UI - Next.js]
Admin[Django Admin]
API[API Gateway - Go]
Auth[Auth Service - Go]
Wallet[Wallet Service - Go]
Market[Market Service - Go]
Streamer[Wallet Streamer - Go]
end
subgraph Data
DB[(PostgreSQL)]
Cache[(Redis)]
MQ[(RabbitMQ)]
end
end
subgraph BlockchainLayer
Ghoghnos[(شبکه ققنوس<br/>بر پایه استلار)]
end
subgraph Monitoring
Prometheus[Prometheus<br/>سرور جداگانه]
Grafana[Grafana]
Alertmanager[Alertmanager]
end
CDN --> Firewall --> Traefik
Traefik --> UI
Traefik --> Admin
Traefik --> API
API --> Auth
API --> Wallet
API --> Market
Auth --> DB
Auth --> Cache
Wallet --> DB
Wallet --> Cache
Market --> DB
Market --> Cache
Market --> MQ
Streamer --> DB
Streamer --> MQ
Wallet --> Ghoghnos
Streamer --> Ghoghnos
Prometheus --> API
Prometheus --> Auth
Prometheus --> Wallet
Prometheus --> Market
Prometheus --> DB
Grafana --> Prometheus
Alertmanager --> Prometheus
```
**مشخصات فنی زیرساخت فعلی:**
| لایه | فناوری | توضیح |
|------|--------|--------|
| میزبانی | سرویس ابری مورد تایید بانک | VPS با گواهی امنیتی بانکی |
| کانتینری‌سازی | Docker + Docker Compose | ایزولاسیون کامل سرویس‌ها |
| Reverse Proxy | Traefik v2.10 | مدیریت TLS و Routing |
| API Gateway | Go + Gin Router | مسیریابی، احراز هویت، Rate Limiting |
| سرویس‌های بیزینس | Go (GORM, Stellar SDK) | Auth, Wallet, Market |
| پنل مدیریت | Python + Django | Server-Side Rendering |
| رابط کاربری | Next.js + React | SSR + Client Rendering |
| پایگاه داده | PostgreSQL 15 | داده‌های رابطه‌ای اصلی |
| کش / Session | Redis 7 | Session، Rate Limit، Cache |
| صف پیام | RabbitMQ 3.12 | Event-Driven آینده |
| مانیتورینگ | Prometheus + Grafana + OpenTelemetry | سرور مانیتورینگ جداگانه |
### ۷.۲ زیرساخت آینده (Roadmap)
```mermaid
flowchart LR
subgraph Current["زیرساخت فعلی (Sync)"]
API --> Auth
API --> Wallet
API --> Market
Market --> Wallet
end
subgraph Future["زیرساخت آینده (Event-Driven)"]
API --> Auth
API --> Wallet
API --> Market
EventBus[(Event Bus<br/>Kafka / RabbitMQ)]
Auth -.->|Events| EventBus
Wallet -.->|Events| EventBus
Market -.->|Events| EventBus
Streamer -.->|Events| EventBus
EventBus --> Notification[Notification Service]
EventBus --> Analytics[Analytics Service]
EventBus --> Audit[Audit Service]
end
style Current fill:#e3f2fd
style Future fill:#e8f5e9
```
| ویژگی | وضعیت فعلی | هدف آینده |
|-------|-----------|-----------|
| الگوی ارتباطی | Synchronous (REST/gRPC) | Event-Driven (Kafka/RabbitMQ) |
| مقیاس‌پذیری | Docker Compose + Horizontal Scaling | Kubernetes (K8s) |
| Event Bus | محدود (فقط RabbitMQ در Wallet) | Event Bus مرکزی با Kafka |
| مدیریت کلیدها | Secret Manager در Git | HashiCorp Vault / AWS KMS |
| CI/CD | GitHub Actions | Pipeline خودکار با تأیید دو مرحله‌ای |
| Service Mesh | ندارد | Istio یا Linkerd |
| Database | PostgreSQL Single | Master-Slave + Read Replicas |
---
## ۸. خلاصه و جمع‌بندی
سامانه دارانو، توسعه‌یافته توسط شرکت توسعه راه‌کارهای نامتمرکز سنا، یک پلتفرم توکن‌سازی دارایی‌های واقعی است که با رعایت کامل ضوابط رگولاتوری و قوانین بانک مرکزی طراحی و پیاده‌سازی شده است. معماری سامانه بر پایه **میکروسرویس**، **بلاکچین ققنوس به عنوان Source of Truth** و **زیرساخت ابری مورد تایید بانک** بنا شده و از خدمات شخص ثالث معتبر برای احراز هویت، ارتباطات و مانیتورینگ بهره می‌برد.
نقاط قوت کلیدی سامانه:
- **امنیت بالا:** مدیریت کلیدها با Secret Manager، احراز هویت چندمرحله‌ای، فایروال و CDN
- **شفافیت:** مالکیت توکن‌ها فقط روی بلاکچین، ردیابی کامل تراکنش‌ها
- **مقیاس‌پذیری:** معماری میکروسرویس با امکان مهاجرت به Event-Driven و Kubernetes
- **نظارت:** مانیتورینگ ۲۴/۷ با ابزارهای استاندارد CNCF و دسترسی بازرس بانکی