-
-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture Overview
Technical overview of Terminal Velocity's architecture and design patterns.
┌─────────────────────────────────────────────────────────────────┐
│ SSH Clients │
│ (Players connecting from anywhere) │
└────────────────────┬────────────────────────────────────────────┘
│ SSH Protocol (Port 2222)
│
┌────────────────────▼────────────────────────────────────────────┐
│ SSH Server Layer │
│ - Multi-method auth (password + public key) │
│ - Session management │
│ - BubbleTea program lifecycle │
└────────────────────┬────────────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────────────┐
│ Application Layer │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ TUI │ │ Game Logic │ │ Background │ │
│ │ (BubbleTea) │ │ (29+ Sys) │ │ Workers │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└────────────────────┬────────────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────────────┐
│ Repository Layer │
│ - 20+ repositories (Player, Ship, Market, Quest, etc.) │
│ - Thread-safe (sync.RWMutex) │
│ - Connection pooling (pgx) │
└────────────────────┬────────────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────────────┐
│ PostgreSQL Database │
│ - 20+ tables │
│ - UUID primary keys │
│ - JSONB for flexible data │
└──────────────────────────────────────────────────────────────────┘
All database access goes through repositories:
type PlayerRepository interface {
Create(ctx context.Context, player *Player) error
GetByID(ctx context.Context, id uuid.UUID) (*Player, error)
Update(ctx context.Context, player *Player) error
Delete(ctx context.Context, id uuid.UUID) error
}Benefits:
- Encapsulates SQL queries
- Type-safe data access
- Easy testing (mock repositories)
- Separation of concerns
UI follows Model-View-Update pattern:
type Model struct {
screen Screen
player *models.Player
repos *Repositories
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Handle messages (keyboard, async results)
}
func (m Model) View() string {
// Render current state
}Benefits:
- Declarative UI
- Clear separation of state and rendering
- Composable components
- Event-driven
All game logic runs on the server:
Player Action → SSH → Server Validates → Database Update → UI Refresh
Benefits:
- No cheating possible
- Consistent multiplayer state
- Centralized game logic
- Fair gameplay
Long-running tasks use goroutines:
func (m *Manager) eventScheduler() {
ticker := time.NewTicker(1 * time.Minute)
for {
select {
case <-m.ctx.Done():
return
case <-ticker.C:
m.updateEvents()
}
}
}Workers:
- Event scheduler (1 minute tick)
- Auto-save (30 second tick)
- Market updates (1 hour tick)
- Session cleanup (5 minute tick)
internal/
├── server/ # SSH server & session management
├── tui/ # 30+ BubbleTea UI screens
├── database/ # 20+ repositories (pgx)
├── models/ # Data structures
├── combat/ # Turn-based combat system
├── missions/ # Mission lifecycle
├── quests/ # Quest & storyline system
├── events/ # Dynamic events manager
├── achievements/ # Achievement tracking
├── news/ # News generation
├── leaderboards/ # Player rankings
├── chat/ # Multiplayer chat
├── factions/ # Player faction system
├── territory/ # Territory control
├── trade/ # Player trading
├── pvp/ # PvP combat
├── presence/ # Player presence
├── encounters/ # Random encounters
├── outfitting/ # Equipment & loadouts
├── settings/ # Player settings
├── tutorial/ # Tutorial system
├── admin/ # Server administration
├── session/ # Auto-save & persistence
└── universe/ # Procedural generation
Algorithm: Prim's MST + Random Connections
1. Generate 100 star systems (spiral galaxy distribution)
2. Create MST for guaranteed connectivity
3. Add 20-30% extra connections for redundancy
4. Assign tech levels (radial distribution from Sol)
5. Distribute factions by distance
6. Generate planets per system (1-4)
7. Assign services based on tech level
Price Calculation:
FinalPrice = BasePrice
× TechLevelModifier
× SupplyDemandModifier
Market Updates:
- Player trades immediately affect prices
- Stock regenerates at 5%/hour
- Demand normalizes at 5%/hour
- Random events: 5% chance/hour
Combat Flow:
1. Initialize combat state
2. Player turn:
- Select weapon
- Calculate hit chance
- Resolve damage
3. Enemy turn:
- AI selects target/weapon
- Calculate hit chance
- Resolve damage
4. Check win/loss conditions
5. Repeat until resolved
AI Decision Tree:
- Assess threat level
- Check hull/shield status
- Evaluate weapon options
- Consider range/accuracy
- Apply difficulty modifiers
- Execute action
Quest Structure:
type Quest struct {
ID string
Type QuestType // Main, Side, Faction, etc.
Objectives []Objective
Choices []Choice // Branching narrative
Rewards Reward
Status Status
}Branching Logic:
- Player choices affect outcomes
- Multiple paths through quests
- Reputation impacts availability
- Dynamic quest generation
Event Lifecycle:
Scheduled → Active → Ending → Ended
↓ ↓ ↓ ↓
Notify Track Warn Rewards
Event Types:
- Trading competitions
- Combat tournaments
- Expeditions (community goals)
- Boss encounters
- Festivals (multipliers)
All shared state uses sync.RWMutex:
type Manager struct {
mu sync.RWMutex
data map[string]*Data
}
func (m *Manager) Get(id string) *Data {
m.mu.RLock()
defer m.mu.RUnlock()
return m.data[id]
}
func (m *Manager) Set(id string, data *Data) {
m.mu.Lock()
defer m.mu.Unlock()
m.data[id] = data
}Connection Pooling (pgx):
- Min connections: 2
- Max connections: 10
- Max idle time: 5 minutes
- Acquire timeout: 10 seconds
BubbleTea uses channels for async operations:
func loadDataCmd() tea.Msg {
data, err := fetchData()
return dataLoadedMsg{data, err}
}
// In Update():
case dataLoadedMsg:
m.data = msg.data
return m, nilplayers:
- UUID primary key
- Nullable password_hash (SSH-only accounts supported)
- Credits, experience, level
- Current location (system_id, planet_id nullable)
ships:
- UUID primary key
- Player foreign key
- Ship type, name
- Hull, shields, fuel, cargo
- Equipment slots (JSONB)
star_systems:
- UUID primary key
- Name, position (x, y, z)
- Tech level, government
- Description
quests:
- UUID primary key
- Quest type, status
- Objectives (JSONB array)
- Choices (JSONB array)
- Rewards (JSONB)
See Database Schema for full details.
-
Database Indexes:
- All foreign keys indexed
- Player lookups by username/email
- System lookups by name
- Quest lookups by player + status
-
Caching Strategy:
- In-memory caching for static data (systems, ships, commodities)
- 15-minute TTL for market prices
- Session state cached in memory
-
Connection Pooling:
- pgx pool for database connections
- SSH connection reuse
-
Efficient Queries:
- Batch operations where possible
- Prepared statements for repeated queries
- JOINs minimized (denormalization where beneficial)
Current Capacity:
- 100+ concurrent players
- Sub-10ms database queries
- 30-second auto-save cycle
- Real-time multiplayer features
Bottlenecks:
- Database writes (auto-save at scale)
- Event leaderboard updates
- Market price calculations
Future Improvements:
- Redis caching layer
- Database read replicas
- Horizontal scaling (multiple servers)
Multi-Method:
- Password: Bcrypt hashing
- SSH Keys: SHA256 fingerprints
Flow:
SSH Connect → Auth Handler → Validate → Create Session
RBAC (Role-Based Access Control):
- 4 roles: Player, Moderator, Admin, SuperAdmin
- 20+ permissions
- Permission checks on all admin actions
- Audit logging (10,000 entry buffer)
- SQL Injection: Parameterized queries (pgx)
- Session Hijacking: Secure token generation
- Input Validation: All user input sanitized
- Rate Limiting: Connection throttling
-
Models: Define data structures in
internal/models/ -
Repository: Create repository in
internal/database/ - Game Logic: Implement in appropriate package
-
UI: Add TUI screens in
internal/tui/ - Tests: Write unit tests
- Documentation: Update wiki pages
Unit Tests:
- Game logic (combat, economy, quests)
- Data models
- Utility functions
Integration Tests:
- Database operations
- Multi-system interactions
- Player workflows
Manual Testing:
- UI/UX testing via SSH
- Multiplayer testing
- Performance testing
Tools:
-
golangci-lint: Linting -
go fmt: Formatting -
go vet: Static analysis -
go test -race: Race detection
Standards:
- Idiomatic Go code
- Comprehensive error handling
- Public function documentation
- Consistent naming conventions
docker compose.yml:
- PostgreSQL container
- Terminal Velocity server container
- Shared network
- Volume mounts for persistence
Infrastructure:
- 2 CPU cores minimum
- 2GB RAM minimum
- PostgreSQL on separate instance (production)
- SSL/TLS for SSH (via reverse proxy)
Monitoring:
- Server metrics (CPU, memory, connections)
- Database performance
- Player activity
- Error logging
Backup Strategy:
- Daily PostgreSQL dumps
- Continuous WAL archiving
- Off-site backups
-
Redis Caching:
- Market price caching
- Session state caching
- Leaderboard caching
-
Microservices (if needed):
- Event service
- Combat service
- Market service
-
Horizontal Scaling:
- Multiple game servers
- Load balancing
- Shared database
-
Web Dashboard:
- REST API
- Player statistics
- Admin interface
-
Modding Support:
- Plugin architecture
- Content loading system
- Scripting support (Lua?)
For detailed API reference, see API Reference
For database details, see Database Schema
For development setup, see Development Setup
- Gameplay Guide
- Trading Guide
- Combat Guide
- Ship Guide
- Quests & Missions
- Multiplayer Guide
- Events Guide
Version: 0.7.0 Status: Feature Complete