🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
12 KiB
Character Season & Series Implementation Plan
Overview
Add season, series, and gacha_available columns to the characters table to properly categorize character variants. This replaces the current approach of disambiguating in name fields (e.g., "Vira (SSR)").
Goals:
- Clean character names without disambiguation suffixes
- Enable filtering by season/series in the UI
- Support gacha bot queries for pool availability
- Centralize gacha metadata in hensei-api (shared database with siero-bot)
Data Model
Season (integer, nullable)
Represents the gacha time period when a character can be pulled.
| Value | Name | Notes |
|---|---|---|
| 1 | Standard | Available year-round (in their respective pool) (1-index to work better with Javascript) |
| 2 | Valentine | February |
| 3 | Formal | June |
| 4 | Summer | July-August (both Summer and Yukata series) |
| 5 | Halloween | October |
| 6 | Holiday | December |
Series (integer array)
Represents the character's identity/pool membership. A character can belong to multiple series (e.g., Summer Zodiac = [summer, zodiac]).
| Value | Name | Notes |
|---|---|---|
| 1 | Standard | Regular gacha pool (1-index to work better with Javascript) |
| 2 | Grand | Flash Gala and Legend Gacha exclusive |
| 3 | Zodiac | Legend Fest exclusive, yearly rotation |
| 4 | Promo | Not in gacha - ticket/code redemption |
| 5 | Collab | Collaboration events |
| 6 | Eternal | Free recruitment (Eternals) |
| 7 | Evoker | Free recruitment (Evokers) |
| 8 | Saint | Free recruitment (similar to Eternals), may have gacha alts |
| 9 | Fantasy | Can combine with other series (e.g., Fantasy + Grand) |
| 10 | Summer | Summer seasonal series |
| 11 | Yukata | Yukata seasonal series (same gacha window as Summer) |
| 12 | Valentine | Valentine seasonal series |
| 13 | Halloween | Halloween seasonal series |
| 14 | Formal | Formal seasonal series |
| 15 | Event | Event reward characters |
Gacha Available (boolean)
Quick filter for characters that can be pulled in gacha vs those that are recruited.
true- Can be pulled from gacha (Standard, Grand, Zodiac, seasonal series, etc.)false- Must be recruited (Eternals, Evokers, Saints, Event, Collab)
Promotion (integer array on weapons/summons)
Move promotion data from the gacha table to weapons and summons directly.
| Value | Name | Notes |
|---|---|---|
| 1 | Premium | Available in regular Premium draws |
| 2 | Classic | Available in Classic draws |
| 3 | Classic II | Available in Classic II draws |
| 4 | Flash | Available in Flash Gala (6% SSR rate) |
| 5 | Legend | Available in Legend Fest (6% SSR rate) |
| 6 | Valentine | Valentine seasonal gacha |
| 7 | Summer | Summer seasonal gacha |
| 8 | Halloween | Halloween seasonal gacha |
| 9 | Holiday | Holiday seasonal gacha |
| 10 | Collab | Collaboration gacha |
| 11 | Formal | Formal seasonal gacha |
Decision: Add promotions as integer array on weapons and summons tables, then deprecate the gacha table. This eliminates the polymorphic join and simplifies queries.
Implementation Tasks
Phase 1: Schema Migration
-
Task 1.1: Create migration to add
season,series, andgacha_availablecolumns:6e62053 -
Task 1.2: Add enum constants to
GranblueEnums:24d8d20,208d1f4
Phase 2: Model Updates
-
Task 2.1: Update
Charactermodel:afa1c51 -
Task 2.2: Update
CharacterBlueprint:a3c33ce,cb01658
Phase 3: Controller & API Updates
-
Task 3.1: Update
CharactersController:db048dc -
Task 3.2: Update search functionality:
9c5c859- Added
season,series,gacha_availablefilters to characters search - Added
promotionsfilter to weapons search - Added
promotionsfilter to summons search - Array filters use PostgreSQL
&&(overlap) operator
- Added
Phase 4: Importer/Parser Updates
-
Task 4.1: Update
CharacterImporter:e0a82bc- Added
season,series,gacha_availabletobuild_attributes
- Added
-
Task 4.2: Update
CharacterParser:e0a82bc- Added
series_from_hash,season_from_hash,gacha_available_from_hashmethods - Extracts data from wiki
|series=and|obtain=fields
- Added
-
Task 4.3: Update
WeaponImporterandSummonImporter:7aa0521- Added
promotionstobuild_attributes
- Added
-
Task 4.4: Update
WeaponParserandSummonParser:c1a5d62- Added
promotions_from_obtainmethod - Added wiki promotions mapping to
Wikiclass
- Added
Phase 5: Data Migration
-
Task 5.1: Create rake task to export characters to CSV:
284ee44 -
Task 5.2: User curates CSV with season/series assignments (manual step)
-
Task 5.3: Create rake task to import curated CSV:
284ee44 -
Task 5.4: Clean up character names (deferred until data populated)
Phase 6: Frontend Updates (hensei-svelte)
-
Task 6.1: Update TypeScript types:
67b87c7d -
Task 6.2: Update search adapter:
f26d3e38 -
Task 6.3: Add filter UI components (CheckboxGroup):
96f040a9 -
Task 6.4: Update character display:
cf694bb1 -
Task 6.5: Update weapon display:
8c45c219 -
Task 6.6: Update summon display:
23ae7f70 -
Task 6.7: Update batch import pages:
1933f3d8 -
Task 6.8: Add recruited_by to character metadata:
cf694bb1
Phase 7: Weapons/Summons Promotion Migration
-
Task 7.1: Add
promotionscolumn to weapons table:6f64610 -
Task 7.2: Add
promotionscolumn to summons table:6f64610 -
Task 7.3: Add PROMOTIONS enum to
GranblueEnums:6f64610,208d1f4 -
Task 7.4: Create data migration rake task:
49e52ff -
Task 7.5: Update Weapon and Summon models:
e81c559 -
Task 7.6: Update WeaponBlueprint and SummonBlueprint:
0dba56c -
Task 7.7: Update controllers to permit
promotions:05dd899 -
Task 7.8: Deprecate
gachatable (after siero-bot deployed and tested)
Phase 8: Siero-bot Integration
- Task 8.1: Update siero-bot to use new columns (branch:
feature/use-promotions-column)210b5dc- AddedPromotionIdenum mapping to hensei-api valuesb0e0972- Addedpromotions: number[]to table interfaces897d86b- Rewrotecache.tsto query weapons/summons directly1b7ac14- Rewroteapi.tsto remove gacha table dependencyd745b0f- Changed rateups to usegranblue_idfor stability
Remaining Work (Pre-Deployment Testing Required)
These tasks require testing and/or manual intervention before completion:
1. Data Population (Manual)
Task 5.2: Curate character season/series data
Options for populating character data:
- Option A: Export CSV, manually curate, re-import
rake characters:export_csv # Creates lib/seeds/characters_export.csv # Edit CSV to add season/series/gacha_available values rake characters:import_csv # Imports curated data - Option B: Use wiki parser to auto-populate (may need manual review)
rails runner "Granblue::Parsers::CharacterParser.fetch_all(save: true, overwrite: true)"
2. Siero-bot Deployment
Deploy and test siero-bot changes before deprecating gacha table:
- Merge
feature/use-promotions-columnbranch - Deploy to production
- Test gacha simulation commands work correctly
- Test rateup functionality works correctly
- Monitor for errors
3. Database Cleanup (Destructive)
Task 7.8: Deprecate gacha table
Only after siero-bot is deployed and verified working:
- Create migration to drop
gachatable - Remove any remaining references to
Gachamodel - Clean up unused code
4. Character Name Cleanup (Optional)
Task 5.4: Remove disambiguation from character names
After season/series data is populated and frontend displays badges:
- Remove suffixes like "(SSR)", "(Summer)", "(Grand)" from
name_en - Update any search indexes if needed
- Verify frontend displays correctly with badges instead of name suffixes
File Changes Summary
hensei-api
| File | Change |
|---|---|
db/migrate/*_add_season_series_to_characters.rb |
Add season, series, gacha_available columns |
db/migrate/*_add_promotions_to_weapons.rb |
Add promotions array column |
db/migrate/*_add_promotions_to_summons.rb |
Add promotions array column |
lib/tasks/characters.rake |
Export/import rake tasks for data migration |
lib/tasks/gacha.rake |
Migration tasks for promotions data |
app/models/concerns/granblue_enums.rb |
Add CHARACTER_SEASONS, CHARACTER_SERIES, PROMOTIONS |
app/models/character.rb |
Add validations, scopes, helpers |
app/models/weapon.rb |
Add promotions validations, scopes, helpers |
app/models/summon.rb |
Add promotions validations, scopes, helpers |
app/blueprints/api/v1/character_blueprint.rb |
Serialize new fields, recruited_by |
app/blueprints/api/v1/weapon_blueprint.rb |
Serialize promotions |
app/blueprints/api/v1/summon_blueprint.rb |
Serialize promotions |
app/controllers/api/v1/characters_controller.rb |
Permit new params, filtering |
app/controllers/api/v1/weapons_controller.rb |
Permit promotions |
app/controllers/api/v1/summons_controller.rb |
Permit promotions |
app/controllers/api/v1/search_controller.rb |
Add season/series/promotions filters |
lib/granblue/importers/character_importer.rb |
Parse new CSV columns |
lib/granblue/importers/weapon_importer.rb |
Parse promotions column |
lib/granblue/importers/summon_importer.rb |
Parse promotions column |
lib/granblue/parsers/character_parser.rb |
Extract season/series from wiki |
lib/granblue/parsers/weapon_parser.rb |
Extract promotions from wiki |
lib/granblue/parsers/summon_parser.rb |
Extract promotions from wiki |
lib/granblue/parsers/wiki.rb |
Add promotions mapping |
hensei-svelte
| File | Change |
|---|---|
src/lib/types/Character.d.ts |
Add season/series/gachaAvailable fields |
src/lib/types/Weapon.d.ts |
Add promotions fields |
src/lib/types/Summon.d.ts |
Add promotions fields |
src/lib/types/enums.ts |
Add CharacterSeason, CharacterSeries, Promotion enums |
src/lib/api/adapters/entity.adapter.ts |
Add new fields to interfaces |
src/lib/api/adapters/search.adapter.ts |
Add filter params |
src/lib/api/adapters/types.ts |
Add SearchFilters types |
src/lib/components/ui/checkbox/CheckboxGroup.svelte |
New multiselect component |
src/lib/components/ui/DetailItem.svelte |
Add multiselect type support |
src/lib/features/database/characters/schema.ts |
Add to edit schema |
src/lib/features/database/characters/sections/CharacterTaxonomySection.svelte |
Add season/series/gacha UI |
src/lib/features/database/characters/sections/CharacterMetadataSection.svelte |
Add recruited_by display |
src/lib/features/database/weapons/schema.ts |
Add promotions to schema |
src/lib/features/database/weapons/sections/WeaponTaxonomySection.svelte |
Add promotions UI |
src/lib/features/database/summons/schema.ts |
Add promotions to schema |
src/lib/features/database/summons/sections/SummonTaxonomySection.svelte |
Add promotions UI |
src/routes/(app)/database/*/import/+page.svelte |
Add new fields to batch import |
siero-bot (branch: feature/use-promotions-column)
| File | Change |
|---|---|
src/services/cache.ts |
Query promotions from weapons/summons instead of gacha table |
src/services/api.ts |
Remove gacha table dependency, use granblue_id for rateups |
src/utils/enums.ts |
Add PromotionId enum, mapping helpers |
src/services/tables.ts |
Add promotions to WeaponTable and SummonTable |
Notes
- The
character_idarray field will remain unchanged (no rename) gacha_availableboolean added for quick filtering of pullable vs recruited characters- All enums are 1-indexed to work better with JavaScript/TypeScript
gachatable will be deprecated after siero-bot migration is complete- Season values represent gacha availability windows (when you can pull)
- Series values represent character identity (what pool/category they belong to)
- Wiki uses "gala" for Flash Gala weapons (mapped to Flash promotion ID 4)