Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
f3bba59
feat: add review cycle time metric with weekly trend chart and slowes…
YuktiNandwana May 31, 2026
0efbf59
Feat/repo contribution distribution chart (#367)
prashant2007-wq May 31, 2026
c61b854
feat: add repository-based collaboration rooms with GitHub user invit…
Ishta-P-Jain May 31, 2026
0c15fa2
Add webhook settings and weekly notifications API (#1098)
RitvikaSavanna May 31, 2026
00c84de
Added today's plan note wedge component (#1254)
nikita-9112 May 31, 2026
971bda9
feat: improve goal creation button feedback (#1513)
Plansha May 31, 2026
ac437b0
fix: validate repo field before GitHub query construction in goals sy…
Ridanshi May 31, 2026
b9d8ffa
fix: resolve auth routing redirects and repair e2e test suite (#1544)
ArshVermaGit May 31, 2026
04890e1
Enhancement: Comprehensive Accessibility (a11y) & Keyboard Navigation…
ArshVermaGit May 31, 2026
524ecde
feat: add 404/500 pages and React Error Boundaries (closes #1307) (#1…
IshitaSingh0822 May 31, 2026
7f5866e
feat: add copy to clipboard quick-action button for public profile li…
prakshithamalla-art May 31, 2026
37edf48
feat: implement native ConfirmModal overlay interceptor before deleti…
prakshithamalla-art May 31, 2026
5667faa
feat: add global theme toggle and fix light mode consistency (#1655)
bhavyanjain3004 May 31, 2026
9f69d6f
feat: add smooth scroll animation for navbar anchor links (#1658)
Manav5234 May 31, 2026
3d22689
feat: implement resilient React Error Boundaries for critical dashboa…
prakshithamalla-art May 31, 2026
a00c0e1
refactor: centralize streak calculation (#1434) (#1684)
ionfwsrijan May 31, 2026
5b7e910
fix: make PR Breakdown tooltip consistent with PR Status Distribution…
tharunika-19 May 31, 2026
a9a5ae1
fix: persist theme preference to localStorage across page refreshes (…
Shivani-ramesh09 May 31, 2026
52bc7e2
refactor: clean up and refresh leaderboard branch (#1705)
karthikapradeep2005 May 31, 2026
93c2d93
fix: replace tiny dropdown chevron with proper icon (#1707)
Plansha May 31, 2026
7b37691
fix: add accessible labels to contribution heatmap cells (#1709)
ramlal-01 May 31, 2026
d392904
fix: add descriptive aria-label to slide navigation dots (#1651) (#1715)
Asritha11111 May 31, 2026
706bb05
fix: make wrapped loading skeleton responsive (#1716)
Chakshu-Bamotra May 31, 2026
6352181
Fix repository name overflow (#1743)
Chakshu-Bamotra May 31, 2026
df0e9ff
fix(security): remove internal data from webhook POST response (#1718)
nyxsky404 May 31, 2026
78c3bbf
"feat: validate package subpath exports in check-deps" (#1719)
namrarafique93-del May 31, 2026
41978b3
fix: show native share button on desktop browsers with Web Share API …
Kokila-chandrakar May 31, 2026
d8c7f56
test: add unit tests for ssrf-protection module (#1731)
tmdeveloper007 May 31, 2026
05ddb0a
added warning (#1732)
indresh404 May 31, 2026
78a873b
feat: add fresh copy success toast for badge markdown (#1747)
codedbydollys10 May 31, 2026
c9d2760
fix: block direct progress updates on activity-derived goals (#1755)
Ridanshi May 31, 2026
f03c7f2
fix(data): include missing tables in account deletion handler (#1758)
nyxsky404 May 31, 2026
48a0154
fix: cap SSE connections per user and lengthen poll interval (#1763)
Ridanshi May 31, 2026
a13c637
fix: match sponsors on immutable github_id instead of mutable login (…
Ridanshi May 31, 2026
81e2688
fix: remove internal Supabase UUID from public profile API response (…
Ridanshi May 31, 2026
9878cb9
fix: validate repo parameter before cache and GitHub API calls (#1767)
Ridanshi May 31, 2026
dd5fead
test: add regression tests for local-coding API key auth mismatch (#1…
Ridanshi May 31, 2026
1059a51
test(resolve-user): add comprehensive unit tests (#1770)
aarushlohit May 31, 2026
955c30e
test(error-handler): add comprehensive unit tests (#1771)
aarushlohit May 31, 2026
15b475c
Fix/1461 gamification hooks tests (#1772)
omkhandare55 May 31, 2026
3e92e48
Fix/1463 contribution graph indexeddb cache (#1776)
omkhandare55 May 31, 2026
2d2868c
fix(middleware): resolve memory leak by adding passive bucket pruning…
ashishraj1504 May 31, 2026
9cf5476
fix: fail closed when CRON_SECRET is absent in WakaTime sync endpoint…
Ridanshi May 31, 2026
abda94b
test: add regression tests for weekly-digest cron auth bypass (#1745)…
Ridanshi May 31, 2026
d83cb7d
fix: invalidate leaderboard cache after visibility settings change (#…
Ridanshi May 31, 2026
f8115bd
test: add unit tests for repoAnalyticsUtils module (#1735)
tmdeveloper007 May 31, 2026
d08bf9c
test: add unit tests for string-utils module (#1736)
tmdeveloper007 May 31, 2026
af65ebe
test: add unit tests for redis-cache-helper module (#1737)
tmdeveloper007 May 31, 2026
ab4345f
test: add unit tests for goal-tracker module (#1738)
tmdeveloper007 May 31, 2026
ca300cd
feat(ui): Add Micro-Animations & Transitions for Dynamic Dashboard UX…
ArshVermaGit May 31, 2026
a455668
refactor: extract reusable ui primitives and standardize dashboard co…
ArshVermaGit May 31, 2026
1f891cd
fix: resolve JSX syntax errors and TypeScript type errors blocking CI
Priyanshu-byte-coder May 31, 2026
1a79fd0
fix: add missing @ducanh2912/next-pwa dependency to package.json
Priyanshu-byte-coder May 31, 2026
b8ca695
fix: remove misplaced page.tsx and RoomClient.tsx from api/rooms dire…
Priyanshu-byte-coder May 31, 2026
9ce5706
fix: escape apostrophe in DailyNoteWidget to fix ESLint error
Priyanshu-byte-coder May 31, 2026
73682c3
security: remove exposed credentials from .env.example and strip toke…
Priyanshu-byte-coder May 31, 2026
40ea375
fix: resolve API errors and browser warnings on dashboard
Priyanshu-byte-coder May 31, 2026
0501c2e
test: add unit tests for repoAnalytics module (#1845)
bhavyanjain3004 Jun 2, 2026
e82ba3a
test: add comprehensive edge-case unit tests for jira-utils (#1846)
bhavyanjain3004 Jun 2, 2026
430b21d
perf: replace timestamp-array rate limiter with sliding window counte…
Ridanshi Jun 2, 2026
6c2b12b
fix(navigation): replace a tags with Next.js Link components for SPA …
ArshVermaGit Jun 2, 2026
c5c91fe
fix(security): resolve ip extraction bypass in rate limiter and type …
ArshVermaGit Jun 2, 2026
754dd47
fix: Prevent Reverse Tabnabbing in Footer (#1860)
gowthamrdyy Jun 2, 2026
fd26bbd
fix: Prevent Reverse Tabnabbing in PRMetrics (#1861)
gowthamrdyy Jun 2, 2026
c7de1e0
fix(api): properly handle abort signals and controller state in SSE s…
ArshVermaGit Jun 2, 2026
8fc7742
fix: add accessible labels to icon-only buttons (#1706)
ramlal-01 Jun 2, 2026
54df9a3
fix: Prevent Reverse Tabnabbing in WrappedExperience (#1862)
gowthamrdyy Jun 2, 2026
37b7ece
Fix/1455 sanitize ai mentor widget (#1796)
omkhandare55 Jun 2, 2026
b06c8c0
fix: Enable Next.js React Strict Mode (#1858)
gowthamrdyy Jun 2, 2026
9c91a60
security: fix debug health endpoint information disclosure (#1816) (#…
Ridanshi Jun 2, 2026
01c00bb
feat: add coding time by hour heatmap widget(most productive hours) (…
MaitrayeeK Jun 2, 2026
0b72920
fix: store ai_insights with users.id and add FK + cascade delete (#1765)
Ridanshi Jun 2, 2026
5a8d24d
fix: Enforce pnpm Package Manager (#1859)
gowthamrdyy Jun 2, 2026
5d94241
fix(discord): add webhook validation and rate limit handling (#1863)
Devexhhh Jun 2, 2026
071c70d
test: add regression tests for Jira credential encryption at rest (#1…
Ridanshi Jun 2, 2026
afa0932
Fix/issue 1835 (#1836)
shankumar7 Jun 2, 2026
32e4efb
fix(tests): resolve api schema mismatch in user settings tests (#1833…
shankumar7 Jun 2, 2026
91b47db
Add a Gists stat chip to the profile header (#1830)
Muragesh-24 Jun 2, 2026
ac29a4d
fix(leaderboard): replace brittle composite string keys with absolute…
shankumar7 Jun 2, 2026
c8e4eaa
feat: add downloadable profile share card for social sharing (#1826)
Kokila-chandrakar Jun 2, 2026
8541db4
fix: reduce N+1 API queries in dashboard metrics endpoints (#1825)
AnushKamble Jun 2, 2026
81bfec0
fix: add SSRF protection and input validation to repo-analytics endpo…
AnushKamble Jun 2, 2026
673ed5f
feat: Implement AI-Powered Contribution Intelligence & Resume/CV Gene…
Divss72 Jun 2, 2026
90ba2ed
test: add comprehensive unit tests for webhooks module (#1721) (#1814)
aarushlohit Jun 2, 2026
d5b446d
feat: add dynamic OG meta tags for public profile pages (#1813)
bindhurapana-2828 Jun 2, 2026
866bd16
fix: calculate daily streak using user local timezone (#1811)
jahnavi-karanwal Jun 2, 2026
155f6d9
fix(navbar): implement missing navbar component (#1810)
mayurigade-hub Jun 2, 2026
22bbd75
fix: add keyboard navigation for wrapped slides (#1809)
Chakshu-Bamotra Jun 2, 2026
da52ed2
feat(settings): add theme preset selection support (#1850)
CyraTechZenith Jun 2, 2026
b1973c3
fix: add webhook_url to user settings test assertions (#1865)
Akshita-2307 Jun 2, 2026
76fc129
fix: redesign logout button to show text in light mode
Priyanshu-byte-coder Jun 2, 2026
bd97dfb
fix: harden IP and bound in-memory rate limiters (#1435) (#1685)
ionfwsrijan Jun 2, 2026
b7ac10e
feat: display Night Owl and Early Bird badges across dashboard header…
prakshithamalla-art Jun 2, 2026
05f2f05
feat: add sticky sidebar navigation for dashboard sections (#1607)
AaryanSingh31 Jun 2, 2026
17c6d24
perf: cache metrics api requests with 1 hour revalidation (#362)
YashKrTripathi Jun 2, 2026
adb9aee
fix: remove Windows-only @next/swc-win32-x64-msvc from dependencies
Priyanshu-byte-coder Jun 2, 2026
6e90c34
fix: resolve remaining TypeScript errors blocking CI
Priyanshu-byte-coder Jun 2, 2026
7dfa492
fix: resolve TypeScript and ESLint errors from merged PRs
Priyanshu-byte-coder Jun 2, 2026
a759940
fix: remove invalid pnpm-workspace.yaml blocking Vercel deployment
Priyanshu-byte-coder Jun 2, 2026
be2749a
fix: remove @emnapi/core and @emnapi/runtime from pnpm-lock.yaml impo…
Priyanshu-byte-coder Jun 2, 2026
1b5e869
fix(dashboard): remove widgets incorrectly nested inside quick-action…
Priyanshu-byte-coder Jun 2, 2026
dc860ce
fix(github): detect rate limits using response headers
Ridanshi Jun 2, 2026
af623f0
fix(goals): preserve recurring goal history on reset
Ridanshi Jun 2, 2026
e12d438
fix(cron): track actual weekly digest delivery results
Ridanshi Jun 2, 2026
19ed959
fix(security): add CSRF protection for state-changing routes
Ridanshi Jun 2, 2026
77a86c2
fix(security): add CSRF protection for state-changing routes
Ridanshi Jun 2, 2026
fab5e16
fix(security): add CSRF protection for state-changing routes
Ridanshi Jun 2, 2026
7eede68
fix(security): add CSRF protection for state-changing routes
Ridanshi Jun 2, 2026
8cfd578
fix(security): add CSRF protection for state-changing routes
Ridanshi Jun 2, 2026
c3f4c6b
fix(security): add CSRF protection for state-changing routes
Ridanshi Jun 2, 2026
3d7d247
test(response-cache): add comprehensive utility coverage
Ridanshi Jun 2, 2026
af9bad7
fix(date-utils): restore expected dateDiffDays export
Ridanshi Jun 2, 2026
3a4c536
fix(daily-focus): persist Today's Focus server-side
Ridanshi Jun 2, 2026
c698b61
fix(github-auth): propagate token-expired errors across remaining met…
Ridanshi Jun 2, 2026
4d8f0f5
fix(github-auth): complete token-revocation handling in remaining wid…
Ridanshi Jun 2, 2026
08cd9c4
fix(stream): prevent unbounded SSE polling load
Ridanshi Jun 2, 2026
d973cda
fix(auth): surface GitHub token expiry instead of silent failures
Ridanshi Jun 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -------------------------------------------------------
# Supabase
# Project Settings → API → Project URL
NEXT_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co

# Project Settings → API → anon / public key
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
Expand All @@ -22,6 +22,14 @@ NEXTAUTH_URL=http://localhost:3000
# Must not have a trailing slash.
# NEXT_PUBLIC_APP_URL=https://devtrack-delta.vercel.app

# -------------------------------------------------------
# CSRF protection — allowed origins for state-changing API requests
# (optional — NEXTAUTH_URL is always included automatically)
# Comma-separated list of additional origins permitted to make authenticated
# mutations. Add preview / staging deployments here.
# Example: ALLOWED_ORIGINS=https://staging.devtrack.app,https://preview.devtrack.app
# ALLOWED_ORIGINS=

# Generate with: openssl rand -base64 32
NEXTAUTH_SECRET=your_nextauth_secret

Expand Down Expand Up @@ -66,7 +74,7 @@ UPSTASH_REDIS_REST_TOKEN=your_upstash_redis_rest_token
# Groq API Key (optional — enables AI-generated weekly summaries in the
# AI Mentor widget using Llama-3).
# console.groq.com → API Keys
GROQ_API_KEY=gsk_...
GROQ_API_KEY=your_groq_api_key

# -------------------------------------------------------
# Leaderboard Configuration
Expand All @@ -75,4 +83,3 @@ GROQ_API_KEY=gsk_...
# Higher values = faster builds but more resource usage
# WARNING: Do not exceed 100 without load testing — risks memory exhaustion
LEADERBOARD_USER_CONCURRENCY=5

18 changes: 15 additions & 3 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ jobs:
runs-on: ubuntu-latest
env:
NEXTAUTH_SECRET: test-nextauth-secret-for-playwright-tests
NEXTAUTH_URL: http://127.0.0.1:3000
NEXT_PUBLIC_APP_URL: http://127.0.0.1:3000
NEXTAUTH_URL: http://127.0.0.1:3002
NEXT_PUBLIC_APP_URL: http://127.0.0.1:3002
GITHUB_ID: playwright-github-id
GITHUB_SECRET: playwright-github-secret
NEXT_PUBLIC_SUPABASE_URL: https://placeholder.supabase.co
Expand All @@ -37,7 +37,19 @@ jobs:
run: npm ci

- name: Build Next.js app
run: npm run build
run: |
cat <<EOF > .env.production
NEXTAUTH_SECRET=test-nextauth-secret-for-playwright-tests
NEXTAUTH_URL=http://127.0.0.1:3000
NEXT_PUBLIC_APP_URL=http://127.0.0.1:3000
GITHUB_ID=playwright-github-id
GITHUB_SECRET=playwright-github-secret
NEXT_PUBLIC_SUPABASE_URL=https://placeholder.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=placeholder-anon-key
SUPABASE_SERVICE_ROLE_KEY=placeholder-service-role-key
PLAYWRIGHT_SERVER_MODE=start
EOF
npm run build

- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,19 @@ on:
pull_request_target:
jobs:
label:
if: github.event.pull_request.head.repo.full_name == github.repository
permissions:
contents: read
pull-requests: write
issues: write
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/labeler@v5
continue-on-error: true
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: .github/labeler.yml
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ out/
# Environment files — NEVER commit these
.env
.env.local
.env.local*
.env.production
.env.*.local

Expand Down
5 changes: 3 additions & 2 deletions e2e/dashboard-widgets.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ test("dashboard widgets render with mocked metrics", async ({ page }) => {
await expect(page.getByRole("heading", { name: /dashboard/i })).toBeVisible({ timeout: 30000 });
await expect(page.getByRole("heading", { name: "Your Commits" })).toBeVisible({ timeout: 10000 });
await expect(page.getByRole("heading", { name: "PR Analytics" })).toBeVisible({ timeout: 10000 });
await expect(page.getByRole("heading", { name: "Goals" })).toBeVisible({ timeout: 10000 });
await expect(page.getByRole("heading", { name: "Goals", exact: true })).toBeVisible({ timeout: 10000 });
await expect(page.getByText("Make 10 commits")).toBeVisible({ timeout: 10000 });
});

Expand All @@ -193,6 +193,7 @@ test("contribution graph range buttons request a new range", async ({ page }) =>

await page.goto("/dashboard", { waitUntil: "load" });
await expect(page.getByRole("heading", { name: /dashboard/i })).toBeVisible({ timeout: 30000 });
await page.getByRole("button", { name: "Show 90-day range" }).first().click();
await page
.locator("#contribution-activity")
.getByRole("button", { name: "Show 90-day range" })
Expand All @@ -214,7 +215,7 @@ test("goal form posts a new goal", async ({ page }) => {
await page.getByLabel("Goal title").fill("Ship one PR");
await page.getByLabel("Target").fill("1");
await page.getByLabel("Unit").selectOption("prs");
await page.getByRole("button", { name: "Add goal" }).click();
await page.getByRole("button", { name: "Create goal" }).click();

await expect.poll(() => goalPosts, { timeout: 15000 }).toHaveLength(1);
expect(goalPosts[0]).toMatchObject({
Expand Down
5 changes: 3 additions & 2 deletions e2e/landing.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ test("[Landing E2E] landing has dashboard link", async ({ page }) => {
await expect(page.getByRole("link", { name: "Dashboard" })).toBeVisible();
});

test("[Landing E2E] landing shows footer via test-id", async ({ page }) => {
test("[Landing E2E] landing shows footer", async ({ page }) => {
await page.goto("/");
await expect(page.locator('[data-testid="landing-footer"]')).toBeVisible();
// Check that the global footer is rendered (e.g. looking for the copyright text)
await expect(page.getByText(/DevTrack. Built for open-source contributors/i)).toBeVisible();
});
3 changes: 1 addition & 2 deletions e2e/notifications.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { expect, test } from "@playwright/test";
import { encode } from "next-auth/jwt";

const authSecret =
process.env.NEXTAUTH_SECRET ||
"test-nextauth-secret-for-playwright-tests";
process.env.NEXTAUTH_SECRET || "test-nextauth-secret-for-playwright-tests";

/** Returns a properly-shaped mock response for each metric endpoint. */
function mockMetricResponse(url) {
Expand Down
50 changes: 45 additions & 5 deletions e2e/theme.spec.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { expect, test } from "@playwright/test";
import { encode } from "next-auth/jwt";

test.beforeEach(async ({ page }) => {
const authSecret =
process.env.NEXTAUTH_SECRET ||
"test-nextauth-secret-for-playwright-tests";
const authSecret =
process.env.NEXTAUTH_SECRET ||
"test-nextauth-secret-for-playwright-tests";

test.beforeEach(async ({ page }) => {
const token = await encode({
secret: authSecret,
token: {
Expand All @@ -27,6 +27,7 @@ test.beforeEach(async ({ page }) => {
httpOnly: true,
sameSite: "Lax",
secure: false,
expires: Math.floor(Date.now() / 1000) + 60 * 60,
},
]);

Expand Down Expand Up @@ -54,15 +55,54 @@ test.beforeEach(async ({ page }) => {
test("theme toggle switches between dark and light mode", async ({ page }) => {
await page.goto("/dashboard");

const themeToggle = page.getByRole("button", { name: "Toggle theme" });
// The DashboardHeader provides the ThemeToggle on the dashboard
const themeToggle = page.getByRole("button", { name: "Toggle theme" }).first();
await expect(themeToggle).toBeVisible();

const initialPressed = await themeToggle.getAttribute("aria-pressed");

await themeToggle.click({ force: true });

await expect(themeToggle).toHaveAttribute(
"aria-pressed",
initialPressed === "true" ? "false" : "true"
);
});

/**
* Issue #964: Public profile page should have a theme toggle.
* The toggle must work without login and persist to localStorage.
* We navigate to the profile-not-found page because no real user exists
* in the test DB — but the layout (ThemeProvider + ThemeToggle) still renders.
*/
test("public profile page theme toggle works without authentication", async ({
page,
}) => {
// Clear cookies so visitor is unauthenticated
await page.context().clearCookies();

// Navigate to any public profile URL — will show "Profile Not Found"
// but the full layout (including ThemeToggle) still renders
await page.goto("/u/no-such-user-for-e2e-test", { waitUntil: "load" });

// Confirm we're on the public profile route (no auth redirect)
await expect(page).toHaveURL(/\/u\//);

// ThemeToggle must be present in the AppNavbar and functional without login
const themeToggle = page.getByRole("banner").getByRole("button", { name: "Toggle theme" });
await expect(themeToggle).toBeVisible({ timeout: 10000 });

const initialPressed = await themeToggle.getAttribute("aria-pressed");

await themeToggle.click();

// Toggle state must have flipped
await expect(themeToggle).toHaveAttribute(
"aria-pressed",
initialPressed === "true" ? "false" : "true"
);

// Theme preference must be persisted to localStorage
const stored = await page.evaluate(() => localStorage.getItem("theme"));
expect(stored === "dark" || stored === "light").toBe(true);
});
3 changes: 2 additions & 1 deletion next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import withPWAInit from "next-pwa";
import withPWAInit from "@ducanh2912/next-pwa";

const withPWA = withPWAInit({
dest: "public",
Expand Down Expand Up @@ -129,6 +129,7 @@ const withPWA = withPWAInit({

/** @type {import("next").NextConfig} */
const nextConfig = {
reactStrictMode: true,
output: "standalone",
images: {
remotePatterns: [
Expand Down
Loading
Loading