Skip to content

feat: Sprint Management Dashboard - Bounty #14 - #31

Open
zhaog100 wants to merge 2 commits into
ubiquity-os:mainfrom
zhaog100:feat/sprint-dashboard
Open

feat: Sprint Management Dashboard - Bounty #14#31
zhaog100 wants to merge 2 commits into
ubiquity-os:mainfrom
zhaog100:feat/sprint-dashboard

Conversation

@zhaog100

@zhaog100 zhaog100 commented Apr 9, 2026

Copy link
Copy Markdown

Closes #14

Sprint Management Dashboard ($1,800 Bounty)

Features

  1. Landing Page — Marketing conversion page with GitHub OAuth
  2. Sprint Dashboard — Calendar view with team member task assignments
  3. Priority System — Tinder-like swipe interface for task prioritization
  4. AI Sprint Planning — Auto-assign tasks based on skills/availability
  5. Metrics — Time/cost savings calculator
  6. Task Import — From GitHub org repos (+ Asana placeholder)

Tech Stack

  • Next.js 14 + TypeScript + Tailwind CSS
  • GitHub OAuth (NextAuth.js)
  • REST API routes

Files Created (18 files, 1396 lines)

  • Backend API routes: auth, org sync, sprint planning, metrics
  • Frontend: landing page, dashboard, calendar, priority swiper, metrics panel, task import
  • Config: package.json, next.config.js, tailwind, tsconfig, .env.example, README

@coderabbitai

coderabbitai Bot commented Apr 9, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@zhaog100 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 58 minutes and 10 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 58 minutes and 10 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, 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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0f14b657-fd36-4f55-9d90-735088c95dbf

📥 Commits

Reviewing files that changed from the base of the PR and between 4b0917c and 863a59a.

📒 Files selected for processing (8)
  • dashboard/package.json
  • dashboard/src/app/api/auth/[...nextauth]/route.ts
  • dashboard/src/app/api/metrics/route.ts
  • dashboard/src/app/api/org/sync/route.ts
  • dashboard/src/app/api/sprint/plan/route.ts
  • dashboard/src/app/dashboard/page.tsx
  • dashboard/src/components/MetricsPanel.tsx
  • dashboard/src/components/TaskImport.tsx
📝 Walkthrough

Walkthrough

This pull request introduces a complete Sprint Management Dashboard application. It includes a Next.js 14 frontend with TypeScript, Tailwind CSS styling, and NextAuth.js for GitHub OAuth authentication. The backend provides API routes for syncing GitHub organization repositories and issues as tasks, generating AI-powered sprint assignments via OpenAI-compatible APIs with fallback heuristics, and computing time/cost savings metrics. The UI features a landing page with sign-in, a dashboard with calendar view for team assignments, a Tinder-like swipe interface for task prioritization, metrics visualization, and GitHub task import functionality. Configuration files, type definitions, and styling are included.

🚥 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
Title check ✅ Passed The PR title clearly identifies the feature (Sprint Management Dashboard) and references the linked bounty issue (#14). It is specific and directly describes the primary deliverable.
Description check ✅ Passed The PR description directly relates to the changeset, listing all six major features, tech stack, and file counts. It provides relevant context for understanding the implementation scope.
Linked Issues check ✅ Passed The PR implements all core coding requirements from issue #14: GitHub OAuth landing page, calendar task assignments, Tinder-like priority swipe UI, AI sprint planning, time/cost metrics, and GitHub task import. All specified features are present.
Out of Scope Changes check ✅ Passed All changes directly support the Sprint Management Dashboard scope defined in issue #14. No unrelated features or out-of-scope modifications were introduced.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 16

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (5)
dashboard/.env.example-8-8 (1)

8-8: ⚠️ Potential issue | 🟡 Minor

Use a non-secret-looking placeholder for OPENAI_API_KEY.

sk-... often trips secret scanners in example files. A placeholder like your_openai_api_key_here avoids noisy alerts.

dashboard/README.md-77-101 (1)

77-101: ⚠️ Potential issue | 🟡 Minor

Add a language tag to the fenced code block.

The architecture block should use a language identifier (for example, text) to satisfy markdownlint MD040.

Proposed fix
-```
+```text
 dashboard/
 ├── src/
 │   ├── app/
 ...
 └── .env.example
</details>

</blockquote></details>
<details>
<summary>dashboard/src/components/PrioritySwiper.tsx-142-144 (1)</summary><blockquote>

`142-144`: _⚠️ Potential issue_ | _🟡 Minor_

**Emoji mismatch in helper text.**

Button uses 👎 for Low but helper text shows "👍 Low".


```diff
-      👍 Low · ⭐ High · 🔥 Urgent
+      👎 Low · ⭐ High · 🔥 Urgent
dashboard/src/components/PrioritySwiper.tsx-30-41 (1)

30-41: ⚠️ Potential issue | 🟡 Minor

Rapid-click vulnerability during animation.

User can click multiple priority buttons before the 300ms timeout advances the index, causing multiple onSetPriority calls for the same task with different priorities.

Proposed fix — guard against re-entry
   const handleSwipe = useCallback(
     (priority: "low" | "high" | "urgent") => {
-      if (!task) return;
+      if (!task || anim) return; // block while animating
       setAnim(priority === "low" ? "left" : "right");
       onSetPriority(task.id, priority);
       setTimeout(() => {
         setAnim(null);
         setIndex((i) => i + 1);
       }, 300);
     },
-    [task, onSetPriority]
+    [task, anim, onSetPriority]
   );
dashboard/src/components/PrioritySwiper.tsx-53-53 (1)

53-53: ⚠️ Potential issue | 🟡 Minor

Dead code — labels variable is unused.

Line 89 calls label.toLowerCase() inline instead.

-  const labels = task.labels.map((l) => l.toLowerCase());
🧹 Nitpick comments (3)
dashboard/src/app/page.tsx (1)

1-10: Keep the landing page server-rendered.

The page is almost entirely static, but use client + hovered forces the whole marketing page to hydrate. Move the GitHub CTA into a small client component and handle the hover effect with CSS classes.

Also applies to: 40-48

dashboard/src/app/dashboard/page.tsx (1)

35-41: Hardcoded team members — acceptable for prototype.

For production, fetch members dynamically from the org. The current approach works for the demo scope.

dashboard/src/components/PrioritySwiper.tsx (1)

9-22: Type duplication with Task in page.tsx.

TaskItem is nearly identical to the Task interface in the dashboard page. Consider extracting to a shared types file to avoid drift.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9d0350f9-7bf3-4ee9-81e2-18763a2e3efb

📥 Commits

Reviewing files that changed from the base of the PR and between 313b29c and 4b0917c.

📒 Files selected for processing (18)
  • dashboard/.env.example
  • dashboard/README.md
  • dashboard/next.config.js
  • dashboard/package.json
  • dashboard/src/app/api/auth/[...nextauth]/route.ts
  • dashboard/src/app/api/metrics/route.ts
  • dashboard/src/app/api/org/sync/route.ts
  • dashboard/src/app/api/sprint/plan/route.ts
  • dashboard/src/app/dashboard/page.tsx
  • dashboard/src/app/globals.css
  • dashboard/src/app/layout.tsx
  • dashboard/src/app/page.tsx
  • dashboard/src/components/CalendarView.tsx
  • dashboard/src/components/MetricsPanel.tsx
  • dashboard/src/components/PrioritySwiper.tsx
  • dashboard/src/components/TaskImport.tsx
  • dashboard/tailwind.config.ts
  • dashboard/tsconfig.json

Comment thread dashboard/package.json Outdated
Comment thread dashboard/src/app/api/auth/[...nextauth]/route.ts Outdated
Comment thread dashboard/src/app/api/auth/[...nextauth]/route.ts
Comment thread dashboard/src/app/api/metrics/route.ts
Comment thread dashboard/src/app/api/metrics/route.ts Outdated
Comment on lines +10 to +12
const { totalTasks, assignedByAI } = (await req.json()) as {
totalTasks: number;
assignedByAI: number;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

assignedByAI is not actually “AI” today.

In dashboard/src/app/dashboard/page.tsx, Lines 100-101 send the count of all assigned tasks, and /api/sprint/plan can still return method: "heuristic" in Lines 50-56. That means fallback plans report full AI savings here.

Comment on lines +50 to +56
try {
const res = await fetch("/api/org/sync", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ org, accessToken: token }),
});
const data = await res.json();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing error handling for failed API response.

If /api/org/sync returns an error status, data.tasks will be undefined and the import silently fails with no user feedback.

Proposed fix
       const res = await fetch("/api/org/sync", {
         method: "POST",
         headers: { "Content-Type": "application/json" },
         body: JSON.stringify({ org, accessToken: token }),
       });
+      if (!res.ok) {
+        const err = await res.json().catch(() => ({}));
+        throw new Error(err.error ?? `Sync failed: ${res.status}`);
+      }
       const data = await res.json();

Consider adding an error state and displaying it to the user.

📝 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
try {
const res = await fetch("/api/org/sync", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ org, accessToken: token }),
});
const data = await res.json();
try {
const res = await fetch("/api/org/sync", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ org, accessToken: token }),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(err.error ?? `Sync failed: ${res.status}`);
}
const data = await res.json();

Comment thread dashboard/src/app/dashboard/page.tsx
Comment thread dashboard/src/components/MetricsPanel.tsx
Comment thread dashboard/src/components/TaskImport.tsx Outdated
Comment on lines +63 to +70
<label className="block text-xs text-gray-500 mb-1">GitHub Token</label>
<input
type="password"
value={token}
onChange={(e) => setToken(e.target.value)}
placeholder="ghp_..."
className="w-full px-3 py-2 text-sm bg-gray-800 border border-gray-700 rounded-lg focus:outline-none focus:ring-1 focus:ring-brand-500 placeholder:text-gray-600"
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Minimize PAT collection in the browser UI.

Prompting users to paste personal access tokens increases credential exposure risk. Prefer using the authenticated OAuth session server-side for org sync calls.

Also applies to: 105-107

- Add eslint and eslint-config-next devDependencies
- Validate OAuth env vars at startup with clear error messages
- Remove accessToken from client-side session (security)
- Add input validation and bounds checking in /api/metrics
- Return structured warnings for partial sync failures in /api/org/sync
- Add auth requirement to /api/sprint/plan endpoint
- Add 30s timeout to upstream AI call via AbortSignal
- Validate AI model output (known members/task IDs only)
- Add error handling for fetch responses in dashboard page
- Add error state in MetricsPanel component
- Require token before submit in TaskImport form
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.

UbiquityOS Sprint Management Dashboard

1 participant