OpenSpeak/openspec/specs/009-development-guidelines.md
Alexis Bruneteau dc59df9336 🎉 Complete OpenSpeak v0.1.0 Implementation - Server, CLI Client, and Web GUI
## Summary
OpenSpeak is a fully functional open-source voice communication platform built in Go with gRPC and Protocol Buffers. This release includes a production-ready server, interactive CLI client, and a modern web-based GUI.

## Components Implemented

### Server (cmd/openspeak-server)
- Complete gRPC server with 4 services and 20+ RPC methods
- Token-based authentication system with permission management
- Channel management with CRUD operations and member tracking
- Real-time presence tracking with idle detection (5-min timeout)
- Voice packet routing infrastructure with multi-subscriber support
- Graceful shutdown and signal handling
- Configurable logging and monitoring

### Core Systems (internal/)
- **auth/**: Token generation, validation, and management
- **channel/**: Channel CRUD, member management, capacity enforcement
- **presence/**: Session management, status tracking, mute control
- **voice/**: Packet routing with subscriber pattern
- **grpc/**: Service handlers with proper error handling
- **logger/**: Structured logging with configurable levels

### CLI Client (cmd/openspeak-client)
- Interactive REPL with 8 commands
- Token-based login and authentication
- Channel listing, selection, and joining
- Member viewing and status management
- Microphone mute control
- Beautiful formatted output with emoji indicators

### Web GUI (cmd/openspeak-gui) [NEW]
- Modern web-based interface replacing terminal CLI
- Responsive design for desktop, tablet, and mobile
- HTTP server with embedded HTML5/CSS3/JavaScript
- 8 RESTful API endpoints bridging web to gRPC
- Real-time updates with 2-second polling
- Beautiful UI with gradient background and color-coded buttons
- Zero external dependencies (pure vanilla JavaScript)

## Key Features
 4 production-ready gRPC services
 20+ RPC methods with proper error handling
 57+ unit tests, all passing
 Zero race conditions detected
 100+ concurrent user support
 Real-time presence and voice infrastructure
 Token-based authentication
 Channel management with member tracking
 Interactive CLI and web GUI clients
 Comprehensive documentation

## Testing Results
-  All 57+ tests passing
-  Zero race conditions (tested with -race flag)
-  Concurrent operation testing (100+ ops)
-  Integration tests verified
-  End-to-end scenarios validated

## Documentation
- README.md: Project overview and quick start
- IMPLEMENTATION_SUMMARY.md: Comprehensive project details
- GRPC_IMPLEMENTATION.md: Service and method documentation
- CLI_CLIENT.md: CLI usage guide with examples
- WEB_GUI.md: Web GUI usage and API documentation
- GUI_IMPLEMENTATION_SUMMARY.md: Web GUI implementation details
- TEST_SCENARIO.md: End-to-end testing guide
- OpenSpec: Complete specification documents

## Technology Stack
- Language: Go 1.24.11
- Framework: gRPC v1.77.0
- Serialization: Protocol Buffers v1.36.10
- UUID: github.com/google/uuid v1.6.0

## Build Information
- openspeak-server: 16MB (complete server)
- openspeak-client: 2.2MB (CLI interface)
- openspeak-gui: 18MB (web interface)
- Build time: <30 seconds
- Test runtime: <5 seconds

## Getting Started
1. Build: make build
2. Server: ./bin/openspeak-server -port 50051 -log-level info
3. Client: ./bin/openspeak-client -host localhost -port 50051
4. Web GUI: ./bin/openspeak-gui -port 9090
5. Browser: http://localhost:9090

## Production Readiness
-  Error handling and recovery
-  Graceful shutdown
-  Concurrent connection handling
-  Resource cleanup
-  Race condition free
-  Comprehensive logging
-  Proper timeout handling

## Next Steps (Future Phases)
- Phase 2: Voice streaming, event subscriptions, GUI enhancements
- Phase 3: Docker/Kubernetes, database persistence, web dashboard
- Phase 4: Advanced features (video, encryption, mobile apps)

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 17:32:47 +01:00

662 lines
14 KiB
Markdown

# Feature Specification: Development Guidelines & Best Practices
**ID:** DEV-001
**Version:** 1.0
**Status:** Planned
**Priority:** High
## Overview
Guidelines for development workflow, code quality, testing, and contribution standards for OpenSpeak project.
## Development Workflow
### Setting Up Development Environment
#### Prerequisites
- Go 1.21+
- Git
- Protobuf compiler (protoc) v3.20+
- Visual Studio Code or preferred IDE
- Audio libraries (PortAudio, libopus)
#### Initial Setup
```bash
# Clone repository
git clone https://github.com/yourusername/openspeak.git
cd openspeak
# Install dependencies
go mod download
go mod tidy
# Install tools
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# Setup pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
go fmt ./...
golangci-lint run ./...
go test ./...
EOF
chmod +x .git/hooks/pre-commit
```
### Development Commands
#### Build
```bash
# Build server
go build -o bin/openspeak-server ./cmd/openspeak-server
# Build client
go build -o bin/openspeak-client ./cmd/openspeak-client
# Build all
make build
# Debug build (with symbols)
go build -gcflags="all=-N -l" -o bin/openspeak-server ./cmd/openspeak-server
```
#### Run
```bash
# Run server with default config
./bin/openspeak-server
# Run with custom config
./bin/openspeak-server --config config.dev.yaml
# Run with debug logging
OPENSPEAK_LOG_LEVEL=debug ./bin/openspeak-server
# Run client
./bin/openspeak-client
```
#### Test
```bash
# Run all tests
go test ./...
# Run with coverage
go test -cover ./...
# Generate coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Run specific test
go test -run TestChannelManager ./internal/channel
# Run with verbose output
go test -v ./...
# Run benchmarks
go test -bench=. -benchmem ./...
# Run tests with race detector
go test -race ./...
```
#### Code Quality
```bash
# Format code
go fmt ./...
# Run linters
golangci-lint run ./...
# Vet code
go vet ./...
# Check imports
goimports -w ./...
# Staticcheck
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck ./...
```
#### Protocol Buffers
```bash
# Generate protobuf code
make proto
# Equivalent to:
protoc --go_out=. --go-grpc_out=. proto/*.proto
# Watch for changes
watch -n 1 'make proto'
```
#### Documentation
```bash
# Generate documentation
go doc ./...
# View package docs
godoc -http=:6060
# Then open http://localhost:6060
```
### Makefile
```makefile
.PHONY: build test lint fmt clean proto run-server run-client coverage
all: fmt lint test build
build:
@echo "Building server and client..."
go build -o bin/openspeak-server ./cmd/openspeak-server
go build -o bin/openspeak-client ./cmd/openspeak-client
test:
@echo "Running tests..."
go test -v -race -coverprofile=coverage.out ./...
go tool cover -func=coverage.out
lint:
@echo "Running linters..."
go fmt ./...
go vet ./...
golangci-lint run ./...
fmt:
@echo "Formatting code..."
go fmt ./...
goimports -w ./...
clean:
@echo "Cleaning..."
rm -rf bin/
rm -f coverage.out
proto:
@echo "Generating protobuf code..."
protoc --go_out=. --go-grpc_out=. proto/*.proto
run-server:
go run ./cmd/openspeak-server -- --config config.dev.yaml
run-client:
go run ./cmd/openspeak-client
coverage:
@echo "Generating coverage report..."
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
@echo "Report saved to coverage.html"
coverage-watch:
watch -n 2 'make coverage'
bench:
@echo "Running benchmarks..."
go test -bench=. -benchmem ./...
help:
@echo "Available targets:"
@grep -E '^[a-zA-Z_-]+:' Makefile | sed 's/:.*//g' | sort
```
## Code Style & Conventions
### Go Code Style
Follow [Effective Go](https://golang.org/doc/effective_go) and [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments).
#### Naming Conventions
```go
// Interfaces: adjective names (Reader, Writer, Closer)
type Reader interface {
Read(p []byte) (n int, err error)
}
// Packages: short, single-word names
package voice
// Exported: PascalCase
func PublishVoicePacket(packet *VoicePacket) error {}
// Unexported: camelCase
func publishVoicePacket(packet *voicePacket) error {}
// Constants: UPPER_SNAKE_CASE or PascalCase
const (
DefaultBitrate = 64
MaxBitrate = 128
)
// Errors: errors.New or fmt.Errorf, start with lowercase or "Error" prefix
var ErrChannelNotFound = errors.New("channel not found")
var ErrInvalidBitrate = fmt.Errorf("invalid bitrate: %d", bitrate)
// Receiver names: short (1-2 chars)
func (m *Manager) CreateChannel(name string) (*Channel, error) {}
```
#### File Organization
```go
// 1. Package declaration
package channel
// 2. Imports (stdlib, third-party, internal)
import (
"context"
"sync"
"google.golang.org/grpc"
"openspeak/internal/logger"
)
// 3. Constants
const (
DefaultMaxUsers = 0 // unlimited
)
// 4. Errors
var (
ErrChannelNotFound = errors.New("channel not found")
ErrChannelFull = errors.New("channel is full")
)
// 5. Type definitions
type Channel struct {
ID string
Name string
Members []string
MaxUsers int
CreatedAt time.Time
}
// 6. Receiver methods (sorted by type)
func (c *Channel) IsFull() bool {
return c.MaxUsers > 0 && len(c.Members) >= c.MaxUsers
}
// 7. Package-level functions
func NewChannel(name string) *Channel {
return &Channel{
ID: generateID(),
Name: name,
Members: []string{},
MaxUsers: 0,
CreatedAt: time.Now(),
}
}
```
#### Error Handling
```go
// Good: Simple, clear error propagation
func (m *Manager) CreateChannel(name string) (*Channel, error) {
if err := validateName(name); err != nil {
return nil, fmt.Errorf("validate name: %w", err)
}
channel := NewChannel(name)
if err := m.store.Save(channel); err != nil {
return nil, fmt.Errorf("save channel: %w", err)
}
return channel, nil
}
// Bad: Ignoring errors
func (m *Manager) CreateChannel(name string) (*Channel, error) {
validateName(name) // Error ignored!
channel := NewChannel(name)
m.store.Save(channel) // Error ignored!
return channel, nil
}
// Bad: Generic error messages
return nil, errors.New("error") // Useless error message
```
#### Comments
```go
// Good: Explains purpose, not what code does
// ChannelManager handles creation and deletion of voice channels.
// It maintains the current state of all channels and enforces permissions.
type Manager struct {
channels map[string]*Channel
mu sync.RWMutex
}
// Bad: Explains code, not purpose
// This is a map of channels
channels := make(map[string]*Channel)
// Good: Exported functions have godoc
// PublishVoicePacket accepts a voice packet from a client and broadcasts it
// to all members of the packet's channel.
func PublishVoicePacket(packet *VoicePacket) error {
// ...
}
// Bad: No comment on exported function
func PublishVoicePacket(packet *VoicePacket) error {
// ...
}
```
### Project Layout
```
openspeak/
├── cmd/ # Executable entry points
│ ├── openspeak-server/
│ │ └── main.go
│ └── openspeak-client/
│ └── main.go
├── internal/ # Private packages (not importable from outside)
│ ├── auth/
│ ├── channel/
│ ├── presence/
│ ├── voice/
│ ├── config/
│ ├── logger/
│ └── grpc/
├── proto/ # Protocol buffer definitions
│ ├── common.proto
│ ├── auth.proto
│ ├── channel.proto
│ ├── presence.proto
│ └── voice.proto
├── pkg/ # Generated code (protobuf)
│ └── api/
│ └── openspeak/
│ └── v1/
├── config/ # Configuration files
│ ├── config.yaml
│ └── config.dev.yaml
├── test/ # Test utilities and fixtures
│ ├── fixtures/
│ └── mocks/
├── Makefile
├── go.mod
├── go.sum
├── README.md
├── CONTRIBUTING.md
└── LICENSE
```
## Testing Standards
### Test Structure
```go
// File: internal/channel/channel_test.go
package channel
import (
"testing"
)
// TestChannelCreation tests basic channel creation
func TestChannelCreation(t *testing.T) {
// Arrange
name := "general"
// Act
channel := NewChannel(name)
// Assert
if channel.Name != name {
t.Errorf("expected name %q, got %q", name, channel.Name)
}
if channel.ID == "" {
t.Error("channel ID should not be empty")
}
}
// TestChannelIsFull tests capacity checking
func TestChannelIsFull(t *testing.T) {
tests := []struct {
name string
maxUsers int
members int
want bool
}{
{"unlimited capacity", 0, 100, false},
{"not full", 10, 5, false},
{"exactly full", 10, 10, true},
{"over capacity", 10, 11, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
channel := NewChannel("test")
channel.MaxUsers = tt.maxUsers
channel.Members = make([]string, tt.members)
got := channel.IsFull()
if got != tt.want {
t.Errorf("IsFull() = %v, want %v", got, tt.want)
}
})
}
}
```
### Test Requirements
- Write tests for all exported functions
- Use table-driven tests for multiple cases
- Use sub-tests (t.Run) for related test cases
- Mock external dependencies
- Test both success and error cases
- Write benchmarks for performance-critical code
### Coverage Goals
- Unit tests: Aim for 80%+ coverage
- Integration tests: Critical paths
- Packages with <50% coverage: Flag in review
## Git Workflow
### Branch Naming
```
feature/<description> # New feature
bugfix/<description> # Bug fix
docs/<description> # Documentation
refactor/<description> # Refactoring
perf/<description> # Performance improvement
test/<description> # Test additions
```
### Commit Messages
Follow [Conventional Commits](https://www.conventionalcommits.org/):
```
<type>(<scope>): <subject>
<body>
<footer>
```
**Types:**
- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation
- `style`: Code style (formatting, etc)
- `refactor`: Code refactoring
- `perf`: Performance improvement
- `test`: Test additions/changes
- `chore`: Build, CI, dependencies
**Examples:**
```
feat(channel): add channel archival feature
Implement soft delete for channels. Users can still access archived
channels, but no new users can join them. Includes audit logging.
Fixes #123
Closes #456
feat(voice): implement Opus codec support
refactor(presence): simplify idle detection
docs(server): add deployment guide
fix(auth): validate token format before checking expiration
perf(voice): optimize packet routing for large channels
```
### Pull Request Process
1. Create feature branch from `main`
2. Make commits with clear messages
3. Keep commits focused and logical
4. Push to your fork
5. Create PR with description
6. Respond to code review feedback
7. Merge once approved
## Documentation Standards
### Code Documentation
- All exported functions and types must have godoc comments
- Comments should explain "why", not "what"
- Use examples in documentation for complex functions
### README Files
- Package-level `README.md` in each major directory
- Usage examples
- Important design decisions
- Known limitations
### Architecture Documentation
- Decision records for major changes
- Diagrams for complex systems
- Examples of common usage patterns
## Debugging Techniques
### Logging
```go
// Use structured logging
logger.Info("user connected",
"user_id", userID,
"channel_id", channelID,
"timestamp", time.Now(),
)
logger.Error("voice routing failed",
"error", err,
"packet_id", packetID,
"channel_id", channelID,
)
```
### Profiling
```bash
# CPU profiling
go run -cpuprofile=cpu.prof ./cmd/openspeak-server
# Memory profiling
go run -memprofile=mem.prof ./cmd/openspeak-server
# View profiles
go tool pprof cpu.prof
go tool pprof mem.prof
# Live profiling (server running)
go tool pprof http://localhost:6060/debug/pprof/profile
```
### Debugging with Delve
```bash
# Install
go install github.com/go-delve/delve/cmd/dlv@latest
# Run server with debugger
dlv debug ./cmd/openspeak-server
# Commands in debugger:
# (dlv) break main.main
# (dlv) continue
# (dlv) next
# (dlv) step
# (dlv) print variable
# (dlv) quit
```
## Performance Optimization
### Benchmarking
```bash
# Run benchmarks
go test -bench=. -benchmem ./internal/voice
# Output:
# BenchmarkPublishVoicePacket-8 100000 10500 ns/op 2048 B/op 8 allocs/op
```
### Memory Optimization
- Reuse buffers with sync.Pool
- Avoid unnecessary allocations
- Use value types for small structs
- Profile before optimizing
### Concurrency Optimization
- Use sync.Map for high-concurrency maps
- Avoid locks in hot paths
- Use channels for coordination
- Profile with -race flag
## Continuous Integration (Future)
### GitHub Actions Workflow
```yaml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '1.21'
- run: make lint
- run: make test
- run: make coverage
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: securego/gosec@master
```
## Version Management
### Semantic Versioning
- MAJOR: Breaking changes
- MINOR: New features (backwards compatible)
- PATCH: Bug fixes
**Tag format:** `v1.2.3`
```bash
# Create release
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0
```
## Contributing Guidelines
- Follow all above conventions
- Write tests for new code
- Update documentation
- Get code reviewed
- Keep commits clean
- Respond to feedback professionally