
card-blueprint-db-manager
by PlayersCommittee
Online Play system for SWCCG
SKILL.md
name: card-blueprint-db-manager description: This skill should be used when you need to create filtered subsets of the card_blueprint_database.json file to resolve slug collisions during card mapping. It provides jq commands to filter by side (LIGHT/DARK) and exclude defensive shields, creating temporary filtered JSON files for use with cube-builder.
Card Blueprint Database Manager
Overview
The card blueprint database (card_blueprint_database.json) contains all SWCCG card data with slugified names for mapping. However, slug collisions occur when:
- Light side and dark side cards have the same name (e.g., "Bespin" exists on both sides)
- Defensive shields share slugs with regular cards
This skill provides jq-based filtering to create side-specific databases that exclude defensive shields, resolving these collisions during cube building.
When to Use This Skill
Use this skill when:
- Building cube drafts with cards that have slug collisions
- Mapping card names to IDs fails due to duplicate slugs
- You need side-specific card databases (light only or dark only)
- You need to exclude defensive shields from mapping
Card Database Structure
Each card in the database has these relevant fields:
{
"cardId": "101_2",
"title": "Luke",
"slug": "luke",
"slugWithSetName": "luke-premiere-introductory-two-player-game",
"side": "LIGHT",
"cardCategory": "CHARACTER",
"cardTypes": ["REBEL"]
}
Key fields for filtering:
side- Either "LIGHT" or "DARK"cardCategory- Card category, including "DEFENSIVE_SHIELD"cardTypes- Array of types, including "DEFENSIVE_SHIELD"
Filtering Commands
Filter by Light Side (Exclude Defensive Shields)
Create a light side only database:
jq '[.[] | select(.side == "LIGHT" and .cardCategory != "DEFENSIVE_SHIELD")]' \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database.json \
> src/gemp-swccg-cards/src/main/resources/card_blueprint_database_light.json
Filter by Dark Side (Exclude Defensive Shields)
Create a dark side only database:
jq '[.[] | select(.side == "DARK" and .cardCategory != "DEFENSIVE_SHIELD")]' \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database.json \
> src/gemp-swccg-cards/src/main/resources/card_blueprint_database_dark.json
Filter Excluding All Defensive Shields
Create database without any defensive shields:
jq '[.[] | select(.cardCategory != "DEFENSIVE_SHIELD")]' \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database.json \
> src/gemp-swccg-cards/src/main/resources/card_blueprint_database_no_shields.json
Verify Filtering Results
Check card counts after filtering:
# Original database count
jq 'length' src/gemp-swccg-cards/src/main/resources/card_blueprint_database.json
# Light side count
jq 'length' src/gemp-swccg-cards/src/main/resources/card_blueprint_database_light.json
# Dark side count
jq 'length' src/gemp-swccg-cards/src/main/resources/card_blueprint_database_dark.json
# Verify no defensive shields
jq '[.[] | select(.cardCategory == "DEFENSIVE_SHIELD")] | length' \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database_light.json
# Should output: 0
Integration with Cube Builder
When building cubes with slug collisions, modify the map_card_names_to_ids script to use filtered databases:
Standard Workflow (No Collisions)
./bin/map_card_names_to_ids \
$CUBE_DIR/cube_worlds_lightside.csv \
$CUBE_DIR/cube_worlds_lightside_mapped.json
Modified Workflow (With Slug Collisions)
Step 1: Create filtered databases
# Light side database (no defensive shields)
jq '[.[] | select(.side == "LIGHT" and .cardCategory != "DEFENSIVE_SHIELD")]' \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database.json \
> src/gemp-swccg-cards/src/main/resources/card_blueprint_database_light.json
# Dark side database (no defensive shields)
jq '[.[] | select(.side == "DARK" and .cardCategory != "DEFENSIVE_SHIELD")]' \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database.json \
> src/gemp-swccg-cards/src/main/resources/card_blueprint_database_dark.json
Step 2: Modify map_card_names_to_ids script to accept database path
The script needs to accept an optional third parameter for the database path:
./bin/map_card_names_to_ids \
$CUBE_DIR/cube_worlds_lightside.csv \
$CUBE_DIR/cube_worlds_lightside_mapped.json \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database_light.json
Step 3: Map with appropriate database
CUBE_DIR="src/gemp-swccg-server/src/main/resources/draft/cube_building/worlds_2025"
# Map light side with light database
./bin/map_card_names_to_ids \
$CUBE_DIR/cube_worlds_lightside.csv \
$CUBE_DIR/cube_worlds_lightside_mapped.json \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database_light.json
# Map dark side with dark database
./bin/map_card_names_to_ids \
$CUBE_DIR/cube_worlds_darkside.csv \
$CUBE_DIR/cube_worlds_darkside_mapped.json \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database_dark.json
# Default cards can use either (or no-shields version if needed)
./bin/map_card_names_to_ids \
$CUBE_DIR/default_cards.csv \
$CUBE_DIR/default_cards_mapped.json
Complete Cube Building Example with Filtering
# 1. Regenerate main card database
./bin/gemp export-cards src/gemp-swccg-cards/src/main/resources/card_blueprint_database.json
# 2. Create filtered databases
jq '[.[] | select(.side == "LIGHT" and .cardCategory != "DEFENSIVE_SHIELD")]' \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database.json \
> src/gemp-swccg-cards/src/main/resources/card_blueprint_database_light.json
jq '[.[] | select(.side == "DARK" and .cardCategory != "DEFENSIVE_SHIELD")]' \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database.json \
> src/gemp-swccg-cards/src/main/resources/card_blueprint_database_dark.json
# 3. Verify filtering worked
echo "Light side cards (no shields):"
jq 'length' src/gemp-swccg-cards/src/main/resources/card_blueprint_database_light.json
echo "Dark side cards (no shields):"
jq 'length' src/gemp-swccg-cards/src/main/resources/card_blueprint_database_dark.json
# 4. Map cards with filtered databases
CUBE_DIR="src/gemp-swccg-server/src/main/resources/draft/cube_building/worlds_2025"
./bin/map_card_names_to_ids \
$CUBE_DIR/cube_worlds_lightside.csv \
$CUBE_DIR/cube_worlds_lightside_mapped.json \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database_light.json
./bin/map_card_names_to_ids \
$CUBE_DIR/cube_worlds_darkside.csv \
$CUBE_DIR/cube_worlds_darkside_mapped.json \
src/gemp-swccg-cards/src/main/resources/card_blueprint_database_dark.json
./bin/map_card_names_to_ids \
$CUBE_DIR/default_cards.csv \
$CUBE_DIR/default_cards_mapped.json
# 5. Verify mapping success
echo "Light side mapping:"
cat $CUBE_DIR/cube_worlds_lightside_mapped_log.json | jq '.summary'
echo "Dark side mapping:"
cat $CUBE_DIR/cube_worlds_darkside_mapped_log.json | jq '.summary'
# 6. Generate cube configuration
python3 bin/create_cube $CUBE_DIR src/gemp-swccg-server/src/main/resources/draft/cubeWorlds2025.json
# 7. Deploy
./bin/gemp reload-fast
Troubleshooting
Issue: jq command not found
Solution: Install jq via Homebrew:
brew install jq
Issue: Filtered database still has wrong cards
Verification:
# Check sides in filtered database
jq '[.[] | .side] | unique' card_blueprint_database_light.json
# Should output: ["LIGHT"]
# Check for defensive shields
jq '[.[] | select(.cardCategory == "DEFENSIVE_SHIELD")] | length' card_blueprint_database_light.json
# Should output: 0
Issue: Mapping still finds wrong cards
Cause: Script still using main database instead of filtered one
Solution: Verify third parameter is being passed and used in the script:
# Check if script accepts database path parameter
grep -n "sys.argv\[3\]" bin/map_card_names_to_ids
If the script doesn't support the third parameter yet, it needs to be modified to accept it.
Issue: Slug still has collisions after filtering
Investigation:
# Find cards with same slug in filtered database
jq -r '.[] | .slug' card_blueprint_database_light.json | sort | uniq -d
# For each duplicate slug, check which cards have it
jq '.[] | select(.slug == "duplicate-slug-here")' card_blueprint_database_light.json
Common causes:
- Multiple versions of same card (Premiere, Special Edition, Virtual)
- Same character with different subtitles
Solution: Use slugWithSetName for disambiguation or add set identifier to CSV.
Cleanup
After successfully building the cube, you can optionally remove the temporary filtered databases:
rm src/gemp-swccg-cards/src/main/resources/card_blueprint_database_light.json
rm src/gemp-swccg-cards/src/main/resources/card_blueprint_database_dark.json
rm src/gemp-swccg-cards/src/main/resources/card_blueprint_database_no_shields.json
However, keeping them can speed up future cube builds with the same filtering requirements.
File Locations
gemp-swccg/
├── src/gemp-swccg-cards/src/main/resources/
│ ├── card_blueprint_database.json # Main database
│ ├── card_blueprint_database_light.json # Light side filtered (temporary)
│ ├── card_blueprint_database_dark.json # Dark side filtered (temporary)
│ └── card_blueprint_database_no_shields.json # No shields (temporary)
│
├── bin/
│ └── map_card_names_to_ids # Mapping script (needs modification)
│
└── src/gemp-swccg-server/src/main/resources/draft/cube_building/
└── <cube_name>/
├── cube_worlds_lightside.csv # Light side cards
├── cube_worlds_darkside.csv # Dark side cards
└── default_cards.csv # Core cards
Advanced Filtering
Filter by Multiple Criteria
Combine filters for complex requirements:
# Light side characters only (no defensive shields)
jq '[.[] | select(.side == "LIGHT" and .cardCategory == "CHARACTER")]' \
card_blueprint_database.json > light_characters.json
# Dark side locations only (no defensive shields)
jq '[.[] | select(.side == "DARK" and .cardCategory == "LOCATION")]' \
card_blueprint_database.json > dark_locations.json
# Specific set only
jq '[.[] | select(.expansionSet == "PREMIERE")]' \
card_blueprint_database.json > premiere_only.json
Count Cards by Category
# Count cards by category for light side
jq '[.[] | select(.side == "LIGHT")] | group_by(.cardCategory) | map({category: .[0].cardCategory, count: length})' \
card_blueprint_database.json
# Count defensive shields
jq '[.[] | select(.cardCategory == "DEFENSIVE_SHIELD")] | length' \
card_blueprint_database.json
Find Slug Collisions
# Find duplicate slugs across sides
jq -r '.[] | .slug' card_blueprint_database.json | sort | uniq -d > duplicate_slugs.txt
# For each duplicate, show which sides/categories have it
while read slug; do
echo "Slug: $slug"
jq ".[] | select(.slug == \"$slug\") | {cardId, title, side, cardCategory}" \
card_blueprint_database.json
echo "---"
done < duplicate_slugs.txt
Resources
See references/ directory for detailed jq filter examples and common slug collision patterns.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon