These are known issues in the codebase. They are documented here so contributors are aware and do not accidentally work around them in ways that obscure the underlying problem. Check this list before debugging unexpected behavior.
Security issues
Cross-org analytics data leak
Routes: analytics/overview, analytics/top-contributors, analytics/trend, analytics/activity-feed
Files: app/api/[organization]/analytics/{overview,top-contributors,trend,activity-feed}/route.ts
These routes call requireOrganizationAccess but then query the signals table without an organization filter. Any authenticated org member receives data aggregated across all organizations’ signals, not just the requested one.
Fix needed: Add an org filter by joining through github_installations → repositories → signals.repository_id.
Webhook secret optional in production
GITHUB_WEBHOOK_SECRET has .optional() in the Zod schema. If unset, the webhook handler logs a warning and accepts all requests without signature verification. See security.
Auth secret fallbacks
AUTH_SESSION_SECRET and TOKEN_ENCRYPTION_KEY both have deterministic weak fallbacks derived from GITHUB_CLIENT_SECRET and GITHUB_APP_ID if not set in the environment. Always set both explicitly in production.
Broken / stub functionality
useSyncStatusQuery → nonexistent endpoint
Calls GET /api/sync/status, which does not exist. Always returns 404. There is no standalone sync endpoint — ingestion is handled internally by POST /api/[org]/leaderboard/score.
useActivityTimelineQuery → hardcoded stub
Returns an empty array ([]) immediately with no API call. The ActivityTimeline page component renders with zero events regardless of data in the signals table.
Analytics overview dateRange disabled
The from/to query params are commented out in useAnalyticsOverviewQuery (hooks/queries/useAnalyticsOverviewQuery.ts). The hook always calls the endpoint without date filters, so the page always shows all-time data regardless of the selected date range.
Org overview page is a placeholder
Route /{org}/organization renders OrganizationOverview, which renders FeaturePlaceholder — a debug/stub card with no real content. File: app/[organization]/organization/page.tsx.
lib/analytics/rollups.ts is type-only
Contains only TypeScript type definitions. No aggregate queries or computations are implemented. Analytics data is computed directly in route handlers rather than through a dedicated aggregation layer.
Code quality issues
Non-standard auth in bulk routes
Routes: bulk-role, teams/bulk-add
Files: app/api/organizations/[login]/bulk-role/route.ts, app/api/organizations/[login]/teams/bulk-add/route.ts
These routes use getRequestSession directly with an inline admin check instead of the standard requireOrganizationAdmin guard. The behavior is equivalent but the implementation is inconsistent with all other admin routes, making the codebase harder to understand and refactor.
N+1 in teams/members
GET /api/[org]/teams/members issues one Supabase count query per team instead of a single GROUP BY with a join. File: app/api/[organization]/teams/members/route.ts. Impact is negligible for orgs with fewer than 100 teams.
Debug console.log in production
GET /api/[org]/repository/metrics (app/api/[organization]/repository/metrics/route.ts) has console.log statements for repoRow.id, from, to, and row count that emit to production logs.
useTeamLeaderboardQuery cache inconsistency
timePeriod is included in the POST body to the leaderboard endpoint but not in the TanStack query key. Changing the time period can serve stale cached data without refetching.
useTeamContributorLeaderboardQuery hardcoded presetId
Hardcodes presetId: '2' as a fallback value, which will break if preset 2 is renamed or deleted.
Query key factory bypassed
Five hooks use inline literal query key arrays instead of the queryKeys factory:
useOrganizationActivityFeedQueryuseOrganizationTopContributorsQueryuseRepositoryTopContributorsQueryuseRepositoryMetricsQueryuseRepositoryActivityTrendQuery
This makes cache invalidation fragile — clearing “all repository queries” or “all analytics queries” cannot be done systematically.
Query key collision
useActivityTimelineQuery and useOrganizationActivityTrendQuery share the same query key (['analytics-timeline', org, {...}]) but return different data shapes. The cache from one overwrites the other.
DELETE preset returns 400 on DB errors
PATCH /api/[org]/leaderboard/rules/presets returns 400 even for server-side errors during preset deletion, making error diagnosis difficult.
Orphaned / dead code
| Code | Location | Status |
|---|---|---|
AuthConsole | components/auth/AuthConsole/ | Exported from auth/index.ts but imported by no page. account/page.tsx reimplements the same UI. |
OrganizationQuickLinks | components/organization/OrganizationQuickLinks.tsx | Exported from organization/index.ts but used nowhere. |
OrganizationActivityFeed | components/analytics/OrganizationActivityFeed.tsx | Not in analytics/index.ts, not imported anywhere. Duplicates ActivityTimeline functionality. |
ChartContainer | components/ui/chart.tsx | shadcn chart wrapper — not used by any feature component. Feature components use Recharts directly. |
PageHeader | components/layout/PageHeader.tsx | Exported but no page uses it — all pages compose headings inline. |
components/docs/ | components/docs/ | Empty directory. Reserved namespace for docs-specific components. |
next-themes (v0.4.6) | package.json | Installed but ThemeProvider is never mounted. App is hard dark-mode via CSS variables. Nextra docs use their own darkMode setting. |
fuse.js (v7.3.0) | package.json | Installed but unused. Contributor search uses cmdk’s CommandInput for client-side filtering. |
useLeaderboardSyncMutation | hooks/mutations/useLeaderboardSyncMutation.ts | Stub mutation — no API call, no invalidation. |
Schema / data quirks
content_hash column width
The signals.content_hash column is declared char(64), but normalizeGitHubData() only stores 32 characters (SHA-256 hash sliced to first 32 hex chars). The column is over-wide but harmless — no data is truncated.
Monthly signal partitions
ensure_signals_monthly_partitions() (008_signals.sql) must be called before inserting signals into a new month. upsertSignals() calls this automatically. Rows landing in the signals_default catch-all partition indicate a partition was not pre-created for that date range.
Orphaned SQL maintenance functions
These functions exist in the database but are never called by application code. They must be invoked manually or via an external scheduler (e.g. Supabase pg_cron, Vercel Cron, GitHub Actions):
| Function | Purpose | Default |
|---|---|---|
drop_old_signals_partitions(p_keep_months) | Drop partitions older than N months | 12 months |
purge_superseded_materializations(p_before) | Delete old leaderboard materializations | — |
purge_expired_auth_sessions() | Delete expired auth_sessions rows | — |
cleanup_expired_sessions() | Delete expired auth_sessions rows (duplicate of above) | — |
Session GC only on login
deleteExpiredSessions() is called fire-and-forget inside the OAuth callback (/api/auth). If logins are infrequent, expired session rows accumulate until the next login event.
skipValidation in production
lib/env/index.ts passes skipValidation: true when NODE_ENV === 'production'. Missing or malformed environment variables do not fail the build — they fail at runtime when the relevant code path is first hit. There is no early warning.