Module: Heatwave::AppType

Defined in:
lib/heatwave/app_type.rb

Overview

Unified app type detection that works identically in development and production (both Puma).

Instead of boot-time detection via environment variables, this detects the app type
at request-time from the subdomain. This ensures:

  • Same code path in development and production
  • No need for multiple server processes locally
  • Testable logic

Usage in middleware:
app_type = Heatwave::AppType.from_request(env)
return @app.call(env) unless app_type == :mcp

Usage in controllers:
Heatwave::AppType.current # Returns :www, :crm, :api, :mcp, or :unknown

Per-request "what subdomain are we serving?" lookup that drives
subdomain-specific routing, layouts, and middleware. Replaces the
historical boot-time WWW=true / CRM=true env-var split with a
single code path that infers the active app from the incoming
request. See file header for full rationale.

Constant Summary collapse

TYPES =

Types.

%i[www crm api mcp media unknown].freeze

Class Method Summary collapse

Class Method Details

.api?Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/heatwave/app_type.rb', line 76

def self.api?
  current == :api
end

.crm?Boolean

Returns:

  • (Boolean)


80
81
82
# File 'lib/heatwave/app_type.rb', line 80

def self.crm?
  current == :crm
end

.currentSymbol

Thread-local storage for current request's app type
Set by middleware early in the stack, read by controllers/services

Returns:

  • (Symbol)

    the current request's app type



31
32
33
# File 'lib/heatwave/app_type.rb', line 31

def self.current
  RequestStore.store[:heatwave_app_type] || :unknown
end

.current=(type) ⇒ Symbol

Returns the assigned app type.

Returns:

  • (Symbol)

    the assigned app type



36
37
38
# File 'lib/heatwave/app_type.rb', line 36

def self.current=(type)
  RequestStore.store[:heatwave_app_type] = type
end

.detect_from_host(host) ⇒ Symbol

Detect app type from host string
Extracted for testability

Returns:

  • (Symbol)

    the detected app type



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/heatwave/app_type.rb', line 51

def self.detect_from_host(host)
  return :unknown if host.blank?

  subdomain = host.split('.').first&.downcase

  case subdomain
  when 'mcp'
    :mcp
  when 'api'
    :api
  when 'crm'
    :crm
  when 'media'
    :media
  else
    # Handle www subdomain, no subdomain (warmlyyours.com), or unknown subdomains
    :www
  end
end

.from_request(env) ⇒ Symbol

Detect app type from Rack env (request)
This is the primary detection method used by middleware

Returns:

  • (Symbol)

    the detected app type



43
44
45
46
# File 'lib/heatwave/app_type.rb', line 43

def self.from_request(env)
  host = extract_host(env)
  detect_from_host(host)
end

.mcp?Boolean

Check if current request is for a specific app type

Returns:

  • (Boolean)


72
73
74
# File 'lib/heatwave/app_type.rb', line 72

def self.mcp?
  current == :mcp
end

.media?Boolean

Returns:

  • (Boolean)


88
89
90
# File 'lib/heatwave/app_type.rb', line 88

def self.media?
  current == :media
end

.run_for?(env, *included_types) ⇒ Boolean

For middleware that should only run on certain app types
Returns true if the middleware should run

Returns:

  • (Boolean)


101
102
103
104
# File 'lib/heatwave/app_type.rb', line 101

def self.run_for?(env, *included_types)
  app_type = from_request(env)
  included_types.include?(app_type)
end

.skip_for?(env, *excluded_types) ⇒ Boolean

For middleware that should only run on certain app types
Returns true if the middleware should be skipped

Returns:

  • (Boolean)


94
95
96
97
# File 'lib/heatwave/app_type.rb', line 94

def self.skip_for?(env, *excluded_types)
  app_type = from_request(env)
  excluded_types.include?(app_type)
end

.www?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/heatwave/app_type.rb', line 84

def self.www?
  current == :www
end