# 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:

```ruby
# 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

```bash
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

```bash
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:

```ruby
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

```bash
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

```bash
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

```bash
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

```bash
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

```bash
rails db:migrate:status
```

Look for:
```
  up     20251120120001  Create break escape missions
  up     20251120120002  Create break escape games
```

Or check in PostgreSQL:
```bash
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:

```ruby
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

```bash
rails console
```

```ruby
# 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`:

```bash
rails db:seed
```

Or manually create missions:

```bash
rails console
```

```ruby
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

```bash
rails console
```

```ruby
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:

```bash
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:

```bash
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

```bash
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:

```javascript
// 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

```javascript
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`

```ruby
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

```bash
rails console
```

```ruby
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:

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

### Step 9.2: Run BreakEscape tests

```bash
cd /path/to/hacktivity
rails test
```

This runs all tests including BreakEscape's.

To run only BreakEscape tests:

```bash
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:

```bash
rails console -e test
```

```ruby
# 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:

```bash
rails console
```

```ruby
# 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:

```erb
<%= csrf_meta_tags %>
```

Test in BreakEscape views:

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

Should include:

```erb
<!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:

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

Make an API call:

```javascript
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:

```ruby
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:

```ruby
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:

```erb
<%= 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:

```ruby
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)

```bash
RAILS_ENV=production rails assets:precompile
```

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

### Step 12.3: Run migrations on staging

```bash
RAILS_ENV=staging rails db:migrate
```

### Step 12.4: Seed missions on staging

```bash
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`

```ruby
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:
```bash
tail -f log/production.log | grep "BreakEscape"
```

**Expected:** Compilation times under 500ms.

### Monitor Database Performance

Check JSONB query performance:

```sql
-- 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:
```sql
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:
```ruby
# mount BreakEscape::Engine, at: '/break_escape'
```

### Step 2: Rollback migrations

```bash
rails db:rollback STEP=3
```

### Step 3: Remove gem

**Location:** `/path/to/hacktivity/Gemfile`

Comment out:
```ruby
# gem 'break_escape', path: '../BreakEscape'
```

Then:
```bash
bundle install
```

### Step 4: Restart server

```bash
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:**

```bash
# .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`

```ruby
# 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

- [00_OVERVIEW.md](./00_OVERVIEW.md) - Project aims and decisions
- [01_ARCHITECTURE.md](./01_ARCHITECTURE.md) - Technical design
- [02_DATABASE_SCHEMA.md](./02_DATABASE_SCHEMA.md) - Database reference
- [03_IMPLEMENTATION_PLAN.md](./03_IMPLEMENTATION_PLAN.md) - Implementation guide
- [04_API_REFERENCE.md](./04_API_REFERENCE.md) - API endpoints
- [05_TESTING_GUIDE.md](./05_TESTING_GUIDE.md) - Testing strategy

### External Documentation

- [Rails Engines Guide](https://guides.rubyonrails.org/engines.html)
- [Pundit Authorization](https://github.com/varvet/pundit)
- [Devise Authentication](https://github.com/heartcombo/devise)
- [PostgreSQL JSONB](https://www.postgresql.org/docs/current/datatype-json.html)
- [Phaser.js](https://phaser.io/docs)
- [Ink](https://github.com/inkle/ink)

---

## 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
