Skip to content

Conversation

@kernelwhisperer
Copy link

@kernelwhisperer kernelwhisperer commented Jan 8, 2026

Summary

Implements https://linear.app/cowswap/issue/COW-142/implement-affiliate-code-creation-flow
and https://linear.app/cowswap/issue/COW-147/adjustable-program-parameters

Adds a new collection called affiliate, when you create codes through the admin UI in Strapi CMS the empty fields are filled with our preset defaults on save. Additionally you can enable or disable a code.

image

Security: we must make sure the collection is not readable without an api key. Reads and writes by the FE will be done via a BFF service.

Testing

  1. nvm use 20
  2. Run yarn dev
  3. Add codes directly in CMS admin
  4. Ensure only enabled can be changed, the rest are immutable.

The reason for this is to make the accounting simpler, for new params new codes must be created.

@kernelwhisperer kernelwhisperer marked this pull request as ready for review January 20, 2026 09:45
@kernelwhisperer kernelwhisperer self-assigned this Jan 20, 2026
@kernelwhisperer kernelwhisperer requested review from a team and Copilot January 20, 2026 09:47
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a new affiliate collection and API endpoints to support the affiliate code creation flow. The implementation includes schema definition, API routes, controllers, services, validation logic, and configuration for default affiliate program parameters.

Changes:

  • Added new /affiliates API endpoints with full CRUD operations
  • Implemented affiliate lifecycle hooks with validation for code format, wallet addresses, and program parameters
  • Added configuration support for affiliate program defaults via environment variables

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/gen/types.ts Generated TypeScript types for affiliate and restricted token list API endpoints
src/api/affiliate/services/affiliate.ts Strapi service factory for affiliate collection
src/api/affiliate/routes/affiliate.ts Strapi router factory for affiliate endpoints
src/api/affiliate/documentation/1.0.0/affiliate.json OpenAPI documentation for affiliate endpoints
src/api/affiliate/controllers/affiliate.ts Strapi controller factory for affiliate operations
src/api/affiliate/content-types/affiliate/schema.json Database schema defining affiliate collection structure
src/api/affiliate/content-types/affiliate/lifecycles.ts Lifecycle hooks with validation logic for affiliate creation and updates
config/affiliate.ts Configuration file for affiliate program default parameters

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@alfetopito alfetopito left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just one comment regarding the code length.

Additionally, can you improve the description a bit, with some screenshots and explanation of the feature?

@@ -0,0 +1,195 @@
import { errors } from "@strapi/utils";

const CODE_REGEX = /^[A-Z0-9_-]{6,12}$/;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to limit code to 6-12 chars?
Lower bound of 6 is ok I guess, but we could probably accept longer codes IMO. How about 20 or 30 char limit?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I set it to match the design in Figma
image

That being said I can't find any requirement in the Alex Marsh's spec.

const hasOwn = (obj: object, key: string) =>
Object.prototype.hasOwnProperty.call(obj, key);

const normalizeWallet = (value?: string | null) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't normalizeWallet and normalizeCode the same?
If you want to keep both for semantics reason, you can do:

const normalizeCode = normalizeWallet

);
const dao = parseNumber(params.revenueSplitDaoPct, "revenueSplitDaoPct");

if (affiliate > 100 || trader > 100 || dao > 100) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great to avoid using magic number and move them to consts

Copy link
Contributor

@shoom3301 shoom3301 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of code style nitpicks

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants