hensei-api/docs/plans/weapon-series-migration.md
Justin Edmund ef7c158736 add implementation plans for artifacts, character series, weapon series
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 20:54:48 -08:00

7.2 KiB

Plan: Convert WeaponSeries from Enum to Database Table

Summary

Convert the hardcoded SERIES_SLUGS hash in Weapon model to a weapon_series database table with full CRUD API support, enabling dynamic management of weapon series without code deploys.

New Table: weapon_series

Column Type Notes
id uuid Primary key
name_en string English name
name_jp string Japanese name
slug string Unique identifier (e.g., 'dark-opus')
order integer Sort order for display
extra boolean Allowed in extra grid positions (9, 10, 11)
element_changeable boolean Weapon element can be changed
has_weapon_keys boolean Series supports weapon keys
has_awakening boolean Series supports awakenings
has_ax_skills boolean Series supports AX skills

Implementation Steps

Phase 1: Database Setup

  1. Create weapon_series table migration

    • db/migrate/TIMESTAMP_create_weapon_series.rb
    • UUID primary key, unique index on slug, index on order
  2. Add weapon_series_id to weapons table

    • db/migrate/TIMESTAMP_add_weapon_series_id_to_weapons.rb
    • Foreign key reference, nullable initially
  3. Create weapon_key_series join table

    • db/migrate/TIMESTAMP_create_weapon_key_series.rb
    • Many-to-many between weapon_keys and weapon_series
    • Replaces the integer array weapon_keys.series column

Phase 2: Models

  1. Create WeaponSeries model

    • File: app/models/weapon_series.rb
    • Associations: has_many :weapons, has_many :weapon_key_series, has_many :weapon_keys, through: :weapon_key_series
    • Validations: presence for name_en, name_jp, slug; uniqueness for slug
    • Scopes: ordered, extra_allowed, element_changeable, etc.
  2. Create WeaponKeySeries join model

    • File: app/models/weapon_key_series.rb
    • Belongs to weapon_key and weapon_series
  3. Update Weapon model

    • File: app/models/weapon.rb
    • Add belongs_to :weapon_series, optional: true
    • Update opus_or_draconic? to use weapon_series.slug
    • Update draconic_or_providence? to use weapon_series.slug
    • Update element_changeable? to use weapon_series.element_changeable
    • Update compatible_with_key? to use new relationship
    • Keep SERIES_SLUGS temporarily for backwards compatibility
  4. Update WeaponKey model

    • File: app/models/weapon_key.rb
    • Add has_many :weapon_key_series and has_many :weapon_series, through: :weapon_key_series
  5. Update GridWeapon model

    • File: app/models/grid_weapon.rb
    • Replace ALLOWED_EXTRA_SERIES constant with weapon.weapon_series&.extra check

Phase 3: Data Migration

  1. Populate weapon_series table

    • db/data/TIMESTAMP_populate_weapon_series.rb
    • Create 45 series records from existing SERIES_SLUGS
    • Set boolean flags appropriately for each series
  2. Migrate weapons to use weapon_series_id

    • db/data/TIMESTAMP_migrate_weapons_to_weapon_series.rb
    • Map legacy integer series to new weapon_series_id
  3. Migrate weapon_key series to join table

    • db/data/TIMESTAMP_migrate_weapon_key_series.rb
    • Convert integer arrays to weapon_key_series records

Phase 4: API

  1. Create WeaponSeriesBlueprint

    • File: app/blueprints/api/v1/weapon_series_blueprint.rb
    • Fields: name (en/ja), slug, order
    • Full view: include boolean flags
  2. Create WeaponSeriesController

    • File: app/controllers/api/v1/weapon_series_controller.rb
    • Actions: index, show, create (admin), update (admin), destroy (admin)
    • Lookup by slug or id
  3. Add routes

    • File: config/routes.rb
    • resources :weapon_series, only: [:index, :show, :create, :update, :destroy]
  4. Update WeaponBlueprint

    • File: app/blueprints/api/v1/weapon_blueprint.rb
    • Change series field to return object: { id, slug, name: { en, ja } }
    • Keep legacy series integer for backwards compatibility during transition
  5. Update GridWeaponBlueprint

    • File: app/blueprints/api/v1/grid_weapon_blueprint.rb
    • Update weapon_keys conditional to use weapon.weapon_series&.has_weapon_keys

Phase 5: Service Updates

  1. Update WeaponProcessor

    • File: app/services/processors/weapon_processor.rb
    • Map incoming series_id integers to weapon_series_id UUIDs
    • Update element_changeable? calls
  2. Update CollectionWeapon model

    • File: app/models/collection_weapon.rb
    • Update by_series scope to use weapon_series_id
    • Update validations to use new associations

Phase 6: Testing

  1. Create WeaponSeries factory

    • File: spec/factories/weapon_series.rb
    • Traits for common series types (opus, draconic, etc.)
  2. Update existing specs

    • Update weapon factory to use weapon_series association
    • Add tests for new controller endpoints
    • Add tests for model methods

Files to Modify

File Changes
app/models/weapon.rb Add association, update methods
app/models/weapon_key.rb Add associations
app/models/grid_weapon.rb Replace ALLOWED_EXTRA_SERIES
app/models/collection_weapon.rb Update scope and validations
app/blueprints/api/v1/weapon_blueprint.rb Update series field
app/blueprints/api/v1/grid_weapon_blueprint.rb Update conditional
app/services/processors/weapon_processor.rb Update series lookups
config/routes.rb Add weapon_series routes

New Files to Create

File Purpose
app/models/weapon_series.rb WeaponSeries model
app/models/weapon_key_series.rb Join table model
app/controllers/api/v1/weapon_series_controller.rb CRUD controller
app/blueprints/api/v1/weapon_series_blueprint.rb API serializer
db/migrate/*_create_weapon_series.rb Table migration
db/migrate/*_add_weapon_series_id_to_weapons.rb FK migration
db/migrate/*_create_weapon_key_series.rb Join table migration
db/data/*_populate_weapon_series.rb Seed data
db/data/*_migrate_weapons_to_weapon_series.rb Data migration
db/data/*_migrate_weapon_key_series.rb WeaponKey data migration
spec/factories/weapon_series.rb Test factory

Boolean Flags by Series

Key series with special flags:

  • element_changeable: revenant, ultima, superlative, class-champion
  • extra: xeno, cosmos, superlative, eternal-splendor, ancestral, militis, menace
  • has_weapon_keys: grand, dark-opus, superlative, vyrmament, menace
  • has_awakening: (to be determined based on current weapon data)
  • has_ax_skills: (to be determined based on current weapon data)

API Response Format

// GET /weapon_series
[
  {
    "id": "uuid",
    "name": { "en": "Dark Opus", "ja": "オプス" },
    "slug": "dark-opus",
    "order": 3
  }
]

// GET /weapons/:id (updated series field)
{
  "id": "uuid",
  "series": {
    "id": "series-uuid",
    "slug": "dark-opus",
    "name": { "en": "Dark Opus", "ja": "オプス" }
  }
}

Backwards Compatibility

  • Keep legacy series integer column on weapons until frontend is updated
  • API can return both formats during transition period
  • SERIES_SLUGS constant can be removed after migration is complete