Files
BreakEscape/planning_notes/rails-engine-migration-simplified/06_HACKTIVITY_INTEGRATION.md
Claude 2433b78ee2 docs: Add Hacktivity integration guide (Phase 12)
Complete step-by-step guide for mounting BreakEscape engine in Hacktivity:
- Gemfile and bundle installation
- Route mounting at /break_escape
- Database migration installation
- User model compatibility verification
- Static asset configuration
- Session and CSRF setup
- Content Security Policy (CSP) configuration
- Testing integration
- Deployment to staging
- Troubleshooting guide
- Verification checklist
- Performance monitoring
- Rollback plan

This completes the full documentation set (7 files, ~140KB total)
2025-11-20 14:13:33 +00:00

24 KiB

Hacktivity Integration Guide

Complete guide for integrating the BreakEscape Rails Engine into the Hacktivity platform.

Target: Hacktivity Rails application Engine: BreakEscape (mountable, isolated namespace) Mount Point: /break_escape Prerequisites: Completed Phases 1-12 of implementation plan


Overview

This guide walks through mounting the BreakEscape engine into Hacktivity, ensuring:

  • Engine mounts at /break_escape
  • Uses Hacktivity's User model for authentication
  • Shares Hacktivity's session and CSRF protection
  • Database migrations install correctly
  • Static assets serve from public/break_escape/
  • Authorization integrates with Hacktivity's policies
  • Tests run in Hacktivity's test suite

Phase 1: Add BreakEscape to Gemfile

Step 1.1: Update Hacktivity's Gemfile

Location: /path/to/hacktivity/Gemfile

Add the BreakEscape engine gem:

# Gaming engines
gem 'break_escape', path: '../BreakEscape'

Note: Adjust the path: to point to your BreakEscape directory. Use relative or absolute paths.

Step 1.2: Install the gem

cd /path/to/hacktivity
bundle install

Expected output:

Fetching gem metadata from https://rubygems.org/...
Using break_escape 0.1.0 from source at `../BreakEscape`
Bundle complete!

Step 1.3: Verify installation

bundle show break_escape

Expected output:

/path/to/BreakEscape

Phase 2: Mount Engine Routes

Step 2.1: Update Hacktivity's routes.rb

Location: /path/to/hacktivity/config/routes.rb

Add the engine mount point:

Rails.application.routes.draw do
  # Existing Hacktivity routes
  devise_for :users

  # ... other routes ...

  # BreakEscape game engine
  mount BreakEscape::Engine, at: '/break_escape'

  # ... remaining routes ...
end

Step 2.2: Verify routes

rails routes | grep break_escape

Expected output:

break_escape     /break_escape     BreakEscape::Engine

Routes for BreakEscape::Engine:
       missions GET  /missions(.:format)                    break_escape/missions#index
        mission GET  /missions/:id(.:format)                break_escape/missions#show
          games POST /games(.:format)                       break_escape/games#create
           game GET  /games/:id(.:format)                   break_escape/games#show
  game_scenario GET  /games/:id/scenario(.:format)          break_escape/games#scenario
       game_ink GET  /games/:id/ink(.:format)               break_escape/games#ink
game_bootstrap GET  /games/:id/bootstrap(.:format)          break_escape/api/games#bootstrap
game_sync_state PUT  /games/:id/sync_state(.:format)        break_escape/api/games#sync_state
    game_unlock POST /games/:id/unlock(.:format)            break_escape/api/games#unlock
 game_inventory POST /games/:id/inventory(.:format)         break_escape/api/games#inventory
           root GET  /                                      break_escape/missions#index

Phase 3: Install Database Migrations

Step 3.1: Copy migrations from engine

cd /path/to/hacktivity
rails break_escape:install:migrations

Expected output:

Copied migration 20251120120001_create_break_escape_missions.break_escape.rb from break_escape
Copied migration 20251120120002_create_break_escape_games.break_escape.rb from break_escape
Copied migration 20251120120003_create_break_escape_demo_users.break_escape.rb from break_escape

Step 3.2: Review migrations

ls -la db/migrate/ | grep break_escape

You should see:

  • *_create_break_escape_missions.break_escape.rb
  • *_create_break_escape_games.break_escape.rb
  • *_create_break_escape_demo_users.break_escape.rb (optional, for standalone mode)

Step 3.3: Run migrations

rails db:migrate

Expected output:

== CreateBreakEscapeMissions: migrating =====================================
-- create_table(:break_escape_missions)
   -> 0.0234s
-- add_index(:break_escape_missions, :name, {:unique=>true})
   -> 0.0089s
