修改 Bootstrap 注入 Gateway Client 依赖到 IotCardHandler 和 DeviceHandler

This commit is contained in:
2026-02-02 17:27:59 +08:00
parent 80f560df33
commit 246ea6e287
8 changed files with 187 additions and 14 deletions

View File

@@ -1,8 +1,8 @@
{
"active_plan": "/Users/break/csxjProject/junhong_cmp_fiber/.sisyphus/plans/add-gateway-admin-api.md",
"started_at": "2026-02-02T07:13:46.674Z",
"started_at": "2026-02-02T09:24:48.582Z",
"session_ids": [
"ses_3e2ccb556ffeOMG11wg2q0HOzK"
"ses_3e254bedbffeBTwWDP2VQqDr7q"
],
"plan_name": "add-gateway-admin-api"
}

View File

@@ -0,0 +1,81 @@
# Context & Architecture Understanding
## Key Findings
### Gateway Client Already Initialized
-`internal/gateway/client.go` - Complete Gateway client implementation
-`internal/bootstrap/dependencies.go` - GatewayClient is a field in Dependencies struct
-`internal/gateway/flow_card.go` - 6+ card-related Gateway methods
-`internal/gateway/device.go` - 7+ device-related Gateway methods
### Current Handler Structure
- `internal/handler/admin/iot_card.go` - Has 4 existing methods (ListStandalone, GetByICCID, AllocateCards, RecallCards)
- `internal/handler/admin/device.go` - Has 5 existing methods (List, GetByID, GetByIMEI, Delete, ListCards)
- Both handlers receive only service, not Gateway client yet
### Service Layer Already Uses Gateway
- `internal/service/iot_card/service.go` - Already has gateway.Client dependency
- `internal/service/device/service.go` - Needs to be checked if it has gateway.Client
### Handler Constructor Pattern
```go
// Current pattern
func NewIotCardHandler(service *iotCardService.Service) *IotCardHandler
func NewDeviceHandler(service *deviceService.Service) *DeviceHandler
// New pattern (needed)
func NewIotCardHandler(service *iotCardService.Service, gatewayClient *gateway.Client) *IotCardHandler
func NewDeviceHandler(service *deviceService.Service, gatewayClient *gateway.Client) *DeviceHandler
```
### Bootstrap Injection Pattern
```go
// In initHandlers() function at internal/bootstrap/handlers.go
IotCard: admin.NewIotCardHandler(svc.IotCard),
Device: admin.NewDeviceHandler(svc.Device),
// Needs to be changed to:
IotCard: admin.NewIotCardHandler(svc.IotCard, deps.GatewayClient),
Device: admin.NewDeviceHandler(svc.Device, deps.GatewayClient),
```
### Route Registration Pattern
```go
// From internal/routes/iot_card.go
Register(iotCards, doc, groupPath, "GET", "/standalone", handler.ListStandalone, RouteSpec{
Summary: "单卡列表(未绑定设备)",
Tags: []string{"IoT卡管理"},
Input: new(dto.ListStandaloneIotCardRequest),
Output: new(dto.ListStandaloneIotCardResponse),
Auth: true,
})
```
## Gateway Method Mappings
### Card Methods (flow_card.go)
- QueryCardStatus(ctx, req) → CardStatusResp
- QueryFlow(ctx, req) → FlowUsageResp
- QueryRealnameStatus(ctx, req) → RealnameStatusResp
- GetRealnameLink(ctx, req) → string (link)
- StopCard(ctx, req) → error
- StartCard(ctx, req) → error
### Device Methods (device.go)
- GetDeviceInfo(ctx, req) → DeviceInfoResp
- GetSlotInfo(ctx, req) → SlotInfoResp
- SetSpeedLimit(ctx, req) → error
- SetWiFi(ctx, req) → error
- SwitchCard(ctx, req) → error
- RebootDevice(ctx, req) → error
- ResetDevice(ctx, req) → error
## Store Methods for Permission Validation
- `IotCardStore.GetByICCID(ctx, iccid)` - Validate card ownership
- `DeviceStore.GetByDeviceNo(ctx, imei)` - Validate device ownership
## Important Conventions
1. Permission errors return: `errors.New(errors.CodeNotFound, "卡不存在或无权限访问")`
2. All card params: ICCID from path param, CardNo = ICCID
3. All device params: IMEI from path param, DeviceID = IMEI
4. Handler methods follow: Get params → Validate permissions → Call Gateway → Format response

View File

@@ -0,0 +1,75 @@
# Learnings - add-gateway-admin-api
## Plan Overview
- **Goal**: Expose 13 Gateway third-party capabilities as admin management APIs
- **Deliverables**: 6 IoT card endpoints + 7 device endpoints
- **Effort**: Medium
- **Parallel Execution**: YES - 2 waves
## Execution Strategy
```
Wave 1: Task 1 (Bootstrap dependency injection)
Wave 2: Task 2 + Task 3 (Parallel - Card handlers + Device handlers)
Wave 3: Task 4 + Task 5 (Parallel - Register routes)
Wave 4: Task 6 (Integration tests)
```
## Critical Dependencies
- Task 1 BLOCKS Task 2, 3
- Task 2 BLOCKS Task 4
- Task 3 BLOCKS Task 5
- Task 4, 5 BLOCK Task 6
## Key Files
- `internal/bootstrap/handlers.go` - Dependency injection for handlers
- `internal/handler/admin/iot_card.go` - Card handler (6 new methods)
- `internal/handler/admin/device.go` - Device handler (7 new methods)
- `internal/routes/iot_card.go` - Card routes registration
- `internal/routes/device.go` - Device routes registration
- `internal/gateway/flow_card.go` - Gateway card methods
- `internal/gateway/device.go` - Gateway device methods
- `tests/integration/iot_card_gateway_test.go` - Card integration tests
- `tests/integration/device_gateway_test.go` - Device integration tests
## API Design Principles
1. Simple passthrough - no additional business logic
2. Permission validation: Query DB to confirm ownership before calling Gateway
3. Error handling: Use `errors.New(errors.CodeNotFound, "卡不存在或无权限访问")`
4. Tags: Use `["IoT卡管理"]` for cards, `["设备管理"]` for devices
## Route Patterns
**Card routes** (base: `/api/admin/iot-cards`):
- GET `/:iccid/gateway-status`
- GET `/:iccid/gateway-flow`
- GET `/:iccid/gateway-realname`
- GET `/:iccid/realname-link`
- POST `/:iccid/stop`
- POST `/:iccid/start`
**Device routes** (base: `/api/admin/devices`):
- GET `/by-imei/:imei/gateway-info`
- GET `/by-imei/:imei/gateway-slots`
- PUT `/by-imei/:imei/speed-limit`
- PUT `/by-imei/:imei/wifi`
- POST `/by-imei/:imei/switch-card`
- POST `/by-imei/:imei/reboot`
- POST `/by-imei/:imei/reset`
## Verification Commands
```bash
# Build check
go build ./cmd/api
# OpenAPI docs generation
go run cmd/gendocs/main.go
# Integration tests
source .env.local && go test -v ./tests/integration/... -run TestGateway
```
## Important Notes
- Do NOT modify Gateway Client itself
- Do NOT add extra business logic (simple passthrough only)
- Do NOT add async task processing
- Do NOT add caching layer
- All handlers must validate permissions first before calling Gateway