Documentation structure: - docs/README.md - Documentation index - docs/getting-started.md - Installation and first run - docs/usage.md - Dashboard features and usage - docs/configuration.md - Full configuration reference - docs/multi-device.md - Agent setup and PKI management - docs/security.md - Authentication, RBAC, mTLS - docs/api.md - Complete REST API reference - docs/deployment.md - Production deployment guide - docs/troubleshooting.md - Common issues and solutions - docs/development.md - Contributing and building Total: ~80KB of documentation covering all features 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
496 lines
9.5 KiB
Markdown
496 lines
9.5 KiB
Markdown
# Development Guide
|
|
|
|
This guide covers building, testing, and contributing to Tyto.
|
|
|
|
## Prerequisites
|
|
|
|
- **Go 1.23+**
|
|
- **Node.js 22+**
|
|
- **Docker & Docker Compose**
|
|
- **Make** (optional)
|
|
- **protoc** (for gRPC development)
|
|
|
|
## Getting the Source
|
|
|
|
```bash
|
|
git clone https://somegit.dev/vikingowl/tyto.git
|
|
cd tyto
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
tyto/
|
|
├── backend/
|
|
│ ├── cmd/
|
|
│ │ ├── server/ # HTTP/SSE server entry point
|
|
│ │ ├── agent/ # Lightweight agent entry point
|
|
│ │ └── tyto/ # CLI tool
|
|
│ ├── internal/
|
|
│ │ ├── api/ # HTTP handlers and routes
|
|
│ │ ├── alerts/ # Alert management
|
|
│ │ ├── auth/ # Authentication (local, LDAP)
|
|
│ │ ├── collectors/ # Metric collectors
|
|
│ │ │ ├── gpu/ # Multi-vendor GPU support
|
|
│ │ │ └── logs/ # Log collectors
|
|
│ │ ├── config/ # Configuration loading
|
|
│ │ ├── database/ # SQLite/PostgreSQL
|
|
│ │ ├── history/ # Historical data storage
|
|
│ │ ├── models/ # Data structures
|
|
│ │ ├── pki/ # Certificate management
|
|
│ │ ├── server/ # gRPC hub for agents
|
|
│ │ └── sse/ # Server-Sent Events broker
|
|
│ ├── proto/ # gRPC protocol definitions
|
|
│ ├── go.mod
|
|
│ └── Dockerfile
|
|
├── frontend/
|
|
│ ├── src/
|
|
│ │ ├── lib/
|
|
│ │ │ ├── api/ # API clients
|
|
│ │ │ ├── components/ # Svelte components
|
|
│ │ │ ├── stores/ # Svelte stores
|
|
│ │ │ ├── types/ # TypeScript types
|
|
│ │ │ └── utils/ # Utility functions
|
|
│ │ └── routes/ # SvelteKit routes
|
|
│ ├── package.json
|
|
│ └── Dockerfile
|
|
├── docs/ # Documentation
|
|
├── scripts/ # Build and install scripts
|
|
├── docker-compose.yml
|
|
└── docker-compose.prod.yml
|
|
```
|
|
|
|
## Backend Development
|
|
|
|
### Running Locally
|
|
|
|
```bash
|
|
cd backend
|
|
|
|
# Install dependencies
|
|
go mod download
|
|
|
|
# Run the server
|
|
go run ./cmd/server
|
|
|
|
# Run with specific config
|
|
go run ./cmd/server --config ../config.dev.yaml
|
|
```
|
|
|
|
### Building
|
|
|
|
```bash
|
|
# Build server binary
|
|
go build -o tyto ./cmd/server
|
|
|
|
# Build agent binary
|
|
go build -o tyto-agent ./cmd/agent
|
|
|
|
# Build CLI
|
|
go build -o tyto-cli ./cmd/tyto
|
|
|
|
# Build with optimizations
|
|
CGO_ENABLED=0 go build -ldflags="-s -w" -o tyto ./cmd/server
|
|
```
|
|
|
|
### Cross-Compilation
|
|
|
|
```bash
|
|
# Linux AMD64
|
|
GOOS=linux GOARCH=amd64 go build -o tyto-linux-amd64 ./cmd/server
|
|
|
|
# Linux ARM64
|
|
GOOS=linux GOARCH=arm64 go build -o tyto-linux-arm64 ./cmd/server
|
|
|
|
# macOS
|
|
GOOS=darwin GOARCH=amd64 go build -o tyto-darwin-amd64 ./cmd/server
|
|
```
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
# All tests
|
|
go test ./...
|
|
|
|
# With coverage
|
|
go test -cover ./...
|
|
|
|
# Specific package
|
|
go test ./internal/collectors/...
|
|
|
|
# Verbose output
|
|
go test -v ./internal/api/...
|
|
```
|
|
|
|
### Linting
|
|
|
|
```bash
|
|
# Install golangci-lint
|
|
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
|
|
|
# Run linter
|
|
golangci-lint run
|
|
```
|
|
|
|
### gRPC Development
|
|
|
|
```bash
|
|
# Install protoc plugins
|
|
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
|
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
|
|
|
# Generate Go code from proto files
|
|
protoc --go_out=. --go-grpc_out=. proto/*.proto
|
|
```
|
|
|
|
## Frontend Development
|
|
|
|
### Running Locally
|
|
|
|
```bash
|
|
cd frontend
|
|
|
|
# Install dependencies
|
|
npm install
|
|
|
|
# Start development server
|
|
npm run dev
|
|
|
|
# With specific API URL
|
|
VITE_API_URL=http://localhost:8080 npm run dev
|
|
```
|
|
|
|
### Building
|
|
|
|
```bash
|
|
# Production build
|
|
npm run build
|
|
|
|
# Preview production build
|
|
npm run preview
|
|
```
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
# Unit tests
|
|
npm test
|
|
|
|
# Watch mode
|
|
npm run test:watch
|
|
|
|
# With coverage
|
|
npm run test:coverage
|
|
```
|
|
|
|
### Linting & Formatting
|
|
|
|
```bash
|
|
# Lint
|
|
npm run lint
|
|
|
|
# Format
|
|
npm run format
|
|
|
|
# Type check
|
|
npm run check
|
|
```
|
|
|
|
## Docker Development
|
|
|
|
### Building Images
|
|
|
|
```bash
|
|
# Build all images
|
|
docker compose build
|
|
|
|
# Build specific service
|
|
docker compose build backend
|
|
docker compose build frontend
|
|
|
|
# Build without cache
|
|
docker compose build --no-cache
|
|
```
|
|
|
|
### Running with Docker
|
|
|
|
```bash
|
|
# Start all services
|
|
docker compose up
|
|
|
|
# Start in background
|
|
docker compose up -d
|
|
|
|
# View logs
|
|
docker compose logs -f
|
|
|
|
# Stop services
|
|
docker compose down
|
|
```
|
|
|
|
### Development with Hot Reload
|
|
|
|
```bash
|
|
# Mount source for hot reload
|
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
|
|
```
|
|
|
|
## Adding a New Collector
|
|
|
|
1. Create collector file in `backend/internal/collectors/`:
|
|
|
|
```go
|
|
// backend/internal/collectors/example.go
|
|
package collectors
|
|
|
|
import "github.com/vikingowl/tyto/internal/models"
|
|
|
|
type ExampleCollector struct {
|
|
// collector state
|
|
}
|
|
|
|
func NewExampleCollector() *ExampleCollector {
|
|
return &ExampleCollector{}
|
|
}
|
|
|
|
func (c *ExampleCollector) Collect() (*models.ExampleStats, error) {
|
|
// Collect metrics from system
|
|
return &models.ExampleStats{
|
|
// ...
|
|
}, nil
|
|
}
|
|
```
|
|
|
|
2. Add model in `backend/internal/models/`:
|
|
|
|
```go
|
|
// backend/internal/models/example.go
|
|
package models
|
|
|
|
type ExampleStats struct {
|
|
Available bool `json:"available"`
|
|
Value int `json:"value"`
|
|
}
|
|
```
|
|
|
|
3. Integrate in `backend/internal/collectors/all.go`:
|
|
|
|
```go
|
|
func (c *AllCollectors) Collect() *models.AllMetrics {
|
|
metrics := &models.AllMetrics{
|
|
// ...existing...
|
|
Example: c.example.Collect(),
|
|
}
|
|
return metrics
|
|
}
|
|
```
|
|
|
|
4. Add frontend component in `frontend/src/lib/components/`.
|
|
|
|
## Adding a New API Endpoint
|
|
|
|
1. Add handler in `backend/internal/api/`:
|
|
|
|
```go
|
|
// backend/internal/api/example.go
|
|
package api
|
|
|
|
import (
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func (s *Server) exampleHandler(c *gin.Context) {
|
|
// Handle request
|
|
c.JSON(200, gin.H{"status": "ok"})
|
|
}
|
|
```
|
|
|
|
2. Register route in `backend/internal/api/routes.go`:
|
|
|
|
```go
|
|
func (s *Server) setupRoutes() {
|
|
// ...existing routes...
|
|
|
|
api := s.router.Group("/api/v1")
|
|
api.GET("/example", s.exampleHandler)
|
|
}
|
|
```
|
|
|
|
3. Add frontend API client in `frontend/src/lib/api/`:
|
|
|
|
```typescript
|
|
// frontend/src/lib/api/example.ts
|
|
export async function getExample(): Promise<ExampleResponse> {
|
|
const response = await fetch('/api/v1/example');
|
|
return response.json();
|
|
}
|
|
```
|
|
|
|
## Testing
|
|
|
|
### Backend Unit Tests
|
|
|
|
```go
|
|
// backend/internal/collectors/cpu_test.go
|
|
package collectors
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestCPUCollector(t *testing.T) {
|
|
collector := NewCPUCollector("/proc")
|
|
stats, err := collector.Collect()
|
|
|
|
if err != nil {
|
|
t.Fatalf("Collect() failed: %v", err)
|
|
}
|
|
|
|
if len(stats.Cores) == 0 {
|
|
t.Error("Expected at least one CPU core")
|
|
}
|
|
}
|
|
```
|
|
|
|
### Frontend Component Tests
|
|
|
|
```typescript
|
|
// frontend/src/lib/components/CpuCard.test.ts
|
|
import { render } from '@testing-library/svelte';
|
|
import CpuCard from './CpuCard.svelte';
|
|
|
|
test('renders CPU usage', () => {
|
|
const { getByText } = render(CpuCard, {
|
|
props: {
|
|
cpu: { totalUsage: 50, cores: [] }
|
|
}
|
|
});
|
|
|
|
expect(getByText('50%')).toBeInTheDocument();
|
|
});
|
|
```
|
|
|
|
### Integration Tests
|
|
|
|
```bash
|
|
# Start test environment
|
|
docker compose -f docker-compose.test.yml up -d
|
|
|
|
# Run integration tests
|
|
go test -tags=integration ./tests/...
|
|
|
|
# Cleanup
|
|
docker compose -f docker-compose.test.yml down
|
|
```
|
|
|
|
## Code Style
|
|
|
|
### Go
|
|
|
|
- Follow [Effective Go](https://golang.org/doc/effective_go)
|
|
- Use `gofmt` for formatting
|
|
- Use meaningful variable names
|
|
- Keep functions small and focused
|
|
- Document exported functions and types
|
|
|
|
### TypeScript/Svelte
|
|
|
|
- Use TypeScript strict mode
|
|
- Follow Svelte conventions
|
|
- Use Prettier for formatting
|
|
- Prefer composition over inheritance
|
|
- Keep components focused
|
|
|
|
## Commit Messages
|
|
|
|
Follow [Conventional Commits](https://www.conventionalcommits.org/):
|
|
|
|
```
|
|
feat: add GPU temperature monitoring
|
|
fix: resolve memory leak in SSE broker
|
|
docs: update API documentation
|
|
refactor: simplify collector interface
|
|
test: add integration tests for auth
|
|
```
|
|
|
|
## Pull Request Process
|
|
|
|
1. Fork the repository
|
|
2. Create a feature branch: `git checkout -b feature/my-feature`
|
|
3. Make changes and commit
|
|
4. Run tests: `go test ./...` and `npm test`
|
|
5. Run linters: `golangci-lint run` and `npm run lint`
|
|
6. Push to your fork
|
|
7. Open a Pull Request
|
|
|
|
### PR Checklist
|
|
|
|
- [ ] Tests pass
|
|
- [ ] Linting passes
|
|
- [ ] Documentation updated
|
|
- [ ] Commit messages follow convention
|
|
- [ ] No breaking changes (or documented)
|
|
|
|
## Release Process
|
|
|
|
1. Update version in `internal/version/version.go`
|
|
2. Update CHANGELOG.md
|
|
3. Create git tag: `git tag v1.2.3`
|
|
4. Push tag: `git push origin v1.2.3`
|
|
5. CI builds and publishes releases
|
|
|
|
## Debugging
|
|
|
|
### Backend
|
|
|
|
```bash
|
|
# Run with debug logging
|
|
TYTO_LOG_LEVEL=debug go run ./cmd/server
|
|
|
|
# Use delve debugger
|
|
dlv debug ./cmd/server
|
|
```
|
|
|
|
### Frontend
|
|
|
|
- Use browser DevTools
|
|
- React/Svelte DevTools extension
|
|
- `console.log` for quick debugging
|
|
|
|
### Docker
|
|
|
|
```bash
|
|
# Shell into container
|
|
docker exec -it tyto-backend /bin/sh
|
|
|
|
# View container logs
|
|
docker logs tyto-backend -f
|
|
|
|
# Inspect container
|
|
docker inspect tyto-backend
|
|
```
|
|
|
|
## Performance Profiling
|
|
|
|
### Go Profiling
|
|
|
|
```go
|
|
import _ "net/http/pprof"
|
|
|
|
// Access at http://localhost:8080/debug/pprof/
|
|
```
|
|
|
|
```bash
|
|
# CPU profile
|
|
go tool pprof http://localhost:8080/debug/pprof/profile?seconds=30
|
|
|
|
# Memory profile
|
|
go tool pprof http://localhost:8080/debug/pprof/heap
|
|
```
|
|
|
|
### Frontend Performance
|
|
|
|
- Use Lighthouse in Chrome DevTools
|
|
- React Profiler for component performance
|
|
- Network tab for API timing
|