-- add_index(:break_escape_missions, :published)
   -> 0.0067s
== CreateBreakEscapeMissions: migrated (0.0392s) ============================

== CreateBreakEscapeGames: migrating ========================================
-- create_table(:break_escape_games)
   -> 0.0456s
-- add_index(:break_escape_games, [:player_type, :player_id, :mission_id], {:unique=>true, :name=>"index_games_on_player_and_mission"})
   -> 0.0123s
-- add_index(:break_escape_games, :scenario_data, {:using=>:gin})
   -> 0.0234s
-- add_index(:break_escape_games, :player_state, {:using=>:gin})
   -> 0.0198s
-- add_index(:break_escape_games, :status)
   -> 0.0078s
== CreateBreakEscapeGames: migrated (0.1091s) ===============================

Step 3.4: Verify tables

rails db:migrate:status

Look for:

  up     20251120120001  Create break escape missions
  up     20251120120002  Create break escape games

Or check in PostgreSQL:

psql -d hacktivity_development -c "\dt break_escape_*"

Expected output:

                   List of relations
 Schema |          Name           | Type  |  Owner
--------+-------------------------+-------+----------
 public | break_escape_games      | table | postgres
 public | break_escape_missions   | table | postgres

Phase 4: Verify User Model Compatibility

Step 4.1: Check User model

Location: /path/to/hacktivity/app/models/user.rb

Ensure the User model exists and uses Devise:

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  # BreakEscape will use polymorphic association
  has_many :break_escape_games,
           class_name: 'BreakEscape::Game',
           as: :player,
           dependent: :destroy
end

Note: The has_many :break_escape_games line is optional but recommended for convenience.

Step 4.2: Test polymorphic association

rails console
# Create a test user
user = User.create!(email: 'test@example.com', password: 'password123')

# Verify BreakEscape can find/use this user
BreakEscape::Game.create!(
  player: user,
  mission: BreakEscape::Mission.first,
  scenario_data: {startRoom: 'test'},
  player_state: {currentRoom: nil}
)

# Should work without errors

Phase 5: Seed Mission Data

Step 5.1: Run BreakEscape seeds

If you have seed data in db/seeds/break_escape_missions.rb:

rails db:seed

Or manually create missions:

rails console
BreakEscape::Mission.create!([
  {
    name: 'ceo_exfil',
    display_name: 'CEO Exfiltration',
    description: 'Infiltrate the corporate office and gather evidence of insider trading.',
    published: true,
    difficulty_level: 3
  },
  {
    name: 'cybok_heist',
    display_name: 'CybOK Heist',
    description: 'Break into the research facility and steal the CybOK framework.',
    published: true,
    difficulty_level: 4
  }
])

Step 5.2: Verify missions

rails console
BreakEscape::Mission.count  # Should be > 0
BreakEscape::Mission.published.pluck(:display_name)
# => ["CEO Exfiltration", "CybOK Heist"]

Phase 6: Configure Static Assets

Step 6.1: Verify public/ directory

Ensure BreakEscape's static assets are in the engine's public/ directory:

ls -la /path/to/BreakEscape/public/break_escape/

Expected structure:

public/break_escape/
├── js/
│   ├── phaser.min.js
│   ├── game.js
│   ├── scenes/
│   └── utils/
├── css/
│   └── game.css
└── assets/
    ├── images/
    └── audio/

Step 6.2: Test asset serving

Start the Rails server:

cd /path/to/hacktivity
rails server

Visit in browser:

http://localhost:3000/break_escape/js/phaser.min.js
http://localhost:3000/break_escape/css/game.css

Expected: Files should load correctly (200 status).

Note: Rails engines automatically serve files from public/ at the mount path.


Phase 7: Test the Integration

Step 7.1: Start Hacktivity server

cd /path/to/hacktivity
rails server

Step 7.2: Test mission listing

Visit: http://localhost:3000/break_escape

Expected: You should see the missions index page listing all published missions.

Step 7.3: Test game creation (as logged-in user)

  1. Log in to Hacktivity as a user
  2. Visit: http://localhost:3000/break_escape/missions/1
  3. Click: "Start Mission" or similar
  4. Expected: Redirects to /break_escape/games/:id

Step 7.4: Test API endpoints

Open browser console and run:

// Get CSRF token
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;

// Get current game ID from URL
const gameId = window.location.pathname.match(/games\/(\d+)/)[1];

// Test bootstrap endpoint
fetch(`/break_escape/games/${gameId}/bootstrap`, {
  method: 'GET',
  credentials: 'same-origin',
  headers: {
    'Accept': 'application/json'
  }
})
  .then(r => r.json())
  .then(data => console.log('Bootstrap:', data));

