The Decentraland Places service is a comprehensive API solution for discovering, managing, and interacting with places in the Decentraland metaverse. It processes deployment notifications from Catalyst servers and World Content Servers, maintaining a searchable database of scenes (Genesis City) and worlds (private virtual spaces). The service provides place discovery, user interactions (likes/favorites), category management, and real-time activity tracking.
- Scene & World Processing: Processes Catalyst scenes and Worlds deployments via SQS messages, fetching metadata and creating/updating place records
- Place Discovery: Full-text search and filtering across places by categories, positions, and popularity with pagination
- Social Features: User likes, dislikes, favorites, content ratings, and aggregated place statistics
- Category Management: Dynamic categorization with automatic POI (Point of Interest) categorization
- Hot Scenes Tracking: Real-time monitoring of active scenes with user counts from Catalyst realms
- Map Integration: Specialized endpoints for coordinate-based queries optimized for map visualization
- Content Moderation: Content rating system (PR/E/T/A/R) and report generation with S3 signed URLs
- Gatsby Frontend: Static site generation for place exploration interface with HTTPS support
Hybrid Architecture:
- Asynchronous Processing: AWS SQS-based message queue for deployment notifications from Catalyst and World Content Servers
- Synchronous REST API: Express.js REST API for client queries, user interactions, and place discovery
- Static Frontend: Gatsby development server with hot reload on HTTPS (port 8000)
- Background Tasks: Continuous polling of SQS queue (batches of 10, 15s wait time), hot scenes updates, POI categorization
- Runtime: Node.js 18.x (see
.nvmrc) - Framework: Express.js (API) + Gatsby 4.x (Frontend) + React 18.x
- Language: TypeScript 4.7.x
- Database: PostgreSQL with
node-pg-migratefor migrations - Message Queue: AWS SQS (LocalStack for local development)
- Testing: Jest with TypeScript, following Decentraland Testing Standards
- Authentication: Ethereum wallet-based authentication via decentraland-gatsby
- Task Management: decentraland-gatsby task system for background jobs
- Monitoring: Prometheus metrics via decentraland-gatsby
- PostgreSQL Database: Stores places, users, categories, place-category relationships, user favorites, and user likes
- AWS SQS: Receives deployment notifications with
entity_id,content_server_url, positions, and deployment metadata - Decentraland Catalyst: Source of scene metadata and deployment information (
https://peer.decentraland.orgby default) - World Content Server: Source of world metadata and deployment information for Decentraland Worlds
- Decentraland Realm Provider: Real-time hot scenes data and user count information from active realms
- AWS S3: Content moderation report storage with pre-signed upload URLs (60s expiry)
- Decentraland Data Team CDN: Scene statistics and visit data (
https://cdn-data.decentraland.org/)
- Places vs Worlds: Places are scenes in Genesis City at specific coordinates; Worlds are private virtual spaces accessed via unique URLs outside Genesis City
- Place UUID Assignment (ADR-186): UUID persistence across deployments ensures favorites/likes/social data persist when scenes update:
- UUID preserved if new deployment encompasses all previous parcels OR maintains same base parcel
- UUID changes when both parcels AND base parcel change (fundamental location change)
- Examples: Expanding scenes keep UUID, reshaping with same base keeps UUID, moving to different parcels gets new UUID
- Base Position: Primary parcel coordinate where users spawn (critical for UUID persistence)
- Positions Array: All parcel coordinates occupied by a scene (format:
"x,y", range: -150 to 150) - Categories: Places belong to multiple categories (art-gallery, social, game, etc.) via many-to-many
place_categoriestable - Like Score: VP-weighted quality metric (0-1) based on Decentraland voting power from Snapshot
- Content Rating: Age-appropriate classification - PR (10+), E (all ages), T (13+), A (18+), R (18+ explicit)
- Hot Scenes: Places with active users, tracked via Catalyst realm provider with real-time user counts
- User Visits: Unique users who visited a place in the last 30 days
- Highlighted Places: Featured places with special promotion status, managed via admin UI at
/admin/highlights/ - Creator Address: Ethereum address of the scene creator, extracted from scene metadata during deployment processing, indexed for efficient creator-based queries (used by tipping systems)
- SDK Version: Runtime version extracted from
runtimeVersionin scene.json during deployment, used for filtering scenes by SDK version. Supports major version matching (e.g., sdk=7 matches 7.x.x). Places with null SDK values are treated as SDK6 (legacy scenes)
The service exposes a REST API under /api with comprehensive documentation in OpenAPI 3.0 format. Key endpoint categories:
- Places:
/api/places,/api/places/:id,/api/places/status,/api/places/:id/categories,/api/places/:id/rating,/api/places/:id/ranking(service token auth viaDATA_TEAM_AUTH_TOKENorPLACES_ADMIN_AUTH_TOKENenv vars),/api/places/:id/highlight(admin only) (POST/api/placesaccepts array of place IDs in body) - Worlds:
/api/worlds,/api/world_names - Destinations:
/api/destinations(GET: combined places + worlds with enhanced filtering including SDK version and LIKE name matching; highlighted items are always returned first, followed by ranking value, then by specified sort order. POST: accepts array of destination IDs in body, maximum 100 IDs per request, supports all GET query parameters for additional filtering) - Map:
/api/map,/api/map/places(coordinate-based queries with higher limits) - Categories:
/api/categories(with optionaltargetfilter for places/worlds/all) - Interactions:
/api/places/:id/likes,/api/places/:id/favorites(authentication required) - Reports:
/api/report(authentication required, returns S3 signed URL) - Social:
/places/place/,/places/world/(metadata injection for social sharing) - Creator Queries:
/api/places?creator_address=0x...(lookup places by scene creator for tipping integration) - SDK Filtering:
/api/places?sdk=7(filter by SDK version, major version prefix match - sdk=7 matches 7, 7.0.0, 7.3.27, etc.)
Authentication: Bearer token authentication using Decentraland wallet signatures. Admin endpoints require additional permissions.
Response Format: All responses follow { "ok": true/false, "data": [...], "total": number } structure.
- Primary Keys: UUIDs for places, Ethereum addresses (text, 42 chars) for users
- Indexing: Optimized indexes on
disabled + positionsfor place queries,activefor categories - Full-Text Search: PostgreSQL
textsearchcolumn with tsvector on title, description, owner for place discovery - Soft Deletes: Places use
disabledboolean anddisabled_attimestamp (not physically deleted) - Timestamps: All tables include
created_atandupdated_atwith timezone support - User Interactions: Composite keys on
(place_id, user)for likes and favorites tables - Category Relationships: Many-to-many via
place_categoriespivot table with automatic POI categorization - Migrations: Managed via
node-pg-migratewith configuration inpackage.json, using.env.developmentfor connection
Key Tables:
places: Main table with UUID, title, description, positions[], base_position, owner, creator_address, sdk, content_rating, disabled, user_count, user_visits, like metricsusers: Registered users with Ethereum addresses and permissionscategories: Place categories with name, active status, i18n translationsplace_categories: Many-to-many relationships between places and categoriesuser_favorites: User's favorited places with timestampsuser_likes: User likes/dislikes with VP-weighted scoring
src/
├── server.ts # Express server setup, CORS, route mounting
├── entities/ # Domain-driven entity organization
│ ├── Place/ # Place entity (scenes)
│ │ ├── routes/ # Place API endpoints
│ │ └── utils.ts # Place utility functions
│ ├── World/ # World entity
│ ├── Category/ # Category management
│ ├── UserFavorite/ # Favorite management
│ ├── UserLikes/ # Like/dislike system
│ ├── Map/ # Map-specific endpoints
│ ├── Social/ # Social metadata injection
│ ├── Report/ # Content reporting
│ ├── CheckScenes/ # SQS message processing
│ ├── PlaceCategories/ # Category automation
│ ├── RealmProvider/ # Hot scenes tracking
│ └── SceneStats/ # Visit statistics
├── migrations/ # Database migrations
├── components/ # Gatsby React components
├── pages/ # Gatsby pages
└── api/ # External API clients
├── CatalystAPI.ts
├── Places.ts
└── RealmProvider.ts
Required Environment Variables:
CONNECTION_STRING: PostgreSQL connection stringAWS_REGION: AWS region for SQSQUEUE_URL: SQS queue URL for deployment messages
Optional: See Configuration section in README for complete list including Gatsby variables, AWS credentials, Slack webhooks, admin addresses, and service URLs.
Local Development: Uses LocalStack for SQS emulation and docker-compose for PostgreSQL. Configuration in .env.development.
Tests written in Jest with TypeScript following Decentraland Testing Standards:
- Structure:
describefor contexts ("when"/"and"),itfor behaviors ("should") - Isolation: Independent tests with proper mock cleanup in
afterEach - Organization: Tests in
src/entities/*/alongside code (*.test.ts,*.spec.ts) - Coverage:
npm test -- --coverage
See Testing Standards for project-specific guidelines.
- README.md: Getting started, installation, configuration, troubleshooting
- OpenAPI Specification: Complete API documentation with schemas, examples, authentication
- Database Schemas: Detailed column definitions and relationships
- Database Operations: Commands for clearing and re-populating database
- SQS Setup: Manual LocalStack configuration and SQS message format details
- Project Structure: Gatsby + Node.js architecture overview