File size: 5,267 Bytes
9853396 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | # Development Guide
---
## Architecture Design
AxonHub implements a bidirectional data transformation pipeline that ensures seamless communication between clients and AI providers.
<div align="center">
<img src="../../transformation-flow.svg" alt="AxonHub Transformation Flow" width="900"/>
</div>
### Pipeline Components
| Component | Purpose | Key Features |
| --- | --- | --- |
| **Client** | Application layer | Web apps, mobile apps, API clients |
| **Inbound Transformer** | Request preprocessing | Parse, validate, normalize input |
| **Unified Request** | Core processing | Route selection, load balancing, failover |
| **Outbound Transformer** | Provider adaptation | Format conversion, protocol mapping |
| **Provider** | AI services | OpenAI, Anthropic, DeepSeek, etc. |
This architecture ensures:
- ⚡ **Low Latency**: Optimized processing pipeline
- 🔄 **Auto Failover**: Seamless provider switching
- 📊 **Real-time Monitoring**: Complete request tracing
- 🛡️ **Security & Validation**: Input sanitization and output verification
## Technology Stack
### Backend Technology Stack
- **Go 1.24+**
- **Gin**
- **Ent ORM**
- **gqlgen**
- **JWT**
### Frontend Technology Stack
- **React 19**
- **TypeScript**
- **Tailwind CSS**
- **TanStack Router**
- **Zustand**
## Development Environment Setup
### Prerequisites
- Go 1.24 or higher
- Node.js 18+ and pnpm
- Git
### Clone the Project
```bash
git clone https://github.com/looplj/axonhub.git
cd axonhub
```
### Start Backend
```bash
# Option 1: Build and run directly
make build-backend
./axonhub
# Option 2: Use air for hot reload (recommended for development)
go install github.com/air-verse/air@latest
air
```
The backend server will start at `http://localhost:8090`.
### Start Frontend
In a new terminal window:
```bash
cd frontend
pnpm install
pnpm dev
```
The frontend development server will start at `http://localhost:5173`.
## Building the Project
### Build Complete Project
```bash
make build
```
This will build both backend and frontend, and embed frontend assets into the backend binary.
### Build Backend Only
```bash
make build-backend
```
### Build Frontend Only
```bash
cd frontend
pnpm build
```
## Code Generation
When changing Ent schema or GraphQL schema, regenerate generated code:
```bash
make generate
```
## Testing
### Run Backend Tests
```bash
go test ./...
```
### Run E2E Tests
```bash
bash ./scripts/e2e/e2e-test.sh
```
## Code Quality
### Run Go Linter
```bash
golangci-lint run -v
```
### Run Frontend Lint/Format
```bash
cd frontend
pnpm lint
pnpm format:check
```
## Transactions (Ent)
### When to use transactions
- Multiple writes must succeed or fail together.
- You need to ensure reads and writes are consistent within one logical operation.
### Recommended: use `AbstractService.RunInTransaction`
`RunInTransaction` will:
- Reuse the existing transaction if `ctx` already carries one.
- Otherwise start a new transaction, attach the tx-bound `*ent.Client` to `ctx`, and commit/rollback automatically.
```go
func (s *SomeService) doWork(ctx context.Context) error {
return s.RunInTransaction(ctx, func(ctx context.Context) error {
// ctx now carries:
// - ent.TxFromContext(ctx) (the current tx)
// - ent.FromContext(ctx) (tx-bound *ent.Client)
//
// You can call other services and they will pick up the same tx via ctx.
return nil
})
}
```
### Notes
- A transaction client is not safe to share across goroutines.
- Prefer keeping the transaction scope as small as possible.
## Adding a Channel
When introducing a new provider channel, keep backend and frontend changes aligned:
1. **Extend the channel enum in the Ent schema**
- Add the provider key to the `field.Enum("type")` list in [internal/ent/schema/channel.go](../../../internal/ent/schema/channel.go)
- Run `make generate` to regenerate artifacts and migrations
2. **Wire the outbound transformer**
- Update the switch in `ChannelService.buildChannel` to construct the correct outbound transformer for the new enum
- Or add a new transformer under `internal/llm/transformer` if necessary
3. **Register provider metadata**
- Add or extend an entry in [frontend/src/features/channels/data/config_providers.ts](../../../frontend/src/features/channels/data/config_providers.ts)
- Keep the helper functions working by ensuring every channel type listed exists in `CHANNEL_CONFIGS`
4. **Sync the frontend schema and presentation**
- Append the enum value to the Zod schema in [frontend/src/features/channels/data/schema.ts](../../../frontend/src/features/channels/data/schema.ts)
- Add channel configuration to [frontend/src/features/channels/data/constants.ts](../../../frontend/src/features/channels/data/constants.ts)
5. **Add internationalization**
- Add translation keys in both locale files:
- [frontend/src/locales/en.json](../../../frontend/src/locales/en.json)
- [frontend/src/locales/zh.json](../../../frontend/src/locales/zh.json)
|