🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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
-
Create
weapon_seriestable migrationdb/migrate/TIMESTAMP_create_weapon_series.rb- UUID primary key, unique index on slug, index on order
-
Add
weapon_series_idto weapons tabledb/migrate/TIMESTAMP_add_weapon_series_id_to_weapons.rb- Foreign key reference, nullable initially
-
Create
weapon_key_seriesjoin tabledb/migrate/TIMESTAMP_create_weapon_key_series.rb- Many-to-many between weapon_keys and weapon_series
- Replaces the integer array
weapon_keys.seriescolumn
Phase 2: Models
-
Create
WeaponSeriesmodel- 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.
- File:
-
Create
WeaponKeySeriesjoin model- File:
app/models/weapon_key_series.rb - Belongs to weapon_key and weapon_series
- File:
-
Update
Weaponmodel- File:
app/models/weapon.rb - Add
belongs_to :weapon_series, optional: true - Update
opus_or_draconic?to useweapon_series.slug - Update
draconic_or_providence?to useweapon_series.slug - Update
element_changeable?to useweapon_series.element_changeable - Update
compatible_with_key?to use new relationship - Keep
SERIES_SLUGStemporarily for backwards compatibility
- File:
-
Update
WeaponKeymodel- File:
app/models/weapon_key.rb - Add
has_many :weapon_key_seriesandhas_many :weapon_series, through: :weapon_key_series
- File:
-
Update
GridWeaponmodel- File:
app/models/grid_weapon.rb - Replace
ALLOWED_EXTRA_SERIESconstant withweapon.weapon_series&.extracheck
- File:
Phase 3: Data Migration
-
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
-
Migrate weapons to use weapon_series_id
db/data/TIMESTAMP_migrate_weapons_to_weapon_series.rb- Map legacy integer
seriesto newweapon_series_id
-
Migrate weapon_key series to join table
db/data/TIMESTAMP_migrate_weapon_key_series.rb- Convert integer arrays to
weapon_key_seriesrecords
Phase 4: API
-
Create
WeaponSeriesBlueprint- File:
app/blueprints/api/v1/weapon_series_blueprint.rb - Fields: name (en/ja), slug, order
- Full view: include boolean flags
- File:
-
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
- File:
-
Add routes
- File:
config/routes.rb resources :weapon_series, only: [:index, :show, :create, :update, :destroy]
- File:
-
Update
WeaponBlueprint- File:
app/blueprints/api/v1/weapon_blueprint.rb - Change
seriesfield to return object:{ id, slug, name: { en, ja } } - Keep legacy
seriesinteger for backwards compatibility during transition
- File:
-
Update
GridWeaponBlueprint- File:
app/blueprints/api/v1/grid_weapon_blueprint.rb - Update weapon_keys conditional to use
weapon.weapon_series&.has_weapon_keys
- File:
Phase 5: Service Updates
-
Update
WeaponProcessor- File:
app/services/processors/weapon_processor.rb - Map incoming
series_idintegers toweapon_series_idUUIDs - Update
element_changeable?calls
- File:
-
Update
CollectionWeaponmodel- File:
app/models/collection_weapon.rb - Update
by_seriesscope to useweapon_series_id - Update validations to use new associations
- File:
Phase 6: Testing
-
Create
WeaponSeriesfactory- File:
spec/factories/weapon_series.rb - Traits for common series types (opus, draconic, etc.)
- File:
-
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
seriesinteger column on weapons until frontend is updated - API can return both formats during transition period
SERIES_SLUGSconstant can be removed after migration is complete