Skip to content

Rework referral tracking flow#556

Open
antoncoding wants to merge 1 commit into
masterfrom
codex/referral-tracking-cleanup
Open

Rework referral tracking flow#556
antoncoding wants to merge 1 commit into
masterfrom
codex/referral-tracking-cleanup

Conversation

@antoncoding
Copy link
Copy Markdown
Owner

@antoncoding antoncoding commented May 31, 2026

Summary

  • Replaces client-authored signature message parsing with server-reconstructed Mainnet wallet ownership checks for API keys and referral links.
  • Adds connected-wallet-only referral block on rewards, referral attribution capture, and platform fee event logging after confirmed transactions.
  • Removes route-local parser/helper clones and documents the simpler env/validation rules.

Verification

  • pnpm exec biome check --write
  • pnpm typecheck
  • pnpm build
  • npx ultracite fix/check attempted; both are blocked by existing biome.jsonc unknown keys: noUselessUndefined, useConsistentArrowReturn, useMaxParams.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added referral tracking system: capture referral codes from URLs, generate shareable referral links through wallet verification, and automatically track referral attribution on transactions.
  • Documentation

    • Updated API Key Console and Referrals documentation with wallet-ownership verification flow and system architecture details.

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
monarch Ready Ready Preview, Comment May 31, 2026 5:37pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Review Change Stack

Warning

Review limit reached

@antoncoding, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 49 minutes and 39 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 65996350-0ad9-4325-a582-4056f3a186ab

📥 Commits

Reviewing files that changed from the base of the PR and between a24b8db and 04cc65b.

📒 Files selected for processing (17)
  • .env.local.example
  • app/api/api-keys/route.ts
  • app/api/referrals/attribute/route.ts
  • app/api/referrals/code/route.ts
  • app/layout.tsx
  • docs/TECHNICAL_OVERVIEW.md
  • docs/VALIDATIONS.md
  • src/components/providers/ReferralTrackingProvider.tsx
  • src/features/api-keys/api-key-console-view.tsx
  • src/features/rewards/referral-rewards-block.tsx
  • src/features/rewards/rewards-view.tsx
  • src/hooks/useTransactionWithToast.tsx
  • src/utils/apiKeyRequest.ts
  • src/utils/dataApiInternal.ts
  • src/utils/referrals.ts
  • src/utils/serverWalletSignature.ts
  • src/utils/walletSignature.ts
📝 Walkthrough

Walkthrough

PR integrates wallet signature verification across API key and referral systems. API key creation now uses deterministic signed messages instead of nonce-based validation. A new referral feature lets users generate and share codes; codes are captured from URL parameters and trigger attribution on transaction confirmation via fire-and-forget POST.

Changes

Wallet Signature Infrastructure, Referrals, and Post-Transaction Analytics

Layer / File(s) Summary
Wallet Signature Contract and Server Verification
src/utils/walletSignature.ts, src/utils/serverWalletSignature.ts
Exports chain ID, TTL, and clock-skew constants; defines WalletSignaturePurpose union type and deterministic message builder; implements server-side verification with time-window validation and viem signature checking.
Internal Data API Client and Environment Setup
.env.local.example, src/utils/dataApiInternal.ts
Adds DATA_API_INTERNAL_ORIGIN and DATA_API_INTERNAL_ADMIN_KEY placeholders; creates server-only helper for authenticated POST calls to internal data API with timeout and no-store caching.
API Key Endpoint and Console Refactor
app/api/api-keys/route.ts, src/features/api-keys/api-key-console-view.tsx
Replaces nonce/origin/message-parsing with wallet signature verification; updates /api/api-keys POST handler to validate and verify signed payloads; refactors console UI to sign timestamped messages and include timestamp in requests.
Referral Code Utilities, Generation, and Storage
src/utils/referrals.ts, app/api/referrals/code/route.ts, src/features/rewards/referral-rewards-block.tsx, src/components/providers/ReferralTrackingProvider.tsx, src/features/rewards/rewards-view.tsx
Implements referral code regex validation and normalization; adds per-address storage helpers; creates /api/referrals/code endpoint for code generation; adds ReferralRewardsBlock UI with sign/share/copy flow; integrates ReferralTrackingProvider to read ref/referral URL params and store codes; mounts block in rewards view.
Referral Attribution Endpoint and Transaction Integration
app/api/referrals/attribute/route.ts, src/hooks/useTransactionWithToast.tsx
Implements /api/referrals/attribute endpoint for normalizing and forwarding attribution data to internal API; extends transaction hook to fire non-blocking referral attribution POST on confirmation using stored referral code.
Provider Integration and Layout Setup
app/layout.tsx
Wraps ReferralTrackingProvider in Suspense boundary; inserts into provider hierarchy under DataPrefetcher.
Documentation and Validation Rules
docs/TECHNICAL_OVERVIEW.md, docs/VALIDATIONS.md
Documents wallet signature proof composition and verification flow; adds referral docs covering sign/share/attribution mechanics; clarifies storage patterns, secrets handling, wallet verification requirements, and fire-and-forget analytics rules.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • antoncoding/monarch#554: Directly refactors the same API-key endpoint and console to use wallet signature verification with the { address, signature, timestamp } contract.
  • antoncoding/monarch#399: Modifies useTransactionWithToast transaction-confirmation flow; main PR adds referral attribution, retrieved PR updates Sentry error handling.
  • antoncoding/monarch#112: Updates same hook; main PR adds referral attribution POST, retrieved PR refactors toast rendering and content updates.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.54% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: reworking the referral tracking flow across API keys, referral links, and transaction attribution.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/referral-tracking-cleanup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added feature request Specific feature ready to be implemented ui User interface labels May 31, 2026
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a referral and platform fee tracking system, including new API routes, a tracking provider, and rewards UI components, while refactoring API key generation to use a shared wallet signature verification utility. Feedback focuses on addressing potential signature verification failures for L2-only smart contract wallets due to a hardcoded Mainnet chain ID, caching generated referral codes in local storage to prevent redundant signature prompts, simplifying URL query parameter parsing, and refining boolean logic in fee calculations to avoid unexpected type coercion.

@@ -0,0 +1,23 @@
import { SupportedNetworks } from '@/utils/supported-networks';

export const WALLET_SIGNATURE_CHAIN_ID = SupportedNetworks.Mainnet;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Hardcoding WALLET_SIGNATURE_CHAIN_ID to SupportedNetworks.Mainnet will break signature verification for smart contract wallets (such as Safe) that are only deployed on L2 networks (e.g., Base, Arbitrum, Optimism).

Since verifyMessage from viem/actions uses ERC-1271 to verify contract signatures, it must query the chain where the contract is deployed. If a contract wallet only exists on an L2, querying Mainnet will fail. Consider allowing the client to specify the chain ID of their connected wallet, or verifying against the chain where the wallet is active, while still using a server-reconstructed message.

Comment thread src/utils/referrals.ts
} catch {
return false;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

To improve user experience and avoid redundant wallet signatures, we can cache the generated referral code in localStorage (using the project's local-storage-fallback adapter) keyed by the wallet address. This avoids forcing the user to sign a wallet message every single time they visit the rewards page.

Suggested change
}
}
export function getOwnReferralCode(address: string): string | null {
if (!canUseReferralStorage) return null;
try {
return referralStorage.getItem(`monarch_own_referral_code_${address.toLowerCase()}`);
} catch {
return null;
}
}
export function storeOwnReferralCode(address: string, code: string): void {
if (!canUseReferralStorage) return;
try {
referralStorage.setItem(`monarch_own_referral_code_${address.toLowerCase()}`, code);
} catch {}
}

import { Modal, ModalBody, ModalFooter, ModalHeader } from '@/components/common/Modal';
import { Button } from '@/components/ui/button';
import { MONARCH_PRIMARY } from '@/constants/chartColors';
import { getWalletSignatureMessage } from '@/utils/walletSignature';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Import the new getOwnReferralCode and storeOwnReferralCode helpers from @/utils/referrals to support caching the user's own referral code.

Suggested change
import { getWalletSignatureMessage } from '@/utils/walletSignature';
import { getWalletSignatureMessage } from '@/utils/walletSignature';
import { getOwnReferralCode, storeOwnReferralCode } from '@/utils/referrals';

Comment on lines +41 to +47
useEffect(() => {
setCode(null);
setError(null);
setRequestState('idle');
setCopied(false);
setIsModalOpen(false);
}, [address, account]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Use the new getOwnReferralCode helper to load the cached referral code on mount or address change, preventing unnecessary wallet signature requests.

  useEffect(() => {
    setError(null);
    setRequestState('idle');
    setCopied(false);
    setIsModalOpen(false);

    if (address) {
      setCode(getOwnReferralCode(address));
    } else {
      setCode(null);
    }
  }, [address, account]);

Comment on lines +79 to +80
setCode(body.code);
return `${window.location.origin}/?ref=${body.code}`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Store the newly created referral code in the cache once it is successfully fetched from the API.

Suggested change
setCode(body.code);
return `${window.location.origin}/?ref=${body.code}`;
setCode(body.code);
if (address) {
storeOwnReferralCode(address, body.code);
}
return `${window.location.origin}/?ref=${body.code}`;

Comment on lines +7 to +11
useEffect(() => {
const url = new URL(window.location.href);
const code = url.searchParams.get('ref') ?? url.searchParams.get('referral');
if (code) storeReferralCodeOnce(code);
}, []);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Instead of parsing the entire window.location.href with new URL(), we can use new URLSearchParams(window.location.search) directly, which is simpler and more efficient.

Suggested change
useEffect(() => {
const url = new URL(window.location.href);
const code = url.searchParams.get('ref') ?? url.searchParams.get('referral');
if (code) storeReferralCodeOnce(code);
}, []);
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const code = params.get('ref') ?? params.get('referral');
if (code) storeReferralCodeOnce(code);
}, []);

Comment thread src/hooks/useSmartRebalance.ts Outdated
Comment on lines +197 to +209
const platformFeeEvents = useMemo(
() =>
feeAmount && feeAmount > 0n
? [
{
source: 'smart-rebalance',
tokenAddress: groupedPosition.loanAssetAddress as Address,
amountRaw: feeAmount,
},
]
: [],
[feeAmount, groupedPosition.loanAssetAddress],
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

In TypeScript/JavaScript, if feeAmount is 0n, feeAmount && feeAmount > 0n evaluates to 0n. While falsy, it's safer and cleaner to use feeAmount != null && feeAmount > 0n to avoid unexpected type coercion or lint issues (especially with Biome's strict boolean rules).

Suggested change
const platformFeeEvents = useMemo(
() =>
feeAmount && feeAmount > 0n
? [
{
source: 'smart-rebalance',
tokenAddress: groupedPosition.loanAssetAddress as Address,
amountRaw: feeAmount,
},
]
: [],
[feeAmount, groupedPosition.loanAssetAddress],
);
const platformFeeEvents = useMemo(
() =>
feeAmount != null && feeAmount > 0n
? [
{
source: 'smart-rebalance',
tokenAddress: groupedPosition.loanAssetAddress as Address,
amountRaw: feeAmount,
},
]
: [],
[feeAmount, groupedPosition.loanAssetAddress],
);

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/api/api-keys/route.ts`:
- Around line 65-85: The fetch to adminUrl (where response is assigned) lacks an
abort/timeout, so slow gateway calls can hang; wrap the request using an
AbortController (create controller, pass controller.signal to fetch) and set a
timer (e.g., const timeoutId = setTimeout(() => controller.abort(), <timeout
ms>)) before calling fetch, then clearTimeout(timeoutId) once the fetch
resolves; also catch the abort error from fetch (check for DOMException name
'AbortError' or similar) to return a proper timeout response instead of letting
the route hang.

In `@src/components/providers/ReferralTrackingProvider.tsx`:
- Around line 7-11: The current useEffect in ReferralTrackingProvider only runs
once on mount so client-side navigations that add ?ref=... are missed; update
the effect to depend on the current route/search params so it re-runs on client
route changes. Specifically, import and use Next.js App Router hooks (e.g.,
usePathname and/or useSearchParams) or another router-derived value inside the
effect dependency array, read the 'ref' or 'referral' param there, and call
storeReferralCodeOnce(code) when present; keep the logic in the
ReferralTrackingProvider and ensure any window access remains inside the
client-only effect.

In `@src/hooks/useTransactionWithToast.tsx`:
- Around line 46-50: When sending a transaction, capture and persist the
submitting wallet's address at submission time (e.g., set submittingWalletRef
when calling sendTransaction / sendTransactionAsync) and use that stored value
for later side-effects (analytics, referral attribution, and trackPlatformFees)
instead of reading the current connection's address from useConnection() at
confirmation time; update the code paths that read address in the
confirmation/error handlers (those that reference reportedErrorKeyRef,
handledConfirmationHashRef, and call trackPlatformFees) to use the
submittingWalletRef so attribution always reflects the wallet that originally
submitted the tx.

In `@src/utils/dataApiInternal.ts`:
- Around line 13-21: The internal POST fetch currently has no timeout and can
hang; wrap the fetch in an AbortController, pass controller.signal into the
fetch options (alongside method/headers/body/cache), and set a timer (e.g.,
setTimeout) to call controller.abort() after a short configurable timeout,
clearing the timer on successful resolution; update the code around the fetch
call that uses INTERNAL_ADMIN_HEADER and adminKey so callers fail fast when the
data API stalls.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f21a891f-2101-4c2e-ba56-caef6eddd14d

📥 Commits

Reviewing files that changed from the base of the PR and between c796fe5 and d285e9c.

📒 Files selected for processing (22)
  • .env.local.example
  • app/api/api-keys/route.ts
  • app/api/platform-fees/route.ts
  • app/api/referrals/attribute/route.ts
  • app/api/referrals/code/route.ts
  • app/layout.tsx
  • docs/TECHNICAL_OVERVIEW.md
  • docs/VALIDATIONS.md
  • src/components/providers/ReferralTrackingProvider.tsx
  • src/features/api-keys/api-key-console-view.tsx
  • src/features/rewards/referral-rewards-block.tsx
  • src/features/rewards/rewards-view.tsx
  • src/hooks/useLeverageTransaction.ts
  • src/hooks/usePlatformFeeTracking.ts
  • src/hooks/useRebalanceExecution.ts
  • src/hooks/useSmartRebalance.ts
  • src/hooks/useTransactionWithToast.tsx
  • src/utils/apiKeyRequest.ts
  • src/utils/dataApiInternal.ts
  • src/utils/referrals.ts
  • src/utils/serverWalletSignature.ts
  • src/utils/walletSignature.ts
💤 Files with no reviewable changes (1)
  • src/utils/apiKeyRequest.ts

Comment thread app/api/api-keys/route.ts
Comment thread src/components/providers/ReferralTrackingProvider.tsx Outdated
Comment thread src/hooks/useTransactionWithToast.tsx Outdated
Comment thread src/utils/dataApiInternal.ts
@antoncoding antoncoding force-pushed the codex/referral-tracking-cleanup branch from d285e9c to a24b8db Compare May 31, 2026 17:06
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/api/api-keys/route.ts (1)

105-109: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate key before returning it.

apiKey is checked, but key is forwarded as unknown. If the admin service returns a non-string there, this route still emits a malformed success payload to the client.

Suggested fix
-  if (typeof body.apiKey !== 'string') {
-    return NextResponse.json({ error: 'Gateway did not return an API key.' }, { status: 502 });
-  }
-
-  return NextResponse.json({ apiKey: body.apiKey, key: body.key }, { status: 201 });
+  if (typeof body.apiKey !== 'string') {
+    return NextResponse.json({ error: 'Gateway did not return an API key.' }, { status: 502 });
+  }
+
+  if (body.key !== undefined && typeof body.key !== 'string') {
+    return NextResponse.json({ error: 'Gateway returned a malformed API key payload.' }, { status: 502 });
+  }
+
+  return NextResponse.json(
+    body.key === undefined ? { apiKey: body.apiKey } : { apiKey: body.apiKey, key: body.key },
+    { status: 201 },
+  );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/api/api-keys/route.ts` around lines 105 - 109, The handler validates
body.apiKey but not body.key, so ensure you check that body.key is a string
before returning it: in the same function that inspects body.apiKey (the block
using body.apiKey and returning NextResponse.json({ apiKey: body.apiKey, key:
body.key }, ...)), add a type check for typeof body.key === 'string' and return
a 502 NextResponse.json({ error: 'Gateway did not return a valid key.' }, {
status: 502 }) if the check fails; only return the success payload with key when
both validations pass.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/hooks/useTransactionWithToast.tsx`:
- Around line 122-135: The referral code retrieved by getStoredReferralCode() is
never removed, causing repeated attributions; add a clearStoredReferralCode()
helper in src/utils/referrals.ts and call it after a successful POST in the
block inside useTransactionWithToast where you POST to
'/api/referrals/attribute' (i.e., after the fetch resolves without error) so the
stored code is cleared and not reused for subsequent confirmed transactions;
ensure you only clear it on successful submission and keep the existing .catch
behaviour for failures.

---

Outside diff comments:
In `@app/api/api-keys/route.ts`:
- Around line 105-109: The handler validates body.apiKey but not body.key, so
ensure you check that body.key is a string before returning it: in the same
function that inspects body.apiKey (the block using body.apiKey and returning
NextResponse.json({ apiKey: body.apiKey, key: body.key }, ...)), add a type
check for typeof body.key === 'string' and return a 502 NextResponse.json({
error: 'Gateway did not return a valid key.' }, { status: 502 }) if the check
fails; only return the success payload with key when both validations pass.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e7e6468f-bca0-4d4b-81d6-331dbe78e84a

📥 Commits

Reviewing files that changed from the base of the PR and between d285e9c and a24b8db.

📒 Files selected for processing (17)
  • .env.local.example
  • app/api/api-keys/route.ts
  • app/api/referrals/attribute/route.ts
  • app/api/referrals/code/route.ts
  • app/layout.tsx
  • docs/TECHNICAL_OVERVIEW.md
  • docs/VALIDATIONS.md
  • src/components/providers/ReferralTrackingProvider.tsx
  • src/features/api-keys/api-key-console-view.tsx
  • src/features/rewards/referral-rewards-block.tsx
  • src/features/rewards/rewards-view.tsx
  • src/hooks/useTransactionWithToast.tsx
  • src/utils/apiKeyRequest.ts
  • src/utils/dataApiInternal.ts
  • src/utils/referrals.ts
  • src/utils/serverWalletSignature.ts
  • src/utils/walletSignature.ts
💤 Files with no reviewable changes (1)
  • src/utils/apiKeyRequest.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/VALIDATIONS.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/components/providers/ReferralTrackingProvider.tsx
  • src/utils/dataApiInternal.ts
  • src/features/rewards/rewards-view.tsx
  • src/utils/serverWalletSignature.ts
  • src/utils/walletSignature.ts
  • app/api/referrals/attribute/route.ts
  • src/features/api-keys/api-key-console-view.tsx
  • src/features/rewards/referral-rewards-block.tsx

Comment thread src/hooks/useTransactionWithToast.tsx
This removes the speculative platform-fee logging path and keeps the PR focused on API-key creation plus referral-code ownership and first-touch attribution. Referral code creation reuses a Mainnet wallet-ownership proof, the Rewards block only exposes a link for the connected wallet after signing, and post-confirmation attribution forwards the receipt sender/referral code without blocking transaction success.

Constraint: Do not track fee amounts or parse transaction logs in this PR.

Rejected: Platform fee event hooks and ERC-20 receipt log validation | user explicitly reduced scope to referral attribution only.

Rejected: Cloudflare/browser gateway fallback origins | private service origins must stay only in deployment secrets.

Confidence: high

Scope-risk: moderate

Directive: Do not reintroduce platform-fee tracking here without a separate design for fee accounting.

Tested: pnpm exec biome check --write <changed files>; pnpm typecheck; pnpm build; git diff --check

Not-tested: End-to-end Vercel to data-api write with production secrets; npx ultracite fix/check blocked by existing biome.jsonc unknown-rule keys.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request Specific feature ready to be implemented ui User interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant