Skip to content

Comments

feat: add public transparency page (#86)#89

Merged
Benjtalkshow merged 2 commits intoboundlessfi:mainfrom
Sendi0011:feat/transparency-page
Feb 21, 2026
Merged

feat: add public transparency page (#86)#89
Benjtalkshow merged 2 commits intoboundlessfi:mainfrom
Sendi0011:feat/transparency-page

Conversation

@Sendi0011
Copy link
Contributor

@Sendi0011 Sendi0011 commented Feb 20, 2026

Summary

Closes #86

Adds a /transparency page showing platform-wide funding stats and a recent payouts feed to build trust and accountability.


Changes

New Files

File Description
lib/api/transparency.ts API module with Zod schemas for PlatformStats and RecentPayout
hooks/use-transparency.ts usePlatformStats and useRecentPayouts hooks via React Query
app/transparency/page.tsx Responsive transparency page with stats grid, payouts feed, skeletons, empty + error states
app/api/transparency/stats/route.ts Next.js API route stub for platform stats
app/api/transparency/payouts/route.ts Next.js API route stub for recent payouts

Modified Files

File Description
components/global-navbar.tsx Added Transparency nav link with active state

Acceptance Criteria

  • Real API data renders correctly via React Query
  • Handles empty/zero state — stats default to 0, payouts show empty message
  • Fully responsive — 1 → 2 → 4 col grid across sm/lg breakpoints
  • No layout breaks — follows existing leaderboard page structure

Screenshots

Desktop

Desktop

Mobile

Mobile


Notes

The API routes (/api/transparency/stats and /api/transparency/payouts) are currently stubs returning empty/zero data. They are structured to be swapped for real DB queries once the backend is ready — no frontend changes will be needed at that point.

Summary by CodeRabbit

  • New Features
    • Added a Transparency dashboard with stats cards and a recent payouts list.
    • Added recent payouts display with contributor, project, amount and date.
    • Added a Transparency navigation item linking to the dashboard.
    • Added backend endpoints for fetching platform stats and recent payouts.
    • Added client-side data hooks and a small API client to fetch transparency data.

@vercel
Copy link

vercel bot commented Feb 20, 2026

@Sendi0011 is attempting to deploy a commit to the Threadflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Feb 20, 2026

No actionable comments were generated in the recent review. 🎉


📝 Walkthrough

Walkthrough

Adds a public Transparency dashboard: a client page that displays platform stats and recent payouts, two new App Router API GET routes returning placeholder data, a typed API client and Zod schemas, React Query hooks for fetching stats/payouts, and a navbar link to /transparency.

Changes

Cohort / File(s) Summary
API Routes
app/api/transparency/stats/route.ts, app/api/transparency/payouts/route.ts
New Next.js App Router GET handlers: /api/transparency/stats returns placeholder PlatformStats; /api/transparency/payouts accepts limit and returns an in-file RecentPayout[] slice. Both use TODO placeholders for DB integration.
Page & UI Components
app/transparency/page.tsx
New client TransparencyPage (default export) with StatCard and PayoutRow internals; fetches stats and recent payouts via hooks; includes loading/error states and uses existing Card/Alert/Avatar/Badge/Button/Skeleton UI primitives.
Navigation
components/global-navbar.tsx
Added "Transparency" nav item linking to /transparency with existing active-state logic.
API Types & Client
lib/api/transparency.ts
Added Zod schemas platformStatsSchema, recentPayoutSchema, exported types PlatformStats, RecentPayout, and transparencyApi client with getStats() and getRecentPayouts(limit).
Data Hooks
hooks/use-transparency.ts
Added TRANSPARENCY_KEYS and React Query hooks usePlatformStats() and useRecentPayouts(limit) with configured staleTimes (10min and 5min).

Sequence Diagram

sequenceDiagram
    participant Browser as Browser
    participant Page as TransparencyPage
    participant Hooks as ReactQueryHooks
    participant ApiClient as transparencyApi
    participant Routes as API Routes
    participant Memory as In-File Data

    Browser->>Page: Navigate to /transparency
    Page->>Hooks: usePlatformStats()
    Hooks->>ApiClient: getStats()
    ApiClient->>Routes: GET /api/transparency/stats
    Routes->>Memory: read placeholder stats
    Memory-->>Routes: stats JSON
    Routes-->>ApiClient: respond JSON
    ApiClient-->>Hooks: PlatformStats
    Hooks-->>Page: stats (data/loading/error)

    Page->>Hooks: useRecentPayouts(limit)
    Hooks->>ApiClient: getRecentPayouts(limit)
    ApiClient->>Routes: GET /api/transparency/payouts?limit=X
    Routes->>Memory: read payouts array
    Memory-->>Routes: payouts slice
    Routes-->>ApiClient: respond JSON
    ApiClient-->>Hooks: RecentPayout[]
    Hooks-->>Page: payouts (data/loading/error)

    Page->>Browser: render StatCards & PayoutRows
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped to the ledger, bright and spry,
Stats and payouts beneath the sky,
Hooks fetch the numbers, schemas keep them true,
A nav link points the way — transparency for you! 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% 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 'feat: add public transparency page (#86)' clearly and concisely summarizes the main change—adding a public transparency page.
Linked Issues check ✅ Passed All coding requirements from issue #86 are met: PlatformStats schema with required fields, Recent Payouts data structure, API routes, React Query hooks, responsive page with stats grid and payouts feed, empty/zero state handling, and navigation integration.
Out of Scope Changes check ✅ Passed All changes are within scope of issue #86: new transparency API routes, data schemas, hooks, page component, and navbar link are directly necessary for the transparency feature.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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.

Copy link

@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

🧹 Nitpick comments (2)
app/transparency/page.tsx (1)

68-70: toLocaleDateString() without a locale produces inconsistent output across users.

For a public financial transparency feed, date formatting should be deterministic. Consider passing an explicit locale and options:

♻️ Proposed fix
-                    {new Date(payout.paidAt).toLocaleDateString()}
+                    {new Date(payout.paidAt).toLocaleDateString('en-US', {
+                        year: 'numeric', month: 'short', day: 'numeric',
+                    })}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/transparency/page.tsx` around lines 68 - 70, The current use of new
Date(payout.paidAt).toLocaleDateString() in the span produces non-deterministic
dates across user locales; replace it with an explicit locale and formatting
options (or use Intl.DateTimeFormat) so the public payout date is
deterministic—update the expression in the span that references new
Date(payout.paidAt).toLocaleDateString() to format with a fixed locale (e.g.
"en-US" or "en-GB") and explicit options like year/month/day (or instantiate a
shared Intl.DateTimeFormat) to ensure consistent output.
app/api/transparency/payouts/route.ts (1)

8-16: Inline type duplicates RecentPayout — extract to a shared types file.

The inline object type at lines 8–16 replicates the shape already defined in lib/api/transparency.ts (recentPayoutSchema / RecentPayout). Importing the client-side fetch module into a server route is not ideal, but maintaining a parallel type in the route creates a silent drift risk: if the schema changes, TypeScript won't catch the mismatch here. Consider extracting the shared shape into a neutral types/transparency.ts (no fetch dependency) and importing it in both lib/api/transparency.ts and this route.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/transparency/payouts/route.ts` around lines 8 - 16, The route
declares an inline payouts type that duplicates RecentPayout/recentPayoutSchema;
extract a neutral shared type (e.g., export interface RecentPayout) into a small
types module (types/transparency.ts) with the same shape used by
recentPayoutSchema, export it, then import that RecentPayout type into both this
route (replace the inline annotation on payouts) and the module that defines
recentPayoutSchema (use the shared type there) so the shape is single-sourced
and won't silently drift; ensure the new types file has no client fetch
dependencies and adjust imports accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/api/transparency/payouts/route.ts`:
- Line 5: The limit parsed from searchParams (const limit) must be constrained
to a safe maximum to prevent very large queries; update the parsing to coerce to
an integer, handle NaN/negative values, and clamp it with a defined max (e.g.,
const MAX_LIMIT = 100) using Math.min/Math.max so limit = clamp(parsed, 1,
MAX_LIMIT); apply this change where const limit is defined in route.ts (the
request handler that reads searchParams.get("limit")).

In `@app/transparency/page.tsx`:
- Around line 137-156: The code is casting statsErr to Error redundantly; update
the AlertDescription rendering to remove the unnecessary cast and use the
existing typed variable directly (replace {(statsErr as Error)?.message} with
statsErr?.message) in the component that shows the error (inside the JSX block
rendering Alert / AlertDescription), ensuring you still handle possible null by
using optional chaining; no other changes to refetchStats or the Alert structure
are required.
- Around line 15-43: StatCard uses the React type namespace (React.ElementType)
but the file does not import React, causing a TS error; fix by importing the
type instead of the whole namespace—add an import type { ElementType } from
'react' at the top and change the prop type to use ElementType (or alternatively
add import React from 'react' if you prefer), and apply the same change to the
other component that references React.ElementType (the tier badge component) so
both compile under the "react-jsx" tsconfig.

In `@lib/api/transparency.ts`:
- Around line 27-33: The transparencyApi methods currently return axios data
without runtime validation; update getStats and getRecentPayouts to validate the
response with the Zod schemas before returning (e.g., import your
PlatformStatsSchema and RecentPayoutSchema and call
PlatformStatsSchema.parse(...) on the result of get in getStats, and
RecentPayoutSchema.array().parse(...) in getRecentPayouts), or alternately
extend the get helper to accept a validator and run parse inside it; target the
transparencyApi.getStats and transparencyApi.getRecentPayouts calls to ensure
parsed/validated data (use the TRANSPARENCY_ENDPOINT and existing
PlatformStats/RecentPayout types as references).

---

Nitpick comments:
In `@app/api/transparency/payouts/route.ts`:
- Around line 8-16: The route declares an inline payouts type that duplicates
RecentPayout/recentPayoutSchema; extract a neutral shared type (e.g., export
interface RecentPayout) into a small types module (types/transparency.ts) with
the same shape used by recentPayoutSchema, export it, then import that
RecentPayout type into both this route (replace the inline annotation on
payouts) and the module that defines recentPayoutSchema (use the shared type
there) so the shape is single-sourced and won't silently drift; ensure the new
types file has no client fetch dependencies and adjust imports accordingly.

In `@app/transparency/page.tsx`:
- Around line 68-70: The current use of new
Date(payout.paidAt).toLocaleDateString() in the span produces non-deterministic
dates across user locales; replace it with an explicit locale and formatting
options (or use Intl.DateTimeFormat) so the public payout date is
deterministic—update the expression in the span that references new
Date(payout.paidAt).toLocaleDateString() to format with a fixed locale (e.g.
"en-US" or "en-GB") and explicit options like year/month/day (or instantiate a
shared Intl.DateTimeFormat) to ensure consistent output.


export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const limit = Number(searchParams.get("limit")) || 10;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add an upper bound to limit before wiring in real DB queries.

Number(searchParams.get("limit")) || 10 accepts arbitrarily large values. A caller can pass limit=1000000, which will become a full-table scan once the TODO is resolved with a real query. Cap it explicitly:

🛡️ Proposed fix
-    const limit = Number(searchParams.get("limit")) || 10;
+    const raw = Number(searchParams.get("limit"));
+    const limit = raw > 0 && Number.isFinite(raw) ? Math.min(raw, 100) : 10;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/transparency/payouts/route.ts` at line 5, The limit parsed from
searchParams (const limit) must be constrained to a safe maximum to prevent very
large queries; update the parsing to coerce to an integer, handle NaN/negative
values, and clamp it with a defined max (e.g., const MAX_LIMIT = 100) using
Math.min/Math.max so limit = clamp(parsed, 1, MAX_LIMIT); apply this change
where const limit is defined in route.ts (the request handler that reads
searchParams.get("limit")).

Comment on lines +15 to +43
function StatCard({
title,
value,
icon: Icon,
isLoading,
}: {
title: string;
value: string;
icon: React.ElementType;
isLoading: boolean;
}) {
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
{title}
</CardTitle>
<Icon className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{isLoading ? (
<Skeleton className="h-8 w-32" />
) : (
<p className="text-2xl font-bold text-foreground">{value}</p>
)}
</CardContent>
</Card>
);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check the actual file to see imports and full context
cat -n app/transparency/page.tsx | head -50

Repository: boundlessfi/bounties

Length of output: 2103


🏁 Script executed:

# Check tsconfig.json for jsx and allowUmdGlobalAccess settings
fd -e json "tsconfig" --max-depth 2 -x cat {}

Repository: boundlessfi/bounties

Length of output: 729


🏁 Script executed:

# Look for global.d.ts files that might define React globally
fd -e "d.ts" "global" --max-depth 3

Repository: boundlessfi/bounties

Length of output: 46


🏁 Script executed:

# Search for other uses of React.ElementType in the codebase
rg "React\.(ElementType|FC|ReactNode)" --type=tsx -A 2 -B 2 | head -100

Repository: boundlessfi/bounties

Length of output: 91


🏁 Script executed:

# Search for React.ElementType or React. type references (using proper rg syntax)
rg "React\." app/transparency/page.tsx -A 1 -B 1

Repository: boundlessfi/bounties

Length of output: 135


🏁 Script executed:

# Look for how other components define icon/component props
rg "icon:|Icon" --type ts --type tsx -A 2 -B 2 | head -150

Repository: boundlessfi/bounties

Length of output: 91


🏁 Script executed:

# Check if React is imported anywhere in the codebase for type usage
rg "import.*React" --type tsx | grep -i "elementtype\|React\.FC\|React\.ReactNode" | head -20

Repository: boundlessfi/bounties

Length of output: 91


🏁 Script executed:

# Look for ElementType imports to see the pattern used elsewhere
rg "ElementType" --type tsx -B 3 | head -50

Repository: boundlessfi/bounties

Length of output: 91


🏁 Script executed:

# Search for React. references in tsx files using glob pattern
rg "React\." -g "*.tsx" -A 1 -B 1 | head -100

Repository: boundlessfi/bounties

Length of output: 4260


🏁 Script executed:

# Search for how icon/Icon props are typed in other components
rg "icon.*:" -g "*.tsx" -A 1 | head -100

Repository: boundlessfi/bounties

Length of output: 7006


🏁 Script executed:

# Check if any component file imports ElementType directly
rg "import.*ElementType" -g "*.tsx"

Repository: boundlessfi/bounties

Length of output: 46


🏁 Script executed:

# Verify by checking if the file would compile - look at how components handle component types
rg "React\.FC\|React\.Component\|ElementType" -g "*.tsx" -B 2 | head -80

Repository: boundlessfi/bounties

Length of output: 46


🏁 Script executed:

# Check tier-badge.tsx imports (it uses React.ElementType)
head -20 components/reputation/tier-badge.tsx

Repository: boundlessfi/bounties

Length of output: 839


🏁 Script executed:

# Check a component using React.ReactNode to see if they import React
head -20 components/ui/alert-dialog.tsx

Repository: boundlessfi/bounties

Length of output: 642


🏁 Script executed:

# Final check: look at full imports of app/transparency/page.tsx
head -15 app/transparency/page.tsx

Repository: boundlessfi/bounties

Length of output: 720


React.ElementType used without importing React — TypeScript compile error.

With the new JSX transform, you still need to import React "in order to use Hooks or other exports that React provides" — and the same applies to type namespace references. Line 23 references React.ElementType but there is no import React from 'react' or import type { ElementType } from 'react' in the file. Under the project's tsconfig ("jsx": "react-jsx", strict: true, no allowUmdGlobalAccess), this produces a TypeScript error and will fail next build.

Note: components/reputation/tier-badge.tsx has the same issue on line 12.

🐛 Proposed fix
+import type { ElementType } from 'react';
 
 function StatCard({
     title,
     value,
     icon: Icon,
     isLoading,
 }: {
     title: string;
     value: string;
-    icon: React.ElementType;
+    icon: ElementType;
     isLoading: boolean;
 }) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function StatCard({
title,
value,
icon: Icon,
isLoading,
}: {
title: string;
value: string;
icon: React.ElementType;
isLoading: boolean;
}) {
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
{title}
</CardTitle>
<Icon className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{isLoading ? (
<Skeleton className="h-8 w-32" />
) : (
<p className="text-2xl font-bold text-foreground">{value}</p>
)}
</CardContent>
</Card>
);
}
function StatCard({
title,
value,
icon: Icon,
isLoading,
}: {
title: string;
value: string;
icon: ElementType;
isLoading: boolean;
}) {
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
{title}
</CardTitle>
<Icon className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{isLoading ? (
<Skeleton className="h-8 w-32" />
) : (
<p className="text-2xl font-bold text-foreground">{value}</p>
)}
</CardContent>
</Card>
);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/transparency/page.tsx` around lines 15 - 43, StatCard uses the React type
namespace (React.ElementType) but the file does not import React, causing a TS
error; fix by importing the type instead of the whole namespace—add an import
type { ElementType } from 'react' at the top and change the prop type to use
ElementType (or alternatively add import React from 'react' if you prefer), and
apply the same change to the other component that references React.ElementType
(the tier badge component) so both compile under the "react-jsx" tsconfig.

Comment on lines +137 to +156
{statsError && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertTitle>Error</AlertTitle>
<AlertDescription className="flex flex-col gap-2">
<p>
Failed to load platform stats.{" "}
{(statsErr as Error)?.message}
</p>
<Button
variant="outline"
size="sm"
onClick={() => refetchStats()}
className="w-fit bg-background text-foreground border-border hover:bg-muted"
>
Try Again
</Button>
</AlertDescription>
</Alert>
)}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

as Error cast is redundant in TanStack Query v5.

In @tanstack/react-query v5, error is typed as Error | null by default, so statsErr is already Error | null. The as Error at line 144 is unnecessary; use statsErr?.message directly.

♻️ Proposed fix
-                            {(statsErr as Error)?.message}
+                            {statsErr?.message}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{statsError && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertTitle>Error</AlertTitle>
<AlertDescription className="flex flex-col gap-2">
<p>
Failed to load platform stats.{" "}
{(statsErr as Error)?.message}
</p>
<Button
variant="outline"
size="sm"
onClick={() => refetchStats()}
className="w-fit bg-background text-foreground border-border hover:bg-muted"
>
Try Again
</Button>
</AlertDescription>
</Alert>
)}
{statsError && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertTitle>Error</AlertTitle>
<AlertDescription className="flex flex-col gap-2">
<p>
Failed to load platform stats.{" "}
{statsErr?.message}
</p>
<Button
variant="outline"
size="sm"
onClick={() => refetchStats()}
className="w-fit bg-background text-foreground border-border hover:bg-muted"
>
Try Again
</Button>
</AlertDescription>
</Alert>
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/transparency/page.tsx` around lines 137 - 156, The code is casting
statsErr to Error redundantly; update the AlertDescription rendering to remove
the unnecessary cast and use the existing typed variable directly (replace
{(statsErr as Error)?.message} with statsErr?.message) in the component that
shows the error (inside the JSX block rendering Alert / AlertDescription),
ensuring you still handle possible null by using optional chaining; no other
changes to refetchStats or the Alert structure are required.

Comment on lines +27 to +33
export const transparencyApi = {
getStats: (): Promise<PlatformStats> =>
get<PlatformStats>(`${TRANSPARENCY_ENDPOINT}/stats`),

getRecentPayouts: (limit = 10): Promise<RecentPayout[]> =>
get<RecentPayout[]>(`${TRANSPARENCY_ENDPOINT}/payouts`, { params: { limit } }),
}; No newline at end of file
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find where the get helper is imported from in transparency.ts
head -30 lib/api/transparency.ts | grep -E "^import|^export"

Repository: boundlessfi/bounties

Length of output: 372


🏁 Script executed:

# Search for the get function definition in lib/client
fd -type f -e ts lib/client

Repository: boundlessfi/bounties

Length of output: 234


🏁 Script executed:

# Also search for any client-related files
fd -type f -name "*client*" lib

Repository: boundlessfi/bounties

Length of output: 234


🏁 Script executed:

# Find client files in lib directory
find lib -name "*client*" -type f

Repository: boundlessfi/bounties

Length of output: 143


🏁 Script executed:

# Also check the directory structure of lib/api
ls -la lib/api/

Repository: boundlessfi/bounties

Length of output: 662


🏁 Script executed:

# Read the client.ts file to see the get() function implementation
cat -n lib/api/client.ts

Repository: boundlessfi/bounties

Length of output: 4964


Zod schemas are defined but never used for runtime validation.

get<PlatformStats>() and get<RecentPayout[]>() accept generic type parameters, not Zod schemas — the get helper in lib/api/client.ts performs no runtime validation and simply returns the axios response data. When the stub routes are replaced with real DB queries, unexpected field types or missing fields will surface as silent runtime bugs rather than Zod parse errors. Either call .parse() in the API methods, or extend the get helper to accept a validator argument.

♻️ Proposed refactor (parse at the call site)
 export const transparencyApi = {
-    getStats: (): Promise<PlatformStats> =>
-        get<PlatformStats>(`${TRANSPARENCY_ENDPOINT}/stats`),
+    getStats: async (): Promise<PlatformStats> => {
+        const data = await get(`${TRANSPARENCY_ENDPOINT}/stats`);
+        return platformStatsSchema.parse(data);
+    },

-    getRecentPayouts: (limit = 10): Promise<RecentPayout[]> =>
-        get<RecentPayout[]>(`${TRANSPARENCY_ENDPOINT}/payouts`, { params: { limit } }),
+    getRecentPayouts: async (limit = 10): Promise<RecentPayout[]> => {
+        const data = await get(`${TRANSPARENCY_ENDPOINT}/payouts`, { params: { limit } });
+        return z.array(recentPayoutSchema).parse(data);
+    },
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const transparencyApi = {
getStats: (): Promise<PlatformStats> =>
get<PlatformStats>(`${TRANSPARENCY_ENDPOINT}/stats`),
getRecentPayouts: (limit = 10): Promise<RecentPayout[]> =>
get<RecentPayout[]>(`${TRANSPARENCY_ENDPOINT}/payouts`, { params: { limit } }),
};
export const transparencyApi = {
getStats: async (): Promise<PlatformStats> => {
const data = await get(`${TRANSPARENCY_ENDPOINT}/stats`);
return platformStatsSchema.parse(data);
},
getRecentPayouts: async (limit = 10): Promise<RecentPayout[]> => {
const data = await get(`${TRANSPARENCY_ENDPOINT}/payouts`, { params: { limit } });
return z.array(recentPayoutSchema).parse(data);
},
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/api/transparency.ts` around lines 27 - 33, The transparencyApi methods
currently return axios data without runtime validation; update getStats and
getRecentPayouts to validate the response with the Zod schemas before returning
(e.g., import your PlatformStatsSchema and RecentPayoutSchema and call
PlatformStatsSchema.parse(...) on the result of get in getStats, and
RecentPayoutSchema.array().parse(...) in getRecentPayouts), or alternately
extend the get helper to accept a validator and run parse inside it; target the
transparencyApi.getStats and transparencyApi.getRecentPayouts calls to ensure
parsed/validated data (use the TRANSPARENCY_ENDPOINT and existing
PlatformStats/RecentPayout types as references).

Copy link
Contributor

@Benjtalkshow Benjtalkshow left a comment

Choose a reason for hiding this comment

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

Hi @Sendi0011 , the workflow is failing.

  1. Fix all any type usages.
  2. Clean up unused variables.
  3. Update useEffect dependency arrays.
  4. Avoid synchronous setState calls in effects.
  5. Fix coderabbit error, see sample below:
image

Copy link
Contributor

@Benjtalkshow Benjtalkshow left a comment

Choose a reason for hiding this comment

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

LGTM!!

@Benjtalkshow Benjtalkshow merged commit 391dbfa into boundlessfi:main Feb 21, 2026
2 of 3 checks passed
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.

Implement Public Transparency Page

2 participants