Development Setup
Prerequisites
- Go: 1.24.6 or later
- Docker: For containerization
- minikube: Local Kubernetes development
- Helm: Package management
- Make: Build automation
Initial Setup
-
Clone Repository
git clone https://github.com/menloresearch/jan-servercd jan-server -
Install Development Tools
cd apps/jan-api-gateway/applicationmake install -
Generate Code
make setup -
Start Development Environment
# From project root./scripts/run.sh
API Gateway Development
Project Structure
apps/jan-api-gateway/application/├── cmd/server/ # Entry point and dependency injection│ ├── server.go # Main server setup│ ├── wire.go # DI configuration│ └── wire_gen.go # Generated DI code├── app/ # Core application logic│ ├── domain/ # Business entities│ ├── repository/ # Data access layer│ ├── service/ # Business logic│ └── handler/ # HTTP handlers├── config/ # Configuration management└── docs/ # Generated API documentation
Build Commands
# Install development dependenciesmake install# Generate API documentationmake doc# Generate dependency injection code make wire# Complete setup (doc + wire)make setup# Build applicationgo build -o jan-api-gateway ./cmd/server
Code Generation
Jan Server uses code generation for several components:
Swagger Documentation:
# Generates docs/swagger.json and docs/swagger.yamlswag init --parseDependency -g cmd/server/server.go -o docs
Dependency Injection:
# Generates wire_gen.go from wire.go providerswire ./cmd/server
Database Models:
# Generate GORM models (when schema changes)go run cmd/codegen/gorm/gorm.go
Local Development
Running API Gateway Locally
cd apps/jan-api-gateway/application# Set environment variablesexport JAN_INFERENCE_MODEL_URL=http://localhost:8101export JWT_SECRET=your-jwt-secretexport DB_POSTGRESQL_WRITE_DSN="host=localhost user=jan-user password=jan-password dbname=jan port=5432 sslmode=disable"# Run the servergo run ./cmd/server
Database Setup
For local development, you can run PostgreSQL directly:
# Using Dockerdocker run -d \ --name jan-postgres \ -e POSTGRES_DB=jan \ -e POSTGRES_USER=jan-user \ -e POSTGRES_PASSWORD=jan-password \ -p 5432:5432 \ postgres:14
Testing
Running Tests
# Run all testsgo test ./...# Run tests with coveragego test -cover ./...# Run specific test packagego test ./app/service/...
Test Structure
app/├── service/│ ├── auth_service.go│ ├── auth_service_test.go│ ├── conversation_service.go│ └── conversation_service_test.go└── handler/ ├── auth_handler.go ├── auth_handler_test.go ├── chat_handler.go └── chat_handler_test.go
Writing Tests
Example service test:
func TestAuthService_ValidateToken(t *testing.T) { // Setup service := NewAuthService(mockRepo, mockConfig) // Test cases tests := []struct { name string token string expectValid bool expectError bool }{ {"valid token", "valid.jwt.token", true, false}, {"invalid token", "invalid.token", false, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { valid, err := service.ValidateToken(tt.token) assert.Equal(t, tt.expectValid, valid) assert.Equal(t, tt.expectError, err != nil) }) }}
Docker Development
Building Images
# Build API gatewaydocker build -t jan-api-gateway:dev ./apps/jan-api-gateway# Build inference modeldocker build -t jan-inference-model:dev ./apps/jan-inference-model
Development Compose
For local development without Kubernetes:
# docker-compose.dev.ymlversion: '3.8'services: postgres: image: postgres:14 environment: POSTGRES_DB: jan POSTGRES_USER: jan-user POSTGRES_PASSWORD: jan-password ports: - "5432:5432" api-gateway: build: ./apps/jan-api-gateway ports: - "8080:8080" environment: - JAN_INFERENCE_MODEL_URL=http://inference-model:8101 - DB_POSTGRESQL_WRITE_DSN=host=postgres user=jan-user password=jan-password dbname=jan port=5432 sslmode=disable depends_on: - postgres inference-model: build: ./apps/jan-inference-model ports: - "8101:8101"
Debugging
Go Debugging
For VS Code debugging, add to .vscode/launch.json
:
{ "version": "0.2.0", "configurations": [ { "name": "Launch Jan API Gateway", "type": "go", "request": "launch", "mode": "auto", "program": "${workspaceFolder}/apps/jan-api-gateway/application/cmd/server", "env": { "JAN_INFERENCE_MODEL_URL": "http://localhost:8101", "JWT_SECRET": "development-secret" } } ]}
Application Logs
# View API gateway logskubectl logs deployment/jan-server-jan-api-gateway -f# View inference model logskubectl logs deployment/jan-server-jan-inference-model -f# View PostgreSQL logskubectl logs statefulset/jan-server-postgresql -f
Log Levels
Set log level via environment variable:
export LOG_LEVEL=debug # debug, info, warn, error
Code Style and Standards
Go Standards
- Follow Go Code Review Comments (opens in a new tab)
- Use
gofmt
for formatting - Run
go vet
for static analysis - Use meaningful variable and function names
API Standards
- RESTful endpoint design
- OpenAPI/Swagger annotations for all endpoints
- Consistent error response format
- Proper HTTP status codes
Git Workflow
# Create feature branchgit checkout -b feature/your-feature-name# Make changes and commitgit add .git commit -m "feat: add new authentication endpoint"# Push and create PRgit push origin feature/your-feature-name
Commit Message Format
Follow conventional commits:
feat: add new featurefix: resolve bug in authentication docs: update API documentationtest: add unit tests for service layerrefactor: improve error handling
Performance Testing
Load Testing
Use k6 (opens in a new tab) for API load testing:
// load-test.jsimport http from 'k6/http';export default function () { const response = http.post('http://localhost:8080/api/v1/chat/completions', { model: 'jan-v1-4b', messages: [ { role: 'user', content: 'Hello!' } ] }, { headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer your-token' } }); check(response, { 'status is 200': (r) => r.status === 200, 'response time < 5000ms': (r) => r.timings.duration < 5000, });}
Run load test:
k6 run --vus 10 --duration 30s load-test.js
Memory Profiling
Enable Go profiling endpoints:
import _ "net/http/pprof"// In main.gogo func() { log.Println(http.ListenAndServe("localhost:6060", nil))}()
Profile memory usage:
go tool pprof http://localhost:6060/debug/pprof/heap
Contributing
Pull Request Process
- Fork the repository
- Create feature branch from
main
- Make changes following code standards
- Add tests for new functionality
- Update documentation if needed
- Submit pull request with clear description
Code Review Checklist
- Code follows Go standards
- Tests added for new features
- Documentation updated
- API endpoints have Swagger annotations
- No breaking changes without version bump
- Security considerations addressed
Issues and Bug Reports
When reporting bugs, include:
- Environment: OS, Go version, minikube version
- Steps to reproduce: Clear, minimal reproduction steps
- Expected behavior: What should happen
- Actual behavior: What actually happens
- Logs: Relevant error messages or logs
For security issues, please report privately to the maintainers instead of creating public issues.
Release Process
Version Management
Jan Server uses semantic versioning (semver):
- Major: Breaking changes
- Minor: New features, backward compatible
- Patch: Bug fixes, backward compatible
Building Releases
# Tag releasegit tag -a v1.2.3 -m "Release v1.2.3"# Build release imagesdocker build -t jan-api-gateway:v1.2.3 ./apps/jan-api-gatewaydocker build -t jan-inference-model:v1.2.3 ./apps/jan-inference-model# Push tagsgit push origin v1.2.3
Deployment
Production deployments follow the same Helm chart structure:
# Deploy specific versionhelm install jan-server ./charts/umbrella-chart \ --set jan-api-gateway.image.tag=v1.2.3 \ --set jan-inference-model.image.tag=v1.2.3