A full-stack application for browsing Mapillary sequences and uploading selected street-level images to Wikimedia Commons.
The Curator application consists of:
- Backend: An Elysia service (Bun) with a REST API and WebSocket endpoint. BullMQ workers handle background upload tasks. Compiles to a single
curator-serverbinary. - Frontend: A Vue 3 application with TypeScript and PrimeVue for browsing Mapillary sequences, configuring upload metadata, and monitoring batch progress. Embedded into the binary at build time.
The application is deployed on Wikimedia Toolforge. The curator-launcher downloads the curator-server binary from the latest GitHub release, verifies its Sigstore attestation, and execs into it.
Every push to main compiles the binary and publishes a GitHub release automatically via the build workflow. The curator-launcher picks up the latest release at container startup — no manual build step is required.
Use toolforge envvars to set them up. The OAuth1 application is at OAuth applications - Wikimedia Meta-Wiki.
Required:
CURATOR_OAUTH1_KEY
CURATOR_OAUTH1_SECRET
TOKEN_ENCRYPTION_KEY
SESSION_SECRET_KEY
MAPILLARY_API_TOKENSESSION_SECRET_KEY signs cookie sessions. Rotating it invalidates all active user sessions. Generate with:
openssl rand -hex 32TOKEN_ENCRYPTION_KEY encrypts OAuth access tokens stored in the database using AES-GCM. Generate with:
openssl rand -base64 32Optional:
| Variable | Default | Description |
|---|---|---|
PORT |
8000 |
HTTP port |
REDIS_HOST |
localhost |
Redis host |
REDIS_PORT |
6379 |
Redis port |
REDIS_PASSWORD |
— | Redis password |
WCQS_OAUTH_TOKEN |
— | Wikimedia Commons Query Service OAuth token |
DB_URL |
mysql://curator:curator@localhost/curator |
MySQL connection URL (on Toolforge, automatically derived from TOOL_TOOLSDB_USER / TOOL_TOOLSDB_PASSWORD) |
GEOCODING_API_URL |
https://geocoding.daxserver.com/reverse |
Reverse geocoding endpoint |
GEOCODING_CONCURRENCY_LIMIT |
10 |
Max concurrent geocoding requests |
CELERY_CONCURRENCY |
2 |
Upload worker concurrency |
CELERY_MAXIMUM_WAIT_TIME |
240 |
Max worker wait time in seconds |
RATE_LIMIT_DEFAULT_NORMAL |
4 |
Default rate limit (requests) |
RATE_LIMIT_DEFAULT_PERIOD |
60 |
Default rate limit window in seconds |
X_USERNAME |
DaxServer |
X (Twitter) username for syndication |
X_API_KEY |
— | X API key |
ENABLE_MAINTENANCE |
— | Set to true to enable maintenance mode |
LOG_LEVEL |
— | Pino log level |
The webservice is run via the curator-launcher image. When deploying for the first time:
toolforge webservice buildservice start --buildservice-image tool-curator/launcher:latest --mount=allFor subsequent deployments (after a new release is published):
toolforge webservice restart- Bun 1.3.14
bun installDEV_MOCK_AUTH=true DB_URL=mysql://curator:curator@localhost/curator \
CURATOR_OAUTH1_KEY=abc123 CURATOR_OAUTH1_SECRET=abc123 \
SESSION_SECRET_KEY=dev-secret TOKEN_ENCRYPTION_KEY=$(openssl rand -base64 32) \
MAPILLARY_API_TOKEN=dev bun devDEV_MOCK_AUTH=true bypasses Commons OAuth — every request without an active session is automatically authenticated as a mock user. The frontend shows an amber banner when running under Vite dev mode with mock auth active.
The backend server will be available at http://localhost:8000 and the Vite dev server at http://localhost:5173.
bun testbun lint
bun formatbun typecheckDB_URL=mysql://curator:curator@localhost/curator bun db:generate
DB_URL=mysql://curator:curator@localhost/curator bun db:migrate