jam-cloud/.planning/codebase/ARCHITECTURE.md

7.2 KiB

Architecture

Analysis Date: 2026-01-11

Pattern Overview

Overall: Hybrid Microservices with Shared Monolithic Database

Key Characteristics:

  • Service-oriented architecture with distinct service boundaries
  • Monolithic Rails backend transitioning to modern React frontend
  • Shared PostgreSQL database across all services
  • Real-time communication via WebSocket gateway with Protocol Buffers
  • Async messaging via RabbitMQ/AMQP between services

Layers

Presentation Layer (Frontend):

  • Purpose: User interface and client-side logic
  • Contains: React 16 SPA with Redux Toolkit state management
  • Location: jam-ui/src/
  • Entry Point: jam-ui/src/index.jsMain.js (providers) → App.js (layout router)
  • Depends on: Rails API (web/) via REST, WebSocket gateway for real-time
  • Used by: End users via browser at http://beta.jamkazam.local:4000
  • Current Status: Under development. This is mostly a UI update of the legacy front end (web)

API Layer (Backend):

  • Purpose: REST API endpoints, request processing, authentication
  • Contains: Rails 4.2.8 controllers, responders, error handling
  • Location: web/app/controllers/ (83 API controller files)
  • Base Controller: api_controller.rb provides auth, error handling, response formatting
  • Depends on: Shared business logic gem (ruby/), PostgreSQL
  • Used by: React frontend, mobile apps, third-party integrations

Real-time Communication Layer:

  • Purpose: WebSocket connections for live session updates
  • Contains: EventMachine-based WebSocket server with Protocol Buffer messaging
  • Location: websocket-gateway/
  • Protocol: Protocol Buffers (.proto definitions in pb/src/client_container.proto)
  • Bridge: jam-ui/src/jamClientProxy.js manages native C++ client communication via QWebChannel
  • Depends on: Shared Ruby gem, WebSocket protocol
  • Used by: React frontend, native desktop client

Shared Business Logic Layer:

  • Purpose: Centralized models, validations, domain logic
  • Contains: ActiveRecord models (217 files), managers, message factory
  • Location: ruby/lib/jam_ruby/ (shared gem embedded via local path)
  • Key Files: ruby/lib/jam_ruby/models/ (217 model files), message_factory.rb, connection_manager.rb
  • Depends on: Rails frameworks, PostgreSQL
  • Used by: All services (web, admin, websocket-gateway)

Data Layer:

  • Purpose: Persistent storage
  • Contains: PostgreSQL schema, migrations
  • Location: db/up/ (403+ migration files)
  • ORM: ActiveRecord models in ruby/lib/jam_ruby/models/
  • Depends on: PostgreSQL server
  • Used by: All services via ActiveRecord

Data Flow

REST API Request (Example: Fetch User Profile):

  1. User action in React component (e.g., JKUserProfile.js)
  2. Redux dispatch or direct API call via apiFetch() (jam-ui/src/helpers/rest.js)
  3. HTTP request to Rails controller (e.g., api_users_controller.rb)
  4. Controller uses shared business logic (ruby/lib/jam_ruby/models/user.rb)
  5. ActiveRecord query to PostgreSQL database
  6. Response serialized (RABL template or JSON)
  7. Redux store updated (jam-ui/src/store/features/*.js)
  8. Component re-renders with new data

Real-time Session Flow (Example: Join Music Session):

  1. Native C++ desktop client sends message
  2. Proxied through jamClientProxy.js (QWebChannel tunnel to frontend)
  3. WebSocket message to gateway (websocket-gateway/)
  4. Protocol Buffer decoding → Rails backend logic
  5. Async processing via Resque jobs or AMQP messages
  6. State changes persisted to PostgreSQL
  7. Broadcast back to all session participants via WebSocket
  8. Protocol Buffer encoding → Frontend updates Redux state

State Management:

  • Redux Toolkit for global app state (sessions, tracks, user, notifications)
  • Context API for UI state (native client connection, media player, global settings)
  • WebSocket for real-time state synchronization

Key Abstractions

Component (React):

  • Purpose: UI building blocks with JK prefix for brand-specific components
  • Examples: JKDashboardMain.js, JKSessionModal.js, JKJamTrackPlayer.js in jam-ui/src/components/
  • Pattern: Functional components with hooks, prop destructuring, Redux integration

Hook (React):

  • Purpose: Reusable stateful logic
  • Examples: useJamServer.js (26KB, WebSocket orchestration), useJamTrack.js, useGearUtils.js in jam-ui/src/hooks/
  • Pattern: use* naming convention, returns state and handlers

Controller (Rails):

  • Purpose: Handle HTTP requests, route to business logic
  • Examples: api_sessions_controller.rb, api_jam_tracks_controller.rb, api_users_controller.rb in web/app/controllers/
  • Pattern: RESTful actions, inherit from api_controller.rb, use responders

Model (Rails/ActiveRecord):

  • Purpose: Domain objects with validations and business rules
  • Examples: user.rb (3,078 lines), music_session.rb (1,481 lines), jam_track.rb in ruby/lib/jam_ruby/models/
  • Pattern: ActiveRecord associations, scopes, state machines (AASM)

API Service Function:

  • Purpose: Frontend-to-backend communication abstractions
  • Examples: getSession(id), joinSession(options), updateUser(id, data) in jam-ui/src/helpers/rest.js
  • Pattern: Promise-based, wraps apiFetch(), returns resolved/rejected promises

Entry Points

Frontend Entry:

  • Location: jam-ui/src/index.js
  • Triggers: Browser loads page at http://beta.jamkazam.local:4000
  • Responsibilities: Render React app, wrap with providers (Redux, Context), route to layouts

Backend API Entry:

  • Location: web/config/routes.rb (51KB route definitions)
  • Triggers: HTTP request to /api/* endpoints
  • Responsibilities: Route to controller actions, apply middleware, return JSON responses

WebSocket Gateway Entry:

  • Location: websocket-gateway/ (EventMachine server)
  • Triggers: WebSocket connection from client
  • Responsibilities: Maintain persistent connections, decode/encode Protocol Buffers, broadcast messages

Shared Library Entry:

  • Location: ruby/lib/jam_ruby.rb
  • Triggers: Required by Rails services
  • Responsibilities: Load all models, managers, and shared utilities

Error Handling

Strategy: Exceptions bubble to top-level handler, logged and returned as JSON errors

Patterns:

  • Controllers use api_controller.rb base class for centralized error handling
  • Frontend catches promise rejections from apiFetch(), displays user-friendly errors
  • Background jobs (Resque) retry on transient failures, log permanent failures
  • WebSocket errors logged server-side, client notified via error messages

Cross-Cutting Concerns

Logging:

  • Rails logger for backend (stdout in development, files in production)
  • Console logging in React frontend (removed in production builds)
  • Bugsnag for error tracking (API key configured in web/config/application.rb)
  • InfluxDB for time-series metrics (configured but disabled for production)

Validation:

  • ActiveRecord validations in model layer (ruby/lib/jam_ruby/models/*)
  • React Hook Form for frontend form validation
  • API parameter validation in controllers

Authentication:

  • Devise for user authentication (session-based cookies)
  • OAuth via OmniAuth (Facebook, Google, Twitter)
  • Session sharing between www.jamkazam.local (Rails) and beta.jamkazam.local (React) via remember_token cookie

Architecture analysis: 2026-01-11 Update when major patterns change