// Test scenario endpoint
fetch(`/break_escape/games/${gameId}/scenario`, {
  method: 'GET',
  credentials: 'same-origin',
  headers: {
    'Accept': 'application/json'
  }
})
  .then(r => r.json())
  .then(data => console.log('Scenario:', data));

Expected: Both should return JSON with game data.

Step 7.5: Test unlock endpoint

fetch(`/break_escape/games/${gameId}/unlock`, {
  method: 'POST',
  credentials: 'same-origin',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-CSRF-Token': csrfToken
  },
  body: JSON.stringify({
    targetType: 'door',
    targetId: 'office',
    attempt: 'test_password',
    method: 'password'
  })
})
  .then(r => r.json())
  .then(data => console.log('Unlock result:', data));

Expected: Returns {success: true/false, ...}


Phase 8: Configure Authorization (Optional)

If using Pundit in Hacktivity, ensure policies work correctly.

Step 8.1: Verify Pundit is installed

Location: /path/to/hacktivity/Gemfile

gem 'pundit'

Step 8.2: Check BreakEscape policies

Location: /path/to/BreakEscape/app/policies/break_escape/

Ensure these exist:

  • game_policy.rb
  • mission_policy.rb

Step 8.3: Test policy enforcement

rails console
user = User.first
game = BreakEscape::Game.create!(player: user, mission: BreakEscape::Mission.first)

# Test policy
policy = BreakEscape::GamePolicy.new(user, game)
policy.show?  # Should be true (user owns game)

# Test with different user
other_user = User.create!(email: 'other@example.com', password: 'password')
policy = BreakEscape::GamePolicy.new(other_user, game)
policy.show?  # Should be false (doesn't own game)

Phase 9: Run Tests in Hacktivity

Step 9.1: Add BreakEscape test helpers to Hacktivity

Location: /path/to/hacktivity/test/test_helper.rb

Add after existing setup:

# Include BreakEscape test helpers
require 'break_escape/test_helper' if defined?(BreakEscape)

Step 9.2: Run BreakEscape tests

cd /path/to/hacktivity
rails test

This runs all tests including BreakEscape's.

To run only BreakEscape tests:

rails test test/models/break_escape/**/*_test.rb
rails test test/controllers/break_escape/**/*_test.rb

Step 9.3: Verify test fixtures work

Check that Hacktivity's User fixtures are accessible:

rails console -e test
# Should find test users
User.find_by(email: 'test@example.com')

# BreakEscape should be able to create games
game = BreakEscape::Game.create!(
  player: User.first,
  mission: BreakEscape::Mission.first
)

Phase 10: Configure Session & CSRF

Step 10.1: Verify session sharing

BreakEscape should automatically share Hacktivity's session. Test:

rails console
# Check session store
Rails.application.config.session_store
# => :cookie_store or :active_record_store

Note: BreakEscape uses credentials: 'same-origin' in API calls to share cookies.

Step 10.2: Verify CSRF protection

Check that Hacktivity includes CSRF meta tags:

Location: /path/to/hacktivity/app/views/layouts/application.html.erb

Should include:

<%= csrf_meta_tags %>

Test in BreakEscape views:

Location: /path/to/BreakEscape/app/views/layouts/break_escape/application.html.erb

Should include:

<!DOCTYPE html>
<html>
<head>
  <meta name="csrf-token" content="<%= form_authenticity_token %>">
  <%= javascript_tag nonce: true do %>
    window.CSRF_TOKEN = '<%= form_authenticity_token %>';
  <% end %>
</head>
<body>
  <%= yield %>
</body>
</html>

Step 10.3: Test CSRF in API calls

From browser console:

const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
console.log('CSRF Token:', csrfToken);  // Should be a long string

Make an API call:

fetch('/break_escape/games/1/sync_state', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken
  },
  body: JSON.stringify({currentRoom: 'test'})
});

Expected: 200 status, not 422 (CSRF verification failed).


Phase 11: Configure Content Security Policy (CSP)

Step 11.1: Check Hacktivity's CSP configuration

Location: /path/to/hacktivity/config/initializers/content_security_policy.rb

If CSP is enabled:

Rails.application.config.content_security_policy do |policy|
  policy.default_src :self, :https
  policy.script_src  :self, :https
  # ... other directives ...
end

Step 11.2: Enable nonces for BreakEscape

Update CSP to allow inline scripts with nonces:

Rails.application.config.content_security_policy do |policy|
  policy.default_src :self, :https
  policy.script_src  :self, :https, :unsafe_inline if Rails.env.development?
  policy.script_src  :self, :https

  # Allow nonces for inline scripts
  policy.script_src_elem :self, :https
