handlers

package
v0.0.0-...-e5d423c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2026 License: MIT Imports: 59 Imported by: 0

Documentation

Overview

Package handlers provides HTTP handlers for the StreamSpace API. This file implements session activity tracking and heartbeat management.

ACTIVITY TRACKING: - Session heartbeat recording to prevent auto-hibernation - Activity status queries (active, idle, hibernation eligibility) - Idle duration calculation - Last activity timestamp tracking

HEARTBEAT MECHANISM: - Clients send periodic heartbeats to indicate active usage - Updates session's lastActivity timestamp - Prevents idle timeout and auto-hibernation - Typically sent every 30-60 seconds from active sessions

ACTIVITY STATUS: - Is session currently active (recent heartbeat) - Is session idle (exceeded idle threshold) - Time since last activity - Should session be hibernated (idle + threshold exceeded) - Configurable idle thresholds per session

USE CASES: - Auto-hibernation prevention for active sessions - Resource optimization by hibernating idle sessions - User activity analytics - Session health monitoring

API Endpoints: - POST /api/v1/sessions/:id/heartbeat - Record session heartbeat - GET /api/v1/sessions/:id/activity - Get session activity status

Thread Safety: - Activity tracker is thread-safe with mutex protection - Kubernetes client operations are thread-safe

Dependencies: - Kubernetes: Session CRDs with status updates - Activity Tracker: In-memory tracking with persistence - External Services: None

Example Usage:

handler := NewActivityHandler(k8sClient, activityTracker)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements the WebSocket handler for agent connections.

AGENT WEBSOCKET CONNECTION: - Agents connect to GET /api/v1/agents/connect?agent_id=xxx - Connection is upgraded from HTTP to WebSocket - Agent sends heartbeats every 10 seconds - Control Plane sends commands to agent - Agent sends back ack/complete/failed/status messages

MESSAGE FLOW: Control Plane → Agent:

  • command: Execute a session command
  • ping: Keep-alive ping
  • shutdown: Graceful shutdown

Agent → Control Plane:

  • heartbeat: Regular status update
  • ack: Command acknowledged
  • complete: Command completed
  • failed: Command failed
  • status: Session status update

CONNECTION LIFECYCLE: 1. Agent sends HTTP GET to /api/v1/agents/connect?agent_id=xxx 2. Handler validates agent exists in database 3. HTTP connection upgraded to WebSocket 4. Connection registered with AgentHub 5. readPump and writePump goroutines started 6. Agent sends heartbeats every 10 seconds 7. On disconnect, connection unregistered from hub

Thread Safety: - readPump and writePump run concurrently - Each connection has dedicated Send/Receive channels - Hub handles all synchronization

Package handlers provides HTTP handlers for the StreamSpace API. This file implements agent registration and management for the v2.0 multi-platform architecture.

AGENT ARCHITECTURE: - Agents are platform-specific execution agents (Kubernetes, Docker, VM, Cloud) - Agents connect to Control Plane via outbound WebSocket connection - Agents receive commands to start/stop/hibernate sessions - Agents tunnel VNC traffic back to Control Plane - Agents send heartbeats every 10 seconds

AGENT PLATFORMS: - kubernetes: Kubernetes cluster agent - docker: Docker host agent - vm: Virtual machine agent - cloud: Cloud provider agent (AWS, Azure, GCP)

AGENT STATUS: - online: Agent is connected and healthy - offline: Agent is disconnected - draining: Agent is not accepting new sessions

API Endpoints: - POST /api/v1/agents/register - Register agent (or re-register) - GET /api/v1/agents - List all agents (with filters) - GET /api/v1/agents/:agent_id - Get agent details - DELETE /api/v1/agents/:agent_id - Deregister agent - POST /api/v1/agents/:agent_id/heartbeat - Update heartbeat - POST /api/v1/agents/:agent_id/command - Send command to agent

Thread Safety: - All database operations are thread-safe

Dependencies: - Database: agents table (v2.0 schema) - Models: api/internal/models/agent.go - AgentHub: WebSocket connection manager - CommandDispatcher: Command queuing and dispatch

Example Usage:

handler := NewAgentHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements API key management for programmatic API access.

API KEY FEATURES: - Secure API key generation with cryptographic randomness - API key CRUD operations (create, list, revoke, delete) - Key metadata (name, description, scopes, rate limits) - Expiration support with configurable durations - Usage tracking (last used timestamp, use count) - Active/inactive state management

SECURITY: - Keys hashed with SHA-256 before storage (never stored in plaintext) - Prefix-based identification (first 8 characters for UI display) - Keys prefixed with "sk_" for easy identification - 32 bytes of cryptographic randomness (256 bits) - Keys only shown once during creation (cannot be retrieved later)

API KEY STRUCTURE: - Format: sk_{base64_encoded_random_bytes} - Storage: SHA-256 hash in database - Display: First 8 characters (sk_xxxxx...)

SCOPE MANAGEMENT: - Configurable scopes limit API key permissions - Examples: sessions:read, sessions:write, admin:all - Scope validation during API requests

RATE LIMITING: - Per-key rate limits independent of user limits - Configurable requests per time window - Tracked via use_count and last_used_at

EXPIRATION: - Optional expiration with duration strings (30d, 1y, etc.) - Automatic enforcement during authentication - Expired keys cannot authenticate

API Endpoints: - POST /api/v1/apikeys - Create new API key - GET /api/v1/apikeys - List user's API keys - GET /api/v1/apikeys/:id - Get API key details - PUT /api/v1/apikeys/:id - Update API key metadata - DELETE /api/v1/apikeys/:id - Delete/revoke API key - POST /api/v1/apikeys/:id/rotate - Rotate API key (generate new)

Thread Safety: - All database operations are thread-safe via connection pooling - Cryptographic random generation is thread-safe

Dependencies: - Database: api_keys table - External Services: None

Example Usage:

handler := NewAPIKeyHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements installed application management endpoints.

APPLICATION FEATURES: - Install applications from catalog templates - Custom display names for user dashboards - Application configuration management - Enable/disable applications - Group-based access control

ACCESS CONTROL: - Grant/revoke group access to applications - Multiple access levels (view, launch, admin) - Filter applications by user's group membership

API Endpoints: - GET /api/v1/applications - List all installed applications - POST /api/v1/applications - Install a new application - GET /api/v1/applications/:id - Get application details - PUT /api/v1/applications/:id - Update application - DELETE /api/v1/applications/:id - Delete application - PUT /api/v1/applications/:id/enabled - Enable/disable application - GET /api/v1/applications/:id/groups - Get groups with access - POST /api/v1/applications/:id/groups - Add group access - PUT /api/v1/applications/:id/groups/:groupId - Update group access level - DELETE /api/v1/applications/:id/groups/:groupId - Remove group access - GET /api/v1/applications/:id/config - Get template config options - GET /api/v1/applications/user - Get applications accessible to current user

Thread Safety: - All database operations are thread-safe via connection pooling

Dependencies: - Database: installed_applications, application_group_access tables

Example Usage:

handler := NewApplicationHandler(database, publisher, "kubernetes")
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements audit log retrieval and export for compliance and security.

AUDIT LOG VIEWER: - Retrieve audit logs with filtering and pagination - Export audit logs for compliance reports (CSV/JSON) - Search and analyze security events - Track user activity and system changes

COMPLIANCE SUPPORT: - SOC2: Audit trail of all system changes (1 year retention) - HIPAA: PHI access logging (6 year retention) - GDPR: Data processing activity records - ISO 27001: User activity logging

FILTERING CAPABILITIES: - Filter by user ID or username - Filter by action (GET, POST, PUT, DELETE) - Filter by resource type (/api/sessions, /api/users, etc.) - Filter by date range (start_date, end_date) - Filter by IP address (security investigations) - Filter by status code (200, 401, 500, etc.)

EXPORT FORMATS: - JSON: Machine-readable, full details - CSV: Human-readable, spreadsheet-compatible - Both formats include all relevant fields for compliance

USE CASES: - Security incident investigation - Compliance audits and reporting - User activity analysis - System change tracking - Failed access attempt detection

API Endpoints: - GET /api/v1/admin/audit - List audit logs (with filters) - GET /api/v1/admin/audit/:id - Get specific audit log entry - GET /api/v1/admin/audit/export - Export audit logs to CSV/JSON

Thread Safety: - Database operations are thread-safe - Read-only queries, no state modification

Dependencies: - Database: PostgreSQL audit_log table - Middleware: Audit logging middleware (captures all requests)

Example Usage:

handler := NewAuditHandler(database)
handler.RegisterRoutes(router.Group("/api/v1/admin"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements batch operations for bulk resource management.

BATCH OPERATION FEATURES: - Bulk session operations (terminate, hibernate, wake, delete) - Bulk snapshot operations (create, delete) - Bulk template operations (install, delete) - Asynchronous job execution with progress tracking - Job status monitoring and cancellation

OPERATION TYPES: - terminate: Stop multiple running sessions - hibernate: Put multiple sessions into hibernated state - wake: Resume multiple hibernated sessions - delete: Remove multiple sessions/snapshots/templates - update: Bulk update tags or resource limits

BATCH JOB LIFECYCLE: 1. Job creation: Create batch_operations record 2. Async execution: Process items in background goroutine 3. Progress tracking: Update processed/success/failure counts 4. Completion: Mark job as completed or failed 5. Cleanup: Jobs can be cancelled or deleted

JOB STATUS TRACKING: - Total items to process - Processed items count - Success count - Failure count - Errors array for failed items - Created/completed timestamps

ASYNC EXECUTION: - All batch operations run asynchronously - Immediate job ID returned to client - Client polls job status endpoint for progress - WebSocket notifications for real-time updates

ERROR HANDLING: - Partial failures: Continue processing remaining items - Error collection: Record all errors for debugging - Job status reflects overall success/failure

API Endpoints: - POST /api/v1/batch/sessions/terminate - Terminate multiple sessions - POST /api/v1/batch/sessions/hibernate - Hibernate multiple sessions - POST /api/v1/batch/sessions/wake - Wake multiple sessions - POST /api/v1/batch/sessions/delete - Delete multiple sessions - POST /api/v1/batch/sessions/update-tags - Update session tags - POST /api/v1/batch/sessions/update-resources - Update resource limits - POST /api/v1/batch/snapshots/delete - Delete multiple snapshots - POST /api/v1/batch/snapshots/create - Create multiple snapshots - POST /api/v1/batch/templates/install - Install multiple templates - POST /api/v1/batch/templates/delete - Delete multiple templates - GET /api/v1/batch/jobs - List batch jobs - GET /api/v1/batch/jobs/:id - Get batch job status - DELETE /api/v1/batch/jobs/:id - Cancel batch job

Thread Safety: - All database operations are thread-safe via connection pooling - Goroutines for async execution are properly managed

Dependencies: - Database: batch_operations, sessions, snapshots, templates tables - External Services: None

Example Usage:

handler := NewBatchHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements template catalog browsing, ratings, and statistics.

CATALOG FEATURES: - Template discovery with advanced search and filtering - Featured, trending, and popular template lists - User ratings and reviews system - View and install tracking for analytics

SEARCH AND FILTERING: - Full-text search across template names and descriptions - Filter by category, tags, app type - Sort by popularity, rating, recency, or install count - Pagination support with customizable page size

RATINGS AND REVIEWS: - Add, update, and delete template ratings - Star ratings (1-5 scale) - User comments and reviews - Average rating calculation - Rating count tracking

STATISTICS: - View count tracking (catalog impressions) - Install count tracking (template usage) - Trending calculation based on recent activity - Popular templates based on install count

API Endpoints: - GET /api/v1/catalog/templates - List templates with filters and search - GET /api/v1/catalog/templates/:id - Get template details - GET /api/v1/catalog/templates/featured - List featured templates - GET /api/v1/catalog/templates/trending - List trending templates - GET /api/v1/catalog/templates/popular - List popular templates - POST /api/v1/catalog/templates/:id/ratings - Add rating/review - GET /api/v1/catalog/templates/:id/ratings - Get template ratings - PUT /api/v1/catalog/templates/:id/ratings/:ratingId - Update rating - DELETE /api/v1/catalog/templates/:id/ratings/:ratingId - Delete rating - POST /api/v1/catalog/templates/:id/view - Record template view - POST /api/v1/catalog/templates/:id/install - Record template install

Thread Safety: - All database operations are thread-safe via connection pooling

Dependencies: - Database: catalog_templates, repositories, template_ratings tables - External Services: Repository sync for template metadata

Example Usage:

handler := NewCatalogHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers - collaboration.go

This file implements real-time collaboration features for StreamSpace sessions.

Collaboration System Overview

The collaboration system enables multiple users to work together in a single session with features like chat, annotations, cursor tracking, and screen sharing. This transforms StreamSpace from single-user isolated sessions into a collaborative platform for remote teamwork.

Use Cases

**Pair Programming**:

  • Developer A creates session with VS Code
  • Developer B joins as collaborator with control permissions
  • Both can see cursor positions and type code
  • Chat for quick questions without switching context

**Teaching/Training**:

  • Instructor creates session with training application
  • Students join as viewers (read-only)
  • Instructor uses annotations to highlight important areas
  • Follow mode keeps students in sync with instructor's view

**Support/Troubleshooting**:

  • User creates session with problematic application
  • Support agent joins with control permissions
  • Agent diagnoses issue while user watches
  • Chat for real-time communication

**Design Review**:

  • Designer creates session with design tool
  • Team joins as participants
  • Annotations for feedback directly on designs
  • Hand-raise feature for structured Q&A

Architecture

Collaboration combines WebSocket (real-time) + database (persistence):

┌────────────────────────────────────────────────────────┐
│                  Collaboration Session                 │
│  - Owner creates session                               │
│  - Participants join via invite/link                   │
│  - Real-time sync via WebSocket                        │
│  - State persisted to database                         │
└──────────────┬─────────────────────────────────────────┘
               │
       ┌───────┴───────┬─────────────┬─────────────┐
       ▼               ▼             ▼             ▼
   Owner          Presenter     Participant    Viewer
 (Full access)  (Can control)  (Can chat)   (Read-only)

**WebSocket Integration**:

  • Cursor movements broadcast to all participants
  • Chat messages delivered in real-time
  • Annotations synced across all viewers
  • Presence updates (user joined/left)

**Database Persistence**:

  • Collaboration sessions stored in collaboration_sessions table
  • Participants tracked in collaboration_participants table
  • Chat history in collaboration_messages table
  • Annotations in collaboration_annotations table

Permission Model

Collaboration uses a role-based permission system:

**Owner Role** (session creator):

  • Full control over session
  • Can change settings
  • Can promote/demote participants
  • Can end collaboration
  • Cannot be removed

**Presenter Role** (co-host):

  • Can control the session
  • Can annotate and chat
  • Can invite others
  • Others can follow their view
  • Can be demoted by owner

**Participant Role** (active user):

  • Can chat and annotate
  • Can view cursor positions
  • Cannot control session
  • Limited to max participants count

**Viewer Role** (read-only):

  • Can only view session
  • Cannot interact or chat
  • Unlimited viewers allowed
  • Useful for webinars/demos

Permissions are granular:

  • can_control: Mouse/keyboard input
  • can_annotate: Draw on screen
  • can_chat: Send messages
  • can_invite: Add participants
  • can_manage: Change settings
  • can_record: Start recording

Real-Time Features

**Cursor Tracking**:

  • Each user's cursor shown with their color and label
  • Position updated every 50ms (throttled)
  • Cursors fade after 5s of inactivity
  • Can be disabled in settings

**Chat System**:

  • Text messages with timestamps
  • System messages (user joined, settings changed)
  • Reactions (emoji responses to messages)
  • Message history persisted
  • Can be disabled by owner

**Annotations**:

  • Drawing tools: line, arrow, rectangle, circle, freehand
  • Text annotations
  • Color and thickness customization
  • Persistent vs temporary (expires after 30s)
  • Can be cleared by owner/presenter

**Follow Mode**:

  • Follow presenter: Viewers automatically pan/zoom with presenter
  • Follow owner: Alternative mode for presentations
  • Can be toggled on/off by participants
  • Prevents viewer viewport drift

Concurrency Handling

Multiple users interacting simultaneously requires careful synchronization:

  1. **Optimistic Locking**: Annotations use version numbers
  2. **Event Ordering**: WebSocket messages timestamped for consistency
  3. **Conflict Resolution**: Last-write-wins for cursor positions
  4. **Rate Limiting**: Max 100 events/sec per user (prevent spam)

Example conflict scenario:

  • User A and User B both create annotation at same time
  • Both annotations stored with timestamps
  • UI renders both (no conflict)
  • If same annotation ID, newer timestamp wins

Performance Characteristics

Performance metrics (tested with 50 concurrent collaborators):

  • **Cursor latency**: <50ms from movement to display on other screens
  • **Chat latency**: <100ms from send to delivery
  • **Annotation sync**: <200ms for complex drawings
  • **Memory per session**: ~5 MB (includes cursor positions, annotations)
  • **Database queries**: ~10 queries/sec for active 10-user session

Scaling limits:

  • **Recommended max**: 10 active participants (can_control)
  • **Tested max**: 50 viewers (read-only)
  • **Bottleneck**: WebSocket broadcast bandwidth

Security Considerations

Collaboration introduces new attack vectors:

  1. **Invitation System**: Only owner can invite (no public join)
  2. **Approval Mode**: Owner approves join requests (optional)
  3. **Permission Enforcement**: Server validates all actions
  4. **Input Sanitization**: Chat messages and annotations sanitized
  5. **Rate Limiting**: Prevent spam/DoS via excessive cursors/annotations

Prevented attacks:

  • **Unauthorized join**: JWT + session ownership verified
  • **Privilege escalation**: Roles cannot be self-promoted
  • **XSS in chat**: All messages HTML-escaped
  • **DoS via annotations**: Max 100 annotations per user

Database Schema

**collaboration_sessions**:

  • id, session_id, owner_id, settings, status, created_at, ended_at

**collaboration_participants**:

  • id, collaboration_id, user_id, role, permissions, joined_at, last_seen_at

**collaboration_messages**:

  • id, collaboration_id, user_id, message, message_type, created_at

**collaboration_annotations**:

  • id, collaboration_id, user_id, type, points, is_persistent, created_at

**collaboration_cursors** (in-memory only, not persisted):

  • user_id, x, y, timestamp, color

Known Limitations

  1. **Single instance**: No cross-server collaboration (yet)
  2. **No video/audio**: Text chat only (no voice calling)
  3. **No screen regions**: Can't restrict viewer to specific area
  4. **No undo/redo**: Annotations permanent until deleted
  5. **No file sharing**: Chat is text-only

Future enhancements:

  • WebRTC for audio/video calling
  • Multi-server collaboration via Redis
  • Recording collaboration sessions
  • Annotation history with undo/redo
  • File sharing in chat
  • Breakout rooms for sub-groups

Example Usage

**Creating a collaboration session**:

POST /api/sessions/{sessionId}/collaboration
{
    "settings": {
        "follow_mode": "follow_presenter",
        "max_participants": 10,
        "require_approval": true,
        "show_cursor_labels": true
    }
}

**Joining a collaboration session**:

POST /api/collaboration/{collabId}/join
{
    "role": "participant"
}

**Sending chat message**:

POST /api/collaboration/{collabId}/chat
{
    "message": "Hello team!"
}

**Creating annotation**:

POST /api/collaboration/{collabId}/annotations
{
    "type": "arrow",
    "points": [{"x": 100, "y": 100}, {"x": 200, "y": 200}],
    "color": "#FF0000",
    "is_persistent": true
}

Package handlers provides HTTP handlers for the StreamSpace API. This file implements system configuration management for platform settings.

SYSTEM CONFIGURATION: - CRUD operations for platform-wide settings - Category-based organization (Ingress, Storage, Resources, Features, Session, Security, Compliance) - Type-aware validation (string, boolean, number, duration, enum, array) - Configuration testing before applying changes - Change history tracking

CONFIGURATION CATEGORIES: 1. Ingress: domain, TLS settings 2. Storage: storage class, default sizes, allowed classes 3. Resources: default CPU/memory limits, max limits 4. Features: feature toggles (metrics, hibernation, recordings) 5. Session: idle timeout, max duration, allowed images 6. Security: MFA required, SAML/OIDC enabled, IP whitelist 7. Compliance: frameworks enabled, retention days, archiving

USE CASES: - Platform deployment configuration - Feature flag management - Resource limit enforcement - Security policy configuration - Compliance settings management

API Endpoints: - GET /api/v1/admin/config - List all settings (optional category filter) - GET /api/v1/admin/config/:key - Get specific setting - PUT /api/v1/admin/config/:key - Update setting with validation - POST /api/v1/admin/config/bulk - Bulk update multiple settings

Thread Safety: - Database operations are thread-safe - Validation happens before update

Dependencies: - Database: PostgreSQL configuration table

Example Usage:

handler := NewConfigurationHandler(database)
handler.RegisterRoutes(router.Group("/api/v1/admin"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements console access and file management for sessions.

CONSOLE FEATURES: - Interactive terminal access to sessions via WebSocket - File manager for browsing session filesystems - File operations (create, delete, rename, copy, move, upload, download) - Multi-shell support (bash, sh, zsh) - Terminal resize and configuration

TERMINAL SESSIONS: - WebSocket-based terminal connections - Configurable rows and columns - Shell type selection (bash, sh, zsh) - Activity tracking and idle timeout - Terminal status monitoring

FILE MANAGEMENT: - Directory browsing with file metadata - File/directory creation and deletion - File rename, copy, and move operations - File upload and download - Permissions, ownership, and size information - MIME type detection - Symlink target resolution

FILE OPERATIONS: - Create: Create new files or directories - Delete: Remove files or directories - Rename: Rename files or directories - Copy: Duplicate files or directories - Move: Move files between locations - Upload: Upload files to session - Download: Download files from session

SECURITY: - Access control via session ownership or sharing - User authentication required - Path validation to prevent directory traversal - Permission checks for file operations

API Endpoints: - POST /api/v1/sessions/:sessionId/console - Create console session - GET /api/v1/console/:consoleId - Get console session details - DELETE /api/v1/console/:consoleId - Disconnect console session - GET /api/v1/console/:consoleId/files - List files in directory - POST /api/v1/console/:consoleId/files - Create file/directory - DELETE /api/v1/console/:consoleId/files - Delete file/directory - PUT /api/v1/console/:consoleId/files/rename - Rename file/directory - POST /api/v1/console/:consoleId/files/copy - Copy file/directory - POST /api/v1/console/:consoleId/files/move - Move file/directory - POST /api/v1/console/:consoleId/files/upload - Upload files - GET /api/v1/console/:consoleId/files/download - Download files

Thread Safety: - All database operations are thread-safe via connection pooling - File operations are isolated per session

Dependencies: - Database: console_sessions, sessions, session_shares tables - External Services: Session container filesystem access

Example Usage:

// Create console handler (integrated in main handler)
handler.RegisterConsoleRoutes(router.Group("/api/v1"))

Package handlers defines constants for HTTP handlers.

This file centralizes all "magic numbers" and timeout values to: - Make configuration changes easier (single source of truth) - Improve code readability (named constants vs. bare numbers) - Document the reasoning behind specific values - Enable easy tuning for different environments

SECURITY FIX (2025-11-14): Extracted all magic numbers to named constants as part of code quality improvements. This makes it easier to understand security-critical values like rate limits, timeouts, and buffer sizes.

Categories: - MFA: Multi-factor authentication limits and timing - WebSocket: Connection parameters and buffer sizes - Webhook: Retry logic and timeouts - Session: Verification and expiry times

Package handlers provides HTTP handlers for the StreamSpace API. This file implements dashboard statistics and resource usage queries.

DASHBOARD FEATURES: - Platform-wide statistics (users, sessions, templates, connections) - Resource usage tracking (CPU, memory, storage quotas) - Recent activity metrics (last 24 hours) - Real-time data from Kubernetes and database

PLATFORM STATISTICS: - Total and active user counts - Session counts by state (running, hibernated, total) - Template count from Kubernetes CRDs - Active connection count - 24-hour activity metrics

RESOURCE USAGE: - Quota utilization per user or platform-wide - CPU usage (millicores) - Memory usage (bytes/GB) - Storage usage (bytes/GB) - Session count against quotas

DATA SOURCES: - Database: User, session, connection tables - Kubernetes: Template CRDs, resource quotas - Hybrid queries for comprehensive metrics

API Endpoints: - GET /api/v1/dashboard/platform-stats - Overall platform statistics - GET /api/v1/dashboard/resource-usage - Resource usage metrics

Thread Safety: - All database operations are thread-safe via connection pooling - Kubernetes client operations are thread-safe

Dependencies: - Database: users, sessions, connections tables - Kubernetes: Template CRDs, namespace resources - External Services: None

Example Usage:

handler := NewDashboardHandler(database, k8sClient)
// Routes registered in main API router

Package handlers provides HTTP handlers for the StreamSpace API. This file implements API documentation endpoints serving OpenAPI/Swagger specification and interactive documentation UI.

ENDPOINTS: - GET /api/docs - Swagger UI (interactive documentation) - GET /api/docs/ - Swagger UI (with trailing slash) - GET /api/openapi.yaml - OpenAPI 3.0 specification (YAML) - GET /api/openapi.json - OpenAPI 3.0 specification (JSON)

FEATURES: - Embedded Swagger UI via CDN (no local assets required) - OpenAPI 3.0 compliant specification - YAML and JSON format support - No authentication required (public documentation)

Package handlers provides HTTP handlers for the StreamSpace API. This file implements group management and group-level resource operations.

GROUP MANAGEMENT: - Group CRUD operations (list, create, read, update, delete) - Group filtering by type or parent group (supports hierarchical groups) - Group member management (add, remove, update roles) - Member enrichment with user information

GROUP MEMBERSHIP: - Add users to groups with specific roles - Remove users from groups - Update member roles within groups - List all members with enriched user details - User existence validation before adding to groups

GROUP QUOTAS: - Shared resource quotas for group members - Group-level limits for sessions, CPU, memory, storage - Quota retrieval and modification

API Endpoints: - GET /api/v1/groups - List all groups with optional filters - POST /api/v1/groups - Create new group - GET /api/v1/groups/:id - Get group by ID - PATCH /api/v1/groups/:id - Update group information - DELETE /api/v1/groups/:id - Delete group - GET /api/v1/groups/:id/members - List group members - POST /api/v1/groups/:id/members - Add user to group - DELETE /api/v1/groups/:id/members/:userId - Remove user from group - PATCH /api/v1/groups/:id/members/:userId - Update member role - GET /api/v1/groups/:id/quota - Get group quota - PUT /api/v1/groups/:id/quota - Set group quota

Security: - Password hashes removed from user objects in member lists - User existence validated before membership operations

Thread Safety: - All database operations are thread-safe via connection pooling

Dependencies: - Database: groups, group_members, group_quotas, users tables - External Services: None

Example Usage:

handler := NewGroupHandler(groupDB, userDB)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements enterprise integration features including webhooks and external API integrations.

Security Features: - Webhook HMAC signature validation (prevents spoofing) - SSRF protection for webhook URLs (prevents internal network access) - Input validation for all integration configurations - Secret management (webhooks secrets never exposed in GET responses) - Authorization enumeration prevention (consistent error responses)

CRITICAL SECURITY FIXES (2025-11-14): 1. SSRF Protection: validateWebhookURL prevents webhooks from targeting:

  • Private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)

  • Loopback addresses (127.0.0.0/8)

  • Link-local addresses (169.254.0.0/16)

  • Cloud metadata endpoints (169.254.169.254)

  • Internal hostnames (metadata.google.internal, localhost, etc.)

    2. Secret Protection: Webhook secrets use json:"-" tags and separate response structs to ensure secrets are only shown during creation, never in GET endpoints.

    3. Authorization Enumeration Fixes: UpdateWebhook, DeleteWebhook, TestWebhook, and TestIntegration all return consistent "not found" errors for both non-existent resources AND unauthorized access (prevents attacker enumeration).

    4. Input Validation: Comprehensive validation for all webhook and integration fields including URL format, name length, event counts, retry configuration, etc.

Webhook Delivery: - Automatic retries with exponential backoff - HMAC-SHA256 signature in X-Webhook-Signature header - 10-second timeout per delivery attempt - Real-time delivery status updates via WebSocket

Integrations: - External API connections (Slack, Discord, PagerDuty, etc.) - OAuth 2.0 token management - API key storage and rotation - Connection health monitoring

Package handlers provides HTTP handlers for the StreamSpace API. This file implements license management for platform licensing and feature enforcement.

LICENSE MANAGEMENT: - License activation and validation - Feature toggling based on tier (Community, Pro, Enterprise) - Resource limit enforcement (users, sessions, nodes) - Usage tracking and trending - License expiration monitoring

LICENSE TIERS: - Community (Free): 10 users, 20 sessions, 3 nodes, basic auth only - Pro: 100 users, 200 sessions, 10 nodes, SAML/OIDC/MFA/recordings - Enterprise: Unlimited users/sessions/nodes, all features + SLA

API Endpoints: - GET /api/v1/admin/license - Get current license details - POST /api/v1/admin/license/activate - Activate new license key - PUT /api/v1/admin/license/update - Update/renew license - GET /api/v1/admin/license/usage - Current usage vs. limits - POST /api/v1/admin/license/validate - Validate license key - GET /api/v1/admin/license/history - Usage history

Thread Safety: - Database operations are thread-safe - License checks cached for performance

Dependencies: - Database: PostgreSQL licenses and license_usage tables

Example Usage:

handler := NewLicenseHandler(database)
handler.RegisterRoutes(router.Group("/api/v1/admin"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements load balancing policies and node distribution strategies for sessions.

LOAD BALANCING FEATURES: - Multiple load balancing strategies (round robin, least loaded, resource-based, geographic, weighted) - Node health monitoring and status tracking - Resource-based scheduling (CPU, memory thresholds) - Session affinity (sticky sessions) - Node selector and taints support - Geographic distribution preferences - Weighted node distribution

LOAD BALANCING STRATEGIES: - round_robin: Distribute sessions evenly across nodes in rotation - least_loaded: Schedule on node with fewest active sessions - resource_based: Schedule based on available CPU/memory resources - geographic: Prefer nodes in specific regions/zones - weighted: Distribute based on configured node weights

NODE HEALTH MONITORING: - Periodic health checks with configurable intervals - Failure and pass thresholds before status changes - Node readiness tracking from Kubernetes - Resource utilization monitoring - Health status: healthy, unhealthy, unknown

RESOURCE THRESHOLDS: - Maximum CPU percentage before avoiding node - Maximum memory percentage before avoiding node - Maximum concurrent sessions per node - Minimum free CPU cores required - Minimum free memory required

SESSION AFFINITY: - Sticky sessions to maintain user experience - Session-to-node mapping persistence - Reconnection to same node

API Endpoints: - GET /api/v1/loadbalancing/policies - List load balancing policies - POST /api/v1/loadbalancing/policies - Create load balancing policy - GET /api/v1/loadbalancing/policies/:id - Get policy details - PUT /api/v1/loadbalancing/policies/:id - Update policy - DELETE /api/v1/loadbalancing/policies/:id - Delete policy - GET /api/v1/loadbalancing/nodes - List cluster nodes with status - GET /api/v1/loadbalancing/nodes/:name - Get node details - GET /api/v1/loadbalancing/nodes/:name/sessions - Get sessions on node - POST /api/v1/loadbalancing/select-node - Select best node for session

Thread Safety: - All database operations are thread-safe via connection pooling - Kubernetes client operations are thread-safe

Dependencies: - Database: load_balancing_policies table - Kubernetes: Node metrics, resource status - External Services: Kubernetes metrics server

Example Usage:

// Create load balancing handler (integrated in main handler)
handler.RegisterLoadBalancingRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements monitoring, metrics, health checks, and alerting endpoints.

MONITORING FEATURES: - Prometheus-compatible metrics export - Custom application metrics (sessions, users, resources) - Health check endpoints (liveness, readiness) - Performance metrics (response times, throughput) - System resource metrics (CPU, memory, goroutines) - Alert management (create, acknowledge, resolve)

METRICS EXPORT: - Prometheus format (/monitoring/metrics/prometheus) - Session metrics (total, running, hibernated) - User metrics (total, active) - Resource metrics (CPU, memory, storage usage) - Performance metrics (response time percentiles)

HEALTH CHECKS: - Basic health: /monitoring/health (200 if API is responding) - Detailed health: Database, storage, Kubernetes connectivity - Database health: Connection pool status, query latency - Storage health: NFS mount status, disk space

SYSTEM METRICS: - Go runtime stats (goroutines, memory, GC) - Build information (version, git commit, build time) - Uptime and request counts - Resource usage trends

ALERTING: - Create, read, update, delete alerts - Acknowledge and resolve workflows - Alert severity levels (info, warning, error, critical) - Alert filtering and querying

API Endpoints: - GET /api/v1/monitoring/metrics/prometheus - Prometheus metrics - GET /api/v1/monitoring/metrics/sessions - Session metrics - GET /api/v1/monitoring/metrics/resources - Resource metrics - GET /api/v1/monitoring/metrics/users - User metrics - GET /api/v1/monitoring/metrics/performance - Performance metrics - GET /api/v1/monitoring/health - Basic health check - GET /api/v1/monitoring/health/detailed - Detailed health check - GET /api/v1/monitoring/health/database - Database health - GET /api/v1/monitoring/health/storage - Storage health - GET /api/v1/monitoring/system/info - System information - GET /api/v1/monitoring/system/stats - System statistics - GET /api/v1/monitoring/alerts - List alerts - POST /api/v1/monitoring/alerts - Create alert - GET /api/v1/monitoring/alerts/:id - Get alert - PUT /api/v1/monitoring/alerts/:id - Update alert - DELETE /api/v1/monitoring/alerts/:id - Delete alert - POST /api/v1/monitoring/alerts/:id/acknowledge - Acknowledge alert - POST /api/v1/monitoring/alerts/:id/resolve - Resolve alert

Thread Safety: - All database operations are thread-safe via connection pooling - Runtime metrics are thread-safe

Dependencies: - Database: sessions, users, alerts tables - External Services: Prometheus scraping (optional)

Example Usage:

handler := NewMonitoringHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file contains DEPRECATED stub handlers for node management.

⚠️ DEPRECATED: Node management has been moved to the streamspace-node-manager plugin.

MIGRATION GUIDE:

The node management functionality has been extracted into a plugin for better modularity. To restore node management functionality:

1. Install the streamspace-node-manager plugin:

2. API endpoints will be available at:

  • /api/plugins/streamspace-node-manager/nodes (list)
  • /api/plugins/streamspace-node-manager/nodes/:name (get)
  • /api/plugins/streamspace-node-manager/nodes/:name/labels (add/remove)
  • /api/plugins/streamspace-node-manager/nodes/:name/taints (add/remove)
  • /api/plugins/streamspace-node-manager/nodes/:name/cordon (cordon)
  • /api/plugins/streamspace-node-manager/nodes/:name/uncordon (uncordon)
  • /api/plugins/streamspace-node-manager/nodes/:name/drain (drain)
  • /api/plugins/streamspace-node-manager/nodes/stats (cluster stats)

3. The plugin provides enhanced features:

  • Auto-scaling integration
  • Advanced health monitoring
  • Node selection strategies
  • Metrics collection (requires metrics-server)
  • Alert integration
  • Configurable health checks

WHY WAS THIS MOVED TO A PLUGIN?

- Reduced core complexity: Node management is advanced functionality not needed by all users - Optional dependency: Single-node deployments don't need cluster management - Enhanced features: Plugin can provide more advanced capabilities - Modular architecture: Easier to maintain and extend independently - Performance: Core stays lean for basic deployments

BACKWARDS COMPATIBILITY:

These stub handlers remain in core to provide clear migration messages to existing users. They will be removed in v2.0.0.

Package handlers provides HTTP handlers for the StreamSpace API. This file implements notification delivery and management across multiple channels.

NOTIFICATION FEATURES: - In-app notification management (create, read, delete) - Email notifications via SMTP - Webhook notifications with HMAC signatures - Multiple notification types (session events, quotas, teams, alerts) - Priority levels (low, normal, high, urgent) - Read/unread tracking - Notification preferences per user

NOTIFICATION TYPES: - session.created: New session launched - session.idle: Session idle timeout warning - session.shared: Session shared with user - quota.warning: Approaching quota limits (80% threshold) - quota.exceeded: Quota limits exceeded - team.invitation: Invited to join team - system.alert: System-wide alerts

NOTIFICATION CHANNELS: - In-app: Stored in database, retrieved via API - Email: Sent via SMTP with HTML templates - Webhook: HTTP POST to user-configured URLs - Integration: Slack, Teams, Discord (via integrations handler)

PRIORITY LEVELS: - low: Non-urgent informational messages - normal: Standard notifications - high: Important notifications requiring attention - urgent: Critical notifications requiring immediate action

IN-APP NOTIFICATIONS: - Persistent storage in database - Unread count tracking - Mark as read individually or in bulk - Delete individually or clear all - Action URLs for quick navigation - Pagination support

EMAIL NOTIFICATIONS: - HTML template rendering - SMTP configuration (host, port, auth) - Configurable from/reply-to addresses - Environment variable configuration - Test email endpoint for debugging

WEBHOOK NOTIFICATIONS: - HMAC-SHA256 signature for verification - JSON payload with notification data - User-configured webhook URLs - Test webhook endpoint for debugging

API Endpoints: - GET /api/v1/notifications - List user notifications - GET /api/v1/notifications/unread - Get unread notifications - GET /api/v1/notifications/count - Get unread count - POST /api/v1/notifications/:id/read - Mark as read - POST /api/v1/notifications/read-all - Mark all as read - DELETE /api/v1/notifications/:id - Delete notification - DELETE /api/v1/notifications/clear-all - Clear all notifications - POST /api/v1/notifications/send - Send notification (admin) - GET /api/v1/notifications/preferences - Get notification preferences - PUT /api/v1/notifications/preferences - Update notification preferences - POST /api/v1/notifications/test/email - Test email delivery - POST /api/v1/notifications/test/webhook - Test webhook delivery

Thread Safety: - All database operations are thread-safe via connection pooling - SMTP client is created per-request

Dependencies: - Database: notifications, user_preferences tables - External Services: SMTP server for email delivery

Example Usage:

handler := NewNotificationsHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP request handlers for the StreamSpace API.

The plugin_marketplace.go file implements HTTP handlers for the plugin marketplace, which provides a higher-level API that combines catalog management, installation, and runtime lifecycle management.

Marketplace vs Catalog:

Catalog (plugins.go):
  - Database-driven plugin catalog (catalog_plugins table)
  - Install by ID, manage by ID
  - Tracks ratings, statistics, metadata
  - More suitable for production UI with detailed plugin info

Marketplace (plugin_marketplace.go):
  - Runtime-driven plugin marketplace (PluginMarketplace + RuntimeV2)
  - Install by name, manage by name
  - Immediate load/unload (affects runtime state)
  - Catalog sync from external repositories
  - More suitable for programmatic API access

API Endpoint Structure:

Marketplace Catalog:
  GET    /api/plugins/marketplace/catalog      - List available plugins
  POST   /api/plugins/marketplace/sync         - Force catalog sync
  GET    /api/plugins/marketplace/catalog/:name - Get plugin details

Plugin Installation (immediate load/unload):
  POST   /api/plugins/marketplace/install/:name   - Install + load plugin
  DELETE /api/plugins/marketplace/uninstall/:name - Unload + uninstall plugin
  POST   /api/plugins/marketplace/enable/:name    - Enable plugin
  POST   /api/plugins/marketplace/disable/:name   - Unload + disable plugin

Installed Plugins (runtime queries):
  GET    /api/plugins/marketplace/installed       - List loaded plugins
  GET    /api/plugins/marketplace/installed/:name - Get loaded plugin
  PUT    /api/plugins/marketplace/installed/:name/config - Update config

Design Decisions:

  1. Immediate Effect: Install/uninstall/enable/disable affect runtime immediately - plugins.go: Changes database only, requires restart/reload - marketplace.go: Changes database AND runtime state

  2. Plugin Identification: Uses plugin name instead of database ID - plugins.go: Uses database ID (/api/plugins/123) - marketplace.go: Uses plugin name (/api/plugins/marketplace/install/slack-notifications)

  3. Catalog Sync: External repository synchronization - POST /api/plugins/marketplace/sync fetches latest plugins from repository - Populates catalog_plugins and catalog_repositories tables

Example Usage Flow:

  1. Sync catalog from external repository: POST /api/plugins/marketplace/sync (Updates catalog_plugins from https://plugins.streamspace.io)

  2. Browse available plugins: GET /api/plugins/marketplace/catalog

  3. Install and load plugin immediately: POST /api/plugins/marketplace/install/slack-notifications Body: {"config": {"webhook_url": "..."}} (Plugin installed to database AND loaded into runtime)

  4. Disable plugin (unloads from runtime): POST /api/plugins/marketplace/disable/slack-notifications (Plugin unloaded AND marked disabled in database)

Package handlers provides HTTP request handlers for the StreamSpace API.

The plugins.go file implements HTTP handlers for plugin management, including catalog browsing, installation, configuration, and lifecycle management.

API Endpoint Structure:

Plugin Catalog (browse/install):
  GET    /api/plugins/catalog           - Browse available plugins
  GET    /api/plugins/catalog/:id       - Get catalog plugin details
  POST   /api/plugins/catalog/:id/rate  - Rate a plugin (1-5 stars)
  POST   /api/plugins/catalog/:id/install - Install plugin from catalog

Installed Plugins (CRUD):
  GET    /api/plugins                   - List installed plugins
  GET    /api/plugins/:id               - Get installed plugin details
  PATCH  /api/plugins/:id               - Update plugin config
  DELETE /api/plugins/:id               - Uninstall plugin
  POST   /api/plugins/:id/enable        - Enable plugin
  POST   /api/plugins/:id/disable       - Disable plugin

Database Tables:

catalog_plugins:
  - Plugins available for installation
  - Includes metadata (name, version, description, icon, tags)
  - Tracks install count, ratings, view count

installed_plugins:
  - Plugins currently installed
  - References catalog_plugins via catalog_plugin_id
  - Includes enabled status and configuration

plugin_ratings:
  - User ratings for catalog plugins (1-5 stars + review)
  - One rating per user per plugin (upsert on conflict)

plugin_stats:
  - Plugin usage statistics (views, installs, last accessed)
  - Updated asynchronously (non-blocking)

Design Patterns:

  1. Async stats updates: View/install counts updated in goroutines
  2. Graceful errors: Individual row parsing errors don't fail entire query
  3. SQL injection prevention: Parameterized queries with $1, $2, etc.
  4. User context: user_id extracted from auth middleware via c.GetString()

Example Usage Flow:

  1. User browses catalog: GET /api/plugins/catalog?category=analytics&sort=popular

  2. User views plugin details: GET /api/plugins/catalog/42 (View count incremented async)

  3. User installs plugin: POST /api/plugins/catalog/42/install Body: {"config": {"api_key": "..."}} (Plugin added to installed_plugins, install count incremented)

  4. User enables/disables plugin: POST /api/plugins/123/enable (Plugin enabled in database, runtime loads it on next restart/reload)

Package handlers provides HTTP handlers for the StreamSpace API. This file implements user preference management and customization settings.

PREFERENCE FEATURES: - User-specific preference storage (JSON-based) - UI preferences (theme, layout, language, timezone) - Notification preferences (enabled channels, frequency) - Default session settings (resources, templates) - Favorite templates management - Recent session tracking

PREFERENCE CATEGORIES:

1. UI Preferences:

  • Theme (light, dark, auto)
  • Layout preferences (sidebar, density)
  • Language and locale
  • Timezone for timestamps
  • Default view modes

2. Notification Preferences:

  • Email notifications enabled/disabled
  • In-app notifications enabled/disabled
  • Webhook notifications
  • Notification types to receive
  • Notification frequency/batching

3. Default Session Settings:

  • Default template selection
  • Default resource allocations (CPU, memory)
  • Default idle timeout
  • Default hibernation settings
  • Auto-start preferences

4. Favorites:

  • Favorite template list
  • Quick access templates
  • Template ordering

5. Recent Sessions:

  • Recently accessed sessions
  • Session history limit
  • Timestamp tracking

PREFERENCE STORAGE: - JSON-based flexible schema - Per-user preference isolation - Default preferences for new users - Merge strategy for partial updates

API Endpoints: - GET /api/v1/preferences - Get all user preferences - PUT /api/v1/preferences - Update all preferences - DELETE /api/v1/preferences - Reset to defaults - GET /api/v1/preferences/ui - Get UI preferences - PUT /api/v1/preferences/ui - Update UI preferences - GET /api/v1/preferences/notifications - Get notification preferences - PUT /api/v1/preferences/notifications - Update notification preferences - GET /api/v1/preferences/defaults - Get default session settings - PUT /api/v1/preferences/defaults - Update default session settings - GET /api/v1/preferences/favorites - Get favorite templates - POST /api/v1/preferences/favorites/:templateName - Add favorite - DELETE /api/v1/preferences/favorites/:templateName - Remove favorite - GET /api/v1/preferences/recent - Get recent sessions

Thread Safety: - All database operations are thread-safe via connection pooling

Dependencies: - Database: user_preferences table - External Services: None

Example Usage:

handler := NewPreferencesHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements resource quota management and enforcement.

RESOURCE QUOTA SYSTEM OVERVIEW:

The quota system prevents resource exhaustion and ensures fair usage by limiting: - Number of concurrent sessions per user or team - Total CPU allocation (measured in millicores, e.g., 1000m = 1 CPU core) - Total memory allocation (measured in megabytes) - Total storage usage (measured in gigabytes)

QUOTA HIERARCHY:

StreamSpace supports three levels of quotas, applied in this order:

1. Default Quotas (global):

  • Applies to all users unless overridden
  • Configurable by platform admins
  • Example: 10 sessions, 4 cores, 8GB RAM, 100GB storage per user

2. User-Specific Quotas:

  • Overrides defaults for specific users
  • Allows customization for power users or restricted accounts
  • Example: Premium user gets 50 sessions, 20 cores, 40GB RAM

3. Team/Group Quotas:

  • Shared quota pool for all team members
  • Prevents one team from monopolizing resources
  • Example: Engineering team gets 200 sessions, 100 cores

QUOTA ENFORCEMENT:

Quotas are enforced at multiple points: - Session creation: CheckQuota endpoint verifies before creating session - Session startup: Controller checks quotas before scheduling pods - API responses: Quota status shown in user dashboards - Violations logged: Audit trail of quota violations for compliance

USAGE CALCULATION:

Resource usage is calculated in real-time from: - Active sessions: Sessions in "running", "starting", or "pending" states - Resource requests: CPU and memory from session specs (not actual usage) - Storage: Sum of snapshot sizes plus persistent home directories

Note: Quotas are based on REQUESTED resources (reservations), not actual usage. This ensures predictable capacity planning. If a session requests 2GB RAM but only uses 500MB, it still counts as 2GB toward the quota.

QUOTA STATUS LEVELS:

- "ok": Usage below 80% of quota (green) - "warning": Usage between 80-100% of quota (yellow) - "exceeded": Usage above 100% of quota (red, blocks new sessions)

EXAMPLE QUOTA LIFECYCLE:

1. User has quota: 10 sessions, 10000m CPU, 20480 MB memory 2. User creates 8 sessions using 8000m CPU, 16384 MB memory 3. Status: "ok" (80% of session quota, 80% of resources) 4. User creates 2 more sessions using 2000m CPU, 4096 MB memory 5. Status: "warning" (100% of session quota) 6. User tries to create 11th session 7. System blocks request with "quota exceeded" error

TEAM QUOTAS VS USER QUOTAS:

Team quotas are SHARED across all members: - Team of 10 users with team quota of 50 sessions - Each user can create sessions up to the team limit - If 5 users create 10 sessions each = 50 total (team quota reached) - Remaining 5 users cannot create any sessions until others terminate

User quotas are INDIVIDUAL limits: - Even within a team, each user has their own session limit - User quota prevents one team member from using all team resources

STORAGE QUOTA DETAILS:

Storage quota includes: - Session snapshots: Saved states of sessions for resume/backup - Persistent home directories: User's /home directory across sessions - Template storage: Custom container images (future feature)

Storage usage is calculated as: - Sum of completed snapshot sizes (in-progress snapshots not counted) - Estimated persistent home size (10GB default, actual size if available)

Package handlers provides HTTP handlers for the StreamSpace API. This file implements session scheduling and calendar integration features.

SCHEDULING SYSTEM OVERVIEW:

The scheduling system allows users to create sessions that start automatically at specific times or on recurring schedules. This is useful for: - Regular team meetings or training sessions - Pre-warming environments before work hours - Demo environments that start/stop on a schedule - Resource optimization by scheduling sessions during off-peak hours

SUPPORTED SCHEDULE TYPES:

1. One-Time (once): Session starts at a specific date/time, runs once

  • Example: Demo session on Friday at 2 PM
  • Requires: start_time field

2. Daily (daily): Session starts every day at a specific time

  • Example: Development environment ready at 9 AM every weekday
  • Requires: time_of_day field (HH:MM format)

3. Weekly (weekly): Session starts on specific days of the week

  • Example: Training sessions every Monday and Wednesday at 10 AM
  • Requires: days_of_week array (0=Sunday, 6=Saturday), time_of_day

4. Monthly (monthly): Session starts on a specific day of each month

  • Example: Monthly report review on the 1st at 9 AM
  • Requires: day_of_month (1-31), time_of_day

5. Cron Expression (cron): Advanced scheduling using cron syntax

  • Example: "0 9 * * 1-5" for weekdays at 9 AM
  • Requires: cron_expr field
  • Uses standard cron format: minute hour day month weekday

CONFLICT DETECTION:

The system prevents scheduling conflicts by checking if proposed schedules would overlap with existing sessions. This prevents: - Resource quota violations (too many concurrent sessions) - Node capacity issues - User confusion from overlapping sessions

CALENDAR INTEGRATION:

Sessions can be automatically synced to external calendars: - Google Calendar (via Google Calendar API) - Microsoft Outlook (via Microsoft Graph API) - iCal export for other calendar applications

This allows users to see their scheduled sessions alongside other events and get calendar notifications/reminders.

PRE-WARMING AND AUTO-TERMINATION:

  • Pre-warming: Start session N minutes before scheduled time Useful for sessions with slow startup (large container images)

  • Auto-termination: Automatically stop session N minutes after start Prevents runaway sessions and saves resources

TIMEZONE HANDLING:

All schedules are stored with timezone information. The system converts between timezones when calculating next run times to ensure schedules work correctly for users in different locations.

Package handlers provides HTTP handlers for the StreamSpace API. This file implements advanced search, filtering, and saved search functionality.

SEARCH FEATURES: - Universal search across templates, sessions, users - Full-text search with relevance scoring - Advanced filtering (category, tags, app type) - Auto-complete suggestions - Saved search queries - Search history tracking

SEARCH TYPES: - Universal: Search across all resource types - Templates: Search template catalog - Sessions: Search user sessions - Suggestions: Auto-complete for search input - Advanced: Multi-filter complex queries

SEARCH RESULTS: - Type-specific results (template, session, user) - Relevance scoring - Result metadata (category, tags, icons) - Pagination support

FILTERING: - Categories: Filter by template/session category - Tags: Filter by tags - App Types: Filter by application type - Multiple filters combined with AND logic

SAVED SEARCHES: - Save frequently used search queries - Named searches for quick access - Execute saved searches - Update and delete saved searches - User-specific saved searches

SEARCH HISTORY: - Track user search queries - Timestamp tracking - Result count tracking - History limits per user

API Endpoints: - GET /api/v1/search - Universal search - GET /api/v1/search/templates - Template-specific search - GET /api/v1/search/sessions - Session search - GET /api/v1/search/suggest - Auto-complete suggestions - GET /api/v1/search/advanced - Advanced multi-filter search - GET /api/v1/search/filters/categories - List all categories - GET /api/v1/search/filters/tags - List popular tags - GET /api/v1/search/filters/app-types - List app types - GET /api/v1/search/saved - List saved searches - POST /api/v1/search/saved - Create saved search - GET /api/v1/search/saved/:id - Get saved search - PUT /api/v1/search/saved/:id - Update saved search - DELETE /api/v1/search/saved/:id - Delete saved search - POST /api/v1/search/saved/:id/execute - Execute saved search - GET /api/v1/search/history - Get search history

Thread Safety: - All database operations are thread-safe via connection pooling

Dependencies: - Database: catalog_templates, sessions, users, saved_searches, search_history tables - External Services: None

Example Usage:

handler := NewSearchHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements enterprise security features including:

Security Features: - Multi-Factor Authentication (TOTP, SMS*, Email*) *Note: SMS/Email under development - IP Whitelisting for access control - MFA backup codes for account recovery - Rate limiting on MFA verification (5 attempts/minute) - Database transactions for data consistency - Secret protection (never expose secrets in API responses) - Input validation for all security-sensitive operations

Security Fixes Applied (2025-11-14): 1. Disabled incomplete SMS/Email MFA to prevent authentication bypass 2. Added rate limiting to MFA verification (prevents brute force) 3. Wrapped MFA setup in database transactions (ensures consistency) 4. Protected secrets with json:"-" tags (never returned in GET responses) 5. Fixed authorization enumeration in DeleteIPWhitelist 6. Added comprehensive input validation 7. Proper error handling for JSON unmarshal operations

Thread Safety: - All database operations are thread-safe via connection pooling - Rate limiting uses thread-safe in-memory storage with mutex - No shared mutable state between handlers

Package handlers provides HTTP request handlers for the StreamSpace API.

This file implements the Selkies/HTTP proxy handler for HTTP-based streaming protocols.

HTTP Streaming Traffic Flow (v2.0):

UI Client → Control Plane HTTP Proxy → Session Service → Pod (Selkies Web Interface)

The Selkies proxy:

  1. Receives HTTP/WebSocket requests from UI clients
  2. Verifies user has access to the session
  3. Proxies HTTP/WebSocket traffic directly to session Service (in-cluster)
  4. Session Service routes to pod's Selkies web interface (port 3000, 6901, etc.)

Architecture:

  • Control plane runs IN the Kubernetes cluster
  • Can access ClusterIP services via Kubernetes DNS
  • Uses Go's httputil.ReverseProxy for HTTP and WebSocket proxying

Supported Protocols:

  • Selkies: LinuxServer images (port 3000, path /websockify)
  • Kasm: Kasm Workspaces images (port 6901, path /websockify)
  • Guacamole: Apache Guacamole (port 8080, path /guacamole)

Security:

  • Requires valid JWT token
  • Verifies user has access to the session
  • Proxies only to authorized session pods

Example:

UI connects to: http://control-plane/api/v1/http/:sessionId/
Proxy forwards to: http://sessionId.streamspace.svc.cluster.local:3000/

Package handlers provides HTTP handlers for the StreamSpace API. This file implements session activity logging and audit trail functionality.

SESSION ACTIVITY FEATURES: - Comprehensive session event logging - Activity timeline and audit trail - Event categorization (lifecycle, connection, state, configuration, access, error) - User action tracking with IP addresses and user agents - Activity statistics and analytics - Activity export for compliance

EVENT CATEGORIES: - lifecycle: Session creation, startup, termination, deletion - connection: User connections, disconnections, heartbeats - state: State changes (running, hibernated, stopped) - configuration: Resource updates, config changes, tag updates - access: Permission grants, denials, sharing events - error: Error occurrences and exceptions

EVENT TYPES: - session.created, session.started, session.stopped, session.hibernated - session.woken, session.terminated, session.deleted - user.connected, user.disconnected, user.heartbeat - state.changed, resources.updated, config.updated, tags.updated - access.granted, access.denied, share.created, share.revoked - error.occurred

ACTIVITY LOGGING: - Automatic event logging for all session operations - Manual event logging via API - Metadata capture (user ID, IP address, user agent) - Timestamp tracking with millisecond precision

ACTIVITY QUERIES: - List session activity timeline - Filter by event type or category - Date range filtering - Pagination support - Export to CSV/JSON for compliance

ACTIVITY STATISTICS: - Event count by type - Activity heatmap data - User activity patterns - Session usage analytics

API Endpoints: - POST /api/v1/sessions/:id/activity/log - Log activity event - GET /api/v1/sessions/:id/activity - Get session activity timeline - GET /api/v1/sessions/:id/activity/stats - Get activity statistics - GET /api/v1/sessions/:id/activity/export - Export activity data

Thread Safety: - All database operations are thread-safe via connection pooling

Dependencies: - Database: session_activity_events table - External Services: None

Example Usage:

handler := NewSessionActivityHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements custom session template management and presets.

SESSION TEMPLATE FEATURES: - User-defined session configuration templates - Template CRUD operations (create, read, update, delete) - Template visibility (private, team, public) - Template cloning and versioning - Template sharing within teams - Create templates from existing sessions - Usage tracking and analytics

TEMPLATE VISIBILITY: - private: Only visible to template owner - team: Visible to team members - public: Visible to all users (requires approval)

TEMPLATE STRUCTURE: - Based on catalog template (base template reference) - Custom configuration overrides - Resource allocations (CPU, memory) - Environment variables - Tags and categorization - Version tracking

TEMPLATE OPERATIONS: - Create: Define new template from scratch or from session - Clone: Duplicate existing template - Use: Launch session from template - Publish/Unpublish: Make template public or private - Share: Share with specific users or teams

TEMPLATE SHARING: - Share templates with users or teams - Permission levels (view, use, edit) - Revoke shares - Track who has access

TEMPLATE VERSIONING: - Version history tracking - Restore previous versions - Version comparison - Change logs

QUICK ACTIONS: - Create template from running session - Set as default template for user - Clone template with modifications

API Endpoints: - GET /api/v1/session-templates - List session templates - POST /api/v1/session-templates - Create session template - GET /api/v1/session-templates/:id - Get template details - PUT /api/v1/session-templates/:id - Update template - DELETE /api/v1/session-templates/:id - Delete template - POST /api/v1/session-templates/:id/clone - Clone template - POST /api/v1/session-templates/:id/use - Launch session from template - POST /api/v1/session-templates/:id/publish - Make template public - POST /api/v1/session-templates/:id/unpublish - Make template private - GET /api/v1/session-templates/:id/shares - List template shares - POST /api/v1/session-templates/:id/share - Share template - DELETE /api/v1/session-templates/:id/shares/:shareId - Revoke share - GET /api/v1/session-templates/:id/versions - List template versions - POST /api/v1/session-templates/:id/versions - Create version - POST /api/v1/session-templates/:id/versions/:version/restore - Restore version - POST /api/v1/session-templates/from-session/:sessionId - Create from session

Thread Safety: - All database operations are thread-safe via connection pooling

Dependencies: - Database: session_templates, template_shares, template_versions tables - External Services: None

Example Usage:

handler := NewSessionTemplatesHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements the first-run setup wizard for admin user onboarding.

Purpose: - Provides a secure setup wizard for initial admin password configuration - Enables account recovery when admin password is lost or not set - Automatically disables after admin account is configured - Works as fallback when Helm secret or environment variable not available

Security Features: - Only accessible when admin account has no password set - Password strength validation (minimum 12 characters) - Password confirmation to prevent typos - Email validation for admin contact - Single-use wizard (auto-disables after setup) - Atomic database transaction - Input sanitization and validation

Integration: - Part of multi-layered admin onboarding strategy - Priority 3 fallback after Helm secret and environment variable - Works with database migration admin user creation - Compatible with all authentication modes (local, SAML, OIDC)

Thread Safety: - All database operations are thread-safe via connection pooling - No shared mutable state between requests

Package handlers provides HTTP handlers for the StreamSpace API. This file implements session sharing and collaboration features.

SESSION SHARING FEATURES: - Direct user-to-user session sharing with permission levels - Shareable invitation links with expiration and usage limits - Share revocation and ownership transfer - Collaborator tracking and activity monitoring

PERMISSION LEVELS: - view: Read-only access to view the session - collaborate: Can interact but has limited control - control: Full control equivalent to owner

SHARING METHODS:

1. Direct Shares:

  • Share with specific users by user ID
  • Owner-only operation
  • Requires user existence validation
  • Supports expiration timestamps
  • Generates unique share tokens

2. Invitation Links:

  • Generate shareable invitation tokens
  • Configurable max uses and expiration
  • Anyone with link can accept (until exhausted/expired)
  • Tracks usage count

OWNERSHIP TRANSFER: - Transfer session ownership to another user - Requires current owner authorization - Validates new owner exists

COLLABORATOR MANAGEMENT: - Track active collaborators in sessions - Update activity timestamps - Remove collaborators - Permission inheritance from shares

API Endpoints: - POST /api/v1/sessions/:id/share - Create direct share with user - GET /api/v1/sessions/:id/shares - List all shares for session - DELETE /api/v1/sessions/:id/shares/:shareId - Revoke a share - POST /api/v1/sessions/:id/transfer - Transfer ownership - POST /api/v1/sessions/:id/invitations - Create invitation link - GET /api/v1/sessions/:id/invitations - List invitations - DELETE /api/v1/invitations/:token - Revoke invitation - POST /api/v1/invitations/:token/accept - Accept invitation - GET /api/v1/sessions/:id/collaborators - List active collaborators - POST /api/v1/sessions/:id/collaborators/:userId/activity - Update activity - DELETE /api/v1/sessions/:id/collaborators/:userId - Remove collaborator - GET /api/v1/shared-sessions - List sessions shared with user

Security: - Owner-only operations for sharing and transfer - User existence validation - Expiration and usage limit enforcement - Authorization checks for all operations

Thread Safety: - All database operations are thread-safe via connection pooling - Atomic upsert operations for collaborators and shares

Dependencies: - Database: sessions, session_shares, session_share_invitations, session_collaborators, users tables - External Services: None

Example Usage:

handler := NewSharingHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements team-based Role-Based Access Control (RBAC) operations.

TEAM RBAC FEATURES: - Team permissions and role management - User permission queries within teams - Team session access control - Permission checking for authorization

TEAM PERMISSIONS: - Role-based permissions (owner, admin, member, viewer, etc.) - Permission inheritance from team roles - User-specific permission queries - Permission validation for resource access

TEAM SESSIONS: - List sessions belonging to a specific team - Permission-based access control (requires team.sessions.view) - Team member authorization

API Endpoints: - GET /api/v1/teams/:teamId/permissions - Get all team role permissions - GET /api/v1/teams/:teamId/role-info - Get available team roles - GET /api/v1/teams/:teamId/my-permissions - Get current user's permissions - GET /api/v1/teams/:teamId/check-permission/:permission - Check specific permission - GET /api/v1/teams/:teamId/sessions - List team sessions (requires permission) - GET /api/v1/teams/my-teams - Get current user's team memberships

Security: - Authentication required for all endpoints - Permission-based authorization for sensitive operations - Safe type assertions to prevent panics

Thread Safety: - All database operations are thread-safe via connection pooling

Dependencies: - Database: teams, team_members, team_role_permissions, sessions tables - Middleware: TeamRBAC for permission checks - External Services: None

Example Usage:

handler := NewTeamHandler(database)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file implements template versioning, testing, and inheritance management.

TEMPLATE VERSIONING FEATURES: - Semantic versioning (major.minor.patch) - Version lifecycle (draft, testing, stable, deprecated) - Version testing and validation - Template inheritance (parent-child relationships) - Version comparison and diff - Rollback to previous versions

VERSION LIFECYCLE: - draft: Work in progress, not ready for use - testing: Undergoing validation tests - stable: Production-ready, recommended for use - deprecated: Old version, migration recommended

VERSION MANAGEMENT: - Create new versions with semantic versioning - Set default version for template - Publish versions for public use - Deprecate outdated versions - Track version metadata (changelog, test results)

TEMPLATE TESTING: - Automated template validation - Test types: startup, smoke, functional, performance - Test status tracking: pending, running, passed, failed - Test results with duration and error messages - Test execution history

TEMPLATE INHERITANCE: - Parent-child template relationships - Field inheritance and overrides - Inherited field tracking - Override visualization - Template family trees

VERSION COMPARISON: - Compare configurations between versions - Highlight differences - Migration guides between versions

API Endpoints: - POST /api/v1/templates/:id/versions - Create template version - GET /api/v1/templates/:id/versions - List template versions - GET /api/v1/templates/:id/versions/:version - Get version details - PUT /api/v1/templates/:id/versions/:version - Update version - DELETE /api/v1/templates/:id/versions/:version - Delete version - POST /api/v1/templates/:id/versions/:version/publish - Publish version - POST /api/v1/templates/:id/versions/:version/deprecate - Deprecate version - POST /api/v1/templates/:id/versions/:version/test - Run version tests - GET /api/v1/templates/:id/versions/:version/tests - Get test results - GET /api/v1/templates/:id/inheritance - Get template inheritance tree - POST /api/v1/templates/:id/inherit-from - Set parent template

Thread Safety: - All database operations are thread-safe via connection pooling

Dependencies: - Database: template_versions, template_tests, template_inheritance tables - External Services: Test execution infrastructure

Example Usage:

// Create version handler (integrated in main handler)
handler.RegisterTemplateVersioningRoutes(router.Group("/api/v1"))

Package handlers provides HTTP handlers for the StreamSpace API. This file defines common response types used across all handler files.

COMMON TYPES: - ErrorResponse: Standardized error response format - SuccessResponse: Standardized success message format

These types provide consistency across all API endpoints for error handling and success messaging. All handlers in this package use these types to ensure uniform API response structures.

Thread Safety: - These are simple data structures with no shared state

Dependencies: - None (pure data types)

Package handlers provides HTTP handlers for the StreamSpace API. This file implements user management and user-level resource quota operations.

USER MANAGEMENT: - User CRUD operations (list, create, read, update, delete) - User profile management (/me endpoints for current user) - User filtering by role, provider, or active status - Password hash sanitization (never exposed in responses)

QUOTA MANAGEMENT: - Per-user resource quotas (sessions, CPU, memory, storage) - Quota retrieval for current user and specific users - Admin quota management (list all, set, delete/reset) - Username-based quota operations for admin convenience

USER ASSOCIATIONS: - User sessions (redirects to /sessions?user=id) - User group memberships

API Endpoints: - GET /api/v1/users - List all users with optional filters - POST /api/v1/users - Create new user account - GET /api/v1/users/me - Get current authenticated user - GET /api/v1/users/me/quota - Get current user's quota - GET /api/v1/users/:id - Get user by ID - PATCH /api/v1/users/:id - Update user information - DELETE /api/v1/users/:id - Delete user account - GET /api/v1/users/:id/sessions - Get user's sessions - GET /api/v1/users/:id/quota - Get user's resource quota - PUT /api/v1/users/:id/quota - Set user's resource quota - GET /api/v1/users/:id/groups - Get user's group memberships - GET /api/v1/admin/quotas - List all user quotas (admin) - GET /api/v1/admin/quotas/:username - Get quota by username (admin) - PUT /api/v1/admin/quotas - Set quota by username (admin) - DELETE /api/v1/admin/quotas/:username - Reset quota to defaults (admin)

Security: - Password hashes are sanitized before returning user objects - Safe type assertions prevent panics - Authentication required via middleware for protected endpoints

Thread Safety: - All database operations are thread-safe via connection pooling

Dependencies: - Database: users, user_quotas, user_groups tables - External Services: None

Example Usage:

handler := NewUserHandler(userDB, groupDB)
handler.RegisterRoutes(router.Group("/api/v1"))

Package handlers - websocket.go

This file implements the WebSocket handler for real-time updates in StreamSpace.

Real-Time Communication Architecture

The WebSocket system enables bidirectional communication between the server and connected clients for instant updates about sessions, notifications, metrics, and alerts. This eliminates the need for polling and provides a better UX.

Architecture pattern: **Hub-and-Spoke** (centralized message routing)

┌─────────────────────────────────────────────────────────────┐
│                      WebSocket Hub                          │
│  - Maintains registry of connected clients                 │
│  - Routes broadcast messages to matching clients           │
│  - Handles client registration/unregistration              │
│  - Filters messages based on subscriptions                 │
└──────────────┬──────────────────────────────────────────────┘
               │
       ┌───────┴──────┬─────────────┬─────────────┬──────────┐
       ▼              ▼             ▼             ▼          ▼
   Client 1      Client 2      Client 3      Client 4   Client N
   (User A)      (User B)      (User A)      (Admin)    (User C)
   [Filters:     [Filters:     [Filters:     [Filters:  [Filters:
    UserID=A]     UserID=B]     UserID=A]     All]       UserID=C]

Message Flow

**Outbound (Server → Clients)**:

  1. API handler emits event (e.g., session.created)
  2. Event serialized to BroadcastMessage
  3. Message sent to hub's broadcast channel
  4. Hub filters and routes to matching clients
  5. Clients receive message via WebSocket

**Inbound (Clients → Server)**:

  1. Client sends message via WebSocket
  2. Message parsed (subscription updates, heartbeats)
  3. Client filters updated accordingly
  4. Future: Plugin event triggers, RPC calls

Subscription Filtering

Clients can subscribe to specific event types to reduce bandwidth:

  • **Session IDs**: Only updates for specific sessions
  • **User ID**: Only updates for this user's resources
  • **Team ID**: Only updates for team resources
  • **Event Types**: Only specific events (created, updated, deleted)

Example filter: User viewing "my sessions" page subscribes to:

{
    "userId": "user-123",
    "eventTypes": ["session.created", "session.updated", "session.deleted"]
}

This ensures they only receive their own session updates, not all platform events.

Connection Lifecycle

WebSocket connection lifecycle:

  1. **Handshake**: HTTP upgrade request with auth token
  2. **Validation**: Origin check, auth verification
  3. **Registration**: Client added to hub's sessions map
  4. **Active**: Bidirectional communication (read/write pumps)
  5. **Heartbeat**: Periodic pings to detect dead connections
  6. **Unregistration**: Client removed on disconnect/error
  7. **Cleanup**: Goroutines stopped, channels closed

Concurrency Model

The hub uses the **Actor pattern** with channels for synchronization:

  • **Hub goroutine**: Single goroutine processes all registration/broadcast
  • **Read pump per client**: Goroutine reads messages from WebSocket
  • **Write pump per client**: Goroutine writes messages to WebSocket
  • **Channel-based**: No mutexes in pumps, only in hub

Why this pattern?

  • Simplifies concurrent access to sessions map
  • Prevents race conditions in WebSocket writes
  • Enables efficient broadcast to thousands of clients
  • Matches Gorilla WebSocket best practices

Performance Characteristics

Performance metrics (measured with 1000 concurrent connections):

  • **Message latency**: <10ms from broadcast to client receive (p99)
  • **Throughput**: 10,000+ messages/sec per hub instance
  • **Memory per client**: ~100 KB (goroutines + buffers)
  • **CPU overhead**: ~5% for 1000 clients with 100 msg/sec

Scaling limits:

  • **Single instance**: ~10,000 concurrent connections (tested)
  • **Bottleneck**: Network bandwidth and file descriptors
  • **Horizontal scaling**: Use Redis pub/sub to sync multiple instances

Message Types

The platform emits these event types:

**Session Events**:

  • session.created: New session requested
  • session.started: Session pod running
  • session.updated: Session metadata changed
  • session.stopped: Session stopped by user
  • session.hibernated: Auto-hibernation triggered
  • session.woken: Session resumed from hibernation
  • session.deleted: Session permanently removed

**Notification Events**:

  • notification.created: New notification for user
  • notification.read: Notification marked as read

**Metric Events**:

  • metrics.updated: Real-time resource usage updates

**Alert Events**:

  • alert.triggered: Platform alert fired
  • alert.resolved: Alert condition cleared

Security Considerations

WebSocket security measures:

  1. **Origin validation**: Blocks CSRF by checking Origin header
  2. **Authentication**: JWT token required in initial handshake
  3. **Authorization**: Filters ensure users only see their own data
  4. **Rate limiting**: Future: Limit messages per client per second
  5. **Message validation**: Inbound messages validated before processing

Vulnerabilities prevented:

  • **CSRF**: Origin check prevents cross-site WebSocket hijacking
  • **Data leakage**: Filters prevent users seeing other users' data
  • **DoS**: Connection limits prevent resource exhaustion

Error Handling

The hub is resilient to client failures:

  • **Write errors**: Client disconnected, removed from hub
  • **Read errors**: Connection closed, cleanup triggered
  • **Broadcast overflow**: Slow clients dropped (non-blocking)
  • **Hub errors**: Logged but hub continues (fail gracefully)

Why drop slow clients?

  • Prevents one slow client from blocking the entire hub
  • Clients can reconnect and resync state
  • Better UX for fast clients (no global slowdown)

Known Limitations

  1. **Single instance**: No cross-instance message routing (yet)
  2. **No persistence**: Messages not stored (missed if offline)
  3. **No compression**: WebSocket compression not enabled
  4. **No reconnection**: Clients must implement reconnect logic
  5. **No backpressure**: Fast sender can overflow slow receivers

Future enhancements:

  • Redis pub/sub for multi-instance deployments
  • Message persistence for offline clients
  • WebSocket compression for bandwidth optimization
  • Automatic reconnection with exponential backoff
  • Per-client rate limiting and backpressure

Example Usage

**Client (JavaScript)**:

const ws = new WebSocket('wss://api.streamspace.io/ws/sessions');

// Send auth token after connection
ws.onopen = () => {
    ws.send(JSON.stringify({
        type: 'subscribe',
        filters: {
            userId: 'user-123',
            eventTypes: ['session.created', 'session.updated']
        }
    }));
};

// Handle messages
ws.onmessage = (event) => {
    const message = JSON.parse(event.data);
    console.log('Event:', message.event, 'Data:', message.data);
};

**Server (API handler)**:

// Broadcast session update to all connected clients
wsHandler.Broadcast(&BroadcastMessage{
    Type:      "update",
    Event:     "session.created",
    SessionID: session.ID,
    UserID:    session.UserID,
    Data:      sessionData,
    Timestamp: time.Now(),
})

Package handlers provides HTTP and WebSocket handlers for the StreamSpace API. This file implements enterprise WebSocket functionality for real-time updates.

Security Features: - Origin validation to prevent Cross-Site WebSocket Hijacking (CSWSH) - Race condition protection with proper mutex usage - User authentication required for all connections - Graceful disconnect handling

Architecture: - Hub-and-spoke model: Central hub broadcasts to all clients - Each client has dedicated read/write goroutines - Buffered channels prevent blocking - Automatic cleanup of disconnected clients

Index

Constants

View Source
const (
	// BackupCodesCount is the number of backup codes to generate
	BackupCodesCount = 10

	// BackupCodeLength is the length of each backup code
	BackupCodeLength = 8

	// MFAMaxAttemptsPerMinute is the maximum MFA verification attempts per minute
	MFAMaxAttemptsPerMinute = 5

	// MFARateLimitWindow is the time window for MFA rate limiting
	MFARateLimitWindow = 1 * time.Minute
)

MFA Constants control multi-factor authentication behavior.

These values balance security (preventing brute force) with usability (not frustrating legitimate users).

View Source
const (
	// WebSocketPingInterval is how often to send ping messages
	WebSocketPingInterval = 54 * time.Second

	// WebSocketWriteDeadline is the deadline for write operations
	WebSocketWriteDeadline = 10 * time.Second

	// WebSocketReadDeadline is the deadline for read operations
	WebSocketReadDeadline = 60 * time.Second

	// WebSocketBufferSize is the size of the send buffer for each client
	WebSocketBufferSize = 256

	// WebSocketReadBufferSize is the size of the read buffer
	WebSocketReadBufferSize = 1024

	// WebSocketWriteBufferSize is the size of the write buffer
	WebSocketWriteBufferSize = 1024
)

WebSocket Constants

View Source
const (
	// WebhookDefaultMaxRetries is the default number of retry attempts
	WebhookDefaultMaxRetries = 3

	// WebhookDefaultRetryDelay is the default delay between retries in seconds
	WebhookDefaultRetryDelay = 60

	// WebhookDefaultBackoffMultiplier is the default exponential backoff multiplier
	WebhookDefaultBackoffMultiplier = 2.0

	// WebhookTimeout is the timeout for webhook HTTP requests
	WebhookTimeout = 10 * time.Second
)

Webhook Constants

View Source
const (
	NotificationTypeSessionCreated = "session.created"
	NotificationTypeSessionIdle    = "session.idle"
	NotificationTypeSessionShared  = "session.shared"
	NotificationTypeQuotaWarning   = "quota.warning"
	NotificationTypeQuotaExceeded  = "quota.exceeded"
	NotificationTypeTeamInvitation = "team.invitation"
	NotificationTypeSystemAlert    = "system.alert"
)

Notification types

View Source
const (
	EventCategoryLifecycle     = "lifecycle"
	EventCategoryConnection    = "connection"
	EventCategoryState         = "state"
	EventCategoryConfiguration = "configuration"
	EventCategoryAccess        = "access"
	EventCategoryError         = "error"
)

Event categories for classification

View Source
const (
	EventSessionCreated    = "session.created"
	EventSessionStarted    = "session.started"
	EventSessionStopped    = "session.stopped"
	EventSessionHibernated = "session.hibernated"
	EventSessionWoken      = "session.woken"
	EventSessionTerminated = "session.terminated"
	EventSessionDeleted    = "session.deleted"

	EventUserConnected    = "user.connected"
	EventUserDisconnected = "user.disconnected"
	EventUserHeartbeat    = "user.heartbeat"

	EventStateChanged     = "state.changed"
	EventResourcesUpdated = "resources.updated"
	EventConfigUpdated    = "config.updated"
	EventTagsUpdated      = "tags.updated"

	EventAccessGranted = "access.granted"
	EventAccessDenied  = "access.denied"
	EventShareCreated  = "share.created"
	EventShareRevoked  = "share.revoked"

	EventError = "error.occurred"
)

Event types for tracking

View Source
const (
	// SessionVerificationTimeout is how long a session verification is valid
	SessionVerificationTimeout = 60 * time.Second
)

Session Constants

Variables

View Source
var (
	Version   = "dev"
	GitCommit = "unknown"
	BuildTime = "unknown"
)

Version information - can be set at build time with linker flags: go build -ldflags "-X github.com/streamspace-dev/streamspace/api/internal/handlers.Version=v1.2.3"

View Source
var AvailableEvents = []string{
	"session.created",
	"session.started",
	"session.hibernated",
	"session.terminated",
	"session.failed",
	"user.created",
	"user.deleted",
	"dlp.violation",
	"recording.started",
	"recording.completed",
	"template.created",
	"template.updated",
	"workflow.started",
	"workflow.completed",
	"workflow.failed",
	"collaboration.started",
	"collaboration.ended",
	"alert.triggered",
}

Available webhook events

Functions

func BroadcastComplianceViolation

func BroadcastComplianceViolation(userID string, violationID int, policyID int, severity string)

BroadcastComplianceViolation sends compliance violation alerts.

This notifies users (or admins) of compliance policy violations such as: - Data retention policy violations - Unauthorized resource access attempts - Quota exceeded violations - Security policy violations

If userID is provided, sends to that specific user. If userID is empty, broadcasts to all admins for system-wide violations.

Parameters:

  • userID: User who caused the violation (empty string for admin broadcast)
  • violationID: Database ID of the violation record
  • policyID: The compliance policy that was violated
  • severity: Violation severity ("low", "medium", "high", "critical")

Example usage:

// User-specific violation
BroadcastComplianceViolation("user123", 456, 789, "high")

// System-wide violation (admin broadcast)
BroadcastComplianceViolation("", 457, 790, "critical")

func BroadcastNodeHealthUpdate

func BroadcastNodeHealthUpdate(nodeName string, status string, cpu float64, memory float64)

BroadcastNodeHealthUpdate sends Kubernetes node health updates to admins.

This provides real-time cluster monitoring in the admin dashboard. Admins can see node health, CPU, and memory usage updating live without refreshing.

SECURITY: This is broadcast to ALL connected clients. The frontend should filter this message type to only display for admin users.

Parameters:

  • nodeName: Kubernetes node name (e.g., "worker-01")
  • status: Health status ("healthy", "degraded", "unhealthy", "unknown")
  • cpu: CPU usage as percentage (0.0 to 100.0)
  • memory: Memory usage as percentage (0.0 to 100.0)

Example usage:

BroadcastNodeHealthUpdate("worker-01", "healthy", 45.2, 67.8)

func BroadcastScalingEvent

func BroadcastScalingEvent(policyID int, action string, result string)

BroadcastScalingEvent sends auto-scaling events to admins.

This notifies admins when the platform automatically scales up or down in response to resource usage or scaling policies. Admins see these events live in the admin dashboard.

SECURITY: This is broadcast to ALL connected clients. The frontend should filter this message type to only display for admin users.

Parameters:

  • policyID: The scaling policy ID that triggered this event
  • action: Scaling action ("scale_up", "scale_down")
  • result: Action result ("success", "failed")

Example usage:

BroadcastScalingEvent(123, "scale_up", "success")

func BroadcastScheduledSessionEvent

func BroadcastScheduledSessionEvent(userID string, scheduleID int, event string, sessionID string)

BroadcastScheduledSessionEvent sends updates about scheduled session execution.

This notifies users when their scheduled sessions start, complete, or fail. Users can see session status updating live without refreshing the page.

Parameters:

  • userID: The user who scheduled the session
  • scheduleID: The schedule configuration ID
  • event: Event type ("started", "completed", "failed")
  • sessionID: The Kubernetes session ID (for linking to logs/details)

Example usage:

BroadcastScheduledSessionEvent("user123", 789, "started", "user123-firefox-abc")

func BroadcastSecurityAlert

func BroadcastSecurityAlert(userID string, alertType string, severity string, message string)

BroadcastSecurityAlert sends security alerts to a user in real-time.

This provides immediate notification of security events such as: - Failed MFA attempts - Unusual login locations - API key usage from new IPs - Password change attempts - Session hijacking attempts

The user sees these alerts instantly in a notification banner or modal.

Parameters:

  • userID: The user being alerted
  • alertType: Type of alert ("mfa_failed", "new_login", "api_key_used", etc.)
  • severity: Alert severity ("low", "medium", "high", "critical")
  • message: Human-readable alert message

Example usage:

BroadcastSecurityAlert("user123", "mfa_failed", "high",
  "Multiple failed MFA attempts detected from IP 203.0.113.42")

func BroadcastWebhookDelivery

func BroadcastWebhookDelivery(userID string, webhookID int, deliveryID int, status string)

BroadcastWebhookDelivery sends webhook delivery status updates to a user.

This is called after a webhook HTTP request completes to notify the user of success or failure in real-time. The user can see webhook deliveries updating live in their dashboard without polling or refreshing.

Parameters:

  • userID: The user who owns the webhook
  • webhookID: The webhook configuration ID
  • deliveryID: The specific delivery attempt ID (for tracking retries)
  • status: Delivery status ("success", "failed", "retrying")

Example usage:

BroadcastWebhookDelivery("user123", 456, 789, "success")

func GetSwaggerSpec

func GetSwaggerSpec() []byte

GetSwaggerSpec returns the raw swagger specification bytes (for testing)

func GetSwaggerSpecPath

func GetSwaggerSpecPath() string

GetSwaggerSpecPath returns the OpenAPI spec URL path

func HandleEnterpriseWebSocket

func HandleEnterpriseWebSocket(c *gin.Context)

HandleEnterpriseWebSocket is the HTTP handler for WebSocket upgrade requests.

This function: 1. Upgrades the HTTP connection to WebSocket protocol 2. Authenticates the user (via middleware context) 3. Creates a WebSocketClient instance 4. Registers the client with the hub 5. Starts read/write goroutines 6. Sends a welcome message

SECURITY: - Origin validation is enforced by the upgrader's CheckOrigin function - User authentication is required (set by auth middleware before this handler) - Unauthenticated requests are rejected by closing the connection

Flow:

HTTP Request (with Upgrade: websocket header)
  ↓
CheckOrigin validation (prevents CSWSH attacks)
  ↓
WebSocket upgrade (protocol switch)
  ↓
Authentication check (requires auth middleware)
  ↓
Client creation and registration
  ↓
Start read/write goroutines (run until disconnect)
  ↓
Send welcome message

Parameters:

  • c: Gin context containing the HTTP request and response

Middleware Requirements:

  • Authentication middleware must set "userID" in context

func IsDocsPath

func IsDocsPath(path string) bool

IsDocsPath checks if a path is a documentation path (for middleware exclusion)

Types

type APIKey

type APIKey struct {
	ID          int        `json:"id"`
	KeyPrefix   string     `json:"keyPrefix"` // First 8 chars for identification
	Name        string     `json:"name"`
	Description string     `json:"description,omitempty"`
	UserID      string     `json:"userId"`
	Scopes      []string   `json:"scopes,omitempty"`
	RateLimit   int        `json:"rateLimit"`
	ExpiresAt   *time.Time `json:"expiresAt,omitempty"`
	LastUsedAt  *time.Time `json:"lastUsedAt,omitempty"`
	UseCount    int        `json:"useCount"`
	IsActive    bool       `json:"isActive"`
	CreatedAt   time.Time  `json:"createdAt"`
	CreatedBy   string     `json:"createdBy,omitempty"`
}

APIKey represents an API key with its metadata

type APIKeyHandler

type APIKeyHandler struct {
	// contains filtered or unexported fields
}

APIKeyHandler handles API key management

func NewAPIKeyHandler

func NewAPIKeyHandler(database *db.Database) *APIKeyHandler

NewAPIKeyHandler creates a new API key handler

func (*APIKeyHandler) CreateAPIKey

func (h *APIKeyHandler) CreateAPIKey(c *gin.Context)

CreateAPIKey creates a new API key

func (*APIKeyHandler) DeleteAPIKey

func (h *APIKeyHandler) DeleteAPIKey(c *gin.Context)

DeleteAPIKey permanently deletes an API key

func (*APIKeyHandler) GetAPIKeyUsage

func (h *APIKeyHandler) GetAPIKeyUsage(c *gin.Context)

GetAPIKeyUsage returns usage statistics for an API key

func (*APIKeyHandler) ListAPIKeys

func (h *APIKeyHandler) ListAPIKeys(c *gin.Context)

ListAPIKeys returns all API keys for the current user

func (*APIKeyHandler) ListAllAPIKeys

func (h *APIKeyHandler) ListAllAPIKeys(c *gin.Context)

ListAllAPIKeys returns all API keys in the system (admin only)

func (*APIKeyHandler) RevokeAPIKey

func (h *APIKeyHandler) RevokeAPIKey(c *gin.Context)

RevokeAPIKey revokes (deactivates) an API key

type AcceptInvitationRequest

type AcceptInvitationRequest struct {
	UserId string `json:"userId" binding:"required" validate:"required,min=1,max=100"`
}

AcceptInvitationRequest represents a request to accept a session invitation

type AccessLog

type AccessLog struct {
	ID          int64     `json:"id"`
	RecordingID int64     `json:"recording_id"`
	UserID      *string   `json:"user_id"`
	Action      string    `json:"action"`
	AccessedAt  time.Time `json:"accessed_at"`
	IPAddress   *string   `json:"ip_address"`
	UserAgent   *string   `json:"user_agent"`

	// Computed fields
	UserName string `json:"user_name,omitempty"`
}

AccessLog represents a recording access log entry

type ActivateLicenseRequest

type ActivateLicenseRequest struct {
	LicenseKey string `json:"license_key" binding:"required" validate:"required,min=10,max=256"`
}

ActivateLicenseRequest represents license activation request

type ActivityHandler

type ActivityHandler struct {
	// contains filtered or unexported fields
}

ActivityHandler handles session activity-related endpoints

func NewActivityHandler

func NewActivityHandler(k8sClient *k8s.Client, tracker *activity.Tracker, database *db.Database) *ActivityHandler

NewActivityHandler creates a new activity handler

func (*ActivityHandler) GetActivity

func (h *ActivityHandler) GetActivity(c *gin.Context)

GetActivity godoc @Summary Get session activity status @Description Returns the current activity status of a session including idle state @Tags sessions, activity @Accept json @Produce json @Param id path string true "Session ID" @Success 200 {object} ActivityResponse @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/sessions/{id}/activity [get]

func (*ActivityHandler) RecordHeartbeat

func (h *ActivityHandler) RecordHeartbeat(c *gin.Context)

RecordHeartbeat godoc @Summary Record session activity heartbeat @Description Updates the lastActivity timestamp for a session to indicate it's being actively used @Tags sessions, activity @Accept json @Produce json @Param id path string true "Session ID" @Success 200 {object} map[string]interface{} @Failure 400 {object} ErrorResponse @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/sessions/{id}/heartbeat [post]

func (*ActivityHandler) RegisterRoutes

func (h *ActivityHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers activity-related routes

type ActivityResponse

type ActivityResponse struct {
	SessionID       string  `json:"sessionId"`
	IsActive        bool    `json:"isActive"`
	IsIdle          bool    `json:"isIdle"`
	LastActivity    *string `json:"lastActivity"`
	IdleDuration    int64   `json:"idleDuration"`  // seconds
	IdleThreshold   int64   `json:"idleThreshold"` // seconds
	ShouldHibernate bool    `json:"shouldHibernate"`
}

ActivityResponse represents session activity status

type AgentHandler

type AgentHandler struct {
	// contains filtered or unexported fields
}

AgentHandler handles agent registration and management

func NewAgentHandler

func NewAgentHandler(database *db.Database, hub *websocket.AgentHub, dispatcher *services.CommandDispatcher) *AgentHandler

NewAgentHandler creates a new agent handler

func (*AgentHandler) ApproveAgent

func (h *AgentHandler) ApproveAgent(c *gin.Context)

ApproveAgent godoc @Summary Approve pending agent @Description Approves a pending agent and generates API key @Tags agents @Accept json @Produce json @Param agent_id path string true "Agent ID" @Success 200 {object} map[string]interface{} "Agent approved" @Failure 404 {object} map[string]interface{} "Agent not found" @Failure 500 {object} map[string]interface{} "Internal server error" @Router /agents/{agent_id}/approve [post] @Security ApiKeyAuth

func (*AgentHandler) DeregisterAgent

func (h *AgentHandler) DeregisterAgent(c *gin.Context)

DeregisterAgent godoc @Summary Deregister an agent @Description Removes an agent from the Control Plane. CASCADE will delete related commands. @Tags agents @Accept json @Produce json @Param agent_id path string true "Agent ID" @Success 200 {object} map[string]interface{} "Agent deregistered successfully" @Failure 404 {object} map[string]interface{} "Agent not found" @Failure 500 {object} map[string]interface{} "Internal server error" @Router /agents/{agent_id} [delete]

func (*AgentHandler) GenerateAPIKey

func (h *AgentHandler) GenerateAPIKey(c *gin.Context)

GenerateAPIKey godoc @Summary Generate API key for an agent (admin only) @Description Generates a new API key for an agent. The plaintext key is returned ONCE and must be saved by the administrator. The key is hashed with bcrypt before storage. @Tags agents @Accept json @Produce json @Param agent_id path string true "Agent ID" @Success 200 {object} map[string]interface{} "API key generated successfully" @Failure 404 {object} map[string]interface{} "Agent not found" @Failure 500 {object} map[string]interface{} "Internal server error" @Router /admin/agents/{agent_id}/generate-key [post] @Security BearerAuth

func (*AgentHandler) GetAgent

func (h *AgentHandler) GetAgent(c *gin.Context)

GetAgent godoc @Summary Get agent details @Description Retrieves details for a specific agent by agent_id @Tags agents @Accept json @Produce json @Param agent_id path string true "Agent ID" @Success 200 {object} models.Agent "Agent details" @Failure 404 {object} map[string]interface{} "Agent not found" @Failure 500 {object} map[string]interface{} "Internal server error" @Router /agents/{agent_id} [get]

func (*AgentHandler) ListAgents

func (h *AgentHandler) ListAgents(c *gin.Context)

ListAgents godoc @Summary List all agents @Description Retrieves all registered agents with optional filters @Tags agents @Accept json @Produce json @Param platform query string false "Filter by platform (kubernetes, docker, vm, cloud)" @Param status query string false "Filter by status (online, offline, draining)" @Param region query string false "Filter by region" @Success 200 {object} map[string]interface{} "List of agents" @Failure 500 {object} map[string]interface{} "Internal server error" @Router /agents [get]

func (*AgentHandler) RegisterAdminRoutes

func (h *AgentHandler) RegisterAdminRoutes(router *gin.RouterGroup)

RegisterAdminRoutes registers admin-only agent management routes (requires JWT admin auth) These routes are used by admin UI to manage agents

func (*AgentHandler) RegisterAgent

func (h *AgentHandler) RegisterAgent(c *gin.Context)

RegisterAgent godoc @Summary Register an agent with the Control Plane @Description Registers a new agent or re-registers an existing agent. Agents use this endpoint when they first connect or reconnect. @Tags agents @Accept json @Produce json @Param request body models.AgentRegistrationRequest true "Agent registration request" @Success 201 {object} models.Agent "Agent registered successfully (new)" @Success 200 {object} models.Agent "Agent re-registered successfully (existing)" @Failure 400 {object} map[string]interface{} "Invalid request" @Failure 500 {object} map[string]interface{} "Internal server error" @Router /agents/register [post]

func (*AgentHandler) RegisterRoutes

func (h *AgentHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers agent routes (for agent self-service - requires API key) These routes are used by agents themselves, not by admin UI Note: router is already prefixed with /agents from main.go

func (*AgentHandler) RejectAgent

func (h *AgentHandler) RejectAgent(c *gin.Context)

RejectAgent godoc @Summary Reject pending agent @Description Rejects a pending agent registration @Tags agents @Accept json @Produce json @Param agent_id path string true "Agent ID" @Success 200 {object} map[string]interface{} "Agent rejected" @Failure 404 {object} map[string]interface{} "Agent not found" @Failure 500 {object} map[string]interface{} "Internal server error" @Router /agents/{agent_id}/reject [post] @Security ApiKeyAuth

func (*AgentHandler) RotateAPIKey

func (h *AgentHandler) RotateAPIKey(c *gin.Context)

RotateAPIKey godoc @Summary Rotate API key for an agent (admin only) @Description Generates a new API key and immediately invalidates the old one. The plaintext key is returned ONCE. @Tags agents @Accept json @Produce json @Param agent_id path string true "Agent ID" @Success 200 {object} map[string]interface{} "API key rotated successfully" @Failure 404 {object} map[string]interface{} "Agent not found" @Failure 500 {object} map[string]interface{} "Internal server error" @Router /admin/agents/{agent_id}/rotate-key [post] @Security BearerAuth

func (*AgentHandler) SendCommand

func (h *AgentHandler) SendCommand(c *gin.Context)

func (*AgentHandler) UpdateHeartbeat

func (h *AgentHandler) UpdateHeartbeat(c *gin.Context)

UpdateHeartbeat godoc @Summary Update agent heartbeat @Description Updates the last heartbeat timestamp and optionally the status and capacity @Tags agents @Accept json @Produce json @Param agent_id path string true "Agent ID" @Param request body models.AgentHeartbeatRequest true "Heartbeat request" @Success 200 {object} map[string]interface{} "Heartbeat updated successfully" @Failure 400 {object} map[string]interface{} "Invalid request" @Failure 404 {object} map[string]interface{} "Agent not found" @Failure 500 {object} map[string]interface{} "Internal server error" @Router /agents/{agent_id}/heartbeat [post]

type AgentWebSocketHandler

type AgentWebSocketHandler struct {
	// contains filtered or unexported fields
}

AgentWebSocketHandler handles WebSocket connections for agents.

The handler is responsible for:

  • Upgrading HTTP connections to WebSocket
  • Validating agent authentication
  • Managing connection lifecycle
  • Starting read/write pumps

func NewAgentWebSocketHandler

func NewAgentWebSocketHandler(hub *wsocket.AgentHub, database *db.Database) *AgentWebSocketHandler

NewAgentWebSocketHandler creates a new WebSocket handler for agents.

Example:

handler := NewAgentWebSocketHandler(hub, database)
router.GET("/api/v1/agents/connect", handler.HandleAgentConnection)

func (*AgentWebSocketHandler) HandleAgentConnection

func (h *AgentWebSocketHandler) HandleAgentConnection(c *gin.Context)

HandleAgentConnection handles the WebSocket upgrade and connection lifecycle.

Query Parameters:

  • agent_id (required): The unique identifier for the agent

Flow:

  1. Validate agent_id query parameter
  2. Verify agent exists in database
  3. Upgrade HTTP connection to WebSocket
  4. Create AgentConnection with channels
  5. Register connection with hub
  6. Start readPump and writePump goroutines
  7. Wait for connection to close

Example Agent Connection:

ws, err := websocket.Dial("ws://localhost:8080/api/v1/agents/connect?agent_id=k8s-prod-us-east-1", "", "http://localhost/")

func (*AgentWebSocketHandler) RegisterRoutes

func (h *AgentWebSocketHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers WebSocket routes for agent connections.

Example:

handler := NewAgentWebSocketHandler(hub, database)
handler.RegisterRoutes(router.Group("/api/v1"))

type Annotation

type Annotation struct {
	ID           string     `json:"id"`
	SessionID    string     `json:"session_id"`
	UserID       string     `json:"user_id"`
	Type         string     `json:"type"` // "line", "arrow", "rectangle", "circle", "text", "freehand"
	Color        string     `json:"color"`
	Thickness    int        `json:"thickness"`
	Points       []Point    `json:"points"`
	Text         string     `json:"text,omitempty"`
	IsPersistent bool       `json:"is_persistent"`
	CreatedAt    time.Time  `json:"created_at"`
	ExpiresAt    *time.Time `json:"expires_at,omitempty"`
}

Annotation represents a drawing/annotation on the session

type ApplicationHandler

type ApplicationHandler struct {
	// contains filtered or unexported fields
}

ApplicationHandler handles installed application endpoints

func NewApplicationHandler

func NewApplicationHandler(database *db.Database, publisher *events.Publisher, k8sClient *k8s.Client, platform string) *ApplicationHandler

NewApplicationHandler creates a new application handler

func (*ApplicationHandler) AddGroupAccess

func (h *ApplicationHandler) AddGroupAccess(c *gin.Context)

AddGroupAccess godoc @Summary Grant group access to an application @Description Add a group with specified access level @Tags applications @Accept json @Produce json @Param id path string true "Application ID" @Param request body models.AddGroupAccessRequest true "Access request" @Success 201 {object} map[string]interface{} @Failure 400 {object} ErrorResponse @Router /api/v1/applications/{id}/groups [post]

func (*ApplicationHandler) DeleteApplication

func (h *ApplicationHandler) DeleteApplication(c *gin.Context)

DeleteApplication godoc @Summary Delete an application @Description Remove an installed application and all its access rules @Tags applications @Accept json @Produce json @Param id path string true "Application ID" @Success 200 {object} map[string]interface{} @Failure 500 {object} ErrorResponse @Router /api/v1/applications/{id} [delete]

func (*ApplicationHandler) GetApplication

func (h *ApplicationHandler) GetApplication(c *gin.Context)

GetApplication godoc @Summary Get application details @Description Get detailed information about an installed application @Tags applications @Accept json @Produce json @Param id path string true "Application ID" @Success 200 {object} models.InstalledApplication @Failure 404 {object} ErrorResponse @Router /api/v1/applications/{id} [get]

func (*ApplicationHandler) GetApplicationGroups

func (h *ApplicationHandler) GetApplicationGroups(c *gin.Context)

GetApplicationGroups godoc @Summary Get groups with access to an application @Description List all groups that have access to this application @Tags applications @Accept json @Produce json @Param id path string true "Application ID" @Success 200 {object} map[string]interface{} @Failure 500 {object} ErrorResponse @Router /api/v1/applications/{id}/groups [get]

func (*ApplicationHandler) GetApplicationIcon

func (h *ApplicationHandler) GetApplicationIcon(c *gin.Context)

GetApplicationIcon godoc @Summary Get application icon @Description Get the icon image for an installed application @Tags applications @Produce image/png,image/svg+xml,image/jpeg @Param id path string true "Application ID" @Success 200 {file} binary @Failure 404 {object} ErrorResponse @Router /api/v1/applications/{id}/icon [get]

func (*ApplicationHandler) GetTemplateConfig

func (h *ApplicationHandler) GetTemplateConfig(c *gin.Context)

GetTemplateConfig godoc @Summary Get application template configuration options @Description Get the configurable options from the template manifest @Tags applications @Accept json @Produce json @Param id path string true "Application ID" @Success 200 {object} map[string]interface{} @Failure 500 {object} ErrorResponse @Router /api/v1/applications/{id}/config [get]

func (*ApplicationHandler) GetUserApplications

func (h *ApplicationHandler) GetUserApplications(c *gin.Context)

GetUserApplications godoc @Summary Get applications accessible to current user @Description Get all applications the user can access via their groups @Tags applications @Accept json @Produce json @Success 200 {object} models.ApplicationListResponse @Failure 401 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/applications/user [get]

func (*ApplicationHandler) InstallApplication

func (h *ApplicationHandler) InstallApplication(c *gin.Context)

InstallApplication godoc @Summary Install a new application @Description Install an application from the catalog. This creates both a Kubernetes Template CRD and a database record for the installed application. The K8s Template is required for users to launch sessions from this application. @Tags applications @Accept json @Produce json @Param request body models.InstallApplicationRequest true "Installation request" @Success 201 {object} models.InstalledApplication @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/applications [post]

Installation Flow: 1. Validate request and authenticate user 2. Fetch template manifest from catalog_templates database 3. Create installed_applications database record (status: pending) 4. Grant group access permissions if specified 5. Publish NATS event for controller to process 6. Return the created application with full details

The controller subscribes to NATS events and creates platform-specific resources (Kubernetes Template CRD, Docker container, Hyper-V VM, etc.). This pattern decouples the API from platform-specific operations.

func (*ApplicationHandler) ListApplications

func (h *ApplicationHandler) ListApplications(c *gin.Context)

ListApplications godoc @Summary List all installed applications @Description Get all installed applications with optional filtering @Tags applications @Accept json @Produce json @Param enabled query boolean false "Filter by enabled status" @Success 200 {object} models.ApplicationListResponse @Failure 500 {object} ErrorResponse @Router /api/v1/applications [get]

func (*ApplicationHandler) RegisterRoutes

func (h *ApplicationHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers application-related routes

func (*ApplicationHandler) RemoveGroupAccess

func (h *ApplicationHandler) RemoveGroupAccess(c *gin.Context)

RemoveGroupAccess godoc @Summary Remove group access from an application @Description Revoke a group's access to an application @Tags applications @Accept json @Produce json @Param id path string true "Application ID" @Param groupId path string true "Group ID" @Success 200 {object} map[string]interface{} @Failure 500 {object} ErrorResponse @Router /api/v1/applications/{id}/groups/{groupId} [delete]

func (*ApplicationHandler) SetApplicationEnabled

func (h *ApplicationHandler) SetApplicationEnabled(c *gin.Context)

func (*ApplicationHandler) UpdateApplication

func (h *ApplicationHandler) UpdateApplication(c *gin.Context)

UpdateApplication godoc @Summary Update an application @Description Update display name, configuration, or enabled status @Tags applications @Accept json @Produce json @Param id path string true "Application ID" @Param request body models.UpdateApplicationRequest true "Update request" @Success 200 {object} models.InstalledApplication @Failure 400 {object} ErrorResponse @Failure 404 {object} ErrorResponse @Router /api/v1/applications/{id} [put]

func (*ApplicationHandler) UpdateGroupAccess

func (h *ApplicationHandler) UpdateGroupAccess(c *gin.Context)

UpdateGroupAccess godoc @Summary Update group access level @Description Change a group's access level for an application @Tags applications @Accept json @Produce json @Param id path string true "Application ID" @Param groupId path string true "Group ID" @Param request body models.UpdateGroupAccessRequest true "Access level" @Success 200 {object} map[string]interface{} @Failure 400 {object} ErrorResponse @Router /api/v1/applications/{id}/groups/{groupId} [put]

type AuditHandler

type AuditHandler struct {
	// contains filtered or unexported fields
}

AuditHandler handles audit log retrieval endpoints

func NewAuditHandler

func NewAuditHandler(database *db.Database) *AuditHandler

NewAuditHandler creates a new audit handler

func (*AuditHandler) ExportAuditLogs

func (h *AuditHandler) ExportAuditLogs(c *gin.Context)

ExportAuditLogs godoc @Summary Export audit logs to CSV or JSON @Description Exports filtered audit logs for compliance reports and analysis @Tags admin, audit @Accept json @Produce text/csv,application/json @Param format query string true "Export format: 'csv' or 'json'" Enums(csv, json) @Param user_id query string false "Filter by user ID" @Param action query string false "Filter by action" @Param resource_type query string false "Filter by resource type" @Param start_date query string false "Filter from date" @Param end_date query string false "Filter to date" @Param limit query int false "Maximum records to export (default: 10000, max: 100000)" @Success 200 {file} file "CSV or JSON file" @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/audit/export [get]

func (*AuditHandler) GetAuditLog

func (h *AuditHandler) GetAuditLog(c *gin.Context)

GetAuditLog godoc @Summary Get specific audit log entry @Description Retrieves a single audit log entry by ID with full details @Tags admin, audit @Accept json @Produce json @Param id path int true "Audit Log ID" @Success 200 {object} AuditLog @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/audit/{id} [get]

func (*AuditHandler) ListAuditLogs

func (h *AuditHandler) ListAuditLogs(c *gin.Context)

ListAuditLogs godoc @Summary List audit logs with filtering and pagination @Description Retrieves audit logs with optional filters for compliance and security investigations @Tags admin, audit @Accept json @Produce json @Param user_id query string false "Filter by user ID" @Param username query string false "Filter by username (searches in changes JSONB)" @Param action query string false "Filter by action (GET, POST, PUT, DELETE, etc.)" @Param resource_type query string false "Filter by resource type (/api/sessions, etc.)" @Param resource_id query string false "Filter by specific resource ID" @Param ip_address query string false "Filter by IP address" @Param status_code query int false "Filter by HTTP status code" @Param start_date query string false "Filter from date (ISO 8601: 2025-01-01T00:00:00Z)" @Param end_date query string false "Filter to date (ISO 8601: 2025-12-31T23:59:59Z)" @Param page query int false "Page number (default: 1)" @Param page_size query int false "Page size (default: 100, max: 1000)" @Success 200 {object} AuditLogListResponse @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/audit [get]

func (*AuditHandler) RegisterRoutes

func (h *AuditHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers audit log routes

type AuditLog

type AuditLog struct {
	ID           int64                  `json:"id"`
	UserID       string                 `json:"user_id,omitempty"`
	Action       string                 `json:"action"`
	ResourceType string                 `json:"resource_type"`
	ResourceID   string                 `json:"resource_id,omitempty"`
	Changes      map[string]interface{} `json:"changes,omitempty"`
	Timestamp    time.Time              `json:"timestamp"`
	IPAddress    string                 `json:"ip_address"`
}

AuditLog represents an audit log entry from the database

type AuditLogListResponse

type AuditLogListResponse struct {
	Logs       []AuditLog `json:"logs"`
	Total      int64      `json:"total"`
	Page       int        `json:"page"`
	PageSize   int        `json:"page_size"`
	TotalPages int        `json:"total_pages"`
}

AuditLogListResponse represents a paginated list of audit logs

type AutoScalingPolicy

type AutoScalingPolicy struct {
	ID                int64                   `json:"id"`
	Name              string                  `json:"name"`
	Description       string                  `json:"description,omitempty"`
	TargetType        string                  `json:"target_type"` // "deployment", "statefulset", "template"
	TargetID          string                  `json:"target_id"`   // Template ID or deployment name
	Enabled           bool                    `json:"enabled"`
	ScalingMode       string                  `json:"scaling_mode"` // "horizontal", "vertical", "both"
	MinReplicas       int                     `json:"min_replicas"`
	MaxReplicas       int                     `json:"max_replicas"`
	MetricType        string                  `json:"metric_type"` // "cpu", "memory", "custom", "schedule"
	TargetMetricValue float64                 `json:"target_metric_value"`
	ScaleUpPolicy     ScalePolicy             `json:"scale_up_policy"`
	ScaleDownPolicy   ScalePolicy             `json:"scale_down_policy"`
	PredictiveScaling PredictiveScalingConfig `json:"predictive_scaling"`
	CooldownPeriod    int                     `json:"cooldown_period_seconds"`
	Metadata          map[string]interface{}  `json:"metadata,omitempty"`
	CreatedBy         string                  `json:"created_by"`
	CreatedAt         time.Time               `json:"created_at"`
	UpdatedAt         time.Time               `json:"updated_at"`
}

AutoScalingPolicy defines auto-scaling rules for sessions

type BackupCode

type BackupCode struct {
	ID        int64     `json:"id"`
	UserID    string    `json:"user_id"`
	Code      string    `json:"code"` // Hashed in DB
	Used      bool      `json:"used"`
	UsedAt    time.Time `json:"used_at,omitempty"`
	CreatedAt time.Time `json:"created_at"`
}

BackupCode represents MFA backup recovery codes

type BatchHandler

type BatchHandler struct {
	// contains filtered or unexported fields
}

BatchHandler handles batch operations on multiple resources

func NewBatchHandler

func NewBatchHandler(database *db.Database) *BatchHandler

NewBatchHandler creates a new batch handler

func (*BatchHandler) CancelBatchJob

func (h *BatchHandler) CancelBatchJob(c *gin.Context)

CancelBatchJob cancels a running batch job

func (*BatchHandler) CreateSnapshots

func (h *BatchHandler) CreateSnapshots(c *gin.Context)

CreateSnapshots creates snapshots for multiple sessions

func (*BatchHandler) DeleteSessions

func (h *BatchHandler) DeleteSessions(c *gin.Context)

DeleteSessions deletes multiple sessions

func (*BatchHandler) DeleteSnapshots

func (h *BatchHandler) DeleteSnapshots(c *gin.Context)

DeleteSnapshots deletes multiple snapshots

func (*BatchHandler) DeleteTemplates

func (h *BatchHandler) DeleteTemplates(c *gin.Context)

DeleteTemplates deletes multiple templates

func (*BatchHandler) GetBatchJob

func (h *BatchHandler) GetBatchJob(c *gin.Context)

GetBatchJob retrieves a specific batch job

func (*BatchHandler) HibernateSessions

func (h *BatchHandler) HibernateSessions(c *gin.Context)

HibernateSessions hibernates multiple sessions

func (*BatchHandler) InstallTemplates

func (h *BatchHandler) InstallTemplates(c *gin.Context)

InstallTemplates installs multiple templates

func (*BatchHandler) ListBatchJobs

func (h *BatchHandler) ListBatchJobs(c *gin.Context)

ListBatchJobs lists user's batch jobs

func (*BatchHandler) RegisterRoutes

func (h *BatchHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers batch operation routes

func (*BatchHandler) TerminateSessions

func (h *BatchHandler) TerminateSessions(c *gin.Context)

TerminateSessions terminates multiple sessions

func (*BatchHandler) UpdateSessionResources

func (h *BatchHandler) UpdateSessionResources(c *gin.Context)

UpdateSessionResources updates resources for multiple sessions

func (*BatchHandler) UpdateSessionTags

func (h *BatchHandler) UpdateSessionTags(c *gin.Context)

UpdateSessionTags updates tags for multiple sessions

func (*BatchHandler) WakeSessions

func (h *BatchHandler) WakeSessions(c *gin.Context)

WakeSessions wakes multiple hibernated sessions

type BatchOperation

type BatchOperation struct {
	ID             string     `json:"id"`
	UserID         string     `json:"userId"`
	OperationType  string     `json:"operationType"` // terminate, hibernate, wake, delete, update
	ResourceType   string     `json:"resourceType"`  // sessions, snapshots, etc.
	Status         string     `json:"status"`        // pending, running, completed, failed
	TotalItems     int        `json:"totalItems"`
	ProcessedItems int        `json:"processedItems"`
	SuccessCount   int        `json:"successCount"`
	FailureCount   int        `json:"failureCount"`
	Errors         []string   `json:"errors,omitempty"`
	CreatedAt      time.Time  `json:"createdAt"`
	CompletedAt    *time.Time `json:"completedAt,omitempty"`
}

BatchOperation represents a batch operation job

type BroadcastMessage

type BroadcastMessage struct {
	Type      string                 `json:"type"`
	Event     string                 `json:"event"`
	SessionID string                 `json:"sessionId,omitempty"`
	UserID    string                 `json:"userId,omitempty"`
	TeamID    string                 `json:"teamId,omitempty"`
	Data      map[string]interface{} `json:"data"`
	Timestamp time.Time              `json:"timestamp"`
}

BroadcastMessage represents a message to be broadcast

type BulkUpdateRequest

type BulkUpdateRequest struct {
	Updates map[string]string `json:"updates" binding:"required"`
}

BulkUpdateRequest represents a request to update multiple configurations

type CalendarEvent

type CalendarEvent struct {
	ID           int64      `json:"id"`
	UserID       string     `json:"user_id"`
	ScheduleID   int64      `json:"schedule_id"`
	CalendarID   string     `json:"calendar_id"`
	EventID      string     `json:"event_id"`
	Provider     string     `json:"provider"`
	Title        string     `json:"title"`
	Description  string     `json:"description,omitempty"`
	StartTime    time.Time  `json:"start_time"`
	EndTime      time.Time  `json:"end_time"`
	Timezone     string     `json:"timezone,omitempty"`
	Status       string     `json:"status"`
	CreatedAt    time.Time  `json:"created_at"`
	LastSyncedAt *time.Time `json:"last_synced_at,omitempty"`
}

CalendarEvent represents a calendar event for a session (DEPRECATED)

type CalendarIntegration

type CalendarIntegration struct {
	ID           int64      `json:"id"`
	UserID       string     `json:"user_id"`
	Provider     string     `json:"provider"`
	AccountEmail string     `json:"account_email"`
	AccessToken  string     `json:"-"`
	RefreshToken string     `json:"-"`
	TokenExpiry  time.Time  `json:"token_expiry,omitempty"`
	CalendarID   string     `json:"calendar_id,omitempty"`
	Enabled      bool       `json:"enabled"`
	SyncEnabled  bool       `json:"sync_enabled"`
	AutoCreate   bool       `json:"auto_create_events"`
	CreatedAt    time.Time  `json:"created_at"`
	LastSyncAt   *time.Time `json:"last_sync_at,omitempty"`
}

CalendarIntegration represents a calendar connection (DEPRECATED)

type CatalogHandler

type CatalogHandler struct {
	// contains filtered or unexported fields
}

CatalogHandler handles template catalog-related endpoints

func NewCatalogHandler

func NewCatalogHandler(database *db.Database) *CatalogHandler

NewCatalogHandler creates a new catalog handler

func (*CatalogHandler) AddRating

func (h *CatalogHandler) AddRating(c *gin.Context)

AddRating godoc @Summary Add or update template rating @Description Rate a template with 1-5 stars and optional review @Tags catalog, ratings @Accept json @Produce json @Param id path int true "Template ID" @Param rating body object true "Rating data" @Success 201 {object} map[string]interface{} @Failure 400 {object} ErrorResponse @Router /api/v1/catalog/templates/{id}/ratings [post]

func (*CatalogHandler) DeleteRating

func (h *CatalogHandler) DeleteRating(c *gin.Context)

DeleteRating deletes a rating

func (*CatalogHandler) GetFeaturedTemplates

func (h *CatalogHandler) GetFeaturedTemplates(c *gin.Context)

GetFeaturedTemplates godoc @Summary Get featured templates @Description Get curated featured templates @Tags catalog @Accept json @Produce json @Success 200 {object} map[string]interface{} @Router /api/v1/catalog/templates/featured [get]

func (*CatalogHandler) GetPopularTemplates

func (h *CatalogHandler) GetPopularTemplates(c *gin.Context)

GetPopularTemplates godoc @Summary Get popular templates @Description Get most installed templates @Tags catalog @Accept json @Produce json @Success 200 {object} map[string]interface{} @Router /api/v1/catalog/templates/popular [get]

func (*CatalogHandler) GetRatings

func (h *CatalogHandler) GetRatings(c *gin.Context)

GetRatings godoc @Summary Get template ratings @Description Get all ratings and reviews for a template @Tags catalog, ratings @Accept json @Produce json @Param id path int true "Template ID" @Success 200 {object} map[string]interface{} @Router /api/v1/catalog/templates/{id}/ratings [get]

func (*CatalogHandler) GetTemplateDetails

func (h *CatalogHandler) GetTemplateDetails(c *gin.Context)

GetTemplateDetails godoc @Summary Get detailed template information @Description Get complete template details including ratings and stats @Tags catalog @Accept json @Produce json @Param id path int true "Template ID" @Success 200 {object} map[string]interface{} @Failure 404 {object} ErrorResponse @Router /api/v1/catalog/templates/{id} [get]

func (*CatalogHandler) GetTrendingTemplates

func (h *CatalogHandler) GetTrendingTemplates(c *gin.Context)

GetTrendingTemplates godoc @Summary Get trending templates @Description Get templates with recent activity @Tags catalog @Accept json @Produce json @Success 200 {object} map[string]interface{} @Router /api/v1/catalog/templates/trending [get]

func (*CatalogHandler) ListTemplates

func (h *CatalogHandler) ListTemplates(c *gin.Context)

ListTemplates godoc @Summary List catalog templates with advanced filtering @Description Get templates from catalog with search, filtering, and sorting @Tags catalog @Accept json @Produce json @Param search query string false "Search query" @Param category query string false "Filter by category" @Param tag query string false "Filter by tag" @Param appType query string false "Filter by app type" @Param featured query boolean false "Show only featured" @Param sort query string false "Sort by (popular, rating, recent, installs)" @Param page query int false "Page number" default(1) @Param limit query int false "Items per page" default(20) @Success 200 {object} map[string]interface{} @Failure 500 {object} ErrorResponse @Router /api/v1/catalog/templates [get]

func (*CatalogHandler) RecordInstall

func (h *CatalogHandler) RecordInstall(c *gin.Context)

RecordInstall records a template installation

func (*CatalogHandler) RecordView

func (h *CatalogHandler) RecordView(c *gin.Context)

RecordView records a template view

func (*CatalogHandler) RegisterRoutes

func (h *CatalogHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers catalog-related routes

func (*CatalogHandler) UpdateRating

func (h *CatalogHandler) UpdateRating(c *gin.Context)

UpdateRating updates a rating

type ChatMessage

type ChatMessage struct {
	ID          int64                  `json:"id"`
	SessionID   string                 `json:"session_id"`
	UserID      string                 `json:"user_id"`
	Username    string                 `json:"username"`
	Message     string                 `json:"message"`
	MessageType string                 `json:"message_type"` // "text", "system", "reaction"
	Metadata    map[string]interface{} `json:"metadata,omitempty"`
	CreatedAt   time.Time              `json:"created_at"`
}

ChatMessage represents a collaboration chat message

type CheckQuotaRequest

type CheckQuotaRequest struct {
	UserID      string `json:"userId" binding:"required" validate:"required,min=1,max=100"`
	CPU         int    `json:"cpu" validate:"gte=0,lte=100000"`
	Memory      int    `json:"memory" validate:"gte=0,lte=1000000"`
	AddSessions int    `json:"addSessions" validate:"gte=0,lte=100"`
}

CheckQuotaRequest represents a request to check quota availability

type CollaborationHandler

type CollaborationHandler struct {
	// DB is the database connection for collaboration queries and updates.
	DB *db.Database
}

Handler handles collaboration-related HTTP requests.

func NewCollaborationHandler

func NewCollaborationHandler(database *db.Database) *CollaborationHandler

NewCollaborationHandler creates a new collaboration handler.

func (*CollaborationHandler) ClearAllAnnotations

func (h *CollaborationHandler) ClearAllAnnotations(c *gin.Context)

ClearAllAnnotations removes all annotations

func (*CollaborationHandler) CreateAnnotation

func (h *CollaborationHandler) CreateAnnotation(c *gin.Context)

CreateAnnotation creates a new annotation

func (*CollaborationHandler) CreateCollaborationSession

func (h *CollaborationHandler) CreateCollaborationSession(c *gin.Context)

CreateCollaborationSession creates a new collaboration session

func (*CollaborationHandler) DeleteAnnotation

func (h *CollaborationHandler) DeleteAnnotation(c *gin.Context)

DeleteAnnotation removes an annotation

func (*CollaborationHandler) GetAnnotations

func (h *CollaborationHandler) GetAnnotations(c *gin.Context)

GetAnnotations retrieves active annotations

func (*CollaborationHandler) GetChatHistory

func (h *CollaborationHandler) GetChatHistory(c *gin.Context)

GetChatHistory retrieves chat history

func (*CollaborationHandler) GetCollaborationParticipants

func (h *CollaborationHandler) GetCollaborationParticipants(c *gin.Context)

GetCollaborationParticipants lists all participants

func (*CollaborationHandler) GetCollaborationStats

func (h *CollaborationHandler) GetCollaborationStats(c *gin.Context)

GetCollaborationStats returns collaboration statistics

func (*CollaborationHandler) JoinCollaborationSession

func (h *CollaborationHandler) JoinCollaborationSession(c *gin.Context)

JoinCollaborationSession allows a user to join a collaboration

func (*CollaborationHandler) LeaveCollaborationSession

func (h *CollaborationHandler) LeaveCollaborationSession(c *gin.Context)

LeaveCollaborationSession removes a user from collaboration

func (*CollaborationHandler) SendChatMessage

func (h *CollaborationHandler) SendChatMessage(c *gin.Context)

SendChatMessage sends a message to the collaboration chat

func (*CollaborationHandler) UpdateParticipantRole

func (h *CollaborationHandler) UpdateParticipantRole(c *gin.Context)

UpdateParticipantRole updates a participant's role and permissions

type CollaborationPermissions

type CollaborationPermissions struct {
	CanControl  bool `json:"can_control"`   // Can interact with session
	CanAnnotate bool `json:"can_annotate"`  // Can create annotations
	CanChat     bool `json:"can_chat"`      // Can send messages
	CanInvite   bool `json:"can_invite"`    // Can invite others
	CanManage   bool `json:"can_manage"`    // Can change settings
	CanRecord   bool `json:"can_record"`    // Can start recording
	CanViewOnly bool `json:"can_view_only"` // View-only mode
}

CollaborationPermissions defines what a user can do

type CollaborationSession

type CollaborationSession struct {
	ID                 string                `json:"id"`
	SessionID          string                `json:"session_id"`
	OwnerID            string                `json:"owner_id"`
	Participants       []CollaborationUser   `json:"participants"`
	Settings           CollaborationSettings `json:"settings"`
	ActiveUsers        int                   `json:"active_users"`
	ChatEnabled        bool                  `json:"chat_enabled"`
	AnnotationsEnabled bool                  `json:"annotations_enabled"`
	CursorTracking     bool                  `json:"cursor_tracking"`
	Status             string                `json:"status"` // "active", "paused", "ended"
	CreatedAt          time.Time             `json:"created_at"`
	EndedAt            *time.Time            `json:"ended_at,omitempty"`
}

CollaborationSession represents a collaborative multi-user session.

A collaboration session wraps a regular StreamSpace session with real-time collaboration features. Multiple users can join the same session and interact via chat, annotations, cursor tracking, and shared control.

Lifecycle:

  1. Owner creates collaboration session from their StreamSpace session
  2. Participants join via invitation or link
  3. Real-time interaction via WebSocket (chat, cursors, annotations)
  4. Owner ends collaboration (session continues, collaboration stops)

State transitions:

  • "active": Collaboration in progress, users can join
  • "paused": Temporarily stopped, can be resumed
  • "ended": Permanently ended, read-only access to history

Persistence:

  • Session metadata stored in collaboration_sessions table
  • Chat history, annotations preserved after session ends
  • Cursor positions ephemeral (not stored in database)

type CollaborationSettings

type CollaborationSettings struct {
	FollowMode       string `json:"follow_mode"` // "none", "follow_presenter", "follow_owner"
	MaxParticipants  int    `json:"max_participants"`
	RequireApproval  bool   `json:"require_approval"`
	AllowAnonymous   bool   `json:"allow_anonymous"`
	LockOnPresenter  bool   `json:"lock_on_presenter"`
	AutoMuteJoiners  bool   `json:"auto_mute_joiners"`
	ShowCursorLabels bool   `json:"show_cursor_labels"`
	EnableHandRaise  bool   `json:"enable_hand_raise"`
}

CollaborationSettings defines session behavior

type CollaborationUser

type CollaborationUser struct {
	UserID         string                   `json:"user_id"`
	Username       string                   `json:"username"`
	Role           string                   `json:"role"` // "owner", "presenter", "participant", "viewer"
	Permissions    CollaborationPermissions `json:"permissions"`
	CursorPosition *CursorPosition          `json:"cursor_position,omitempty"`
	IsActive       bool                     `json:"is_active"`
	JoinedAt       time.Time                `json:"joined_at"`
	LastSeenAt     time.Time                `json:"last_seen_at"`
	Color          string                   `json:"color"` // User color for cursor/annotations
}

CollaborationUser represents a user in a collaborative session

type Configuration

type Configuration struct {
	Key         string    `json:"key"`
	Value       string    `json:"value"`
	Type        string    `json:"type"` // string, boolean, number, duration, enum, array
	Category    string    `json:"category"`
	Description string    `json:"description"`
	UpdatedAt   time.Time `json:"updated_at"`
	UpdatedBy   string    `json:"updated_by,omitempty"`
}

Configuration represents a single configuration setting

type ConfigurationHandler

type ConfigurationHandler struct {
	// contains filtered or unexported fields
}

ConfigurationHandler handles system configuration endpoints

func NewConfigurationHandler

func NewConfigurationHandler(database *db.Database) *ConfigurationHandler

NewConfigurationHandler creates a new configuration handler

func (*ConfigurationHandler) BulkUpdateConfigurations

func (h *ConfigurationHandler) BulkUpdateConfigurations(c *gin.Context)

BulkUpdateConfigurations godoc @Summary Bulk update multiple configuration settings @Description Updates multiple configuration settings in a single transaction @Tags admin, configuration @Accept json @Produce json @Param body body BulkUpdateRequest true "Configuration updates" @Success 200 {object} map[string]interface{} @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/config/bulk [post]

func (*ConfigurationHandler) GetConfiguration

func (h *ConfigurationHandler) GetConfiguration(c *gin.Context)

GetConfiguration godoc @Summary Get specific configuration setting @Description Retrieves a single configuration setting by key @Tags admin, configuration @Accept json @Produce json @Param key path string true "Configuration key" @Success 200 {object} Configuration @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/config/{key} [get]

func (*ConfigurationHandler) ListConfigurations

func (h *ConfigurationHandler) ListConfigurations(c *gin.Context)

ListConfigurations godoc @Summary List all configuration settings @Description Retrieves all platform configuration settings, optionally filtered by category @Tags admin, configuration @Accept json @Produce json @Param category query string false "Filter by category (ingress, storage, resources, features, session, security, compliance)" @Success 200 {object} ConfigurationListResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/config [get]

func (*ConfigurationHandler) RegisterRoutes

func (h *ConfigurationHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers configuration routes

func (*ConfigurationHandler) UpdateConfiguration

func (h *ConfigurationHandler) UpdateConfiguration(c *gin.Context)

UpdateConfiguration godoc @Summary Update configuration setting @Description Updates a single configuration setting with validation @Tags admin, configuration @Accept json @Produce json @Param key path string true "Configuration key" @Param body body UpdateConfigurationRequest true "New value" @Success 200 {object} Configuration @Failure 400 {object} ErrorResponse @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/config/{key} [put]

type ConfigurationListResponse

type ConfigurationListResponse struct {
	Configurations []Configuration            `json:"configurations"`
	Grouped        map[string][]Configuration `json:"grouped"`
}

ConfigurationListResponse represents a list of configurations grouped by category

type ConsoleHandler

type ConsoleHandler struct {
	DB *db.Database
}

Handler is the console handler with database access.

func NewConsoleHandler

func NewConsoleHandler(database *db.Database) *ConsoleHandler

NewConsoleHandler creates a new console handler.

func (*ConsoleHandler) CreateConsoleSession

func (h *ConsoleHandler) CreateConsoleSession(c *gin.Context)

CreateConsoleSession creates a new console session for a workspace session

func (*ConsoleHandler) CreateDirectory

func (h *ConsoleHandler) CreateDirectory(c *gin.Context)

CreateDirectory creates a new directory

func (*ConsoleHandler) DeleteFile

func (h *ConsoleHandler) DeleteFile(c *gin.Context)

DeleteFile deletes a file or directory

func (*ConsoleHandler) DisconnectConsoleSession

func (h *ConsoleHandler) DisconnectConsoleSession(c *gin.Context)

DisconnectConsoleSession disconnects an active console session

func (*ConsoleHandler) DownloadFile

func (h *ConsoleHandler) DownloadFile(c *gin.Context)

DownloadFile downloads a file from the session

func (*ConsoleHandler) GetFileContent

func (h *ConsoleHandler) GetFileContent(c *gin.Context)

GetFileContent retrieves the content of a file

func (*ConsoleHandler) GetFileOperationHistory

func (h *ConsoleHandler) GetFileOperationHistory(c *gin.Context)

GetFileOperationHistory retrieves file operation history

func (*ConsoleHandler) ListConsoleSessions

func (h *ConsoleHandler) ListConsoleSessions(c *gin.Context)

ListConsoleSessions lists all console sessions for a workspace session

func (*ConsoleHandler) ListFiles

func (h *ConsoleHandler) ListFiles(c *gin.Context)

ListFiles lists files in a directory

func (*ConsoleHandler) RenameFile

func (h *ConsoleHandler) RenameFile(c *gin.Context)

RenameFile renames a file or directory

func (*ConsoleHandler) UploadFile

func (h *ConsoleHandler) UploadFile(c *gin.Context)

UploadFile uploads a file to the session

type ConsoleSession

type ConsoleSession struct {
	ID             string                 `json:"id"`
	SessionID      string                 `json:"session_id"`
	UserID         string                 `json:"user_id"`
	Type           string                 `json:"type"`   // "terminal", "file_manager"
	Status         string                 `json:"status"` // "active", "idle", "disconnected"
	WebSocketURL   string                 `json:"websocket_url,omitempty"`
	CurrentPath    string                 `json:"current_path,omitempty"`
	ShellType      string                 `json:"shell_type,omitempty"` // "bash", "sh", "zsh"
	Columns        int                    `json:"columns,omitempty"`    // Terminal columns
	Rows           int                    `json:"rows,omitempty"`       // Terminal rows
	Metadata       map[string]interface{} `json:"metadata,omitempty"`
	ConnectedAt    time.Time              `json:"connected_at"`
	LastActivityAt time.Time              `json:"last_activity_at"`
	DisconnectedAt *time.Time             `json:"disconnected_at,omitempty"`
}

ConsoleSession represents an active console session

type CreateAPIKeyRequest

type CreateAPIKeyRequest struct {
	Name        string   `json:"name" binding:"required" validate:"required,min=3,max=100"`
	Description string   `json:"description" validate:"omitempty,max=500"`
	Scopes      []string `json:"scopes" validate:"omitempty,dive,min=3,max=50"`
	RateLimit   int      `json:"rateLimit" validate:"omitempty,gte=0,lte=100000"`
	ExpiresIn   string   `json:"expiresIn" validate:"omitempty,min=2,max=10"` // Duration string like "30d", "1y"
}

CreateAPIKeyRequest is the request body for creating an API key

type CreateIntegrationRequest

type CreateIntegrationRequest struct {
	Type        string                 `json:"type" binding:"required" validate:"required,oneof=custom"`
	Name        string                 `json:"name" binding:"required" validate:"required,min=1,max=200"`
	Description string                 `json:"description" validate:"omitempty,max=1000"`
	Config      map[string]interface{} `json:"config"`
	Enabled     bool                   `json:"enabled"`
	Events      []string               `json:"events" validate:"omitempty,max=50,dive,min=3,max=100"`
	TestMode    bool                   `json:"test_mode"`
}

CreateIntegrationRequest is the request body for creating an integration

type CreateInvitationRequest

type CreateInvitationRequest struct {
	PermissionLevel string     `json:"permissionLevel" binding:"required" validate:"required,oneof=view collaborate control"`
	MaxUses         int        `json:"maxUses" validate:"omitempty,gte=1,lte=1000"`
	ExpiresAt       *time.Time `json:"expiresAt"`
}

CreateInvitationRequest represents a request to create a shareable invitation link

type CreatePolicyRequest

type CreatePolicyRequest struct {
	Name              string                 `json:"name" binding:"required"`
	Description       *string                `json:"description"`
	AutoRecord        bool                   `json:"auto_record"`
	RecordingFormat   string                 `json:"recording_format"`
	RetentionDays     int                    `json:"retention_days"`
	ApplyToUsers      map[string]interface{} `json:"apply_to_users"`
	ApplyToTeams      map[string]interface{} `json:"apply_to_teams"`
	ApplyToTemplates  map[string]interface{} `json:"apply_to_templates"`
	RequireReason     bool                   `json:"require_reason"`
	AllowUserPlayback bool                   `json:"allow_user_playback"`
	AllowUserDownload bool                   `json:"allow_user_download"`
	RequireApproval   bool                   `json:"require_approval"`
	NotifyOnRecording bool                   `json:"notify_on_recording"`
	Metadata          map[string]interface{} `json:"metadata"`
	Enabled           bool                   `json:"enabled"`
	Priority          int                    `json:"priority"`
}

CreatePolicyRequest represents a policy creation request

type CreateSessionTemplateRequest

type CreateSessionTemplateRequest struct {
	Name          string                 `json:"name" binding:"required" validate:"required,min=3,max=100"`
	Description   string                 `json:"description" validate:"omitempty,max=1000"`
	Icon          string                 `json:"icon" validate:"omitempty,max=100"`
	Category      string                 `json:"category" validate:"omitempty,min=2,max=50"`
	Tags          []string               `json:"tags" validate:"omitempty,dive,min=2,max=50"`
	Visibility    string                 `json:"visibility" validate:"omitempty,oneof=private team public"`
	TeamID        string                 `json:"teamId" validate:"omitempty,uuid"`
	BaseTemplate  string                 `json:"baseTemplate" binding:"required" validate:"required,min=3,max=100"`
	Configuration map[string]interface{} `json:"configuration"`
	Resources     map[string]interface{} `json:"resources"`
	Environment   map[string]string      `json:"environment" validate:"omitempty,dive,keys,min=1,max=100,endkeys,min=0,max=10000"`
	IsDefault     bool                   `json:"isDefault"`
}

CreateSessionTemplateRequest is the request body for creating a session template

type CreateShareRequest

type CreateShareRequest struct {
	SharedWithUserId string     `json:"sharedWithUserId" binding:"required" validate:"required,min=1,max=100"`
	PermissionLevel  string     `json:"permissionLevel" binding:"required" validate:"required,oneof=view collaborate control"`
	ExpiresAt        *time.Time `json:"expiresAt"`
}

CreateShareRequest represents a request to share a session with a user

type CreateWebhookRequest

type CreateWebhookRequest struct {
	Name        string                 `json:"name" binding:"required" validate:"required,min=1,max=200"`
	Description string                 `json:"description" validate:"omitempty,max=1000"`
	URL         string                 `json:"url" binding:"required" validate:"required,url,max=2048"`
	Secret      string                 `json:"secret" validate:"omitempty,min=16,max=256"`
	Events      []string               `json:"events" binding:"required" validate:"required,min=1,max=50,dive,min=3,max=100"`
	Headers     map[string]string      `json:"headers" validate:"omitempty,max=50,dive,keys,max=100,endkeys,max=1000"`
	Enabled     bool                   `json:"enabled"`
	RetryPolicy WebhookRetryPolicy     `json:"retry_policy"`
	Filters     WebhookFilters         `json:"filters"`
	Metadata    map[string]interface{} `json:"metadata"`
}

CreateWebhookRequest is the request body for creating a webhook

type CurrentLicenseResponse

type CurrentLicenseResponse struct {
	License         License           `json:"license"`
	Usage           LicenseUsageStats `json:"usage"`
	DaysUntilExpiry int               `json:"days_until_expiry"`
	IsExpired       bool              `json:"is_expired"`
	IsExpiringSoon  bool              `json:"is_expiring_soon"` // < 30 days
	LimitWarnings   []LimitWarning    `json:"limit_warnings"`
}

CurrentLicenseResponse represents current license with usage information

type CursorPosition

type CursorPosition struct {
	X         int       `json:"x"`
	Y         int       `json:"y"`
	Timestamp time.Time `json:"timestamp"`
}

CursorPosition represents cursor location

type DashboardHandler

type DashboardHandler struct {
	// contains filtered or unexported fields
}

DashboardHandler handles dashboard and resource usage queries

func NewDashboardHandler

func NewDashboardHandler(database *db.Database, k8sClient *k8s.Client) *DashboardHandler

NewDashboardHandler creates a new dashboard handler

func (*DashboardHandler) GetActivityTimeline

func (h *DashboardHandler) GetActivityTimeline(c *gin.Context)

GetActivityTimeline returns activity timeline data for charts

func (*DashboardHandler) GetPlatformStats

func (h *DashboardHandler) GetPlatformStats(c *gin.Context)

GetPlatformStats returns overall platform statistics

func (*DashboardHandler) GetResourceUsage

func (h *DashboardHandler) GetResourceUsage(c *gin.Context)

GetResourceUsage returns resource usage statistics

func (*DashboardHandler) GetTemplateUsageStats

func (h *DashboardHandler) GetTemplateUsageStats(c *gin.Context)

GetTemplateUsageStats returns per-template usage statistics

func (*DashboardHandler) GetUserDashboard

func (h *DashboardHandler) GetUserDashboard(c *gin.Context)

GetUserDashboard returns personalized dashboard for the current user

func (*DashboardHandler) GetUserUsageStats

func (h *DashboardHandler) GetUserUsageStats(c *gin.Context)

GetUserUsageStats returns per-user usage statistics

type DevicePosture

type DevicePosture struct {
	DeviceID          string    `json:"device_id"`
	OSVersion         string    `json:"os_version"`
	BrowserVersion    string    `json:"browser_version"`
	ScreenResolution  string    `json:"screen_resolution"`
	Timezone          string    `json:"timezone"`
	Language          string    `json:"language"`
	Plugins           []string  `json:"plugins"`
	Extensions        []string  `json:"extensions"`
	AntivirusEnabled  bool      `json:"antivirus_enabled"`
	FirewallEnabled   bool      `json:"firewall_enabled"`
	EncryptionEnabled bool      `json:"encryption_enabled"`
	LastChecked       time.Time `json:"last_checked"`
	Compliant         bool      `json:"compliant"`
	Issues            []string  `json:"issues,omitempty"`
}

DevicePosture represents device security posture

type DocsHandler

type DocsHandler struct{}

DocsHandler handles API documentation endpoints

func NewDocsHandler

func NewDocsHandler() *DocsHandler

NewDocsHandler creates a new documentation handler

func (*DocsHandler) OpenAPIJSON

func (h *DocsHandler) OpenAPIJSON(c *gin.Context)

OpenAPIJSON serves the OpenAPI specification in JSON format @Summary OpenAPI Specification (JSON) @Description Get the OpenAPI 3.0 specification in JSON format @Tags documentation @Produce application/json @Success 200 {object} map[string]interface{} "OpenAPI JSON specification" @Router /api/openapi.json [get]

func (*DocsHandler) OpenAPIYAML

func (h *DocsHandler) OpenAPIYAML(c *gin.Context)

OpenAPIYAML serves the OpenAPI specification in YAML format @Summary OpenAPI Specification (YAML) @Description Get the OpenAPI 3.0 specification in YAML format @Tags documentation @Produce application/x-yaml @Success 200 {string} string "OpenAPI YAML specification" @Router /api/openapi.yaml [get]

func (*DocsHandler) RegisterRoutes

func (h *DocsHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers documentation routes (no auth required)

func (*DocsHandler) SwaggerUI

func (h *DocsHandler) SwaggerUI(c *gin.Context)

SwaggerUI serves the Swagger UI HTML page @Summary API Documentation UI @Description Interactive Swagger UI for exploring the StreamSpace API @Tags documentation @Produce html @Success 200 {string} string "HTML page" @Router /api/docs [get]

type ErrorResponse

type ErrorResponse struct {
	Error   string `json:"error"`
	Message string `json:"message,omitempty"`
}

ErrorResponse represents an error response

type FileInfo

type FileInfo struct {
	Name          string    `json:"name"`
	Path          string    `json:"path"`
	Size          int64     `json:"size"`
	IsDirectory   bool      `json:"is_directory"`
	Permissions   string    `json:"permissions"`
	Owner         string    `json:"owner"`
	Group         string    `json:"group"`
	ModifiedAt    time.Time `json:"modified_at"`
	MimeType      string    `json:"mime_type,omitempty"`
	SymlinkTarget string    `json:"symlink_target,omitempty"`
}

FileInfo represents file/directory information

type FileOperation

type FileOperation struct {
	Operation      string `json:"operation"` // "create", "delete", "rename", "copy", "move", "upload", "download"
	SourcePath     string `json:"source_path"`
	TargetPath     string `json:"target_path,omitempty"`
	Success        bool   `json:"success"`
	Error          string `json:"error,omitempty"`
	BytesProcessed int64  `json:"bytes_processed,omitempty"`
}

FileOperation represents a file operation result

type GeoRestriction

type GeoRestriction struct {
	ID          int64    `json:"id"`
	UserID      string   `json:"user_id,omitempty"` // Empty for org-wide
	Countries   []string `json:"countries"`         // ISO country codes
	Action      string   `json:"action"`            // "allow" or "deny"
	Enabled     bool     `json:"enabled"`
	Description string   `json:"description,omitempty"`
}

GeoRestriction represents geographic access controls

type GroupHandler

type GroupHandler struct {
	// contains filtered or unexported fields
}

GroupHandler handles group-related API requests

func NewGroupHandler

func NewGroupHandler(groupDB *db.GroupDB, userDB *db.UserDB) *GroupHandler

NewGroupHandler creates a new group handler

func (*GroupHandler) AddGroupMember

func (h *GroupHandler) AddGroupMember(c *gin.Context)

AddGroupMember godoc @Summary Add group member @Description Add a user to a group @Tags groups @Accept json @Produce json @Param id path string true "Group ID" @Param member body models.AddGroupMemberRequest true "Member add request" @Success 200 {object} SuccessResponse @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/groups/{id}/members [post]

func (*GroupHandler) CreateGroup

func (h *GroupHandler) CreateGroup(c *gin.Context)

CreateGroup godoc @Summary Create a new group @Description Create a new group/team @Tags groups @Accept json @Produce json @Param group body models.CreateGroupRequest true "Group creation request" @Success 201 {object} models.Group @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/groups [post]

func (*GroupHandler) DeleteGroup

func (h *GroupHandler) DeleteGroup(c *gin.Context)

DeleteGroup godoc @Summary Delete group @Description Delete a group/team @Tags groups @Accept json @Produce json @Param id path string true "Group ID" @Success 200 {object} SuccessResponse @Failure 500 {object} ErrorResponse @Router /api/v1/groups/{id} [delete]

func (*GroupHandler) GetGroup

func (h *GroupHandler) GetGroup(c *gin.Context)

GetGroup godoc @Summary Get group by ID @Description Get detailed information about a specific group @Tags groups @Accept json @Produce json @Param id path string true "Group ID" @Success 200 {object} models.Group @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/groups/{id} [get]

func (*GroupHandler) GetGroupMembers

func (h *GroupHandler) GetGroupMembers(c *gin.Context)

GetGroupMembers godoc @Summary Get group members @Description Get all members of a group @Tags groups @Accept json @Produce json @Param id path string true "Group ID" @Success 200 {object} gin.H @Failure 500 {object} ErrorResponse @Router /api/v1/groups/{id}/members [get]

func (*GroupHandler) GetGroupQuota

func (h *GroupHandler) GetGroupQuota(c *gin.Context)

GetGroupQuota godoc @Summary Get group quota @Description Get resource quota for a group @Tags groups, quotas @Accept json @Produce json @Param id path string true "Group ID" @Success 200 {object} models.GroupQuota @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/groups/{id}/quota [get]

func (*GroupHandler) ListGroups

func (h *GroupHandler) ListGroups(c *gin.Context)

ListGroups godoc @Summary List all groups @Description Get a list of all groups with optional filtering @Tags groups @Accept json @Produce json @Param type query string false "Filter by group type" @Param parentId query string false "Filter by parent group" @Success 200 {array} models.Group @Failure 500 {object} ErrorResponse @Router /api/v1/groups [get]

func (*GroupHandler) RegisterRoutes

func (h *GroupHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers group management routes

func (*GroupHandler) RemoveGroupMember

func (h *GroupHandler) RemoveGroupMember(c *gin.Context)

RemoveGroupMember godoc @Summary Remove group member @Description Remove a user from a group @Tags groups @Accept json @Produce json @Param id path string true "Group ID" @Param userId path string true "User ID" @Success 200 {object} SuccessResponse @Failure 500 {object} ErrorResponse @Router /api/v1/groups/{id}/members/{userId} [delete]

func (*GroupHandler) SetGroupQuota

func (h *GroupHandler) SetGroupQuota(c *gin.Context)

SetGroupQuota godoc @Summary Set group quota @Description Set or update resource quota for a group @Tags groups, quotas @Accept json @Produce json @Param id path string true "Group ID" @Param quota body models.SetQuotaRequest true "Quota settings" @Success 200 {object} models.GroupQuota @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/groups/{id}/quota [put]

func (*GroupHandler) UpdateGroup

func (h *GroupHandler) UpdateGroup(c *gin.Context)

UpdateGroup godoc @Summary Update group @Description Update group information @Tags groups @Accept json @Produce json @Param id path string true "Group ID" @Param group body models.UpdateGroupRequest true "Group update request" @Success 200 {object} models.Group @Failure 400 {object} ErrorResponse @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/groups/{id} [patch]

func (*GroupHandler) UpdateMemberRole

func (h *GroupHandler) UpdateMemberRole(c *gin.Context)

UpdateMemberRole godoc @Summary Update member role @Description Update a user's role in a group @Tags groups @Accept json @Produce json @Param id path string true "Group ID" @Param userId path string true "User ID" @Param role body gin.H true "Role update" @Success 200 {object} SuccessResponse @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/groups/{id}/members/{userId} [patch]

type HealthCheckConfig

type HealthCheckConfig struct {
	Enabled       bool   `json:"enabled"`
	Interval      int    `json:"interval_seconds"`   // How often to check
	Timeout       int    `json:"timeout_seconds"`    // Timeout for each check
	FailThreshold int    `json:"fail_threshold"`     // Failures before marking unhealthy
	PassThreshold int    `json:"pass_threshold"`     // Successes before marking healthy
	Endpoint      string `json:"endpoint,omitempty"` // Health check endpoint
}

HealthCheckConfig defines node health checking

type HeartbeatRequest

type HeartbeatRequest struct {
	SessionID string `json:"sessionId"`
}

HeartbeatRequest represents a session heartbeat request

type IPWhitelist

type IPWhitelist struct {
	ID          int64     `json:"id"`
	UserID      string    `json:"user_id,omitempty"` // Empty for org-wide rules
	IPAddress   string    `json:"ip_address"`        // Single IP or CIDR
	Description string    `json:"description,omitempty"`
	Enabled     bool      `json:"enabled"`
	CreatedBy   string    `json:"created_by"`
	CreatedAt   time.Time `json:"created_at"`
	ExpiresAt   time.Time `json:"expires_at,omitempty"`
}

IPWhitelist represents IP access control rules

type Integration

type Integration struct {
	ID            int64                  `json:"id"`
	Type          string                 `json:"type"` // "slack", "teams", "discord", "pagerduty", "email", "custom"
	Name          string                 `json:"name"`
	Description   string                 `json:"description"`
	Config        map[string]interface{} `json:"config"`
	Enabled       bool                   `json:"enabled"`
	Events        []string               `json:"events"`
	TestMode      bool                   `json:"test_mode"`
	LastTestAt    *time.Time             `json:"last_test_at,omitempty"`
	LastSuccessAt *time.Time             `json:"last_success_at,omitempty"`
	CreatedBy     string                 `json:"created_by"`
	CreatedAt     time.Time              `json:"created_at"`
	UpdatedAt     time.Time              `json:"updated_at"`
}

Integration represents an external integration

type IntegrationsHandler

type IntegrationsHandler struct {
	DB *db.Database
}

IntegrationsHandler handles webhook and external integration requests.

func NewIntegrationsHandler

func NewIntegrationsHandler(database *db.Database) *IntegrationsHandler

NewIntegrationsHandler creates a new integrations handler.

func (*IntegrationsHandler) CreateIntegration

func (h *IntegrationsHandler) CreateIntegration(c *gin.Context)

CreateIntegration creates a new integration

func (*IntegrationsHandler) CreateWebhook

func (h *IntegrationsHandler) CreateWebhook(c *gin.Context)

CreateWebhook creates a new webhook

func (*IntegrationsHandler) DeleteWebhook

func (h *IntegrationsHandler) DeleteWebhook(c *gin.Context)

DeleteWebhook deletes a webhook

func (*IntegrationsHandler) GetAvailableEvents

func (h *IntegrationsHandler) GetAvailableEvents(c *gin.Context)

GetAvailableEvents returns list of available webhook events

func (*IntegrationsHandler) GetWebhookDeliveries

func (h *IntegrationsHandler) GetWebhookDeliveries(c *gin.Context)

GetWebhookDeliveries retrieves delivery history

func (*IntegrationsHandler) ListIntegrations

func (h *IntegrationsHandler) ListIntegrations(c *gin.Context)

ListIntegrations lists all integrations

func (*IntegrationsHandler) ListWebhooks

func (h *IntegrationsHandler) ListWebhooks(c *gin.Context)

ListWebhooks lists all webhooks

func (*IntegrationsHandler) TestIntegration

func (h *IntegrationsHandler) TestIntegration(c *gin.Context)

TestIntegration tests an integration

func (*IntegrationsHandler) TestWebhook

func (h *IntegrationsHandler) TestWebhook(c *gin.Context)

TestWebhook sends a test event to a webhook

func (*IntegrationsHandler) UpdateWebhook

func (h *IntegrationsHandler) UpdateWebhook(c *gin.Context)

UpdateWebhook updates an existing webhook

type License

type License struct {
	ID          int                    `json:"id"`
	LicenseKey  string                 `json:"license_key"`
	Tier        string                 `json:"tier"` // community, pro, enterprise
	Features    map[string]interface{} `json:"features"`
	MaxUsers    *int                   `json:"max_users"`    // nil = unlimited
	MaxSessions *int                   `json:"max_sessions"` // nil = unlimited
	MaxNodes    *int                   `json:"max_nodes"`    // nil = unlimited
	IssuedAt    time.Time              `json:"issued_at"`
	ExpiresAt   time.Time              `json:"expires_at"`
	ActivatedAt *time.Time             `json:"activated_at"`
	Status      string                 `json:"status"` // active, expired, revoked
	Metadata    map[string]interface{} `json:"metadata"`
	CreatedAt   time.Time              `json:"created_at"`
	UpdatedAt   time.Time              `json:"updated_at"`
}

License represents a platform license

type LicenseHandler

type LicenseHandler struct {
	// contains filtered or unexported fields
}

LicenseHandler handles license management endpoints

func NewLicenseHandler

func NewLicenseHandler(database *db.Database) *LicenseHandler

NewLicenseHandler creates a new license handler

func (*LicenseHandler) ActivateLicense

func (h *LicenseHandler) ActivateLicense(c *gin.Context)

ActivateLicense godoc @Summary Activate a new license key @Description Activates a new license key and deactivates the current license @Tags admin, license @Accept json @Produce json @Param body body ActivateLicenseRequest true "License key to activate" @Success 200 {object} License @Failure 400 {object} ErrorResponse @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/license/activate [post]

func (*LicenseHandler) GetCurrentLicense

func (h *LicenseHandler) GetCurrentLicense(c *gin.Context)

GetCurrentLicense godoc @Summary Get current active license @Description Retrieves the currently active license with usage statistics @Tags admin, license @Accept json @Produce json @Success 200 {object} CurrentLicenseResponse @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/license [get]

func (*LicenseHandler) GetLicenseUsage

func (h *LicenseHandler) GetLicenseUsage(c *gin.Context)

GetLicenseUsage godoc @Summary Get current license usage @Description Retrieves current usage statistics vs. license limits @Tags admin, license @Accept json @Produce json @Success 200 {object} LicenseUsageStats @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/license/usage [get]

func (*LicenseHandler) GetUsageHistory

func (h *LicenseHandler) GetUsageHistory(c *gin.Context)

GetUsageHistory godoc @Summary Get usage history @Description Retrieves historical usage data for the active license @Tags admin, license @Accept json @Produce json @Param days query int false "Number of days to retrieve (default: 30)" @Success 200 {array} LicenseUsage @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/license/history [get]

func (*LicenseHandler) RegisterRoutes

func (h *LicenseHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers license routes

func (*LicenseHandler) UpdateLicense

func (h *LicenseHandler) UpdateLicense(c *gin.Context)

UpdateLicense godoc @Summary Update/renew license @Description Updates the current license (for renewals or upgrades) @Tags admin, license @Accept json @Produce json @Param body body UpdateLicenseRequest true "New license key" @Success 200 {object} License @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/license/update [put]

func (*LicenseHandler) ValidateLicense

func (h *LicenseHandler) ValidateLicense(c *gin.Context)

ValidateLicense godoc @Summary Validate a license key @Description Validates a license key without activating it @Tags admin, license @Accept json @Produce json @Param body body ValidateLicenseRequest true "License key to validate" @Success 200 {object} ValidateLicenseResponse @Failure 400 {object} ErrorResponse @Router /api/v1/admin/license/validate [post]

type LicenseUsage

type LicenseUsage struct {
	ID             int       `json:"id"`
	LicenseID      int       `json:"license_id"`
	SnapshotDate   string    `json:"snapshot_date"` // YYYY-MM-DD
	ActiveUsers    int       `json:"active_users"`
	ActiveSessions int       `json:"active_sessions"`
	ActiveNodes    int       `json:"active_nodes"`
	CreatedAt      time.Time `json:"created_at"`
}

LicenseUsage represents usage snapshot for a specific date

type LicenseUsageStats

type LicenseUsageStats struct {
	CurrentUsers    int      `json:"current_users"`
	CurrentSessions int      `json:"current_sessions"`
	CurrentNodes    int      `json:"current_nodes"`
	MaxUsers        *int     `json:"max_users"`       // nil = unlimited
	MaxSessions     *int     `json:"max_sessions"`    // nil = unlimited
	MaxNodes        *int     `json:"max_nodes"`       // nil = unlimited
	UserPercent     *float64 `json:"user_percent"`    // nil if unlimited
	SessionPercent  *float64 `json:"session_percent"` // nil if unlimited
	NodePercent     *float64 `json:"node_percent"`    // nil if unlimited
}

LicenseUsageStats represents current usage statistics

type LimitWarning

type LimitWarning struct {
	Resource   string  `json:"resource"` // users, sessions, nodes
	Current    int     `json:"current"`
	Limit      int     `json:"limit"`
	Percentage float64 `json:"percentage"`
	Severity   string  `json:"severity"` // warning (80%), critical (90%), exceeded (100%)
	Message    string  `json:"message"`
}

LimitWarning represents a warning when approaching limits

type LoadBalancingHandler

type LoadBalancingHandler struct {
	DB *db.Database
}

LoadBalancingHandler handles load balancing and node distribution requests.

func NewLoadBalancingHandler

func NewLoadBalancingHandler(database *db.Database) *LoadBalancingHandler

NewLoadBalancingHandler creates a new load balancing handler.

func (*LoadBalancingHandler) CreateAutoScalingPolicy

func (h *LoadBalancingHandler) CreateAutoScalingPolicy(c *gin.Context)

CreateAutoScalingPolicy creates a new auto-scaling policy

func (*LoadBalancingHandler) CreateLoadBalancingPolicy

func (h *LoadBalancingHandler) CreateLoadBalancingPolicy(c *gin.Context)

CreateLoadBalancingPolicy creates a new load balancing policy

func (*LoadBalancingHandler) GetNodeStatus

func (h *LoadBalancingHandler) GetNodeStatus(c *gin.Context)

GetNodeStatus gets current status of all cluster nodes

func (*LoadBalancingHandler) GetScalingHistory

func (h *LoadBalancingHandler) GetScalingHistory(c *gin.Context)

GetScalingHistory gets scaling event history

func (*LoadBalancingHandler) ListAutoScalingPolicies

func (h *LoadBalancingHandler) ListAutoScalingPolicies(c *gin.Context)

ListAutoScalingPolicies lists all auto-scaling policies

func (*LoadBalancingHandler) ListLoadBalancingPolicies

func (h *LoadBalancingHandler) ListLoadBalancingPolicies(c *gin.Context)

ListLoadBalancingPolicies lists all load balancing policies

func (*LoadBalancingHandler) SelectNode

func (h *LoadBalancingHandler) SelectNode(c *gin.Context)

SelectNode selects best node for a new session based on policy

func (*LoadBalancingHandler) TriggerScaling

func (h *LoadBalancingHandler) TriggerScaling(c *gin.Context)

TriggerScaling manually triggers a scaling action

type LoadBalancingPolicy

type LoadBalancingPolicy struct {
	ID                 int64                  `json:"id"`
	Name               string                 `json:"name"`
	Description        string                 `json:"description,omitempty"`
	Strategy           string                 `json:"strategy"` // "round_robin", "least_loaded", "resource_based", "geographic", "weighted"
	Enabled            bool                   `json:"enabled"`
	SessionAffinity    bool                   `json:"session_affinity"` // Sticky sessions
	HealthCheckConfig  HealthCheckConfig      `json:"health_check_config"`
	NodeSelector       map[string]string      `json:"node_selector,omitempty"`   // Kubernetes node selector
	NodeWeights        map[string]int         `json:"node_weights,omitempty"`    // For weighted distribution
	GeoPreferences     []string               `json:"geo_preferences,omitempty"` // Preferred regions
	ResourceThresholds ResourceThresholds     `json:"resource_thresholds"`
	Metadata           map[string]interface{} `json:"metadata,omitempty"`
	CreatedBy          string                 `json:"created_by"`
	CreatedAt          time.Time              `json:"created_at"`
	UpdatedAt          time.Time              `json:"updated_at"`
}

LoadBalancingPolicy defines how sessions are distributed across nodes

type MFAMethod

type MFAMethod struct {
	ID          int64     `json:"id"`
	UserID      string    `json:"user_id"`
	Type        string    `json:"type"` // "totp", "sms", "email", "backup_codes"
	Enabled     bool      `json:"enabled"`
	Secret      string    `json:"-"` // SECURITY: Never expose secret in API responses
	PhoneNumber string    `json:"phone_number,omitempty"`
	Email       string    `json:"email,omitempty"`
	IsPrimary   bool      `json:"is_primary"`
	Verified    bool      `json:"verified"`
	CreatedAt   time.Time `json:"created_at"`
	LastUsedAt  time.Time `json:"last_used_at,omitempty"`
}

MFAMethod represents different MFA verification methods

type MFASetupResponse

type MFASetupResponse struct {
	ID      int64  `json:"id"`
	Type    string `json:"type"`
	Secret  string `json:"secret,omitempty"`  // Only for TOTP setup
	QRCode  string `json:"qr_code,omitempty"` // Only for TOTP setup
	Message string `json:"message"`
}

MFASetupResponse is used only for SetupMFA response to show secret/QR once

type MonitoringHandler

type MonitoringHandler struct {
	// contains filtered or unexported fields
}

MonitoringHandler handles monitoring and metrics endpoints

func NewMonitoringHandler

func NewMonitoringHandler(database *db.Database) *MonitoringHandler

NewMonitoringHandler creates a new monitoring handler

func (*MonitoringHandler) AcknowledgeAlert

func (h *MonitoringHandler) AcknowledgeAlert(c *gin.Context)

AcknowledgeAlert acknowledges an alert

func (*MonitoringHandler) CreateAlert

func (h *MonitoringHandler) CreateAlert(c *gin.Context)

CreateAlert creates a new alert

func (*MonitoringHandler) DatabaseHealth

func (h *MonitoringHandler) DatabaseHealth(c *gin.Context)

DatabaseHealth returns database-specific health metrics

func (*MonitoringHandler) DeleteAlert

func (h *MonitoringHandler) DeleteAlert(c *gin.Context)

DeleteAlert deletes an alert

func (*MonitoringHandler) DetailedHealthCheck

func (h *MonitoringHandler) DetailedHealthCheck(c *gin.Context)

DetailedHealthCheck returns detailed component health

func (*MonitoringHandler) GetAlert

func (h *MonitoringHandler) GetAlert(c *gin.Context)

GetAlert returns a specific alert

func (*MonitoringHandler) GetAlerts

func (h *MonitoringHandler) GetAlerts(c *gin.Context)

GetAlerts returns all alerts

func (*MonitoringHandler) HealthCheck

func (h *MonitoringHandler) HealthCheck(c *gin.Context)

HealthCheck returns basic health status

func (*MonitoringHandler) PerformanceMetrics

func (h *MonitoringHandler) PerformanceMetrics(c *gin.Context)

PerformanceMetrics returns system performance metrics

func (*MonitoringHandler) PrometheusMetrics

func (h *MonitoringHandler) PrometheusMetrics(c *gin.Context)

PrometheusMetrics returns metrics in Prometheus format

func (*MonitoringHandler) RegisterRoutes

func (h *MonitoringHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers monitoring routes

func (*MonitoringHandler) ResolveAlert

func (h *MonitoringHandler) ResolveAlert(c *gin.Context)

ResolveAlert resolves an alert

func (*MonitoringHandler) ResourceMetrics

func (h *MonitoringHandler) ResourceMetrics(c *gin.Context)

ResourceMetrics returns resource utilization metrics

func (*MonitoringHandler) SessionMetrics

func (h *MonitoringHandler) SessionMetrics(c *gin.Context)

SessionMetrics returns detailed session metrics

func (*MonitoringHandler) StorageHealth

func (h *MonitoringHandler) StorageHealth(c *gin.Context)

StorageHealth returns storage-specific health metrics

func (*MonitoringHandler) SystemInfo

func (h *MonitoringHandler) SystemInfo(c *gin.Context)

SystemInfo returns static system information

func (*MonitoringHandler) SystemStats

func (h *MonitoringHandler) SystemStats(c *gin.Context)

SystemStats returns current system statistics

func (*MonitoringHandler) UpdateAlert

func (h *MonitoringHandler) UpdateAlert(c *gin.Context)

UpdateAlert updates an alert

func (*MonitoringHandler) UserMetrics

func (h *MonitoringHandler) UserMetrics(c *gin.Context)

UserMetrics returns user activity metrics

type NodeHandler

type NodeHandler struct {
	// contains filtered or unexported fields
}

NodeHandler provides deprecated stub handlers for node management

func NewNodeHandler

func NewNodeHandler(database *db.Database, k8sClient *k8s.Client, publisher *events.Publisher, platform string) *NodeHandler

NewNodeHandler creates a new node handler (deprecated)

func (*NodeHandler) AddNodeLabel

func (h *NodeHandler) AddNodeLabel(c *gin.Context)

AddNodeLabel returns a deprecation message

func (*NodeHandler) AddNodeTaint

func (h *NodeHandler) AddNodeTaint(c *gin.Context)

AddNodeTaint returns a deprecation message

func (*NodeHandler) CordonNode

func (h *NodeHandler) CordonNode(c *gin.Context)

CordonNode returns a deprecation message

func (*NodeHandler) DrainNode

func (h *NodeHandler) DrainNode(c *gin.Context)

DrainNode returns a deprecation message

func (*NodeHandler) GetClusterStats

func (h *NodeHandler) GetClusterStats(c *gin.Context)

GetClusterStats returns a deprecation message

func (*NodeHandler) GetNode

func (h *NodeHandler) GetNode(c *gin.Context)

GetNode returns a deprecation message

func (*NodeHandler) ListNodes

func (h *NodeHandler) ListNodes(c *gin.Context)

ListNodes returns a deprecation message

func (*NodeHandler) RemoveNodeLabel

func (h *NodeHandler) RemoveNodeLabel(c *gin.Context)

RemoveNodeLabel returns a deprecation message

func (*NodeHandler) RemoveNodeTaint

func (h *NodeHandler) RemoveNodeTaint(c *gin.Context)

RemoveNodeTaint returns a deprecation message

func (*NodeHandler) UncordonNode

func (h *NodeHandler) UncordonNode(c *gin.Context)

UncordonNode returns a deprecation message

type NodeStatus

type NodeStatus struct {
	NodeName        string            `json:"node_name"`
	Status          string            `json:"status"` // "ready", "not_ready", "unknown"
	CPUAllocated    float64           `json:"cpu_allocated"`
	CPUCapacity     float64           `json:"cpu_capacity"`
	CPUPercent      float64           `json:"cpu_percent"`
	MemoryAllocated int64             `json:"memory_allocated"`
	MemoryCapacity  int64             `json:"memory_capacity"`
	MemoryPercent   float64           `json:"memory_percent"`
	ActiveSessions  int               `json:"active_sessions"`
	HealthStatus    string            `json:"health_status"` // "healthy", "unhealthy", "unknown"
	LastHealthCheck time.Time         `json:"last_health_check"`
	Region          string            `json:"region,omitempty"`
	Zone            string            `json:"zone,omitempty"`
	Labels          map[string]string `json:"labels,omitempty"`
	Taints          []string          `json:"taints,omitempty"`
	Weight          int               `json:"weight"` // For weighted load balancing
}

NodeStatus represents current status of a cluster node

type Notification

type Notification struct {
	ID         string                 `json:"id"`
	UserID     string                 `json:"userId"`
	Type       string                 `json:"type"`
	Title      string                 `json:"title"`
	Message    string                 `json:"message"`
	Data       map[string]interface{} `json:"data,omitempty"`
	Priority   string                 `json:"priority"` // low, normal, high, urgent
	Read       bool                   `json:"read"`
	ActionURL  string                 `json:"actionUrl,omitempty"`
	ActionText string                 `json:"actionText,omitempty"`
	CreatedAt  time.Time              `json:"createdAt"`
	ReadAt     *time.Time             `json:"readAt,omitempty"`
}

Notification represents an in-app notification

type NotificationsHandler

type NotificationsHandler struct {
	// contains filtered or unexported fields
}

NotificationsHandler handles notification delivery and management

func NewNotificationsHandler

func NewNotificationsHandler(database *db.Database) *NotificationsHandler

NewNotificationsHandler creates a new notifications handler

func (*NotificationsHandler) ClearAllNotifications

func (h *NotificationsHandler) ClearAllNotifications(c *gin.Context)

ClearAllNotifications deletes all read notifications

func (*NotificationsHandler) DeleteNotification

func (h *NotificationsHandler) DeleteNotification(c *gin.Context)

DeleteNotification deletes a notification

func (*NotificationsHandler) GetNotificationPreferences

func (h *NotificationsHandler) GetNotificationPreferences(c *gin.Context)

GetNotificationPreferences returns user's notification preferences

func (*NotificationsHandler) GetUnreadCount

func (h *NotificationsHandler) GetUnreadCount(c *gin.Context)

GetUnreadCount returns count of unread notifications

func (*NotificationsHandler) GetUnreadNotifications

func (h *NotificationsHandler) GetUnreadNotifications(c *gin.Context)

GetUnreadNotifications returns only unread notifications

func (*NotificationsHandler) ListNotifications

func (h *NotificationsHandler) ListNotifications(c *gin.Context)

ListNotifications returns paginated user notifications

func (*NotificationsHandler) MarkAllAsRead

func (h *NotificationsHandler) MarkAllAsRead(c *gin.Context)

MarkAllAsRead marks all notifications as read

func (*NotificationsHandler) MarkAsRead

func (h *NotificationsHandler) MarkAsRead(c *gin.Context)

MarkAsRead marks a notification as read

func (*NotificationsHandler) RegisterRoutes

func (h *NotificationsHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers notification routes

func (*NotificationsHandler) SendNotification

func (h *NotificationsHandler) SendNotification(c *gin.Context)

SendNotification sends a notification via all enabled channels

func (*NotificationsHandler) TestEmailNotification

func (h *NotificationsHandler) TestEmailNotification(c *gin.Context)

TestEmailNotification sends a test email

func (*NotificationsHandler) TestWebhookNotification

func (h *NotificationsHandler) TestWebhookNotification(c *gin.Context)

TestWebhookNotification sends a test webhook

func (*NotificationsHandler) UpdateNotificationPreferences

func (h *NotificationsHandler) UpdateNotificationPreferences(c *gin.Context)

UpdateNotificationPreferences updates user's notification preferences

type PluginHandler

type PluginHandler struct {
	// contains filtered or unexported fields
}

PluginHandler handles plugin-related HTTP requests.

This handler provides HTTP endpoints for:

  • Browsing the plugin catalog (search, filter, sort)
  • Installing plugins from the catalog
  • Managing installed plugins (enable, disable, configure, uninstall)
  • Rating plugins (user reviews)

All methods interact with the database to query/modify plugin data.

func NewPluginHandler

func NewPluginHandler(database *db.Database, pluginDir string) *PluginHandler

NewPluginHandler creates a new plugin handler.

Parameters:

  • database: Database connection for plugin operations
  • pluginDir: Directory where plugins will be installed

Returns:

  • Configured PluginHandler ready to register routes

Example:

handler := NewPluginHandler(db, "/plugins")
handler.RegisterRoutes(router.Group("/api"))

func (*PluginHandler) BrowsePluginCatalog

func (h *PluginHandler) BrowsePluginCatalog(c *gin.Context)

BrowsePluginCatalog browses available plugins from the catalog.

Endpoint: GET /api/plugins/catalog

Query Parameters:

  • category: Filter by category (e.g., "analytics", "notifications")
  • type: Filter by plugin type (e.g., "builtin", "community")
  • search: Search in display_name, description, tags (case-insensitive)
  • sort: Sort order (popular, rating, newest, name) - default: popular

Response: JSON with plugins array and total count

Example Requests:

GET /api/plugins/catalog?category=analytics&sort=rating
GET /api/plugins/catalog?search=slack&sort=popular
GET /api/plugins/catalog?type=builtin&sort=name

Example Response:

{
  "plugins": [
    {
      "id": 1,
      "name": "analytics-tracker",
      "display_name": "Analytics Tracker",
      "description": "Track session usage metrics",
      "category": "analytics",
      "plugin_type": "community",
      "icon_url": "https://...",
      "tags": ["analytics", "metrics"],
      "install_count": 1500,
      "avg_rating": 4.5,
      "rating_count": 42
    }
  ],
  "total": 1
}

Sorting Options:

  • popular: By install count desc, then rating desc
  • rating: By average rating desc, then rating count desc
  • newest: By created_at desc
  • name: By display_name asc

HTTP Status Codes:

  • 200: Success (may return empty array if no matches)
  • 500: Database error

func (*PluginHandler) DisablePlugin

func (h *PluginHandler) DisablePlugin(c *gin.Context)

DisablePlugin disables an installed plugin.

Endpoint: POST /api/plugins/:id/disable

Path Parameters:

  • id: Installed plugin ID

Behavior:

  • Sets enabled=false in database
  • Plugin runtime should unload the plugin on next reload

Example Request:

POST /api/plugins/123/disable

HTTP Status Codes:

  • 200: Plugin disabled successfully
  • 404: Plugin not found
  • 500: Database error

func (*PluginHandler) EnablePlugin

func (h *PluginHandler) EnablePlugin(c *gin.Context)

EnablePlugin enables an installed plugin.

Endpoint: POST /api/plugins/:id/enable

Path Parameters:

  • id: Installed plugin ID

Behavior:

  • Sets enabled=true in database
  • Plugin runtime should load the plugin on next startup/reload

Example Request:

POST /api/plugins/123/enable

HTTP Status Codes:

  • 200: Plugin enabled successfully
  • 404: Plugin not found
  • 500: Database error

func (*PluginHandler) GetCatalogPlugin

func (h *PluginHandler) GetCatalogPlugin(c *gin.Context)

GetCatalogPlugin gets a specific plugin from the catalog by ID.

Endpoint: GET /api/plugins/catalog/:id

Path Parameters:

  • id: Catalog plugin ID

Response: JSON with complete plugin details including repository info

Side Effects:

  • Increments view count asynchronously (non-blocking)
  • Updates last_viewed_at timestamp

Example Request:

GET /api/plugins/catalog/42

Example Response:

{
  "id": 42,
  "name": "slack-notifications",
  "version": "1.2.3",
  "display_name": "Slack Notifications",
  "description": "Send session notifications to Slack",
  "category": "notifications",
  "plugin_type": "community",
  "icon_url": "https://...",
  "manifest": {...},
  "tags": ["notifications", "slack"],
  "install_count": 500,
  "avg_rating": 4.8,
  "rating_count": 20,
  "repository": {
    "id": 1,
    "name": "official",
    "url": "https://plugins.streamspace.io",
    "type": "official"
  }
}

HTTP Status Codes:

  • 200: Success
  • 404: Plugin not found
  • 500: Database error

func (*PluginHandler) GetInstalledPlugin

func (h *PluginHandler) GetInstalledPlugin(c *gin.Context)

GetInstalledPlugin gets details of a specific installed plugin.

Endpoint: GET /api/plugins/:id

Path Parameters:

  • id: Installed plugin ID (not catalog ID)

Response: JSON with complete plugin details

Example Request:

GET /api/plugins/123

HTTP Status Codes:

  • 200: Success
  • 404: Plugin not found
  • 500: Database error

func (*PluginHandler) InstallPlugin

func (h *PluginHandler) InstallPlugin(c *gin.Context)

InstallPlugin installs a plugin from the catalog.

Endpoint: POST /api/plugins/catalog/:id/install

Path Parameters:

  • id: Catalog plugin ID to install

Request Body (optional):

{
  "config": {"api_key": "..."}  // Plugin-specific configuration
}

Behavior:

  1. Fetches plugin details from catalog_plugins
  2. Checks if already installed (returns 409 if yes)
  3. Inserts into installed_plugins with enabled=true
  4. Increments install count asynchronously
  5. Updates plugin_stats table

Side Effects:

  • Plugin install count incremented (async, non-blocking)
  • Plugin stats updated with last_installed_at timestamp
  • user_id saved as installed_by

Example Request:

POST /api/plugins/catalog/42/install
{
  "config": {
    "webhook_url": "https://hooks.slack.com/...",
    "channel": "#general"
  }
}

Example Response:

{
  "message": "Plugin installed successfully",
  "pluginId": 123
}

HTTP Status Codes:

  • 201: Plugin installed successfully
  • 404: Catalog plugin not found
  • 409: Plugin already installed
  • 500: Database error

func (*PluginHandler) ListInstalledPlugins

func (h *PluginHandler) ListInstalledPlugins(c *gin.Context)

ListInstalledPlugins lists all installed plugins.

Endpoint: GET /api/plugins

Query Parameters:

  • enabled: Filter by enabled status ("true" for enabled only)

Response: JSON with plugins array and total count

Example Requests:

GET /api/plugins              // All installed plugins
GET /api/plugins?enabled=true // Only enabled plugins

Example Response:

{
  "plugins": [
    {
      "id": 123,
      "catalog_plugin_id": 42,
      "name": "slack-notifications",
      "version": "1.2.3",
      "enabled": true,
      "config": {"webhook_url": "..."},
      "installed_by": "user123",
      "installed_at": "2025-01-15T10:30:00Z",
      "display_name": "Slack Notifications",
      "description": "...",
      "plugin_type": "community",
      "icon_url": "..."
    }
  ],
  "total": 1
}

HTTP Status Codes:

  • 200: Success (may return empty array if no plugins installed)
  • 500: Database error

func (*PluginHandler) RatePlugin

func (h *PluginHandler) RatePlugin(c *gin.Context)

RatePlugin allows a user to rate a catalog plugin.

Endpoint: POST /api/plugins/catalog/:id/rate

Path Parameters:

  • id: Catalog plugin ID to rate

Request Body:

{
  "rating": 5,          // Required: 1-5 stars
  "review": "Great!"    // Optional: Text review
}

Behavior:

  • Upserts rating (inserts new or updates existing for this user)
  • Updates plugin's avg_rating and rating_count
  • user_id extracted from auth middleware (c.GetString("user_id"))

Example Request:

POST /api/plugins/catalog/42/rate
{
  "rating": 5,
  "review": "Excellent plugin, works perfectly!"
}

HTTP Status Codes:

  • 200: Rating submitted successfully
  • 400: Invalid rating (not 1-5) or invalid request body
  • 500: Database error

func (*PluginHandler) RegisterRoutes

func (h *PluginHandler) RegisterRoutes(r *gin.RouterGroup)

RegisterRoutes registers plugin routes to the provided router group.

Mounts all plugin endpoints under /plugins prefix:

  • Catalog endpoints: /plugins/catalog, /plugins/catalog/:id, etc.
  • Installed endpoints: /plugins, /plugins/:id, /plugins/:id/enable, etc.

Parameters:

  • r: Gin router group to mount routes on (typically /api)

Example:

api := router.Group("/api")
handler.RegisterRoutes(api)
// Routes available at: /api/plugins/catalog, /api/plugins, etc.

func (*PluginHandler) UninstallPlugin

func (h *PluginHandler) UninstallPlugin(c *gin.Context)

UninstallPlugin removes a plugin from the system.

Endpoint: DELETE /api/plugins/:id

Path Parameters:

  • id: Installed plugin ID

Behavior:

  • Deletes plugin from installed_plugins table
  • Plugin runtime should unload the plugin

WARNING: This does not clean up plugin data tables or configuration. Plugin should implement cleanup in OnUnload hook.

Example Request:

DELETE /api/plugins/123

HTTP Status Codes:

  • 200: Plugin uninstalled successfully
  • 404: Plugin not found
  • 500: Database error

func (*PluginHandler) UpdateInstalledPlugin

func (h *PluginHandler) UpdateInstalledPlugin(c *gin.Context)

UpdateInstalledPlugin updates a plugin's configuration or enabled status.

Endpoint: PATCH /api/plugins/:id

Path Parameters:

  • id: Installed plugin ID

Request Body (all fields optional):

{
  "enabled": true,                // Enable/disable plugin
  "config": {"api_key": "new..."}  // Update configuration
}

Behavior:

  • Only provided fields are updated
  • updated_at timestamp automatically set

Example Request:

PATCH /api/plugins/123
{
  "config": {"webhook_url": "https://new-url.com"}
}

HTTP Status Codes:

  • 200: Plugin updated successfully
  • 400: Invalid request body
  • 404: Plugin not found
  • 500: Database error

type PluginMarketplaceHandler

type PluginMarketplaceHandler struct {
	// contains filtered or unexported fields
}

PluginMarketplaceHandler handles plugin marketplace HTTP requests.

This handler provides higher-level plugin management endpoints that:

  • Sync catalog from external repositories
  • Install/uninstall with immediate runtime effect
  • Query runtime state directly (loaded plugins)

Dependencies:

  • database: For plugin metadata and state persistence
  • marketplace: For catalog sync and plugin discovery
  • runtime: For immediate load/unload operations

func NewPluginMarketplaceHandler

func NewPluginMarketplaceHandler(database *db.Database, marketplace *plugins.PluginMarketplace, runtime *plugins.RuntimeV2) *PluginMarketplaceHandler

NewPluginMarketplaceHandler creates a new plugin marketplace handler.

Parameters:

  • database: Database connection
  • marketplace: Plugin marketplace for catalog operations
  • runtime: Plugin runtime for load/unload operations

Returns:

  • Configured PluginMarketplaceHandler ready to register routes

Example:

marketplace := plugins.NewPluginMarketplace(db, repoURL)
runtime := plugins.NewRuntimeV2(db)
handler := NewPluginMarketplaceHandler(db, marketplace, runtime)
handler.RegisterRoutes(router.Group("/api"))

func (*PluginMarketplaceHandler) DisablePlugin

func (h *PluginMarketplaceHandler) DisablePlugin(c *gin.Context)

DisablePlugin unloads and disables a plugin.

Endpoint: POST /api/plugins/marketplace/disable/:name

Path Parameters:

  • name: Plugin name to disable

Behavior:

  1. Calls runtime.UnloadPlugin (unloads from runtime)
  2. Sets enabled=false in database

Example Request:

POST /api/plugins/marketplace/disable/slack-notifications

HTTP Status Codes:

  • 200: Plugin disabled successfully
  • 500: Database update failed

func (*PluginMarketplaceHandler) EnablePlugin

func (h *PluginMarketplaceHandler) EnablePlugin(c *gin.Context)

EnablePlugin enables a plugin in the database.

Endpoint: POST /api/plugins/marketplace/enable/:name

Path Parameters:

  • name: Plugin name to enable

Behavior:

  • Sets enabled=true in installed_plugins table
  • TODO: Should load plugin into runtime (not currently implemented)

Example Request:

POST /api/plugins/marketplace/enable/slack-notifications

HTTP Status Codes:

  • 200: Plugin enabled successfully
  • 500: Database update failed

func (*PluginMarketplaceHandler) GetInstalledPlugin

func (h *PluginMarketplaceHandler) GetInstalledPlugin(c *gin.Context)

GetInstalledPlugin gets details of a specific loaded plugin from runtime.

Endpoint: GET /api/plugins/marketplace/installed/:name

Path Parameters:

  • name: Plugin name

Response: JSON with loaded plugin details

Example Request:

GET /api/plugins/marketplace/installed/slack-notifications

HTTP Status Codes:

  • 200: Success
  • 404: Plugin not loaded in runtime

func (*PluginMarketplaceHandler) GetPluginDetails

func (h *PluginMarketplaceHandler) GetPluginDetails(c *gin.Context)

GetPluginDetails gets details for a specific plugin from the marketplace catalog.

Endpoint: GET /api/plugins/marketplace/catalog/:name

Path Parameters:

  • name: Plugin name (e.g., "slack-notifications")

Response: JSON with complete plugin metadata and manifest

Example Request:

GET /api/plugins/marketplace/catalog/slack-notifications

Example Response:

{
  "name": "slack-notifications",
  "version": "1.2.3",
  "display_name": "Slack Notifications",
  "description": "Send session notifications to Slack",
  "manifest": {
    "permissions": ["sessions.read", "users.read"],
    "config_schema": {...}
  }
}

HTTP Status Codes:

  • 200: Success
  • 404: Plugin not found in catalog
  • 500: Database or marketplace error

func (*PluginMarketplaceHandler) InstallPlugin

func (h *PluginMarketplaceHandler) InstallPlugin(c *gin.Context)

InstallPlugin installs a plugin from the marketplace and loads it immediately.

Endpoint: POST /api/plugins/marketplace/install/:name

Path Parameters:

  • name: Plugin name to install

Request Body:

{
  "config": {"api_key": "..."}  // Plugin-specific configuration
}

Behavior:

  1. Calls marketplace.InstallPlugin (adds to installed_plugins table)
  2. Fetches plugin metadata from marketplace.GetPlugin
  3. Calls runtime.LoadPluginWithConfig (loads into runtime immediately)

This is the key difference from plugins.go:

  • plugins.go: Install to database only, requires restart/reload
  • marketplace.go: Install to database AND load into runtime

Example Request:

POST /api/plugins/marketplace/install/slack-notifications
{
  "config": {
    "webhook_url": "https://hooks.slack.com/...",
    "channel": "#general"
  }
}

Example Response:

{
  "message": "Plugin installed and activated successfully",
  "plugin": {
    "name": "slack-notifications",
    "version": "1.2.3",
    "manifest": {...}
  }
}

HTTP Status Codes:

  • 200: Plugin installed and loaded successfully
  • 400: Invalid request body
  • 500: Install or load failed

func (*PluginMarketplaceHandler) ListAvailablePlugins

func (h *PluginMarketplaceHandler) ListAvailablePlugins(c *gin.Context)

ListAvailablePlugins lists all plugins available in the marketplace.

Endpoint: GET /api/plugins/marketplace/catalog

Response: JSON with plugins array and count

Data Source:

  • marketplace.ListAvailable() queries catalog_plugins table
  • Populated by POST /sync or periodic background sync

Example Request:

GET /api/plugins/marketplace/catalog

Example Response:

{
  "plugins": [
    {
      "name": "slack-notifications",
      "version": "1.2.3",
      "display_name": "Slack Notifications",
      "description": "...",
      "manifest": {...}
    }
  ],
  "count": 1
}

HTTP Status Codes:

  • 200: Success (may return empty array if catalog not synced)
  • 500: Database or marketplace error

func (*PluginMarketplaceHandler) ListInstalledPlugins

func (h *PluginMarketplaceHandler) ListInstalledPlugins(c *gin.Context)

ListInstalledPlugins lists all plugins currently loaded in the runtime.

Endpoint: GET /api/plugins/marketplace/installed

Response: JSON with plugins array and count

Data Source:

  • runtime.ListPlugins() returns currently loaded plugins from memory
  • This shows runtime state, not database state

Example Request:

GET /api/plugins/marketplace/installed

Example Response:

{
  "plugins": [
    {
      "name": "slack-notifications",
      "version": "1.2.3",
      "enabled": true,
      "loaded_at": "2025-01-15T10:30:00Z",
      "is_builtin": false
    }
  ],
  "count": 1
}

HTTP Status Codes:

  • 200: Success (always succeeds, may return empty array)

func (*PluginMarketplaceHandler) RegisterRoutes

func (h *PluginMarketplaceHandler) RegisterRoutes(r *gin.RouterGroup)

RegisterRoutes registers plugin marketplace routes to the provided router group.

Mounts all marketplace endpoints under /plugins/marketplace prefix:

  • Catalog endpoints: /plugins/marketplace/catalog, /plugins/marketplace/sync
  • Installation endpoints: /plugins/marketplace/install/:name, etc.
  • Installed endpoints: /plugins/marketplace/installed

Parameters:

  • r: Gin router group to mount routes on (typically /api)

Example:

api := router.Group("/api")
handler.RegisterRoutes(api)
// Routes available at: /api/plugins/marketplace/catalog, etc.

func (*PluginMarketplaceHandler) SyncCatalog

func (h *PluginMarketplaceHandler) SyncCatalog(c *gin.Context)

SyncCatalog forces a synchronization of the plugin catalog from external repository.

Endpoint: POST /api/plugins/marketplace/sync

Behavior:

  • Fetches latest plugin list from configured repository URL
  • Updates catalog_plugins table with new/updated plugins
  • Updates catalog_repositories table with repository metadata

Example Request:

POST /api/plugins/marketplace/sync

Example Response:

{
  "message": "Catalog synced successfully"
}

Use Cases:

  • Manual catalog refresh after repository update
  • Troubleshooting catalog sync issues
  • Initial catalog population

HTTP Status Codes:

  • 200: Catalog synced successfully
  • 500: Sync failed (network error, invalid catalog format, etc.)

func (*PluginMarketplaceHandler) UninstallPlugin

func (h *PluginMarketplaceHandler) UninstallPlugin(c *gin.Context)

UninstallPlugin unloads and uninstalls a plugin.

Endpoint: DELETE /api/plugins/marketplace/uninstall/:name

Path Parameters:

  • name: Plugin name to uninstall

Behavior:

  1. Calls runtime.UnloadPlugin (unloads from runtime)
  2. Calls marketplace.UninstallPlugin (removes from database)

Note: Unload errors are logged but don't fail the request (plugin might not be loaded).

Example Request:

DELETE /api/plugins/marketplace/uninstall/slack-notifications

HTTP Status Codes:

  • 200: Plugin uninstalled successfully
  • 500: Uninstall failed

func (*PluginMarketplaceHandler) UpdatePluginConfig

func (h *PluginMarketplaceHandler) UpdatePluginConfig(c *gin.Context)

UpdatePluginConfig updates a plugin's configuration.

Endpoint: PUT /api/plugins/marketplace/installed/:name/config

Path Parameters:

  • name: Plugin name

Request Body:

{
  "config": {"api_key": "new-value"}
}

TODO: Implementation needed

  • Update installed_plugins.config column
  • Reload plugin with new config

Example Request:

PUT /api/plugins/marketplace/installed/slack-notifications/config
{
  "config": {"webhook_url": "https://new-url.com"}
}

HTTP Status Codes:

  • 200: Config updated (currently always succeeds - TODO)
  • 400: Invalid request body

type Point

type Point struct {
	X int `json:"x"`
	Y int `json:"y"`
}

Point represents a coordinate point

type PredictiveScalingConfig

type PredictiveScalingConfig struct {
	Enabled          bool           `json:"enabled"`
	SchedulePattern  map[string]int `json:"schedule_pattern,omitempty"` // Hour -> replica count
	LookAheadMinutes int            `json:"look_ahead_minutes"`         // Pre-scale before demand
}

PredictiveScalingConfig for schedule-based scaling

type PreferencesHandler

type PreferencesHandler struct {
	// contains filtered or unexported fields
}

PreferencesHandler handles user preferences and settings

func NewPreferencesHandler

func NewPreferencesHandler(database *db.Database) *PreferencesHandler

NewPreferencesHandler creates a new preferences handler

func (*PreferencesHandler) AddFavorite

func (h *PreferencesHandler) AddFavorite(c *gin.Context)

AddFavorite adds a template to favorites

func (*PreferencesHandler) GetDefaultsPreferences

func (h *PreferencesHandler) GetDefaultsPreferences(c *gin.Context)

GetDefaultsPreferences returns default session preferences

func (*PreferencesHandler) GetFavorites

func (h *PreferencesHandler) GetFavorites(c *gin.Context)

GetFavorites returns user's favorite templates

func (*PreferencesHandler) GetNotificationPreferences

func (h *PreferencesHandler) GetNotificationPreferences(c *gin.Context)

GetNotificationPreferences returns notification preferences

func (*PreferencesHandler) GetPreferences

func (h *PreferencesHandler) GetPreferences(c *gin.Context)

GetPreferences returns all user preferences

func (*PreferencesHandler) GetRecentSessions

func (h *PreferencesHandler) GetRecentSessions(c *gin.Context)

GetRecentSessions returns user's recent sessions

func (*PreferencesHandler) GetUIPreferences

func (h *PreferencesHandler) GetUIPreferences(c *gin.Context)

GetUIPreferences returns UI-specific preferences

func (*PreferencesHandler) RegisterRoutes

func (h *PreferencesHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers preference routes

func (*PreferencesHandler) RemoveFavorite

func (h *PreferencesHandler) RemoveFavorite(c *gin.Context)

RemoveFavorite removes a template from favorites

func (*PreferencesHandler) ResetPreferences

func (h *PreferencesHandler) ResetPreferences(c *gin.Context)

Reset Preferences resets to defaults

func (*PreferencesHandler) UpdateDefaultsPreferences

func (h *PreferencesHandler) UpdateDefaultsPreferences(c *gin.Context)

UpdateDefaultsPreferences updates default session preferences

func (*PreferencesHandler) UpdateNotificationPreferences

func (h *PreferencesHandler) UpdateNotificationPreferences(c *gin.Context)

UpdateNotificationPreferences updates notification preferences

func (*PreferencesHandler) UpdatePreferences

func (h *PreferencesHandler) UpdatePreferences(c *gin.Context)

UpdatePreferences updates user preferences

func (*PreferencesHandler) UpdateUIPreferences

func (h *PreferencesHandler) UpdateUIPreferences(c *gin.Context)

UpdateUIPreferences updates UI-specific preferences

type QuotaPolicyRequest

type QuotaPolicyRequest struct {
	Name        string `json:"name" binding:"required" validate:"required,min=1,max=200"`
	Description string `json:"description" validate:"omitempty,max=1000"`
	Rules       string `json:"rules" binding:"required" validate:"required,max=10000"`
	Priority    int    `json:"priority" validate:"gte=0,lte=100"`
	Enabled     bool   `json:"enabled"`
}

QuotaPolicyRequest represents a quota policy create/update request

type QuotasHandler

type QuotasHandler struct {
	// contains filtered or unexported fields
}

QuotasHandler handles resource quotas and limits.

This handler provides endpoints for: - Getting and setting quotas for users and teams - Checking current resource usage against quotas - Detecting and reporting quota violations - Managing quota policies and rules

func NewQuotasHandler

func NewQuotasHandler(database *db.Database) *QuotasHandler

NewQuotasHandler creates a new quotas handler

func (*QuotasHandler) CheckQuota

func (h *QuotasHandler) CheckQuota(c *gin.Context)

CheckQuota checks if a quota would be exceeded

func (*QuotasHandler) CreatePolicy

func (h *QuotasHandler) CreatePolicy(c *gin.Context)

CreatePolicy creates a new quota policy

func (*QuotasHandler) DeletePolicy

func (h *QuotasHandler) DeletePolicy(c *gin.Context)

DeletePolicy deletes a quota policy

func (*QuotasHandler) DeleteTeamQuota

func (h *QuotasHandler) DeleteTeamQuota(c *gin.Context)

DeleteTeamQuota deletes quota for a specific team

func (*QuotasHandler) DeleteUserQuota

func (h *QuotasHandler) DeleteUserQuota(c *gin.Context)

DeleteUserQuota deletes quota for a specific user

func (*QuotasHandler) GetDefaultQuotas

func (h *QuotasHandler) GetDefaultQuotas(c *gin.Context)

GetDefaultQuotas returns default quotas

func (*QuotasHandler) GetPolicies

func (h *QuotasHandler) GetPolicies(c *gin.Context)

GetPolicies returns all quota policies

func (*QuotasHandler) GetPolicy

func (h *QuotasHandler) GetPolicy(c *gin.Context)

GetPolicy returns a specific quota policy

func (*QuotasHandler) GetQuotaViolations

func (h *QuotasHandler) GetQuotaViolations(c *gin.Context)

GetQuotaViolations returns users/teams exceeding quotas

func (*QuotasHandler) GetTeamQuota

func (h *QuotasHandler) GetTeamQuota(c *gin.Context)

GetTeamQuota returns quota for a specific team

func (*QuotasHandler) GetTeamQuotaStatus

func (h *QuotasHandler) GetTeamQuotaStatus(c *gin.Context)

GetTeamQuotaStatus returns quota vs usage status for a team

func (*QuotasHandler) GetTeamUsage

func (h *QuotasHandler) GetTeamUsage(c *gin.Context)

GetTeamUsage returns current resource usage for a team

func (*QuotasHandler) GetUserQuota

func (h *QuotasHandler) GetUserQuota(c *gin.Context)

GetUserQuota returns quota for a specific user

func (*QuotasHandler) GetUserQuotaStatus

func (h *QuotasHandler) GetUserQuotaStatus(c *gin.Context)

GetUserQuotaStatus returns quota vs usage status for a user

func (*QuotasHandler) GetUserUsage

func (h *QuotasHandler) GetUserUsage(c *gin.Context)

GetUserUsage returns current resource usage for a user

func (*QuotasHandler) ListAllQuotas

func (h *QuotasHandler) ListAllQuotas(c *gin.Context)

ListAllQuotas returns all configured quotas

func (*QuotasHandler) RegisterRoutes

func (h *QuotasHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers quota routes

func (*QuotasHandler) SetDefaultQuotas

func (h *QuotasHandler) SetDefaultQuotas(c *gin.Context)

SetDefaultQuotas sets default quotas (stored in config or database)

func (*QuotasHandler) SetTeamQuota

func (h *QuotasHandler) SetTeamQuota(c *gin.Context)

SetTeamQuota sets quota for a specific team

func (*QuotasHandler) SetUserQuota

func (h *QuotasHandler) SetUserQuota(c *gin.Context)

SetUserQuota sets quota for a specific user

func (*QuotasHandler) UpdatePolicy

func (h *QuotasHandler) UpdatePolicy(c *gin.Context)

UpdatePolicy updates a quota policy

type Recording

type Recording struct {
	ID              int64      `json:"id"`
	SessionID       string     `json:"session_id"`
	RecordingType   string     `json:"recording_type"`
	StoragePath     string     `json:"storage_path"`
	FileSizeBytes   int64      `json:"file_size_bytes"`
	DurationSeconds int        `json:"duration_seconds"`
	StartedAt       *time.Time `json:"started_at"`
	EndedAt         *time.Time `json:"ended_at"`
	Status          string     `json:"status"`
	ErrorMessage    *string    `json:"error_message"`
	CreatedBy       *string    `json:"created_by"`
	CreatedAt       time.Time  `json:"created_at"`
	UpdatedAt       time.Time  `json:"updated_at"`

	// Computed fields
	SessionName       string  `json:"session_name,omitempty"`
	UserName          string  `json:"user_name,omitempty"`
	FileSizeMB        float64 `json:"file_size_mb,omitempty"`
	DurationFormatted string  `json:"duration_formatted,omitempty"`
}

Recording represents a session recording

type RecordingHandler

type RecordingHandler struct {
	// contains filtered or unexported fields
}

RecordingHandler handles session recording management

func NewRecordingHandler

func NewRecordingHandler(database *db.Database) *RecordingHandler

NewRecordingHandler creates a new recording handler

func (*RecordingHandler) CreatePolicy

func (h *RecordingHandler) CreatePolicy(c *gin.Context)

CreatePolicy creates a new recording policy

func (*RecordingHandler) DeletePolicy

func (h *RecordingHandler) DeletePolicy(c *gin.Context)

DeletePolicy deletes a recording policy

func (*RecordingHandler) DeleteRecording

func (h *RecordingHandler) DeleteRecording(c *gin.Context)

DeleteRecording deletes a recording

func (*RecordingHandler) DownloadRecording

func (h *RecordingHandler) DownloadRecording(c *gin.Context)

DownloadRecording downloads a recording file

func (*RecordingHandler) GetPolicy

func (h *RecordingHandler) GetPolicy(c *gin.Context)

GetPolicy gets a specific recording policy

func (*RecordingHandler) GetRecording

func (h *RecordingHandler) GetRecording(c *gin.Context)

GetRecording gets a specific recording

func (*RecordingHandler) GetRecordingAccessLog

func (h *RecordingHandler) GetRecordingAccessLog(c *gin.Context)

GetRecordingAccessLog gets access log for a recording

func (*RecordingHandler) ListPolicies

func (h *RecordingHandler) ListPolicies(c *gin.Context)

ListPolicies lists all recording policies

func (*RecordingHandler) ListRecordings

func (h *RecordingHandler) ListRecordings(c *gin.Context)

ListRecordings lists all recordings with filtering

func (*RecordingHandler) RegisterRoutes

func (h *RecordingHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers recording routes

func (*RecordingHandler) StartRecording

func (h *RecordingHandler) StartRecording(c *gin.Context)

StartRecording starts a recording for a session

func (*RecordingHandler) StopRecording

func (h *RecordingHandler) StopRecording(c *gin.Context)

StopRecording stops a recording

func (*RecordingHandler) UpdatePolicy

func (h *RecordingHandler) UpdatePolicy(c *gin.Context)

UpdatePolicy updates a recording policy

type RecordingPolicy

type RecordingPolicy struct {
	ID                int64                  `json:"id"`
	Name              string                 `json:"name"`
	Description       *string                `json:"description"`
	AutoRecord        bool                   `json:"auto_record"`
	RecordingFormat   string                 `json:"recording_format"`
	RetentionDays     int                    `json:"retention_days"`
	ApplyToUsers      map[string]interface{} `json:"apply_to_users"`
	ApplyToTeams      map[string]interface{} `json:"apply_to_teams"`
	ApplyToTemplates  map[string]interface{} `json:"apply_to_templates"`
	RequireReason     bool                   `json:"require_reason"`
	AllowUserPlayback bool                   `json:"allow_user_playback"`
	AllowUserDownload bool                   `json:"allow_user_download"`
	RequireApproval   bool                   `json:"require_approval"`
	NotifyOnRecording bool                   `json:"notify_on_recording"`
	Metadata          map[string]interface{} `json:"metadata"`
	Enabled           bool                   `json:"enabled"`
	Priority          int                    `json:"priority"`
	CreatedAt         time.Time              `json:"created_at"`
	UpdatedAt         time.Time              `json:"updated_at"`
}

RecordingPolicy represents a recording policy

type ResourceConfig

type ResourceConfig struct {
	Memory   string `json:"memory" validate:"required,min=2,max=20"`       // e.g., "512Mi", "2Gi"
	CPU      string `json:"cpu" validate:"required,min=1,max=20"`          // e.g., "100m", "2"
	Storage  string `json:"storage,omitempty" validate:"omitempty,max=20"` // e.g., "1Gi", "10Gi"
	GPUCount int    `json:"gpu_count,omitempty" validate:"omitempty,gte=0,lte=8"`
}

ResourceConfig for scheduled sessions

type ResourceThresholds

type ResourceThresholds struct {
	CPUPercent    float64 `json:"cpu_percent"`     // Max CPU % before avoiding node
	MemoryPercent float64 `json:"memory_percent"`  // Max memory % before avoiding node
	MaxSessions   int     `json:"max_sessions"`    // Max concurrent sessions per node
	MinFreeCPU    float64 `json:"min_free_cpu"`    // Min free CPU cores required
	MinFreeMemory int64   `json:"min_free_memory"` // Min free memory in bytes
}

ResourceThresholds for load balancing decisions

type SavedSearch

type SavedSearch struct {
	ID          string                 `json:"id"`
	UserID      string                 `json:"userId"`
	Name        string                 `json:"name"`
	Description string                 `json:"description,omitempty"`
	Query       string                 `json:"query"`
	Filters     map[string]interface{} `json:"filters,omitempty"`
	CreatedAt   time.Time              `json:"createdAt"`
	UpdatedAt   time.Time              `json:"updatedAt"`
}

SavedSearch represents a saved search query

type ScalePolicy

type ScalePolicy struct {
	Threshold     float64 `json:"threshold"`             // Metric threshold to trigger
	Increment     int     `json:"increment"`             // How many replicas to add/remove
	Stabilization int     `json:"stabilization_seconds"` // Wait before next action
	MaxIncrement  int     `json:"max_increment"`         // Max replicas to add at once
}

ScalePolicy defines how to scale up or down

type ScalingEvent

type ScalingEvent struct {
	ID               int64     `json:"id"`
	PolicyID         int64     `json:"policy_id"`
	TargetType       string    `json:"target_type"`
	TargetID         string    `json:"target_id"`
	Action           string    `json:"action"` // "scale_up", "scale_down"
	PreviousReplicas int       `json:"previous_replicas"`
	NewReplicas      int       `json:"new_replicas"`
	Trigger          string    `json:"trigger"` // "metric", "schedule", "manual"
	MetricValue      float64   `json:"metric_value,omitempty"`
	Reason           string    `json:"reason"`
	Status           string    `json:"status"` // "pending", "in_progress", "completed", "failed"
	CreatedAt        time.Time `json:"created_at"`
}

ScalingEvent represents a scaling action

type ScheduleConfig

type ScheduleConfig struct {
	Type       string    `json:"type" validate:"required,oneof=once daily weekly monthly cron"`
	StartTime  time.Time `json:"start_time,omitempty"`
	CronExpr   string    `json:"cron_expr,omitempty" validate:"omitempty,max=100"`
	DaysOfWeek []int     `json:"days_of_week,omitempty" validate:"omitempty,dive,gte=0,lte=6"` // 0=Sunday, 6=Saturday
	DayOfMonth int       `json:"day_of_month,omitempty" validate:"omitempty,gte=1,lte=31"`
	TimeOfDay  string    `json:"time_of_day,omitempty" validate:"omitempty,len=5"` // HH:MM format (5 chars)
	EndDate    time.Time `json:"end_date,omitempty"`
	Exceptions []string  `json:"exceptions,omitempty" validate:"omitempty,dive,len=10"` // YYYY-MM-DD format (10 chars)
}

ScheduleConfig defines when a session should run

type ScheduledSession

type ScheduledSession struct {
	ID             int64                  `json:"id"`
	UserID         string                 `json:"user_id"`
	TemplateID     string                 `json:"template_id" validate:"required,min=1,max=100"`
	Name           string                 `json:"name" validate:"required,min=1,max=200"`
	Description    string                 `json:"description,omitempty" validate:"omitempty,max=1000"`
	Timezone       string                 `json:"timezone" validate:"required,min=1,max=50"`
	Schedule       ScheduleConfig         `json:"schedule" validate:"required"`
	Resources      ResourceConfig         `json:"resources" validate:"required"`
	AutoTerminate  bool                   `json:"auto_terminate"`
	TerminateAfter int                    `json:"terminate_after_minutes,omitempty" validate:"omitempty,gte=1,lte=1440"` // 1-1440 minutes (24 hours)
	PreWarm        bool                   `json:"pre_warm"`
	PreWarmMinutes int                    `json:"pre_warm_minutes,omitempty" validate:"omitempty,gte=1,lte=120"` // 1-120 minutes
	PostCleanup    bool                   `json:"post_cleanup"`
	Enabled        bool                   `json:"enabled"`
	NextRunAt      time.Time              `json:"next_run_at,omitempty"`
	LastRunAt      time.Time              `json:"last_run_at,omitempty"`
	LastSessionID  string                 `json:"last_session_id,omitempty"`
	LastRunStatus  string                 `json:"last_run_status,omitempty"`
	Metadata       map[string]interface{} `json:"metadata,omitempty"`
	CreatedAt      time.Time              `json:"created_at"`
	UpdatedAt      time.Time              `json:"updated_at"`
}

ScheduledSession represents a scheduled workspace session that starts automatically.

This struct defines a session that will be created at specific times based on the configured schedule. Unlike on-demand sessions, scheduled sessions are managed by a background scheduler process that monitors next_run_at timestamps.

Lifecycle: 1. User creates scheduled session via API 2. System calculates next_run_at based on schedule configuration 3. Scheduler daemon checks for due schedules every minute 4. When next_run_at is reached, system creates actual Session resource 5. After session is created, next_run_at is recalculated for recurring schedules 6. System optionally terminates session after terminate_after minutes

Example use cases: - Development environment that starts at 9 AM and terminates at 6 PM - Weekly demo session every Friday at 2 PM - Training environment that pre-warms 15 minutes before scheduled time

type SchedulingHandler

type SchedulingHandler struct {
	DB *db.Database
}

SchedulingHandler handles session scheduling and calendar integration requests.

func NewSchedulingHandler

func NewSchedulingHandler(database *db.Database) *SchedulingHandler

NewSchedulingHandler creates a new scheduling handler.

func (*SchedulingHandler) CalendarOAuthCallback

func (h *SchedulingHandler) CalendarOAuthCallback(c *gin.Context)

CalendarOAuthCallback handles OAuth callback (DEPRECATED)

func (*SchedulingHandler) ConnectCalendar

func (h *SchedulingHandler) ConnectCalendar(c *gin.Context)

ConnectCalendar initiates calendar OAuth flow (DEPRECATED)

func (*SchedulingHandler) CreateScheduledSession

func (h *SchedulingHandler) CreateScheduledSession(c *gin.Context)

CreateScheduledSession creates a new scheduled session.

This endpoint allows users to schedule sessions that will start automatically at specific times. The system performs several validations and checks before accepting the schedule:

VALIDATION STEPS:

1. Schedule Validation:

  • Ensures required fields are present for the schedule type
  • For "daily": requires time_of_day
  • For "weekly": requires time_of_day and days_of_week
  • For "monthly": requires time_of_day and day_of_month
  • For "cron": validates cron expression syntax
  • For "once": requires start_time

2. Next Run Calculation:

  • Computes when the schedule will next trigger
  • Uses the user's timezone for proper time conversion
  • For recurring schedules, calculates first occurrence after current time

3. Conflict Detection:

  • Checks if the proposed schedule would overlap with existing schedules
  • Prevents double-booking that could violate quotas or confuse users
  • Considers session duration (terminate_after) when detecting overlaps
  • Returns HTTP 409 Conflict if overlaps are found

CONFLICT DETECTION LOGIC:

Two schedules conflict if their time windows overlap: - Schedule A: [next_run_at, next_run_at + terminate_after] - Schedule B: [next_run_at, next_run_at + terminate_after] - Conflict if: A.start < B.end AND B.start < A.end

EXAMPLE REQUEST:

{
  "name": "Daily Dev Environment",
  "template_id": "vscode",
  "timezone": "America/New_York",
  "schedule": {
    "type": "daily",
    "time_of_day": "09:00"
  },
  "terminate_after": 540,  // 9 hours
  "pre_warm": true,
  "pre_warm_minutes": 15
}

RESPONSE:

{
  "id": 42,
  "message": "Scheduled session created",
  "next_run_at": "2025-11-17T09:00:00-05:00",
  "schedule": { ... }
}

SECURITY:

- User can only create schedules for themselves (userID enforced) - Schedule is validated to prevent malicious cron expressions - Timezone must be valid IANA timezone name

func (*SchedulingHandler) DeleteScheduledSession

func (h *SchedulingHandler) DeleteScheduledSession(c *gin.Context)

DeleteScheduledSession deletes a scheduled session

func (*SchedulingHandler) DisableScheduledSession

func (h *SchedulingHandler) DisableScheduledSession(c *gin.Context)

DisableScheduledSession disables a schedule

func (*SchedulingHandler) DisconnectCalendar

func (h *SchedulingHandler) DisconnectCalendar(c *gin.Context)

DisconnectCalendar removes a calendar integration (DEPRECATED)

func (*SchedulingHandler) EnableScheduledSession

func (h *SchedulingHandler) EnableScheduledSession(c *gin.Context)

EnableScheduledSession enables a schedule

func (*SchedulingHandler) ExportICalendar

func (h *SchedulingHandler) ExportICalendar(c *gin.Context)

ExportICalendar exports scheduled sessions as iCal format (DEPRECATED)

func (*SchedulingHandler) GetScheduledSession

func (h *SchedulingHandler) GetScheduledSession(c *gin.Context)

GetScheduledSession gets details of a scheduled session

func (*SchedulingHandler) ListCalendarIntegrations

func (h *SchedulingHandler) ListCalendarIntegrations(c *gin.Context)

ListCalendarIntegrations lists user's calendar integrations (DEPRECATED)

func (*SchedulingHandler) ListScheduledSessions

func (h *SchedulingHandler) ListScheduledSessions(c *gin.Context)

ListScheduledSessions lists all scheduled sessions for a user

func (*SchedulingHandler) SyncCalendar

func (h *SchedulingHandler) SyncCalendar(c *gin.Context)

SyncCalendar manually triggers calendar sync (DEPRECATED)

func (*SchedulingHandler) UpdateScheduledSession

func (h *SchedulingHandler) UpdateScheduledSession(c *gin.Context)

UpdateScheduledSession updates a scheduled session

type SearchHandler

type SearchHandler struct {
	// contains filtered or unexported fields
}

SearchHandler handles advanced search and filtering

func NewSearchHandler

func NewSearchHandler(database *db.Database) *SearchHandler

NewSearchHandler creates a new search handler

func (*SearchHandler) AdvancedSearch

func (h *SearchHandler) AdvancedSearch(c *gin.Context)

AdvancedSearch performs multi-criteria search

func (*SearchHandler) ClearSearchHistory

func (h *SearchHandler) ClearSearchHistory(c *gin.Context)

ClearSearchHistory clears user's search history

func (*SearchHandler) CreateSavedSearch

func (h *SearchHandler) CreateSavedSearch(c *gin.Context)

CreateSavedSearch creates a new saved search

func (*SearchHandler) DeleteSavedSearch

func (h *SearchHandler) DeleteSavedSearch(c *gin.Context)

DeleteSavedSearch deletes a saved search

func (*SearchHandler) ExecuteSavedSearch

func (h *SearchHandler) ExecuteSavedSearch(c *gin.Context)

ExecuteSavedSearch executes a saved search

func (*SearchHandler) GetAppTypes

func (h *SearchHandler) GetAppTypes(c *gin.Context)

GetAppTypes returns all app types

func (*SearchHandler) GetCategories

func (h *SearchHandler) GetCategories(c *gin.Context)

GetCategories returns all template categories

func (*SearchHandler) GetPopularTags

func (h *SearchHandler) GetPopularTags(c *gin.Context)

GetPopularTags returns most popular tags

func (*SearchHandler) GetSavedSearch

func (h *SearchHandler) GetSavedSearch(c *gin.Context)

GetSavedSearch retrieves a specific saved search

func (*SearchHandler) GetSearchHistory

func (h *SearchHandler) GetSearchHistory(c *gin.Context)

GetSearchHistory returns user's recent searches

func (*SearchHandler) ListSavedSearches

func (h *SearchHandler) ListSavedSearches(c *gin.Context)

ListSavedSearches returns user's saved searches

func (*SearchHandler) RegisterRoutes

func (h *SearchHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers search routes

func (*SearchHandler) Search

func (h *SearchHandler) Search(c *gin.Context)

Search performs universal search across all entities

func (*SearchHandler) SearchSessions

func (h *SearchHandler) SearchSessions(c *gin.Context)

SearchSessions searches user sessions

func (*SearchHandler) SearchSuggestions

func (h *SearchHandler) SearchSuggestions(c *gin.Context)

SearchSuggestions provides auto-complete suggestions

func (*SearchHandler) SearchTemplates

func (h *SearchHandler) SearchTemplates(c *gin.Context)

SearchTemplates performs advanced template search

func (*SearchHandler) UpdateSavedSearch

func (h *SearchHandler) UpdateSavedSearch(c *gin.Context)

UpdateSavedSearch updates a saved search

type SearchResult

type SearchResult struct {
	Type        string                 `json:"type"` // template, session, user, etc.
	ID          string                 `json:"id"`
	Name        string                 `json:"name"`
	DisplayName string                 `json:"displayName,omitempty"`
	Description string                 `json:"description,omitempty"`
	Category    string                 `json:"category,omitempty"`
	Tags        []string               `json:"tags,omitempty"`
	Icon        string                 `json:"icon,omitempty"`
	Score       float64                `json:"score"` // Relevance score
	Metadata    map[string]interface{} `json:"metadata,omitempty"`
}

SearchResult represents a search result item

type SecurityHandler

type SecurityHandler struct {
	DB *sql.DB
}

SecurityHandler handles security-related endpoints (MFA, IP whitelisting, etc.)

func NewSecurityHandler

func NewSecurityHandler(database *db.Database) *SecurityHandler

NewSecurityHandler creates a new SecurityHandler instance

func (*SecurityHandler) CheckDevicePosture

func (h *SecurityHandler) CheckDevicePosture(c *gin.Context)

CheckDevicePosture checks device security posture

func (*SecurityHandler) CheckIPAccess

func (h *SecurityHandler) CheckIPAccess(c *gin.Context)

CheckIPAccess checks if an IP is allowed access

func (*SecurityHandler) CreateIPWhitelist

func (h *SecurityHandler) CreateIPWhitelist(c *gin.Context)

CreateIPWhitelist adds an IP to whitelist

func (*SecurityHandler) DeleteIPWhitelist

func (h *SecurityHandler) DeleteIPWhitelist(c *gin.Context)

DeleteIPWhitelist removes an IP whitelist entry.

CRITICAL SECURITY FIX (2025-11-14): Fixed authorization enumeration vulnerability by returning consistent "not found" error for both non-existent entries AND unauthorized access attempts.

Authorization Enumeration Attack: Before fix:

  • Try to delete entry 123: "Forbidden" → Entry exists but you can't access it
  • Try to delete entry 999: "Not found" → Entry doesn't exist
  • Attacker can enumerate which entries exist by trying many IDs

After fix:

  • Try to delete entry 123: "Not found" → Could be either case
  • Try to delete entry 999: "Not found" → Could be either case
  • Attacker cannot determine if entry exists or just lacks permission

Implementation: - Admins: DELETE any entry - Users: DELETE only if (user_id = $userID OR user_id IS NULL) - Check rows affected: 0 = either not found OR unauthorized - Always return 404 when rowsAffected = 0 (no information leakage)

Parameters:

  • entryId: IP whitelist entry ID from URL path
  • userID: From authentication context
  • role: User role ("admin" or "user")

Returns:

  • 200 OK: Entry deleted successfully
  • 404 Not Found: Entry doesn't exist OR user lacks permission (secure, no information leakage)
  • 500 Internal Server Error: Database error

func (*SecurityHandler) DisableMFA

func (h *SecurityHandler) DisableMFA(c *gin.Context)

DisableMFA disables an MFA method

func (*SecurityHandler) GenerateBackupCodes

func (h *SecurityHandler) GenerateBackupCodes(c *gin.Context)

GenerateBackupCodes generates new backup codes

func (*SecurityHandler) GetSecurityAlerts

func (h *SecurityHandler) GetSecurityAlerts(c *gin.Context)

GetSecurityAlerts gets security alerts for a user

func (*SecurityHandler) ListIPWhitelist

func (h *SecurityHandler) ListIPWhitelist(c *gin.Context)

ListIPWhitelist lists IP whitelist entries

func (*SecurityHandler) ListMFAMethods

func (h *SecurityHandler) ListMFAMethods(c *gin.Context)

ListMFAMethods lists all MFA methods for a user

func (*SecurityHandler) SetupMFA

func (h *SecurityHandler) SetupMFA(c *gin.Context)

func (*SecurityHandler) VerifyMFA

func (h *SecurityHandler) VerifyMFA(c *gin.Context)

VerifyMFA verifies MFA code during login (used after username/password authentication).

CRITICAL SECURITY FIX (2025-11-14): Added rate limiting (5 attempts per minute) to prevent brute force attacks on 6-digit TOTP codes.

Why Rate Limiting is Critical: - TOTP codes are only 6 digits (1,000,000 possible values) - Codes are valid for 30-60 seconds (time window allows some drift) - Without rate limiting, attacker could brute force in ~15 minutes - With 5 attempts/minute, brute force takes ~3,850 hours (160 days)

Process: 1. Check rate limit (5 attempts/minute per user) 2. Reject SMS/Email MFA (not implemented) 3. Verify code (TOTP or backup code) 4. If successful, set MFA session flag 5. Optionally trust device (sets long-lived cookie)

Security: - Rate limiting prevents brute force (5 attempts/minute) - Backup codes are single-use and hashed (SHA-256) - TOTP codes expire every 30 seconds - "Trust device" cookie has limited lifetime and device fingerprint

Parameters:

  • userID: From authentication context (JWT)
  • req.Code: 6-digit TOTP code or 8-character backup code
  • req.MethodType: "totp" (default), "sms" (disabled), "email" (disabled), "backup_code"
  • req.TrustDevice: If true, set remember-me cookie for this device

Returns:

  • 200 OK: MFA verification successful
  • 400 Bad Request: Invalid input
  • 401 Unauthorized: Invalid code
  • 404 Not Found: MFA method not enabled
  • 429 Too Many Requests: Rate limit exceeded (>5 attempts/minute)
  • 501 Not Implemented: SMS/Email MFA requested

func (*SecurityHandler) VerifyMFASetup

func (h *SecurityHandler) VerifyMFASetup(c *gin.Context)

VerifyMFASetup verifies and enables MFA method (Step 2: Confirm setup)

func (*SecurityHandler) VerifySession

func (h *SecurityHandler) VerifySession(c *gin.Context)

VerifySession performs continuous session verification

type SelkiesProxyHandler

type SelkiesProxyHandler struct {
	// contains filtered or unexported fields
}

SelkiesProxyHandler manages HTTP/WebSocket connections to Selkies-based sessions.

It proxies HTTP and WebSocket traffic between UI clients and session Services, enabling remote access to web-based streaming interfaces (Selkies, Kasm, Guacamole).

func NewSelkiesProxyHandler

func NewSelkiesProxyHandler(database *db.Database, agentHub *ws.AgentHub, namespace string) *SelkiesProxyHandler

NewSelkiesProxyHandler creates a new Selkies/HTTP proxy handler.

Example:

handler := NewSelkiesProxyHandler(database, agentHub, "streamspace")
router.Any("/http/:sessionId/*path", handler.HandleHTTPProxy)

func (*SelkiesProxyHandler) HandleHTTPProxy

func (h *SelkiesProxyHandler) HandleHTTPProxy(c *gin.Context)

HandleHTTPProxy handles HTTP/WebSocket proxy connections to Selkies-based sessions.

Endpoint: ANY /api/v1/http/:sessionId/*path

Query Parameters:

  • token: JWT authentication token (required)

Flow:

  1. Authenticate user via JWT
  2. Verify user has access to session
  3. Look up session streaming protocol metadata
  4. Verify session uses HTTP-based streaming (selkies, guacamole, etc.)
  5. Look up agent hosting the session
  6. Verify agent is connected
  7. Proxy HTTP/WebSocket traffic to agent → pod

Example:

http://control-plane/api/v1/http/sess-123/
http://control-plane/api/v1/http/sess-123/websockify

func (*SelkiesProxyHandler) RegisterRoutes

func (h *SelkiesProxyHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers the Selkies/HTTP proxy routes.

Routes:

  • ANY /http/:sessionId/*path - HTTP/WebSocket proxy for Selkies-based sessions

Example:

selkiesProxyHandler.RegisterRoutes(router)

type SendCommandRequest

type SendCommandRequest struct {
	Action    string                 `json:"action" binding:"required" validate:"required,oneof=start_session stop_session hibernate_session wake_session"`
	SessionID string                 `json:"sessionId,omitempty" validate:"omitempty,min=1,max=100"`
	Payload   map[string]interface{} `json:"payload,omitempty"`
}

SendCommand godoc @Summary Send a command to an agent @Description Creates and dispatches a command to an agent. The command is queued and sent via WebSocket. @Tags agents @Accept json @Produce json @Param agent_id path string true "Agent ID" @Param request body models.SendCommandRequest true "Command request" @Success 201 {object} models.AgentCommand "Command created and queued" @Failure 400 {object} map[string]interface{} "Invalid request" @Failure 404 {object} map[string]interface{} "Agent not found" @Failure 503 {object} map[string]interface{} "Agent not connected" @Failure 500 {object} map[string]interface{} "Internal server error" @Router /agents/{agent_id}/command [post] SendCommandRequest represents a command to send to an agent

type SessionActivityEvent

type SessionActivityEvent struct {
	ID            int                    `json:"id"`
	SessionID     string                 `json:"sessionId"`
	UserID        string                 `json:"userId,omitempty"`
	EventType     string                 `json:"eventType"`
	EventCategory string                 `json:"eventCategory"`
	Description   string                 `json:"description,omitempty"`
	Metadata      map[string]interface{} `json:"metadata,omitempty"`
	IPAddress     string                 `json:"ipAddress,omitempty"`
	UserAgent     string                 `json:"userAgent,omitempty"`
	Timestamp     time.Time              `json:"timestamp"`
}

SessionActivityEvent represents a session activity event

type SessionActivityHandler

type SessionActivityHandler struct {
	// contains filtered or unexported fields
}

SessionActivityHandler handles session activity logging and queries

func NewSessionActivityHandler

func NewSessionActivityHandler(database *db.Database) *SessionActivityHandler

NewSessionActivityHandler creates a new session activity handler

func (*SessionActivityHandler) GetActivityStats

func (h *SessionActivityHandler) GetActivityStats(c *gin.Context)

GetActivityStats returns activity statistics

func (*SessionActivityHandler) GetSessionActivity

func (h *SessionActivityHandler) GetSessionActivity(c *gin.Context)

GetSessionActivity returns activity log for a specific session

func (*SessionActivityHandler) GetSessionTimeline

func (h *SessionActivityHandler) GetSessionTimeline(c *gin.Context)

GetSessionTimeline returns a timeline view of session activity

func (*SessionActivityHandler) GetUserSessionActivity

func (h *SessionActivityHandler) GetUserSessionActivity(c *gin.Context)

GetUserSessionActivity returns all session activity for a specific user

func (*SessionActivityHandler) LogActivityEvent

func (h *SessionActivityHandler) LogActivityEvent(c *gin.Context)

LogActivityEvent logs a session activity event

type SessionTemplate

type SessionTemplate struct {
	ID            string                 `json:"id"`
	UserID        string                 `json:"userId"`
	TeamID        string                 `json:"teamId,omitempty"`
	Name          string                 `json:"name"`
	Description   string                 `json:"description,omitempty"`
	Icon          string                 `json:"icon,omitempty"`
	Category      string                 `json:"category,omitempty"`
	Tags          []string               `json:"tags,omitempty"`
	Visibility    string                 `json:"visibility"`   // private, team, public
	BaseTemplate  string                 `json:"baseTemplate"` // Reference to catalog template
	Configuration map[string]interface{} `json:"configuration"`
	Resources     map[string]interface{} `json:"resources"`
	Environment   map[string]string      `json:"environment,omitempty"`
	IsDefault     bool                   `json:"isDefault"`
	UsageCount    int                    `json:"usageCount"`
	Version       string                 `json:"version"`
	CreatedAt     time.Time              `json:"createdAt"`
	UpdatedAt     time.Time              `json:"updatedAt"`
}

SessionTemplate represents a user-defined session configuration template

type SessionTemplatesHandler

type SessionTemplatesHandler struct {
	// contains filtered or unexported fields
}

SessionTemplatesHandler handles custom session templates and presets

func NewSessionTemplatesHandler

func NewSessionTemplatesHandler(database *db.Database, k8sClient *k8s.Client, publisher *events.Publisher, platform string) *SessionTemplatesHandler

NewSessionTemplatesHandler creates a new session templates handler

func (*SessionTemplatesHandler) CloneSessionTemplate

func (h *SessionTemplatesHandler) CloneSessionTemplate(c *gin.Context)

CloneSessionTemplate creates a copy of a template

func (*SessionTemplatesHandler) CreateSessionTemplate

func (h *SessionTemplatesHandler) CreateSessionTemplate(c *gin.Context)

CreateSessionTemplate creates a new session template

func (*SessionTemplatesHandler) CreateTemplateFromSession

func (h *SessionTemplatesHandler) CreateTemplateFromSession(c *gin.Context)

CreateTemplateFromSession creates a template from an existing session

func (*SessionTemplatesHandler) CreateTemplateVersion

func (h *SessionTemplatesHandler) CreateTemplateVersion(c *gin.Context)

func (*SessionTemplatesHandler) DeleteSessionTemplate

func (h *SessionTemplatesHandler) DeleteSessionTemplate(c *gin.Context)

DeleteSessionTemplate deletes a template

func (*SessionTemplatesHandler) GetDefaultTemplates

func (h *SessionTemplatesHandler) GetDefaultTemplates(c *gin.Context)

GetDefaultTemplates returns user's default templates

func (*SessionTemplatesHandler) GetSessionTemplate

func (h *SessionTemplatesHandler) GetSessionTemplate(c *gin.Context)

GetSessionTemplate retrieves a specific template

func (*SessionTemplatesHandler) ListPublicTemplates

func (h *SessionTemplatesHandler) ListPublicTemplates(c *gin.Context)

ListPublicTemplates returns all public templates

func (*SessionTemplatesHandler) ListSessionTemplates

func (h *SessionTemplatesHandler) ListSessionTemplates(c *gin.Context)

ListSessionTemplates returns user's session templates

func (*SessionTemplatesHandler) ListTeamTemplates

func (h *SessionTemplatesHandler) ListTeamTemplates(c *gin.Context)

ListTeamTemplates returns team templates

func (*SessionTemplatesHandler) ListTemplateShares

func (h *SessionTemplatesHandler) ListTemplateShares(c *gin.Context)

func (*SessionTemplatesHandler) ListTemplateVersions

func (h *SessionTemplatesHandler) ListTemplateVersions(c *gin.Context)

func (*SessionTemplatesHandler) PublishSessionTemplate

func (h *SessionTemplatesHandler) PublishSessionTemplate(c *gin.Context)

PublishSessionTemplate makes a template public

func (*SessionTemplatesHandler) RegisterRoutes

func (h *SessionTemplatesHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers session template routes

func (*SessionTemplatesHandler) RestoreTemplateVersion

func (h *SessionTemplatesHandler) RestoreTemplateVersion(c *gin.Context)

func (*SessionTemplatesHandler) RevokeTemplateShare

func (h *SessionTemplatesHandler) RevokeTemplateShare(c *gin.Context)

func (*SessionTemplatesHandler) SetAsDefaultTemplate

func (h *SessionTemplatesHandler) SetAsDefaultTemplate(c *gin.Context)

SetAsDefaultTemplate sets a template as the user's default

func (*SessionTemplatesHandler) ShareSessionTemplate

func (h *SessionTemplatesHandler) ShareSessionTemplate(c *gin.Context)

func (*SessionTemplatesHandler) UnpublishSessionTemplate

func (h *SessionTemplatesHandler) UnpublishSessionTemplate(c *gin.Context)

UnpublishSessionTemplate makes a template private

func (*SessionTemplatesHandler) UpdateSessionTemplate

func (h *SessionTemplatesHandler) UpdateSessionTemplate(c *gin.Context)

UpdateSessionTemplate updates a template

func (*SessionTemplatesHandler) UseSessionTemplate

func (h *SessionTemplatesHandler) UseSessionTemplate(c *gin.Context)

UseSessionTemplate creates a session from a template

type SessionVerification

type SessionVerification struct {
	ID             int64     `json:"id"`
	SessionID      string    `json:"session_id"`
	UserID         string    `json:"user_id"`
	DeviceID       string    `json:"device_id"`
	IPAddress      string    `json:"ip_address"`
	Location       string    `json:"location,omitempty"`
	RiskScore      int       `json:"risk_score"` // 0-100
	RiskLevel      string    `json:"risk_level"` // "low", "medium", "high", "critical"
	Verified       bool      `json:"verified"`
	LastVerifiedAt time.Time `json:"last_verified_at"`
	CreatedAt      time.Time `json:"created_at"`
}

SessionVerification represents continuous session verification

type SetApplicationEnabledRequest

type SetApplicationEnabledRequest struct {
	Enabled bool `json:"enabled"`
}

SetApplicationEnabled godoc @Summary Enable or disable an application @Description Toggle the application's enabled status @Tags applications @Accept json @Produce json @Param id path string true "Application ID" @Param request body object true "Enabled status" @Success 200 {object} map[string]interface{} @Failure 400 {object} ErrorResponse @Router /api/v1/applications/{id}/enabled [put] SetApplicationEnabledRequest is the request to enable/disable an application

type SetDefaultQuotasRequest

type SetDefaultQuotasRequest struct {
	User struct {
		MaxSessions int `json:"maxSessions" validate:"gte=0,lte=1000"`
		MaxCPU      int `json:"maxCPU" validate:"gte=0,lte=100000"`
		MaxMemory   int `json:"maxMemory" validate:"gte=0,lte=1000000"`
		MaxStorage  int `json:"maxStorage" validate:"gte=0,lte=10000"`
	} `json:"user" validate:"required"`
	Team struct {
		MaxSessions int `json:"maxSessions" validate:"gte=0,lte=10000"`
		MaxCPU      int `json:"maxCPU" validate:"gte=0,lte=1000000"`
		MaxMemory   int `json:"maxMemory" validate:"gte=0,lte=10000000"`
		MaxStorage  int `json:"maxStorage" validate:"gte=0,lte=100000"`
	} `json:"team" validate:"required"`
}

SetDefaultQuotasRequest represents a request to set default quotas

type SetQuotaRequest

type SetQuotaRequest struct {
	MaxSessions int `json:"maxSessions" validate:"gte=0,lte=10000"`
	MaxCPU      int `json:"maxCPU" validate:"gte=0,lte=1000000"`     // millicores, max 1000 cores
	MaxMemory   int `json:"maxMemory" validate:"gte=0,lte=10000000"` // MB, max ~10TB
	MaxStorage  int `json:"maxStorage" validate:"gte=0,lte=100000"`  // GB, max 100TB
}

SetQuotaRequest represents a request to set resource quotas

type SetupAdminRequest

type SetupAdminRequest struct {
	Password        string `json:"password" binding:"required" validate:"required,password"`
	PasswordConfirm string `json:"passwordConfirm" binding:"required" validate:"required,eqfield=Password"`
	Email           string `json:"email" binding:"required,email" validate:"required,email"`
}

SetupAdminRequest is the request body for admin setup

type SetupAdminResponse

type SetupAdminResponse struct {
	Message  string `json:"message"`
	Username string `json:"username"`
	Email    string `json:"email"`
}

SetupAdminResponse is the response after successful setup

type SetupHandler

type SetupHandler struct {
	DB *db.Database
}

SetupHandler handles initial admin setup wizard

func NewSetupHandler

func NewSetupHandler(database *db.Database) *SetupHandler

NewSetupHandler creates a new setup handler

func (*SetupHandler) GetSetupStatus

func (h *SetupHandler) GetSetupStatus(c *gin.Context)

GetSetupStatus checks if the setup wizard should be enabled GET /api/v1/auth/setup/status

Returns:

200 OK: Setup status information
500 Internal Server Error: Database error

Response body:

{
  "setupRequired": true/false,
  "adminExists": true/false,
  "hasPassword": true/false,
  "message": "Setup wizard is enabled/disabled"
}

func (*SetupHandler) RegisterRoutes

func (h *SetupHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers setup wizard endpoints These routes are public (no authentication required) as they are needed for initial admin account setup before authentication is possible.

Routes:

GET  /setup/status - Check if setup wizard is enabled
POST /setup        - Configure admin account

func (*SetupHandler) SetupAdmin

func (h *SetupHandler) SetupAdmin(c *gin.Context)

SetupAdmin configures the initial admin password POST /api/v1/auth/setup

This endpoint is only available when the admin account exists but has no password. After successful setup, it automatically disables the setup wizard.

Request body:

{
  "password": "secure-password-min-12-chars",
  "passwordConfirm": "secure-password-min-12-chars",
  "email": "admin@example.com"
}

Returns:

200 OK: Setup completed successfully
400 Bad Request: Invalid input or validation error
403 Forbidden: Setup wizard is disabled (admin already configured)
500 Internal Server Error: Database error

type SetupStatusResponse

type SetupStatusResponse struct {
	SetupRequired bool   `json:"setupRequired"`
	AdminExists   bool   `json:"adminExists"`
	HasPassword   bool   `json:"hasPassword"`
	Message       string `json:"message,omitempty"`
}

SetupStatusResponse returns whether the setup wizard should be displayed

type SharingHandler

type SharingHandler struct {
	// contains filtered or unexported fields
}

SharingHandler handles session sharing and collaboration

func NewSharingHandler

func NewSharingHandler(database *db.Database) *SharingHandler

NewSharingHandler creates a new sharing handler

func (*SharingHandler) AcceptInvitation

func (h *SharingHandler) AcceptInvitation(c *gin.Context)

AcceptInvitation accepts an invitation and creates a share

func (*SharingHandler) CreateInvitation

func (h *SharingHandler) CreateInvitation(c *gin.Context)

CreateInvitation creates a shareable invitation link

func (*SharingHandler) CreateShare

func (h *SharingHandler) CreateShare(c *gin.Context)

CreateShare creates a direct share with a specific user

func (*SharingHandler) ListCollaborators

func (h *SharingHandler) ListCollaborators(c *gin.Context)

ListCollaborators lists active collaborators for a session

func (*SharingHandler) ListInvitations

func (h *SharingHandler) ListInvitations(c *gin.Context)

ListInvitations lists all invitations for a session

func (*SharingHandler) ListSharedSessions

func (h *SharingHandler) ListSharedSessions(c *gin.Context)

ListSharedSessions lists all sessions shared with the requesting user

func (*SharingHandler) ListShares

func (h *SharingHandler) ListShares(c *gin.Context)

ListShares lists all shares for a session

func (*SharingHandler) RegisterRoutes

func (h *SharingHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers the sharing routes

func (*SharingHandler) RemoveCollaborator

func (h *SharingHandler) RemoveCollaborator(c *gin.Context)

RemoveCollaborator removes a collaborator from a session

func (*SharingHandler) RevokeInvitation

func (h *SharingHandler) RevokeInvitation(c *gin.Context)

RevokeInvitation revokes an invitation

func (*SharingHandler) RevokeShare

func (h *SharingHandler) RevokeShare(c *gin.Context)

RevokeShare revokes a session share

func (*SharingHandler) TransferOwnership

func (h *SharingHandler) TransferOwnership(c *gin.Context)

TransferOwnership transfers session ownership to another user

func (*SharingHandler) UpdateCollaboratorActivity

func (h *SharingHandler) UpdateCollaboratorActivity(c *gin.Context)

UpdateCollaboratorActivity updates collaborator activity timestamp

type SubscriptionFilters

type SubscriptionFilters struct {
	SessionIDs []string `json:"sessionIds"`
	UserID     string   `json:"userId"`
	TeamID     string   `json:"teamId"`
	EventTypes []string `json:"eventTypes"`
}

SubscriptionFilters defines what updates a client wants to receive

type SuccessResponse

type SuccessResponse struct {
	Message string `json:"message"`
}

SuccessResponse represents a success response

type TeamHandler

type TeamHandler struct {
	// contains filtered or unexported fields
}

TeamHandler handles team-related API requests with RBAC

func NewTeamHandler

func NewTeamHandler(database *db.Database) *TeamHandler

NewTeamHandler creates a new team handler

func (*TeamHandler) CheckPermission

func (h *TeamHandler) CheckPermission(c *gin.Context)

CheckPermission checks if the authenticated user has a specific permission in a team

func (*TeamHandler) GetMyTeamPermissions

func (h *TeamHandler) GetMyTeamPermissions(c *gin.Context)

GetMyTeamPermissions returns the authenticated user's permissions in a team

func (*TeamHandler) GetMyTeams

func (h *TeamHandler) GetMyTeams(c *gin.Context)

GetMyTeams returns all teams the authenticated user is a member of

func (*TeamHandler) GetTeamPermissions

func (h *TeamHandler) GetTeamPermissions(c *gin.Context)

GetTeamPermissions returns all permissions defined for team roles

func (*TeamHandler) GetTeamRoleInfo

func (h *TeamHandler) GetTeamRoleInfo(c *gin.Context)

GetTeamRoleInfo returns information about available team roles

func (*TeamHandler) ListTeamSessions

func (h *TeamHandler) ListTeamSessions(c *gin.Context)

ListTeamSessions returns all sessions belonging to a team

func (*TeamHandler) RegisterRoutes

func (h *TeamHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers team RBAC routes

type TemplateInheritance

type TemplateInheritance struct {
	ChildTemplateID  string                 `json:"child_template_id"`
	ParentTemplateID string                 `json:"parent_template_id"`
	OverriddenFields []string               `json:"overridden_fields"`
	InheritedFields  []string               `json:"inherited_fields"`
	Metadata         map[string]interface{} `json:"metadata"`
}

TemplateInheritance represents template inheritance/parent-child relationship

type TemplateShare

type TemplateShare struct {
	ID                 string     `json:"id"`
	TemplateID         string     `json:"templateId"`
	SharedBy           string     `json:"sharedBy"`
	SharedWithUserID   *string    `json:"sharedWithUserId,omitempty"`
	SharedWithTeamID   *string    `json:"sharedWithTeamId,omitempty"`
	SharedWithUserName string     `json:"sharedWithUserName,omitempty"`
	SharedWithTeamName string     `json:"sharedWithTeamName,omitempty"`
	PermissionLevel    string     `json:"permissionLevel"` // read, write, manage
	CreatedAt          time.Time  `json:"createdAt"`
	RevokedAt          *time.Time `json:"revokedAt,omitempty"`
}

TemplateShare represents a template share record

type TemplateSnapshot

type TemplateSnapshot struct {
	ID            int                    `json:"id"`
	TemplateID    string                 `json:"templateId"`
	VersionNumber int                    `json:"versionNumber"`
	TemplateData  map[string]interface{} `json:"templateData"`
	Description   string                 `json:"description,omitempty"`
	CreatedBy     string                 `json:"createdBy"`
	CreatedAt     time.Time              `json:"createdAt"`
	Tags          []string               `json:"tags,omitempty"`
}

TemplateSnapshot represents a version snapshot of a template

type TemplateTest

type TemplateTest struct {
	ID           int64                  `json:"id"`
	TemplateID   string                 `json:"template_id"`
	VersionID    int64                  `json:"version_id"`
	Version      string                 `json:"version"`
	TestType     string                 `json:"test_type"` // "startup", "smoke", "functional", "performance"
	Status       string                 `json:"status"`    // "pending", "running", "passed", "failed"
	Results      map[string]interface{} `json:"results"`
	Duration     int                    `json:"duration"` // in seconds
	ErrorMessage string                 `json:"error_message,omitempty"`
	StartedAt    time.Time              `json:"started_at"`
	CompletedAt  *time.Time             `json:"completed_at,omitempty"`
	CreatedBy    string                 `json:"created_by"`
	CreatedAt    time.Time              `json:"created_at"`
}

TemplateTest represents a test for a template version

type TemplateVersion

type TemplateVersion struct {
	ID               int64                  `json:"id"`
	TemplateID       string                 `json:"template_id"`
	Version          string                 `json:"version"`
	MajorVersion     int                    `json:"major_version"`
	MinorVersion     int                    `json:"minor_version"`
	PatchVersion     int                    `json:"patch_version"`
	DisplayName      string                 `json:"display_name"`
	Description      string                 `json:"description"`
	Configuration    map[string]interface{} `json:"configuration"`
	BaseImage        string                 `json:"base_image"`
	ParentTemplateID string                 `json:"parent_template_id,omitempty"`
	ParentVersion    string                 `json:"parent_version,omitempty"`
	ChangeLog        string                 `json:"changelog"`
	Status           string                 `json:"status"` // "draft", "testing", "stable", "deprecated"
	IsDefault        bool                   `json:"is_default"`
	TestResults      map[string]interface{} `json:"test_results,omitempty"`
	CreatedBy        string                 `json:"created_by"`
	CreatedAt        time.Time              `json:"created_at"`
	PublishedAt      *time.Time             `json:"published_at,omitempty"`
	DeprecatedAt     *time.Time             `json:"deprecated_at,omitempty"`
}

TemplateVersion represents a version of a template

type TemplateVersioningHandler

type TemplateVersioningHandler struct {
	DB *db.Database
}

TemplateVersioningHandler handles template versioning endpoints

func NewTemplateVersioningHandler

func NewTemplateVersioningHandler(database *db.Database) *TemplateVersioningHandler

NewTemplateVersioningHandler creates a new TemplateVersioningHandler instance

func (*TemplateVersioningHandler) CloneTemplateVersion

func (h *TemplateVersioningHandler) CloneTemplateVersion(c *gin.Context)

CloneTemplateVersion creates a new version based on an existing one

func (*TemplateVersioningHandler) CreateTemplateTest

func (h *TemplateVersioningHandler) CreateTemplateTest(c *gin.Context)

CreateTemplateTest creates a test for a template version

func (*TemplateVersioningHandler) CreateTemplateVersion

func (h *TemplateVersioningHandler) CreateTemplateVersion(c *gin.Context)

CreateTemplateVersion creates a new version of a template

func (*TemplateVersioningHandler) DeprecateTemplateVersion

func (h *TemplateVersioningHandler) DeprecateTemplateVersion(c *gin.Context)

DeprecateTemplateVersion marks a version as deprecated

func (*TemplateVersioningHandler) GetTemplateInheritance

func (h *TemplateVersioningHandler) GetTemplateInheritance(c *gin.Context)

GetTemplateInheritance retrieves the inheritance chain for a template

func (*TemplateVersioningHandler) GetTemplateVersion

func (h *TemplateVersioningHandler) GetTemplateVersion(c *gin.Context)

GetTemplateVersion retrieves a specific template version

func (*TemplateVersioningHandler) ListTemplateTests

func (h *TemplateVersioningHandler) ListTemplateTests(c *gin.Context)

ListTemplateTests lists all tests for a template version

func (*TemplateVersioningHandler) ListTemplateVersions

func (h *TemplateVersioningHandler) ListTemplateVersions(c *gin.Context)

ListTemplateVersions lists all versions of a template

func (*TemplateVersioningHandler) PublishTemplateVersion

func (h *TemplateVersioningHandler) PublishTemplateVersion(c *gin.Context)

PublishTemplateVersion publishes a template version (draft -> stable)

func (*TemplateVersioningHandler) SetDefaultTemplateVersion

func (h *TemplateVersioningHandler) SetDefaultTemplateVersion(c *gin.Context)

SetDefaultTemplateVersion sets a version as the default for a template

func (*TemplateVersioningHandler) UpdateTemplateTestStatus

func (h *TemplateVersioningHandler) UpdateTemplateTestStatus(c *gin.Context)

UpdateTemplateTestStatus updates the status of a test (used by test runners)

type TransferOwnershipRequest

type TransferOwnershipRequest struct {
	NewOwnerUserId string `json:"newOwnerUserId" binding:"required" validate:"required,min=1,max=100"`
}

TransferOwnershipRequest represents a request to transfer session ownership

type TrustedDevice

type TrustedDevice struct {
	ID           int64     `json:"id"`
	UserID       string    `json:"user_id"`
	DeviceID     string    `json:"device_id"` // Browser fingerprint
	DeviceName   string    `json:"device_name"`
	UserAgent    string    `json:"user_agent"`
	IPAddress    string    `json:"ip_address"`
	TrustedUntil time.Time `json:"trusted_until"`
	LastSeenAt   time.Time `json:"last_seen_at"`
	CreatedAt    time.Time `json:"created_at"`
}

TrustedDevice represents a device trusted for MFA bypass

type UpdateConfigurationRequest

type UpdateConfigurationRequest struct {
	Value string `json:"value" binding:"required"`
}

UpdateConfigurationRequest represents a request to update a configuration setting

type UpdateLicenseRequest

type UpdateLicenseRequest struct {
	LicenseKey string `json:"license_key" binding:"required"`
}

UpdateLicenseRequest represents license update request

type UpdateSessionTemplateRequest

type UpdateSessionTemplateRequest struct {
	Name          string                 `json:"name" validate:"omitempty,min=3,max=100"`
	Description   string                 `json:"description" validate:"omitempty,max=1000"`
	Icon          string                 `json:"icon" validate:"omitempty,max=100"`
	Category      string                 `json:"category" validate:"omitempty,min=2,max=50"`
	Tags          []string               `json:"tags" validate:"omitempty,dive,min=2,max=50"`
	Configuration map[string]interface{} `json:"configuration"`
	Resources     map[string]interface{} `json:"resources"`
	Environment   map[string]string      `json:"environment" validate:"omitempty,dive,keys,min=1,max=100,endkeys,min=0,max=10000"`
}

UpdateSessionTemplateRequest is the request body for updating a session template

type UpdateWebhookRequest

type UpdateWebhookRequest struct {
	Name        string                 `json:"name" validate:"omitempty,min=1,max=200"`
	Description string                 `json:"description" validate:"omitempty,max=1000"`
	URL         string                 `json:"url" validate:"omitempty,url,max=2048"`
	Events      []string               `json:"events" validate:"omitempty,min=1,max=50,dive,min=3,max=100"`
	Headers     map[string]string      `json:"headers" validate:"omitempty,max=50,dive,keys,max=100,endkeys,max=1000"`
	Enabled     *bool                  `json:"enabled"`
	RetryPolicy *WebhookRetryPolicy    `json:"retry_policy"`
	Filters     *WebhookFilters        `json:"filters"`
	Metadata    map[string]interface{} `json:"metadata"`
}

UpdateWebhookRequest is the request body for updating a webhook

type UserHandler

type UserHandler struct {
	// contains filtered or unexported fields
}

UserHandler handles user-related API requests

func NewUserHandler

func NewUserHandler(userDB *db.UserDB, groupDB *db.GroupDB) *UserHandler

NewUserHandler creates a new user handler

func (*UserHandler) CreateUser

func (h *UserHandler) CreateUser(c *gin.Context)

CreateUser godoc @Summary Create a new user @Description Create a new user account @Tags users @Accept json @Produce json @Param user body models.CreateUserRequest true "User creation request" @Success 201 {object} models.User @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/users [post]

func (*UserHandler) DeleteAdminUserQuota

func (h *UserHandler) DeleteAdminUserQuota(c *gin.Context)

DeleteAdminUserQuota godoc @Summary Delete user quota @Description Delete (reset to default) resource quota for a user (admin only) @Tags admin, quotas @Accept json @Produce json @Param username path string true "Username" @Success 200 {object} SuccessResponse @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/quotas/{username} [delete]

func (*UserHandler) DeleteUser

func (h *UserHandler) DeleteUser(c *gin.Context)

DeleteUser godoc @Summary Delete user @Description Delete a user account @Tags users @Accept json @Produce json @Param id path string true "User ID" @Success 200 {object} SuccessResponse @Failure 500 {object} ErrorResponse @Router /api/v1/users/{id} [delete]

func (*UserHandler) GetAdminUserQuota

func (h *UserHandler) GetAdminUserQuota(c *gin.Context)

GetAdminUserQuota godoc @Summary Get user quota by username @Description Get resource quota for a user by username (admin only) @Tags admin, quotas @Accept json @Produce json @Param username path string true "Username" @Success 200 {object} models.UserQuota @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/quotas/{username} [get]

func (*UserHandler) GetCurrentUser

func (h *UserHandler) GetCurrentUser(c *gin.Context)

GetCurrentUser godoc @Summary Get current user @Description Get information about the currently authenticated user @Tags users @Accept json @Produce json @Success 200 {object} models.User @Failure 401 {object} ErrorResponse @Router /api/v1/users/me [get]

func (*UserHandler) GetCurrentUserQuota

func (h *UserHandler) GetCurrentUserQuota(c *gin.Context)

GetCurrentUserQuota godoc @Summary Get current user quota @Description Get quota information for the currently authenticated user @Tags users, quotas @Accept json @Produce json @Success 200 {object} models.UserQuota @Failure 401 {object} ErrorResponse @Failure 404 {object} ErrorResponse @Router /api/v1/users/me/quota [get]

func (*UserHandler) GetUser

func (h *UserHandler) GetUser(c *gin.Context)

GetUser godoc @Summary Get user by ID @Description Get detailed information about a specific user @Tags users @Accept json @Produce json @Param id path string true "User ID" @Success 200 {object} models.User @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/users/{id} [get]

func (*UserHandler) GetUserGroups

func (h *UserHandler) GetUserGroups(c *gin.Context)

GetUserGroups godoc @Summary Get user groups @Description Get all groups a user belongs to @Tags users, groups @Accept json @Produce json @Param id path string true "User ID" @Success 200 {object} gin.H @Failure 500 {object} ErrorResponse @Router /api/v1/users/{id}/groups [get]

func (*UserHandler) GetUserQuota

func (h *UserHandler) GetUserQuota(c *gin.Context)

GetUserQuota godoc @Summary Get user quota @Description Get resource quota for a user @Tags users, quotas @Accept json @Produce json @Param id path string true "User ID" @Success 200 {object} models.UserQuota @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/users/{id}/quota [get]

func (*UserHandler) GetUserSessions

func (h *UserHandler) GetUserSessions(c *gin.Context)

GetUserSessions godoc @Summary Get user sessions @Description Get all sessions for a specific user @Tags users @Accept json @Produce json @Param id path string true "User ID" @Success 200 {object} gin.H @Failure 307 {object} gin.H @Router /api/v1/users/{id}/sessions [get]

func (*UserHandler) ListAllUserQuotas

func (h *UserHandler) ListAllUserQuotas(c *gin.Context)

ListAllUserQuotas godoc @Summary List all user quotas @Description Get resource quotas for all users (admin only) @Tags admin, quotas @Accept json @Produce json @Success 200 {object} gin.H @Failure 500 {object} ErrorResponse @Router /api/v1/admin/quotas [get]

func (*UserHandler) ListUsers

func (h *UserHandler) ListUsers(c *gin.Context)

ListUsers godoc @Summary List all users @Description Get a list of all users with optional filtering @Tags users @Accept json @Produce json @Param role query string false "Filter by role" @Param provider query string false "Filter by auth provider" @Param active query boolean false "Filter active users only" @Success 200 {array} models.User @Failure 500 {object} ErrorResponse @Router /api/v1/users [get]

func (*UserHandler) RegisterRoutes

func (h *UserHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers user management routes

func (*UserHandler) SetAdminUserQuota

func (h *UserHandler) SetAdminUserQuota(c *gin.Context)

SetAdminUserQuota godoc @Summary Set user quota by username @Description Set or update resource quota for a user by username (admin only) @Tags admin, quotas @Accept json @Produce json @Param quota body models.SetQuotaRequest true "Quota settings with username" @Success 200 {object} models.UserQuota @Failure 400 {object} ErrorResponse @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/admin/quotas [put]

func (*UserHandler) SetUserQuota

func (h *UserHandler) SetUserQuota(c *gin.Context)

SetUserQuota godoc @Summary Set user quota @Description Set or update resource quota for a user @Tags users, quotas @Accept json @Produce json @Param id path string true "User ID" @Param quota body models.SetQuotaRequest true "Quota settings" @Success 200 {object} models.UserQuota @Failure 400 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/users/{id}/quota [put]

func (*UserHandler) UpdateUser

func (h *UserHandler) UpdateUser(c *gin.Context)

UpdateUser godoc @Summary Update user @Description Update user information @Tags users @Accept json @Produce json @Param id path string true "User ID" @Param user body models.UpdateUserRequest true "User update request" @Success 200 {object} models.User @Failure 400 {object} ErrorResponse @Failure 404 {object} ErrorResponse @Failure 500 {object} ErrorResponse @Router /api/v1/users/{id} [patch]

type ValidateLicenseRequest

type ValidateLicenseRequest struct {
	LicenseKey string `json:"license_key" binding:"required" validate:"required,min=10,max=256"`
}

ValidateLicenseRequest represents license validation request

type ValidateLicenseResponse

type ValidateLicenseResponse struct {
	Valid     bool                   `json:"valid"`
	Tier      string                 `json:"tier,omitempty"`
	Features  map[string]interface{} `json:"features,omitempty"`
	ExpiresAt *time.Time             `json:"expires_at,omitempty"`
	Message   string                 `json:"message"`
}

ValidateLicenseResponse represents license validation result

type WebSocketClient

type WebSocketClient struct {
	ID     string                // Unique client identifier (format: "userID-unixnano")
	UserID string                // User ID for authorization and targeted broadcasts
	Conn   *websocket.Conn       // Underlying WebSocket connection
	Send   chan WebSocketMessage // Buffered channel for outbound messages (prevents blocking)
	Hub    *WebSocketHub         // Reference to hub for broadcasting
	Mu     sync.Mutex            // Mutex for thread-safe client state operations
}

WebSocketClient represents a single connected WebSocket client.

Each client has: - Unique ID for tracking (format: "userID-timestamp") - UserID for authorization and targeted messaging - WebSocket connection (Conn) - Buffered send channel to prevent blocking - Reference to hub for broadcasting - Mutex for thread-safe operations (currently unused but available for future state)

The Send channel is buffered (256 messages) to handle burst traffic without blocking. If the buffer fills, the client is considered slow/disconnected and removed.

type WebSocketHandler

type WebSocketHandler struct {
	// contains filtered or unexported fields
}

WebSocketHandler handles WebSocket connections for real-time platform updates.

The handler implements a centralized hub pattern where all clients connect to a single hub that routes broadcast messages based on subscription filters.

Key responsibilities:

  • Upgrade HTTP connections to WebSocket
  • Maintain registry of active client connections
  • Route broadcast messages to matching clients
  • Enforce origin validation and authentication
  • Handle client lifecycle (connect, disconnect, cleanup)

Concurrency:

  • Hub runs in a single goroutine (actor pattern)
  • Each client has two goroutines (read pump, write pump)
  • Channel-based synchronization (register, unregister, broadcast)
  • Thread-safe session map protected by RWMutex

Memory usage:

  • Handler: ~10 KB (hub state)
  • Per client: ~100 KB (goroutines + 256-message buffer)
  • 1000 clients: ~100 MB total memory

Performance:

  • Supports 10,000+ concurrent connections
  • <10ms message latency (broadcast to delivery)
  • 10,000+ messages/sec throughput

Typical usage:

wsHandler := NewWebSocketHandler(database)
wsHandler.RegisterRoutes(router.Group("/api"))

// Later, broadcast message from API handler
wsHandler.Broadcast(&BroadcastMessage{
    Event: "session.created",
    Data:  sessionData,
})

func NewWebSocketHandler

func NewWebSocketHandler(database *db.Database) *WebSocketHandler

NewWebSocketHandler creates a new WebSocket handler

func (*WebSocketHandler) AlertUpdates

func (h *WebSocketHandler) AlertUpdates(c *gin.Context)

AlertUpdates handles WebSocket connections for alert updates

func (*WebSocketHandler) BroadcastAlertEvent

func (h *WebSocketHandler) BroadcastAlertEvent(event string, data map[string]interface{})

BroadcastAlertEvent broadcasts an alert event

func (*WebSocketHandler) BroadcastNotificationEvent

func (h *WebSocketHandler) BroadcastNotificationEvent(event string, userID string, data map[string]interface{})

BroadcastNotificationEvent broadcasts a notification event

func (*WebSocketHandler) BroadcastSessionEvent

func (h *WebSocketHandler) BroadcastSessionEvent(event string, sessionID string, userID string, data map[string]interface{})

BroadcastSessionEvent broadcasts a session event to all connected clients

func (*WebSocketHandler) DisconnectUser

func (h *WebSocketHandler) DisconnectUser(userID string)

DisconnectUser disconnects all WebSocket sessions for a user

func (*WebSocketHandler) GetClientsByUser

func (h *WebSocketHandler) GetClientsByUser(userID string) []*WebSocketSession

GetClientsByUser returns connected clients for a specific user

func (*WebSocketHandler) GetConnectedClients

func (h *WebSocketHandler) GetConnectedClients() int

GetConnectedClients returns the number of connected WebSocket clients

func (*WebSocketHandler) MetricsUpdates

func (h *WebSocketHandler) MetricsUpdates(c *gin.Context)

MetricsUpdates handles WebSocket connections for metrics updates

func (*WebSocketHandler) NotificationUpdates

func (h *WebSocketHandler) NotificationUpdates(c *gin.Context)

NotificationUpdates handles WebSocket connections for notification updates

func (*WebSocketHandler) RegisterRoutes

func (h *WebSocketHandler) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers WebSocket routes

func (*WebSocketHandler) SessionUpdates

func (h *WebSocketHandler) SessionUpdates(c *gin.Context)

SessionUpdates handles WebSocket connections for session updates

type WebSocketHub

type WebSocketHub struct {
	Clients    map[string]*WebSocketClient // All connected clients (key: client ID)
	Register   chan *WebSocketClient       // Channel for new client registrations
	Unregister chan *WebSocketClient       // Channel for client disconnections
	Broadcast  chan WebSocketMessage       // Buffered channel for broadcast messages
	Mu         sync.RWMutex                // Read-write mutex for thread-safe map access
}

WebSocketHub is the central manager for all WebSocket connections.

It uses a hub-and-spoke architecture: - Hub maintains all active clients in a map - Clients register/unregister via channels - Broadcast channel for sending to all clients - RWMutex for safe concurrent access to the clients map

Thread Safety: - Register/Unregister: Processed sequentially in Run() with write lock - Broadcast: Uses read lock for iteration, write lock for cleanup - BroadcastToUser: Uses read lock only (no modifications)

The hub runs in a single goroutine (via Run()) to avoid race conditions when modifying the clients map.

func GetWebSocketHub

func GetWebSocketHub() *WebSocketHub

GetWebSocketHub returns the singleton hub instance using thread-safe lazy initialization.

This function uses sync.Once to ensure the hub is created exactly once, even if called concurrently from multiple goroutines. This is the standard Go singleton pattern.

The hub is initialized with: - Empty clients map - Unbuffered register/unregister channels (sequential processing) - Buffered broadcast channel (256 messages) to handle burst traffic - Background goroutine running hub.Run() for message processing

Thread Safety: sync.Once guarantees Run() is called exactly once

Returns:

  • *WebSocketHub: The global hub instance

func (*WebSocketHub) BroadcastToAll

func (h *WebSocketHub) BroadcastToAll(message WebSocketMessage)

BroadcastToAll sends a message to all connected clients (typically for admin-level events).

This function sends the message to the hub's broadcast channel, where it's processed by the Run() goroutine and distributed to all clients.

Use cases: - System-wide notifications (maintenance window, new features, etc.) - Admin-level events (node health changes, scaling events, etc.) - Platform status updates (high load warnings, service degradation, etc.)

IMPORTANT: This sends to ALL users regardless of role. For admin-only messages, the client-side code should filter based on the user's role.

Thread Safety: - Broadcast channel is buffered (256 messages) - Non-blocking as long as buffer isn't full - Safe to call concurrently from multiple goroutines

Parameters:

  • message: The WebSocketMessage to broadcast to all clients

func (*WebSocketHub) BroadcastToUser

func (h *WebSocketHub) BroadcastToUser(userID string, message WebSocketMessage)

BroadcastToUser sends a message to all connections belonging to a specific user.

A single user can have multiple WebSocket connections open simultaneously (e.g., multiple browser tabs, mobile app + desktop app). This function sends the message to ALL of that user's connections.

Use cases: - User-specific notifications (session started, MFA required, etc.) - Account security alerts (new login detected, password changed, etc.) - Personal updates (quota warnings, scheduled session reminders, etc.)

Thread Safety: - Uses read lock only (no map modifications) - Non-blocking send via select/default - Safe to call concurrently from multiple goroutines

Parameters:

  • userID: The user ID to target (from authentication context)
  • message: The WebSocketMessage to send

func (*WebSocketHub) Run

func (h *WebSocketHub) Run()

Run is the main event loop for the WebSocket hub.

This function runs in a dedicated goroutine for the lifetime of the application. It processes three types of events via select statement:

1. Register: Add new client connections 2. Unregister: Remove disconnected clients 3. Broadcast: Send message to all connected clients

CRITICAL RACE CONDITION FIX: The broadcast case uses a two-phase approach to prevent race conditions:

Phase 1: Read lock - Iterate clients and collect slow/disconnected ones
Phase 2: Write lock - Remove collected clients from map

This prevents: - Concurrent map read/write errors - Deadlocks from holding write lock during iteration - Message loss from blocking sends

Why not hold write lock during broadcast? - Broadcasting can be slow (network I/O) - Write lock blocks ALL reads (BroadcastToUser, Register, Unregister) - This would freeze the entire system during broadcasts

Thread Safety: - All map modifications use write lock (h.Mu.Lock) - Map iteration uses read lock (h.Mu.RLock) - Locks are held for minimum time necessary

type WebSocketMessage

type WebSocketMessage struct {
	Type      string                 `json:"type"`      // Message type/category for client-side routing
	Timestamp time.Time              `json:"timestamp"` // Server timestamp for accurate event ordering
	Data      map[string]interface{} `json:"data"`      // Flexible payload containing event-specific data
}

WebSocketMessage represents a real-time update message sent to clients.

Type field determines the message category (e.g., "webhook.delivery", "security.alert"). Timestamp is set server-side to ensure accurate event timing. Data contains the message payload as a flexible map.

Example message:

{
  "type": "security.alert",
  "timestamp": "2025-11-15T10:30:00Z",
  "data": {
    "alert_type": "mfa_failed",
    "severity": "high",
    "message": "Multiple failed MFA attempts detected"
  }
}

type WebSocketSession

type WebSocketSession struct {
	ID     string
	UserID string
	Conn   *websocket.Conn
	Send   chan []byte

	Filters *SubscriptionFilters
	// contains filtered or unexported fields
}

WebSocketSession represents a client WebSocket connection

type Webhook

type Webhook struct {
	ID          int64                  `json:"id"`
	Name        string                 `json:"name"`
	Description string                 `json:"description"`
	URL         string                 `json:"url"`
	Secret      string                 `json:"-"` // SECURITY: Never expose secret in API responses
	Events      []string               `json:"events"`
	Headers     map[string]string      `json:"headers,omitempty"`
	Enabled     bool                   `json:"enabled"`
	RetryPolicy WebhookRetryPolicy     `json:"retry_policy"`
	Filters     WebhookFilters         `json:"filters,omitempty"`
	Metadata    map[string]interface{} `json:"metadata,omitempty"`
	CreatedBy   string                 `json:"created_by"`
	CreatedAt   time.Time              `json:"created_at"`
	UpdatedAt   time.Time              `json:"updated_at"`
}

Webhook represents a webhook configuration

type WebhookDelivery

type WebhookDelivery struct {
	ID           int64                  `json:"id"`
	WebhookID    int64                  `json:"webhook_id"`
	Event        string                 `json:"event"`
	Payload      map[string]interface{} `json:"payload"`
	Status       string                 `json:"status"` // "pending", "success", "failed"
	StatusCode   int                    `json:"status_code,omitempty"`
	ResponseBody string                 `json:"response_body,omitempty"`
	ErrorMessage string                 `json:"error_message,omitempty"`
	Attempts     int                    `json:"attempts"`
	NextRetryAt  *time.Time             `json:"next_retry_at,omitempty"`
	DeliveredAt  *time.Time             `json:"delivered_at,omitempty"`
	CreatedAt    time.Time              `json:"created_at"`
}

WebhookDelivery represents a webhook delivery attempt

type WebhookEvent

type WebhookEvent struct {
	Event     string                 `json:"event"`
	Timestamp time.Time              `json:"timestamp"`
	Data      map[string]interface{} `json:"data"`
	Metadata  map[string]interface{} `json:"metadata,omitempty"`
}

WebhookEvent represents an event that can trigger webhooks

type WebhookFilters

type WebhookFilters struct {
	Users         []string `json:"users,omitempty"`
	Templates     []string `json:"templates,omitempty"`
	SessionStates []string `json:"session_states,omitempty"`
}

WebhookFilters allows filtering events

type WebhookRetryPolicy

type WebhookRetryPolicy struct {
	MaxRetries        int     `json:"max_retries"`
	RetryDelay        int     `json:"retry_delay_seconds"`
	BackoffMultiplier float64 `json:"backoff_multiplier"`
}

WebhookRetryPolicy defines retry behavior

type WebhookWithSecret

type WebhookWithSecret struct {
	Webhook
	Secret string `json:"secret"` // Only exposed on creation
}

WebhookWithSecret is used only for CreateWebhook response to show the secret once

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL