Studio Engine
Shared Rails engine for McRitchie apps. Provides authentication, error handling, dynamic theming, and common concerns used by McRitchie Studio and Turf Monster.
Part of the McRitchie ecosystem — see
ECOSYSTEM.mdfor the 5-repo map;house-burn-down.mdfor fresh-Mac recovery.
Installation
# Gemfile — pin to a tag (recommended; see Releases section)
gem "studio-engine", git: "https://github.com/amcritchie/studio-engine.git", tag: "v0.3.0"
Then bundle install. The current release is v0.3.0; see CHANGELOG.md for the history.
Pinning to a tag (not
main) is now the recommended pattern. Consumer apps that trackmainwill silently inherit any engine merge — bad when one merge breaks several apps at once.
What It Provides
- Authentication: Session-based login/signup controllers and views, Google OAuth via OmniAuth, one-way SSO (hub to satellite)
- Error handling:
Studio::ErrorHandlingconcern withrescue_and_log,ErrorLogmodel withcapture!, error log viewer at/error_logs - Theme system: Dynamic CSS custom properties generated from 7 role colors (primary, dark, light, success, accent, warning, danger). Dark/light mode toggle. Admin theme editor at
/admin/theme. - Sluggable concern:
before_save :set_slugwithto_paramfor human-readable URLs - ThemeSetting model: Per-app DB overrides with fallback to config defaults
Configuration
Each consuming app configures the engine in config/initializers/studio.rb:
Studio.configure do |config|
config.app_name = "My App"
config.session_key = :my_app_user_id
config.sso_logo = "/logo.svg"
config. = ->(user) { "Welcome, #{user.display_name}!" }
config.registration_params = [:name, :email, :password, :password_confirmation]
config.theme_primary = "#4BAF50" # Override default violet
config.theme_logos = ["logo.svg"]
end
Routes
In the consuming app's config/routes.rb:
Rails.application.routes.draw do
Studio.routes(self)
# ... app routes
end
This draws: /login, /signup, /logout, /sso_continue, /sso_login, /auth/:provider/callback, /auth/failure, /error_logs, /admin/theme (GET, PATCH), /admin/theme/regenerate.
Overriding Views
This is a non-isolated engine -- app views at the same path automatically override engine views. For example, placing app/views/sessions/new.html.erb in the consuming app replaces the engine's login page.
Releasing
Engine releases are git tags (semver: MAJOR.MINOR.PATCH). Both consumer apps pin to a tag in their Gemfile — bumping the tag is the release.
- Make + commit changes on
main. - Update
CHANGELOG.mdwith the new version + a### Added/### Changed/### Removedsummary. Keep entries terse. - Bump
lib/studio/version.rbto match. - Commit the version bump + CHANGELOG together (
v0.X.Y: <summary>). - Tag:
git tag -a v0.X.Y -m "<one-line summary>". - Push:
git push origin main --tags. - In each consumer app's Gemfile, update the
tag:field. Commit + push. - On consumer prod:
bundle installruns as part of the deploy buildpack.
Semver guide
- PATCH: bug fix; no API change. Consumers can bump tag with zero diff elsewhere.
- MINOR: backward-compatible feature add. Consumers may opt in to new APIs.
- MAJOR: breaking change. Consumers will need code changes alongside the tag bump.
Local development (against an unreleased engine)
When iterating on engine code from a consumer app, point bundler at the local path so you don't need to push + tag for every edit:
# in the consumer app
bundle config set --local local.studio /Users/alex/projects/studio-engine
bundle install
# ... iterate in both repos ...
bundle config unset --local local.studio # restore tag-pinned resolution
Note: bundle config local.studio requires branch: in the Gemfile entry. If you frequently develop locally, change the Gemfile to gem "studio-engine", git: "...", branch: "main" during dev and back to tag: before merging.
Development Notes
See CLAUDE.md for detailed development context including the theme architecture, SSO protocol, color scale system, and code conventions.