end

Rails.application.config.content_security_policy_nonce_generator = ->(request) {
  SecureRandom.base64(16)
}

Rails.application.config.content_security_policy_nonce_directives = %w[script-src]

Step 11.3: Verify nonces in BreakEscape views

Check that BreakEscape views use nonces:

<%= javascript_tag nonce: true do %>
  window.GAME_ID = <%= @game.id %>;
<% end %>

Phase 12: Deploy to Staging

Step 12.1: Update production config

Location: /path/to/hacktivity/config/environments/production.rb

Ensure static assets are served:

config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?

Or use a CDN/nginx to serve public/break_escape/ assets.

Step 12.2: Precompile assets (if using asset pipeline)

RAILS_ENV=production rails assets:precompile

Note: BreakEscape uses static assets in public/, so this is optional.

Step 12.3: Run migrations on staging

RAILS_ENV=staging rails db:migrate

Step 12.4: Seed missions on staging

RAILS_ENV=staging rails db:seed

Step 12.5: Test on staging

Visit staging URL:

https://staging.hacktivity.com/break_escape

Test:

  1. Mission listing loads
  2. User can start a game
  3. API endpoints work
  4. Ink scripts load correctly
  5. Game state persists across page reloads

Troubleshooting

Problem: "Uninitialized constant BreakEscape"

Solution:

  1. Verify gem 'break_escape' is in Gemfile
  2. Run bundle install
  3. Restart Rails server

Problem: Routes not found (404)

Solution:

  1. Check mount BreakEscape::Engine, at: '/break_escape' in routes.rb
  2. Run rails routes | grep break_escape
  3. Restart Rails server

Problem: Migrations don't run

Solution:

  1. Run rails break_escape:install:migrations
  2. Check db/migrate/ for copied migrations
  3. Run rails db:migrate
  4. Verify with rails db:migrate:status

Problem: "Player must exist" validation error

Solution:

  1. Ensure User model exists
  2. Check polymorphic association: player_type and player_id are set correctly
  3. Verify: BreakEscape::Game.create!(player: User.first, mission: ...)

Problem: Static assets return 404

Solution:

  1. Check files exist: ls -la /path/to/BreakEscape/public/break_escape/
  2. Verify mount path matches: mount BreakEscape::Engine, at: '/break_escape'
  3. Restart Rails server
  4. Check config.public_file_server.enabled in production.rb

Problem: CSRF token invalid

Solution:

  1. Verify <%= csrf_meta_tags %> in layout
  2. Check window.CSRF_TOKEN is set in JavaScript
  3. Ensure API calls include 'X-CSRF-Token': csrfToken header
  4. Verify credentials: 'same-origin' in fetch calls

Problem: Ink scripts fail to load

Solution:

  1. Check bin/inklecate exists and is executable: ls -la bin/inklecate
  2. Test compilation manually: bin/inklecate -o /tmp/test.json scenarios/ink/test.ink
  3. Check file permissions
  4. Verify controller resolve_and_compile_ink logic

Problem: Authorization errors (Pundit)

Solution:

  1. Ensure Pundit is installed: gem 'pundit' in Gemfile
  2. Check policies exist: app/policies/break_escape/game_policy.rb
  3. Verify authorize @game in controllers
  4. Test policy: BreakEscape::GamePolicy.new(user, game).show?

Problem: Tests fail with "table does not exist"

Solution:

  1. Run migrations in test environment: RAILS_ENV=test rails db:migrate
  2. Verify schema.rb includes BreakEscape tables
  3. Reset test database: RAILS_ENV=test rails db:reset

Problem: Game state doesn't persist

Solution:

  1. Check PUT /games/:id/sync_state endpoint works
  2. Verify player_state JSONB column exists
  3. Test in console: game.update!(player_state: {currentRoom: 'test'})
  4. Check logs for errors during API calls

Problem: Scenario randomization not working

