IMPORTANT: This migration is BLOCKED until Impress 2020 is retired. Created comprehensive deployment guide documenting: - Why this migration is blocked (Impress 2020 uses openneo_id directly) - Two paths forward: retire Impress 2020 (recommended) or coordinated update - Complete step-by-step deployment checklist for when ready - Rollback procedures - Risk assessment and mitigations - Success criteria and timeline estimates This ensures we don't accidentally deploy this change before addressing the Impress 2020 dependency. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|---|---|---|
| .devcontainer | ||
| .husky | ||
| app | ||
| bin | ||
| config | ||
| db | ||
| deploy | ||
| docs | ||
| lib | ||
| public | ||
| spec | ||
| test | ||
| vendor | ||
| .eslintrc.json | ||
| .gitignore | ||
| .rspec | ||
| .ruby-version | ||
| .solargraph.yml | ||
| .yarnrc.yml | ||
| config.ru | ||
| falcon.rb | ||
| Gemfile | ||
| Gemfile.lock | ||
| LICENSE.md | ||
| package.json | ||
| Procfile.dev | ||
| Rakefile | ||
| README.md | ||
| yarn.lock | ||
Dress to Impress
Dress to Impress (DTI) is a tool for designing Neopets outfits. Load your pet, browse items, and see how they look together—all with a mobile-friendly interface!
Architecture Overview
DTI is a Rails application with a React-based outfit editor, backed by MySQL databases and a crowdsourced data collection system.
Core Components
- Rails backend (Ruby 3.4, Rails 8.0): Serves web pages, API endpoints, and manages data
- MySQL database: Single database (
openneo_impress) containing all application and authentication data - React outfit editor: Embedded in
app/javascript/wardrobe-2020/, provides the main customization UI - Modeling system: Crowdsources pet/item appearance data by fetching from Neopets APIs when users load their pets
The Impress 2020 Complication
In 2020, we started a NextJS rewrite ("Impress 2020") to modernize the frontend. We've since consolidated back into Rails, but Impress 2020 still provides essential services:
- GraphQL API: Some outfit appearance data still loads via GraphQL (being migrated to Rails REST APIs)
- Image generation: Runs a headless browser to render outfit thumbnails and convert HTML5 assets to PNGs
See docs/impress-2020-dependencies.md for migration status.
Key Concepts
Customization Data Model
The core data model powers outfit rendering and item compatibility. See docs/customization-architecture.md for details.
Quick summary:
body_idis the key compatibility constraint (not species or color directly)- Items have different
swf_assets(visual layers) for different bodies - Restrictions are subtractive: start with all layers, hide some based on zone restrictions
- Data is crowdsourced through "modeling" (users loading pets to contribute appearance data)
Modeling (Crowdsourced Data)
DTI doesn't pre-populate item/pet data. Instead:
- User loads a pet (via pet name lookup)
- DTI fetches appearance data from Neopets APIs (legacy Flash/AMF protocol)
- New
SwfAssetrecords and relationships are created - Over time, the database learns which items fit which pet bodies
This "self-sustaining" approach means the site stays up-to-date as Neopets releases new content, without manual data entry.
Directory Map
Key Application Files
app/
├── controllers/
│ ├── outfits_controller.rb # Outfit editor + CRUD
│ ├── items_controller.rb # Item search, pages, and JSON APIs
│ ├── pets_controller.rb # Pet loading (triggers modeling)
│ └── closet_hangers_controller.rb # User item lists ("closets")
│
├── models/
│ ├── item.rb # Items + compatibility prediction logic
│ ├── pet_type.rb # Species+Color combinations (has body_id)
│ ├── pet_state.rb # Visual variants (pose/gender/mood)
│ ├── swf_asset.rb # Visual layers (biology/object)
│ ├── outfit.rb # Saved outfits + rendering logic (visible_layers)
│ ├── alt_style.rb # Alternative pet appearances (Nostalgic, etc.)
│ └── pet/
│ └── modeling_snapshot.rb # Processes Neopets API data into models
│
├── services/
│ ├── neopets/
│ │ ├── custom_pets.rb # Neopets AMF/Flash API client (pet data)
│ │ ├── nc_mall.rb # NC Mall item scraping
│ │ └── neopass.rb # NeoPass OAuth integration
│ ├── neopets_media_archive.rb # Local mirror of images.neopets.com
│ └── lebron_nc_values.rb # NC item trading values (external API)
│
├── javascript/
│ ├── wardrobe-2020/ # React outfit editor (extracted from Impress 2020)
│ │ ├── loaders/ # REST API calls (migrated from GraphQL)
│ │ ├── WardrobePage/ # Main editor UI
│ │ └── components/ # Shared React components
│ └── application.js # Rails asset pipeline entrypoint
│
└── views/
├── outfits/
│ └── edit.html.haml # Outfit editor page (loads React app)
├── items/
│ └── show.html.haml # Item detail page
└── closet_hangers/
└── index.html.haml # User closet/item lists
Configuration & Docs
config/
├── routes.rb # All Rails routes
├── database.yml # Database configuration
└── environments/
└── *.rb # Env-specific config (incl. impress_2020_origin)
Documentation:
- docs/customization-architecture.md - Deep dive into data model & rendering
- docs/impress-2020-dependencies.md - What still depends on Impress 2020 service
Tests:
test/- Test::Unit tests (privacy features)spec/- RSpec tests (models, services, integrations)- Coverage is focused on key areas: modeling, prediction logic, external APIs
- Not comprehensive, but thorough for critical behaviors
Tech Stack
- Backend: Ruby on Rails (Ruby 3.4, Rails 8.0)
- Frontend: Mix of Rails views (Turbo/HAML) and React (for outfit editor)
- Database: MySQL (
openneo_impress) - Styling: CSS, Sass (moving toward modern Rails conventions)
- External Integrations:
- Neopets.com: Legacy Flash/AMF protocol for pet appearance data (modeling)
- Neopets NC Mall: Web scraping for NC item availability/pricing
- NeoPass: OAuth integration for Neopets account linking
- Neopets Media Archive: Local filesystem mirror of
images.neopets.com(never discards old files) - Lebron's NC Values: Third-party API for NC item trading values (lebron-values.netlify.app)
- Impress 2020: GraphQL for some outfit data, image generation service (being phased out)
Development Notes
Authentication Architecture
Authentication data lives in the auth_users table (managed by the AuthUser model). This was historically in a separate openneo_id database (a legacy from when "OpenNeo ID" was envisioned as a service to unify auth across multiple OpenNeo projects). As of November 2025, the databases have been consolidated into a single database for simplicity.
User accounts are split across two related tables:
auth_users- Authentication data (passwords, email, OAuth connections) via Deviseusers- Application data (points, closet settings, etc.)
These are linked via User.remote_id → AuthUser.id. See db/openneo_id_migrate/README.md for the historical context.
Rails/React Hybrid
Most pages are traditional Rails views using Turbo for interactivity. The outfit editor (/outfits/new) is a full React app that:
- Loads into a
#wardrobe-2020-rootdiv - Uses React Query for data fetching
- Calls both Rails REST APIs (in
loaders/) and Impress 2020 GraphQL (being migrated)
The goal is to simplify this over time—either consolidate into Rails+Turbo, or commit fully to React. For now, we're in a hybrid state.
Deployment
- Main app: VPS running Rails (Puma, MySQL)
- Impress 2020: Separate VPS in same datacenter (NextJS, GraphQL, headless browser for images)
- Both services share the same MySQL database (Impress 2020 makes SQL calls over the network)
Project maintained by @matchu • OpenNeo.net