docs(refactor): complete api architecture phase
This commit is contained in:
@@ -30,10 +30,10 @@ The `api` gateway is the **only** HTTP-facing service. All inter-service communi
|
||||
|
||||
### 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).
|
||||
- **Entry/composition**: `api/main.go` → `cmd.Execute()` (Cobra) → `cmd/apiRuntime`, which explicitly owns clients, handlers, router, HTTP servers, permission synchronization, and cleanup.
|
||||
- **Upstream boundary**: `api/application/port.Upstreams` composes generated service contracts. `api/infrastructure/grpcclient` implements lazy connection creation, active-call tracking, configurable idle closure (**2-minute default**), reconnection, health checks, and explicit shutdown without reflection.
|
||||
- **Handlers**: `api/interface/http/handler/` — one file per domain. Handlers depend on `application/port.Upstreams`.
|
||||
- **Routing**: `api/interface/http/handler/routing.go` — routes grouped into `/v1/public/`, `/v1/client/`, `/v1/admin/`. The admin group is protected but currently empty; internal routes remain disabled.
|
||||
- **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
|
||||
@@ -150,12 +150,12 @@ In `wallet`, `core/` contains sub-packages: `walletImp/`, `marketImp/`, `alertIm
|
||||
### Request/Response Flow
|
||||
|
||||
```
|
||||
HTTP request → middleware chain → routing.go → handler/*.go → DaranoService.gRPC → backend service
|
||||
HTTP request → interface/http middleware → interface/http/handler → application Upstreams port → infrastructure/grpcclient → 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`.
|
||||
- **Response helpers**: `interface/http/handler/response.go` — `JSON()` and `JSONList[X]()` wrap responses in `transport.Response{Meta, Data}`. Pointer-backed empty lists use the `EmptyList` sentinel to serialize `[]` rather than `null`.
|
||||
- **HTTP-to-gRPC context**: `interface/http/handler/contextWithMetadata()` copies HTTP headers into incoming and outgoing gRPC metadata.
|
||||
- **Handler interface**: `interface/http/handler.Server` receives the `application/port.Upstreams` boundary and configuration explicitly.
|
||||
|
||||
### Route conventions
|
||||
|
||||
@@ -186,9 +186,9 @@ All Go services instrumented with Elastic APM and Prometheus metrics. Traefik ha
|
||||
## 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>`).
|
||||
2. **gRPC connection lifecycle**: Connections are lazy — created on first RPC. Active calls prevent idle closure; peers close after the configured inactivity timeout (2-minute default) and reconnect on the next call.
|
||||
3. **Peer mapping**: `infrastructure/grpcclient` maps configured peers explicitly; the former reflection/enum generator is removed.
|
||||
4. **Swagger docs**: Generated by `swag init` and served via `interface/http`. 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/`.
|
||||
@@ -212,7 +212,7 @@ All Go services instrumented with Elastic APM and Prometheus metrics. Traefik ha
|
||||
|
||||
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.
|
||||
**Go services current state**: API, Auth, and Wallet configuration and architecture phases are complete on `feat/refactor-v1`; use the refactoring tracker and audit for the current package boundaries and verification evidence.
|
||||
|
||||
**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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user