Solution:

  1. Verify ERB templates exist: app/assets/scenarios/*/scenario.json.erb
  2. Check Mission#generate_scenario_data method
  3. Test: mission.generate_scenario_data in console
  4. Ensure before_create :generate_scenario_data callback in Game model

Verification Checklist

After integration, verify all these work:

  • Engine mounts at /break_escape
  • Mission listing page loads
  • User can start a game
  • Game redirects to /break_escape/games/:id
  • API endpoint /games/:id/bootstrap works
  • API endpoint /games/:id/scenario works
  • API endpoint /games/:id/ink?npc=X works
  • API endpoint /games/:id/sync_state works
  • API endpoint /games/:id/unlock works
  • Static assets load (JS, CSS, images)
  • Ink scripts compile on-demand (~300ms)
  • Scenario has unique passwords per game
  • Game state persists across page reloads
  • Authorization policies work (can't access other user's games)
  • CSRF protection works
  • Tests pass: rails test
  • Database has 2 tables: break_escape_missions, break_escape_games
  • Polymorphic player works (User or DemoUser)
  • Multiple users can play simultaneously

Performance Monitoring

Monitor JIT Ink Compilation

Add logging to track compilation times:

Location: /path/to/BreakEscape/app/controllers/break_escape/games_controller.rb

def compile_ink(ink_path)
  start_time = Time.now

  # ... compilation logic ...

  duration = ((Time.now - start_time) * 1000).round
  Rails.logger.info "[BreakEscape] Compiled #{File.basename(ink_path)} in #{duration}ms"
end

Monitor logs:

tail -f log/production.log | grep "BreakEscape"

Expected: Compilation times under 500ms.

Monitor Database Performance

Check JSONB query performance:

-- Find slow queries
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
WHERE query LIKE '%break_escape_games%'
ORDER BY mean_exec_time DESC
LIMIT 10;

Ensure GIN indexes are used:

EXPLAIN ANALYZE
SELECT * FROM break_escape_games
WHERE player_state->>'currentRoom' = 'office';

Expected: Should show Bitmap Index Scan on break_escape_games_player_state_idx.


Rollback Plan

If integration fails, rollback:

Step 1: Remove routes

Location: /path/to/hacktivity/config/routes.rb

Comment out:

# mount BreakEscape::Engine, at: '/break_escape'

Step 2: Rollback migrations

rails db:rollback STEP=3

Step 3: Remove gem

Location: /path/to/hacktivity/Gemfile

Comment out:

# gem 'break_escape', path: '../BreakEscape'

Then:

bundle install

Step 4: Restart server

rails server

Next Steps After Integration

Once integrated successfully:

  1. User Testing

    • Invite beta users to play
    • Gather feedback on gameplay
    • Monitor for errors
  2. Performance Tuning

    • Add database indexes if queries are slow
    • Cache compiled Ink scripts if needed
    • Optimize scenario ERB generation
  3. Analytics

    • Track game completions
    • Monitor average play time
    • Identify difficult missions
  4. Enhancements

    • Leaderboards
    • Save/load game states
    • Achievements system
    • Admin dashboard
  5. Monitoring

    • Set up error tracking (Sentry, Rollbar)
    • Monitor server logs
    • Track API response times

Configuration Reference

Environment Variables

Optional environment variables for BreakEscape:

# .env or config/application.yml
BREAK_ESCAPE_MOUNT_PATH=/break_escape           # Default mount path
BREAK_ESCAPE_INK_COMPILE_TIMEOUT=5000           # Compilation timeout (ms)
BREAK_ESCAPE_MAX_GAMES_PER_USER=10              # Limit games per user
BREAK_ESCAPE_ENABLE_DEMO_USERS=false            # Disable in production
BREAK_ESCAPE_LOG_LEVEL=info                     # debug, info, warn, error

Initializer (Optional)

Location: /path/to/hacktivity/config/initializers/break_escape.rb

# Optional configuration
BreakEscape.configure do |config|
  # Enable/disable features
  config.enable_demo_users = Rails.env.development?

  # Limits
  config.max_games_per_user = 10
  config.ink_compile_timeout = 5000  # milliseconds

  # Logging
  config.log_ink_compilation = true
  config.log_scenario_generation = true
end

Support and Documentation

BreakEscape Documentation

External Documentation


Success Criteria

Integration is successful when:

  • All routes work without errors
  • Users can create and play games
  • Game state persists across sessions
  • API endpoints validate correctly
  • Static assets load properly
  • Ink scripts compile on-demand
  • Authorization prevents unauthorized access
  • Tests pass in Hacktivity environment
  • No errors in production logs
  • Performance is acceptable (<500ms for most requests)

Conclusion

BreakEscape is now integrated into Hacktivity! 🎉

Users can:

  • Browse missions at /break_escape
  • Start games with unique passwords
  • Play with persistent state
  • Complete missions and track progress

The engine is:

  • Self-contained (isolated namespace)
  • Secure (server-side validation)
  • Performant (JIT compilation ~300ms)
  • Scalable (2-table architecture)
  • Maintainable (well-tested, documented)

For ongoing support, refer to the documentation files and Rails Engine guides.


Version: 2.0 Last Updated: November 2025 Status: Ready for Production Maintained by: BreakEscape Team