Skip to content

Consolidate the duplicate merchant and merchants modules serving overlapping profile routes #486

Description

@Cedarich
  • Complexity: Medium
  • Labels: Backend, api, merchants, Medium
  • Overview: There are two independent merchant modules in the backend, each with its own controller, service, DTOs, entities, and specs, serving overlapping merchant-profile functionality on two different URL prefixes. src/merchant/ declares @Controller("merchants") and src/merchants/ declares @Controller("merchant/profile"). Both are registered in AppModule. A client updating a merchant profile has two endpoints to choose from, backed by two code paths that can and will diverge.
  • Details:
    • src/merchant/merchant.controller.ts is @Controller("merchants") and exposes GET /merchants/profile, PATCH /merchants/settings, GET /merchants/checklist, PATCH /merchants/checklist, and PATCH /merchants/checklist/sync.
    • src/merchants/merchants.controller.ts is @Controller("merchant/profile") and exposes GET /merchant/profile, PUT /merchant/profile, and PATCH /merchant/profile.
    • So the same conceptual resource is reachable at both /merchants/profile and /merchant/profile, differing by one character, backed by MerchantService and MerchantsService respectively. The singular and plural prefixes are inverted between the two modules, which makes the collision easy to miss in review and easy to hit by mistake in a client.
    • Each module carries its own dto/ and entities/ directory, so the merchant shape is declared twice. A field added to one profile DTO does not appear in the other, and validation rules can differ per endpoint for the same underlying record.
    • MerchantRolesGuard is applied per route in both controllers, so authorisation is configured twice for the same resource, with no guarantee the two stay aligned.
    • Both are registered in AppModule as MerchantsModule and MerchantModule, one line apart, which is exactly the kind of near-identical import pairing that survives review indefinitely.
    • This is the same duplication pattern already filed for the two SorobanService classes in Consolidate the duplicated SorobanService and the split ADMIN_SECRET_KEY/SOROBAN_SECRET_KEY configuration #459. With no published API contract (Bootstrap SwaggerModule and publish an OpenAPI contract for the backend API #458), neither the split nor a subsequent divergence is visible to client authors.
    • Web and mobile currently each hand-maintain merchant service clients, so a divergence between the two backend paths surfaces as a runtime inconsistency in one client and not the other.
  • Scope:
    • Determine which module is authoritative and which routes each client actually calls today, including web, mobile, and any external consumer.
    • Consolidate onto a single merchant module with one service, one DTO set, and one entity definition covering profile, settings, and checklist.
    • Settle on one URL prefix, and keep the retired path working as an explicit deprecated alias for a stated period rather than removing it silently.
    • Reconcile the two DTOs into one, resolving any field or validation differences deliberately rather than by whichever module wins.
    • Apply the merchant role guard once, consistently, across the consolidated surface.
    • Update the web and mobile merchant service clients to the retained path.
    • Fold the retained and deprecated routes into the OpenAPI document from Bootstrap SwaggerModule and publish an OpenAPI contract for the backend API #458 so the deprecation is discoverable.
  • Technical scope:
    • backend/src/merchant/
    • backend/src/merchants/
    • backend/src/app.module.ts
    • backend/src/common/guards/merchant-roles.guard.ts
    • web/lib/merchant-service.ts
    • mobile/lib/merchant-service.ts
  • Acceptance criteria:
    • One module and one service own merchant profile, settings, and checklist.
    • The merchant shape is declared once, with a single set of validation rules.
    • The retired route responds as a documented deprecated alias rather than disappearing or silently diverging.
    • Role-based authorisation is configured once and applies uniformly across the consolidated routes.
    • Web and mobile call the retained path.
    • Existing merchant tests are consolidated and continue to pass against the single implementation.
    • The deprecation is reflected in the API documentation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

BackendGrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardMediumMedium-complexity taskThird CampaignCampaign: Third CampaignapiAPI design or implementationmerchants

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions