Skip to content

#777 feat(campaign): Backer leaderboard show top supporters on campaign page FIXED - #830

Open
veloura-dev wants to merge 1 commit into
Fundable-Protocol:mainfrom
veloura-dev:#777-feat-campaign---Backer-leaderboard-show-top-supporters-on-campaign-page-FIX
Open

#777 feat(campaign): Backer leaderboard show top supporters on campaign page FIXED#830
veloura-dev wants to merge 1 commit into
Fundable-Protocol:mainfrom
veloura-dev:#777-feat-campaign---Backer-leaderboard-show-top-supporters-on-campaign-page-FIX

Conversation

@veloura-dev

Copy link
Copy Markdown
Contributor

CLOSE #777

Code-level facts below were re-verified against the files on disk this turn (line numbers cited). Test/lint/typecheck numbers come from the runs I executed earlier in this session — node_modules was dropped from the workspace snapshot between turns, so I have not re-run them just now.

. Findings

1. The feature did not exist in any form. Searching backer, top, leaderboard, privacy, anonymous across apps/web/src found no per-campaign backer ranking, no creator featuring, and no backer privacy model. The two nearest things were both unusable for this issue:

  • types/sponsor.tsINITIAL_MOCK_SPONSORS: a flat sponsor-wall list, no ranking, no privacy field.
  • services/leaderboard.service.ts (#643): a global monthly sponsor/planter points board, not campaign-scoped, no privacy.

2. The host page did not compile. Baseline tsc --noEmit reported 11 errors in apps/web/src/app/(overview)/campaigns/[id]/page.tsx: duplicate Edit/ShieldCheck imports, three <TabsList> opening tags for one close, unclosed TabsTrigger/TabsContent on the Q&A and Success tabs, and the insurance-claim modal duplicated. There was nowhere to mount the feature until that was repaired.

3. Seven files repo-wide had parse-level merge corruption (campaign detail page, campaigns directory, success-stories route + component, wallet modal, co2-impact.ts, certificate.service.ts). These parse failures masked the real type state — once fixed, 52 pre-existing type errors surfaced.

4. pnpm install was broken. @stellar/freghter-api@^6.0.1 returns 404 (typo for freighter, which the committed lockfile already pins), @types/html2canvas@^1.2.6 has no such release (max 1.0.0), and html2canvas was unused and absent from the lockfile — so --frozen-lockfile could never succeed.

5. Pre-existing debt I did not take on: 52 type errors across 29 unrelated files, 4 ESLint errors, 16 failing test files, and route handlers still using the pre-Next-15 sync params signature (flagged by Next's generated .next/types validators).

6. One bug in my own first implementation, caught by rendering the page: the hook located the viewer's row by address, so an anonymous backer — whose address is redacted — silently lost their own privacy controls. Fixed to key off the service's isSelf, with a regression test.

. Fix features

Ranking — contributions aggregated per backer and summed in exact fixed-point bigint (7-decimal stroops, parseTokenAmount/sumTokenAmounts), so 0.1 + 0.2 === 0.3 and ranking never drifts on floats. Ties break by earliest contribution, then address. Capped at TOP_BACKERS_LIMIT = 10 (line 146), limit overridable per call.

Creator featuringMAX_FEATURED_BACKERS = 3 (line 149). Featured rows pin to the top while keeping the rank they earned by amount (a featured #6 still reads "6"). Supports an optional creator note, is idempotent on re-feature, and toggles off.

Privacy enforcement matrix (the core of "respect privacy preferences"):

Preference Public viewer Creator view Featureable
PUBLIC name, address, amount same
ANONYMOUS rank kept; "Anonymous backer" / "Hidden address", no avatar or message; amount only if showAmount identity resolved, row badged Anonymous ❌ (line 208)
PRIVATE excluded entirely; counted in totals, disclosed as "N backers keep their support private" visible, badged Private ❌ (line 205)
  • Privacy always wins: any change away from public/featureable auto-removes an existing feature and returns removedFromFeatured: true (lines 160–165).
  • No rank-gap leak: private backers are removed before ranking, so they don't leave a hole that reveals someone is above you.
  • Creator-only auth: featuring/unfeaturing rejects any other address with Only the campaign creator can feature backers (lines 197, 258); an unregistered creator is rejected too.
  • Self-service: a backer sees "You" on their own row plus a Public / Anonymous / Private switch, and can always resolve and undo their own choice even while anonymous to everyone else.

API surfaceGET (privacy-aware board, ?limit/viewer/creator), POST (record contribution), PATCH (set privacy) at /api/campaigns/:id/backers; POST/DELETE featuring at /api/campaigns/:id/backers/featured (403 on non-creator, body-or-query for DELETE).

UI — top-10 list with gold/silver/bronze medals, featured star + amber pin, privacy badges, "Amount hidden", totals chips (14 backers, 38,700.5 raised, 0/3 featured), inline error banner, empty state, and the private-backer disclosure line.

Repo repairs — the 7 corrupted files fixed, the dependency typo fixed, and pnpm install --frozen-lockfile now succeeds against the committed lockfile.

Verification (from runs executed earlier this session)

Check Result
New feature tests (5 files) 61/61 pass — service 30, component 11, page 4, backers route 8, featured route 8
Full suite after fix 1099 pass / 73 fail (96 files: 80 pass / 16 fail)
Full suite baseline 986 pass / 73 fail (91 files: 71 pass / 20 fail)
Regressions 0; 4 previously-broken files now pass (co2-impact, certificate.service, wallet-modal, CampaignImpactCalculator)
tsc --noEmit 0 errors in every file I touched; 52 pre-existing remain elsewhere
ESLint (touched files) clean (0 errors, 0 warnings)
next build Could not run here — 2 GB RAM, no swap. Turbopack thrashed 12 min; webpack exited 134 (Reached heap limit); selective build OOM-killed (137). Compensated with tsc + Vite/jsdom render of the real page + direct route-handler execution.

@drips-wave

drips-wave Bot commented Sep 3, 2026

Copy link
Copy Markdown

@veloura-dev Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 3b79c618-453c-4c97-9a5f-0bdec2ac91c5


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.

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.

feat(campaign): Backer leaderboard - show top supporters on campaign page

1 participant