GitHub Issue Draft: Provider Decoupling Architecture
Title
feat: Decouple audnexus from Audible-specific implementation to support multiple providers
Labels
enhancement
refactor
architecture
breaking-change (if migration required)
Description
Problem Statement
Currently, audnexus is tightly coupled to Audible as the sole data source. All code assumes Audible's data model, API structure, and identifier formats (ASIN). This prevents integration with other audiobook data providers.
Goal
Implement a provider abstraction layer that allows audnexus to fetch data from multiple sources (Audible, AudiobookGuild, etc.) while maintaining backward compatibility with existing API consumers.
Use Cases
- Support audiobook data from sources other than Audible
- Enable providers with different data retrieval methods (API vs scraping)
- Allow gradual migration without breaking existing integrations
- Provide fallback data sources when Audible data is unavailable
Proposed Solution
Provider Selection Strategy
- Query Parameter:
/books/{id}?provider=audible
- Default: Audible (for backward compatibility)
- Invalid Provider: Returns 400 with
VALIDATION_ERROR
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ API Layer │
│ GET /books/{id}?provider=audiobookguild │
└─────────────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Provider Registry │
│ Map provider name → Provider instance │
└─────────────────────────┬───────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ AudibleProvider │ │ AudiobookGuild │
│ (existing code) │ │ Provider (new) │
└──────────┬──────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ ApiHelper │ │ ScrapeHelper │
│ ScrapeHelper │ │ (new) │
│ StitchHelper │ └─────────────────────┘
└─────────────────────┘
Database Changes
Add provider field to all models:
// Book.ts, Author.ts, Chapter.ts
provider: types.string({
enum: ['audible', 'audiobookguild'],
required: true,
default: 'audible'
})
Migration Required: Backfill provider='audible' for all existing records.
Files to Create/Modify
New Files:
src/providers/types.ts - Provider interface definitions
src/providers/registry.ts - Provider registry
src/providers/index.ts - Provider exports
src/providers/AudibleProvider.ts - Audible adapter
src/providers/AudiobookGuildProvider.ts - New provider
src/helpers/books/audiobookguild/ScrapeHelper.ts - AudiobookGuild scraper
tests/providers/audiobookguild/ - Test suite
scripts/migrate-add-provider-field.ts - Migration script
Modified Files:
src/config/models/Book.ts - Add provider field
src/config/models/Author.ts - Add provider field
src/config/models/Chapter.ts - Add provider field
src/helpers/database/papr/audible/*.ts - Add provider to queries
src/helpers/routes/GenericShowHelper.ts - Use provider registry
src/helpers/routes/RouteCommonHelper.ts - Validate provider param
src/helpers/database/redis/RedisHelper.ts - Provider in cache keys
src/helpers/utils/UpdateScheduler.ts - Provider-aware updates
Implementation Plan
Phase 1: Foundation (Week 1)
- Add
provider field to Book, Author, Chapter models
- Create database migration script
- Define Provider interface
- Create ProviderRegistry
Phase 2: Audible Abstraction (Week 1-2)
- Create AudibleProvider adapter
- Update Papr helpers to include provider
- Update route handlers with provider parameter
- Ensure all existing tests pass
Phase 3: AudiobookGuild Implementation (Week 2-3)
- Implement AudiobookGuild ScrapeHelper
- Create AudiobookGuildProvider
- Write comprehensive tests
- Register in ProviderRegistry
Phase 4: Integration & Testing (Week 3-4)
- Update UpdateScheduler for provider awareness
- Update Redis cache key structure
- Integration testing
- Documentation updates
Acceptance Criteria
Functional Requirements
Technical Requirements
Quality Requirements
API Changes
New Query Parameter
| Parameter |
Type |
Required |
Default |
Description |
provider |
string |
No |
audible |
Data provider to use |
Valid Providers
audible - Audible API + scraping
audiobookguild - AudiobookGuild scraping (new)
Example Requests
# Existing behavior (backward compatible)
GET /books/B017V4U2VQ
# Explicit Audible provider
GET /books/B017V4U2VQ?provider=audible
# AudiobookGuild provider
GET /books/12345?provider=audiobookguild
# Invalid provider (400 error)
GET /books/B017V4U2VQ?provider=invalid
Migration Guide
Database Migration
# Run migration script
npx ts-node scripts/migrate-add-provider-field.ts
# Verify migration
mongosh audnexus --eval "db.books.countDocuments({provider: {$exists: false}})"
# Expected: 0
Client Impact
No breaking changes for existing clients.
Clients not using the ?provider= parameter will continue to receive Audible data.
Clients wanting to use new providers should add ?provider=audiobookguild to requests.
Testing Strategy
Unit Tests
- Provider interface implementation
- ProviderRegistry lookup
- Database helpers with provider filter
- AudiobookGuild scraping logic
Integration Tests
- End-to-end provider selection
- Database migration verification
- Cache behavior with provider context
- UpdateScheduler with multiple providers
Regression Tests
- All existing tests must pass
- Backward compatibility verified
- Performance impact measured
Breaking Changes
None - This is designed to be fully backward compatible.
However, this sets the stage for a future v2.0 where:
- Provider parameter may become required
- Response format may change
- Default provider may be removed
Documentation Updates
Related Issues
N/A - This is a foundational architecture change.
Checklist
GitHub Issue Draft: Provider Decoupling Architecture
Title
feat: Decouple audnexus from Audible-specific implementation to support multiple providers
Labels
enhancementrefactorarchitecturebreaking-change(if migration required)Description
Problem Statement
Currently, audnexus is tightly coupled to Audible as the sole data source. All code assumes Audible's data model, API structure, and identifier formats (ASIN). This prevents integration with other audiobook data providers.
Goal
Implement a provider abstraction layer that allows audnexus to fetch data from multiple sources (Audible, AudiobookGuild, etc.) while maintaining backward compatibility with existing API consumers.
Use Cases
Proposed Solution
Provider Selection Strategy
/books/{id}?provider=audibleVALIDATION_ERRORArchitecture Overview
Database Changes
Add
providerfield to all models:Migration Required: Backfill
provider='audible'for all existing records.Files to Create/Modify
New Files:
src/providers/types.ts- Provider interface definitionssrc/providers/registry.ts- Provider registrysrc/providers/index.ts- Provider exportssrc/providers/AudibleProvider.ts- Audible adaptersrc/providers/AudiobookGuildProvider.ts- New providersrc/helpers/books/audiobookguild/ScrapeHelper.ts- AudiobookGuild scrapertests/providers/audiobookguild/- Test suitescripts/migrate-add-provider-field.ts- Migration scriptModified Files:
src/config/models/Book.ts- Add provider fieldsrc/config/models/Author.ts- Add provider fieldsrc/config/models/Chapter.ts- Add provider fieldsrc/helpers/database/papr/audible/*.ts- Add provider to queriessrc/helpers/routes/GenericShowHelper.ts- Use provider registrysrc/helpers/routes/RouteCommonHelper.ts- Validate provider paramsrc/helpers/database/redis/RedisHelper.ts- Provider in cache keyssrc/helpers/utils/UpdateScheduler.ts- Provider-aware updatesImplementation Plan
Phase 1: Foundation (Week 1)
providerfield to Book, Author, Chapter modelsPhase 2: Audible Abstraction (Week 1-2)
Phase 3: AudiobookGuild Implementation (Week 2-3)
Phase 4: Integration & Testing (Week 3-4)
Acceptance Criteria
Functional Requirements
?provider=parameter continue to work (backward compatible)?provider=audiblereturns same data as no parameter?provider=audiobookguildfetches from AudiobookGuildVALIDATION_ERRORproviderfield on all recordsTechnical Requirements
(provider, asin, region)for uniquenessQuality Requirements
API Changes
New Query Parameter
provideraudibleValid Providers
audible- Audible API + scrapingaudiobookguild- AudiobookGuild scraping (new)Example Requests
Migration Guide
Database Migration
Client Impact
No breaking changes for existing clients.
Clients not using the
?provider=parameter will continue to receive Audible data.Clients wanting to use new providers should add
?provider=audiobookguildto requests.Testing Strategy
Unit Tests
Integration Tests
Regression Tests
Breaking Changes
None - This is designed to be fully backward compatible.
However, this sets the stage for a future v2.0 where:
Documentation Updates
Related Issues
N/A - This is a foundational architecture change.
Checklist