You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add first-party Discogs user integration to discogsography: users create an account, connect their Discogs profile via OAuth 1.0a, then sync their personal collection and wantlist to both Neo4j and PostgreSQL. Unlocks a new category of personalized features on top of the existing global Discogs knowledge graph.
Motivation
The current discogsography pipeline ingests the complete Discogs data dump (50GB+) into Neo4j and PostgreSQL, enabling exploration of the full music graph. Adding user identity and personal data creates:
Personal collection browsing within the knowledge graph
Wantlist analysis with graph-powered context
Recommendations based on collection graph traversal
Foundation for future features (price tracking, social comparison, collection completeness scores)
Reference Implementation
vinyldigger (/Users/Robert/Code/public/vinyldigger) has a fully working implementation of all the key pieces:
Feature
vinyldigger location
Discogs OAuth 1.0a (OOB flow)
backend/src/api/v1/endpoints/oauth.py
DiscogsOAuth1Auth httpx class
backend/src/services/discogs.py
Redis request token store
backend/src/core/token_store.py
Collection/wantlist sync
backend/src/workers/tasks.py
Celery task setup
backend/src/workers/celery_app.py
OAuth token model
backend/src/models/oauth_token.py
Collection/item models
backend/src/models/collection.py
Collection/wantlist flags on results
backend/src/models/search_result.py
Connect UI (settings page)
frontend/src/pages/SettingsPage.tsx
OAuth API client
frontend/src/lib/api.ts
Architecture
Three new components:
Component
Type
Purpose
auth
New microservice (FastAPI, port 8004/8005)
User accounts + JWT + Discogs OAuth 1.0a
collector
New microservice (FastAPI + Celery, port 8010/8011)
Collection/wantlist sync to Neo4j + PostgreSQL
Explore extensions
Existing service + new endpoints
Personalized graph queries and UI
Data Flow
User registers/logs in → auth service (JWT tokens)
↓
User connects Discogs → auth service
OAuth 1.0a OOB flow:
1. Backend → Discogs: request token (callback_uri="oob")
2. State stored in Redis (10-min TTL, CSRF protection)
3. Frontend opens Discogs in popup window
4. User pastes verification code into app
5. Backend exchanges verifier → access token + secret
6. Identity fetched from /oauth/identity
7. Token stored in oauth_tokens table (unique per user/provider)
↓
User triggers sync → collector service
Celery background task:
- Paginate Discogs collection API (100/page, 0.5s delay)
- Paginate Discogs wantlist API
- Upsert to PostgreSQL (user_collections, user_wantlists)
- MERGE relationships in Neo4j (COLLECTED, WANTS on existing Release nodes)
- Track in sync_history
↓
User explores → explore service
New endpoints: /user/collection, /user/wantlist, /user/recommendations
Existing endpoints: decorated with in_collection/in_wantlist flags
Key Implementation Details from vinyldigger
OAuth Flow: Out-of-Band (OOB)
Discogs supports OOB where the user gets a verification code on the Discogs site and types it into the app. No web callback URL is required. Use callback_uri="oob" in the initial request token call.
Discogs API Response Key Difference
Collection: response key is releases, release ID at item["basic_information"]["id"]
Wantlist: response key is wants, release ID at item["id"]
This is a critical gotcha — the wantlist ID is at the top level while collection ID is nested.
Rate Limiting
Use asyncio.sleep(0.5) between paginated requests (vinyldigger-validated, keeps well under the 60 req/min limit).
App Credentials Storage
Store Discogs consumer key/secret in app_config database table (admin-configured via API), not environment variables. This matches vinyldigger's per-instance configuration approach.
Background Processing
Use Celery for sync tasks with Redis as broker. Each Celery task creates a fresh SQLAlchemy async engine (required for greenlet context compatibility). APScheduler can be added for periodic resyncs.
Overview
Add first-party Discogs user integration to discogsography: users create an account, connect their Discogs profile via OAuth 1.0a, then sync their personal collection and wantlist to both Neo4j and PostgreSQL. Unlocks a new category of personalized features on top of the existing global Discogs knowledge graph.
Motivation
The current discogsography pipeline ingests the complete Discogs data dump (50GB+) into Neo4j and PostgreSQL, enabling exploration of the full music graph. Adding user identity and personal data creates:
Reference Implementation
vinyldigger (
/Users/Robert/Code/public/vinyldigger) has a fully working implementation of all the key pieces:backend/src/api/v1/endpoints/oauth.pyDiscogsOAuth1Authhttpx classbackend/src/services/discogs.pybackend/src/core/token_store.pybackend/src/workers/tasks.pybackend/src/workers/celery_app.pybackend/src/models/oauth_token.pybackend/src/models/collection.pybackend/src/models/search_result.pyfrontend/src/pages/SettingsPage.tsxfrontend/src/lib/api.tsArchitecture
Three new components:
authcollectorData Flow
Key Implementation Details from vinyldigger
OAuth Flow: Out-of-Band (OOB)
Discogs supports OOB where the user gets a verification code on the Discogs site and types it into the app. No web callback URL is required. Use
callback_uri="oob"in the initial request token call.Discogs API Response Key Difference
releases, release ID atitem["basic_information"]["id"]wants, release ID atitem["id"]This is a critical gotcha — the wantlist ID is at the top level while collection ID is nested.
Rate Limiting
Use
asyncio.sleep(0.5)between paginated requests (vinyldigger-validated, keeps well under the 60 req/min limit).App Credentials Storage
Store Discogs consumer key/secret in
app_configdatabase table (admin-configured via API), not environment variables. This matches vinyldigger's per-instance configuration approach.Background Processing
Use Celery for sync tasks with Redis as broker. Each Celery task creates a fresh SQLAlchemy async engine (required for greenlet context compatibility). APScheduler can be added for periodic resyncs.
New Database Objects
PostgreSQL (new tables)
users— email, hashed_password, is_activeoauth_tokens— Discogs access_token + secret, provider_username, provider_user_id (unique per user+provider)app_config— Discogs consumer key/secret (admin-managed)user_collections— per-user collection items with title, artist, year, format, label, condition, rating, notes, JSONB metadatauser_wantlists— per-user wantlist items with title, artist, year, format, rating, notes, JSONB metadatasync_history— sync job tracking (status, items synced, pages fetched, errors, timestamps)Neo4j (new nodes + relationships)
Usernode — internal UUID + Discogs username/IDCOLLECTEDrelationship — User → Release (with rating, folder_id, instance_id, date_added, format)WANTSrelationship — User → Release (with rating, date_added, notes)Sub-Tasks (implement in order — each depends on the previous)
Step 1 — feat(auth): Add user account system with JWT authentication #56 — feat(auth): Add user account system with JWT authentication
authmicroservice;usersandoauth_tokenstables; register/login/me endpointsbackend/src/models/user.py+ apolloniaapi/endpoints/auth.pyStep 2 — feat(auth): Implement Discogs OAuth 1.0a account connection #57 — (requires feat(auth): Add user account system with JWT authentication #56) feat(auth): Implement Discogs OAuth 1.0a account connection
DiscogsOAuth1Authhttpx class/oauth/authorize/discogs,/oauth/verify/discogs,/oauth/status/discogs,/oauth/revoke/discogsSettingsPage.tsx)Step 3 — feat(collector): Create collector microservice for Discogs collection & wantlist sync #58 — (requires feat(auth): Add user account system with JWT authentication #56, feat(auth): Implement Discogs OAuth 1.0a account connection #57) feat(collector): Create collector microservice for Discogs collection & wantlist sync
releaseskey + nested ID; wantlist useswantskey + top-level IDStep 4 — feat(explore): User collection & wantlist graph queries and UI #59 — (requires feat(collector): Create collector microservice for Discogs collection & wantlist sync #58) feat(explore): User collection & wantlist graph queries and UI
is_in_collection/is_in_wantlist)Environment Variables Required
Future Features Unlocked
Acceptance Criteria
oauth_tokenstable