Part of #1381. Depends on #1382.
Problem / Context
Once AllegroCategoryCatalogClient exists (#1382), ErliOfferManagerAdapter needs to expose CategoryBrowser/CategoryParametersReader — but only for connections that actually configured Allegro app credentials, reflected accurately through the is* guards on the resolved adapter instance. connection.supportedCapabilities (consumed today by the bulk-wizard's #1367 capability gate at apps/web/src/features/listings/components/bulk/bulk-wizard.tsx) turned out to be a static, per-adapterKey manifest value, not per-connection-instance — it cannot serve as this signal (see ADR-031 "Correction"); the FE-visible signal is instead a new config.allegroCategoryAccessEnabled boolean (added post-review, PR #1399). Making the class statically implement these capabilities would break that gate for every Erli connection regardless of configuration — see ADR-031 for why this must be a per-instance, runtime-reflected wiring instead.
Proposed Solution
Full detail: docs/plans/implementation-plan-erli-allegro-category-catalog.md § Sub-task 2 (Phase 2).
ErliOfferManagerAdapter (libs/integrations/erli/src/infrastructure/adapters/erli-offer-manager.adapter.ts): add an optional constructor param allegroCategoryCatalog?: AllegroCategoryCatalogClient. Do NOT add CategoryBrowser/CategoryParametersReader to the class's static implements clause. Declare fetchCategories?/fetchCategoryParameters? as optional instance properties, assigned in the constructor only when allegroCategoryCatalog is provided, so isCategoryBrowser/isCategoryParametersReader (typeof adapter.fetchCategories === 'function') correctly reflect per-connection configuration.
ErliAdapterFactory (libs/integrations/erli/src/application/erli-adapter.factory.ts): in createAdapters, check credentials.allegroClientId/allegroClientSecret; when both present, construct AllegroCategoryCatalogClient (environment from config.allegroEnvironment ?? 'production') and pass to the adapter constructor.
- Credentials shape validator (
libs/integrations/erli/src/infrastructure/adapters/erli-connection-credentials-shape-validator.adapter.ts): enforce "both or neither" for allegroClientId/allegroClientSecret.
- Config shape validator (
libs/integrations/erli/src/infrastructure/adapters/erli-connection-config-shape-validator.adapter.ts): allegroEnvironment, when present, must be 'sandbox' or 'production'.
- Verify (do not assume) that
CategoriesCacheService.getAllegroCategories and GET /listings/connections/:connectionId/categories/:categoryId/parameters need NO code changes — a misconfigured Erli connection should behave exactly like today's "adapter doesn't implement this capability" case (empty array / 501), not a new error path.
Classification
Type: Integration
Layer: Application / Infrastructure
File(s): libs/integrations/erli/src/infrastructure/adapters/erli-offer-manager.adapter.ts, libs/integrations/erli/src/application/erli-adapter.factory.ts, libs/integrations/erli/src/infrastructure/adapters/erli-connection-credentials-shape-validator.adapter.ts, libs/integrations/erli/src/infrastructure/adapters/erli-connection-config-shape-validator.adapter.ts
Dependencies
Assumptions
- No changes needed to
apps/api/src/categories/categories-cache.service.ts or apps/api/src/listings/http/listings.controller.ts — both already resolve capabilities generically via getCapabilityAdapter + is* guards.
Acceptance Criteria
Part of #1381. Depends on #1382.
Problem / Context
Once
AllegroCategoryCatalogClientexists (#1382),ErliOfferManagerAdapterneeds to exposeCategoryBrowser/CategoryParametersReader— but only for connections that actually configured Allegro app credentials, reflected accurately through theis*guards on the resolved adapter instance.connection.supportedCapabilities(consumed today by the bulk-wizard's#1367capability gate atapps/web/src/features/listings/components/bulk/bulk-wizard.tsx) turned out to be a static, per-adapterKey manifest value, not per-connection-instance — it cannot serve as this signal (see ADR-031 "Correction"); the FE-visible signal is instead a newconfig.allegroCategoryAccessEnabledboolean (added post-review, PR #1399). Making the class statically implement these capabilities would break that gate for every Erli connection regardless of configuration — see ADR-031 for why this must be a per-instance, runtime-reflected wiring instead.Proposed Solution
Full detail:
docs/plans/implementation-plan-erli-allegro-category-catalog.md§ Sub-task 2 (Phase 2).ErliOfferManagerAdapter(libs/integrations/erli/src/infrastructure/adapters/erli-offer-manager.adapter.ts): add an optional constructor paramallegroCategoryCatalog?: AllegroCategoryCatalogClient. Do NOT addCategoryBrowser/CategoryParametersReaderto the class's staticimplementsclause. DeclarefetchCategories?/fetchCategoryParameters?as optional instance properties, assigned in the constructor only whenallegroCategoryCatalogis provided, soisCategoryBrowser/isCategoryParametersReader(typeof adapter.fetchCategories === 'function') correctly reflect per-connection configuration.ErliAdapterFactory(libs/integrations/erli/src/application/erli-adapter.factory.ts): increateAdapters, checkcredentials.allegroClientId/allegroClientSecret; when both present, constructAllegroCategoryCatalogClient(environment fromconfig.allegroEnvironment ?? 'production') and pass to the adapter constructor.libs/integrations/erli/src/infrastructure/adapters/erli-connection-credentials-shape-validator.adapter.ts): enforce "both or neither" forallegroClientId/allegroClientSecret.libs/integrations/erli/src/infrastructure/adapters/erli-connection-config-shape-validator.adapter.ts):allegroEnvironment, when present, must be'sandbox'or'production'.CategoriesCacheService.getAllegroCategoriesandGET /listings/connections/:connectionId/categories/:categoryId/parametersneed NO code changes — a misconfigured Erli connection should behave exactly like today's "adapter doesn't implement this capability" case (empty array / 501), not a new error path.Classification
Type: Integration
Layer: Application / Infrastructure
File(s):
libs/integrations/erli/src/infrastructure/adapters/erli-offer-manager.adapter.ts,libs/integrations/erli/src/application/erli-adapter.factory.ts,libs/integrations/erli/src/infrastructure/adapters/erli-connection-credentials-shape-validator.adapter.ts,libs/integrations/erli/src/infrastructure/adapters/erli-connection-config-shape-validator.adapter.tsDependencies
AllegroCategoryCatalogClientmust exist first).Assumptions
apps/api/src/categories/categories-cache.service.tsorapps/api/src/listings/http/listings.controller.ts— both already resolve capabilities generically viagetCapabilityAdapter+is*guards.Acceptance Criteria
ErliOfferManagerAdapterinstance exposes workingfetchCategories/fetchCategoryParametersonly when constructed with a validAllegroCategoryCatalogClientisCategoryBrowser/isCategoryParametersReaderreturntrueonly for correctly-configured connectionsallegroClientId/allegroClientSecretallegroEnvironmentvaluesapps/api/test/integration/listings/erli-category-catalog.int-spec.ts— covers configured vs unconfigured Erli connections, including theis*guard results and HTTP endpoint behavior (notconnection.supportedCapabilities, which is static per-adapterKey)apps/web/src/features/listings/components/bulk/bulk-edit-modal.test.tsx) passes unmodified