Skip to content

feat(api): enrich GET /bounties/:id with creator, assignee, and application count#91

Open
automaton365-sys wants to merge 3 commits intodevasignhq:mainfrom
automaton365-sys:feat/issue-21-bounty-detail
Open

feat(api): enrich GET /bounties/:id with creator, assignee, and application count#91
automaton365-sys wants to merge 3 commits intodevasignhq:mainfrom
automaton365-sys:feat/issue-21-bounty-detail

Conversation

@automaton365-sys
Copy link

Fixes #21

Changes

  • Enriched the GET /bounties/:id endpoint to return creator info (username, avatar), assignee info, and application count
  • Added test coverage for the bounty detail endpoint

/claim #21

@devasign-app
Copy link

devasign-app bot commented Mar 3, 2026

🟠 AI Code Review Results

Status: Changes Needed
Confidence: 95%


🟠 Merge Score: 65/100

🔴 █████████████░░░░░░░ 65%

Recommendation: ❌ This PR needs significant improvements before it should be merged.

The PR successfully enriches the bounty detail endpoint and adds good test coverage. However, there is a critical performance issue in how the application count is calculated that must be addressed before merging. A minor code redundancy was also found.

💡 Code Suggestions (1)

🔴 High Priority (1)

  1. packages/api/src/routes/bounties.ts (Line 129)
    ⚡ The handler for GET /api/bounties/:id inefficiently calculates application_count by fetching all application records from the database. It also contains a redundant status field in the returned JSON object.

💭 Reasoning: Loading all related application records into memory just to get a count scales poorly and will cause performance degradation on bounties with many applicants. Using a database-level aggregation (e.g., a subquery with COUNT(*)) is significantly more efficient. Additionally, removing redundant code improves clarity and maintainability.

Suggested Code:

bountiesRouter.get('/:id', async (c) => {
    const id = c.req.param('id');

    const bounty = await db.query.bounties.findFirst({
        where: eq(bounties.id, id),
        columns: {
            id: true,
            githubIssueId: true,
            repoOwner: true,
            repoName: true,
            title: true,
            description: true,
            amountUsdc: true,
            techTags: true,
            difficulty: true,
            status: true,
            deadline: true,
            creatorId: true,
            assigneeId: true,
            createdAt: true,
            updatedAt: true,
        },
        with: {
            creator: {
                columns: {
                    id: true,
                    username: true,
                    avatarUrl: true,
                },
            },
            assignee: {
                columns: {
                    id: true,
                    username: true,
                    avatarUrl: true,
                },
            },
        },
        extras: {
            application_count: sql<number>`(SELECT count(*) FROM ${applications} WHERE ${applications.bountyId} = ${bounties.id})`.as('application_count'),
        },
    });

    if (!bounty) {
        return c.json({ error: 'Bounty not found' }, 404);
    }

    const { creator, assignee, ...base } = bounty;

    return c.json({
        ...base,
        creator: creator
            ? {
                id: creator.id,
                username: creator.username,
                avatar: creator.avatarUrl,
            }
            : null,
        assignee: assignee
            ? {
                id: assignee.id,
                username: assignee.username,
                avatar: assignee.avatarUrl,
            }
            : null,
    });
});
📊 Review Metadata
  • Processing Time: 158s
  • Analysis Date: 3/3/2026, 7:51:26 PM

🤖 This review was generated by AI. While we strive for accuracy, please use your judgment when applying suggestions.

💬 Questions about this review? Open an issue or contact support.

@devasign-app
Copy link

devasign-app bot commented Mar 3, 2026

❌ PR Review Failed


Error Details

The PR review system encountered an error while analyzing this pull request:

Follow-up review failed: Gemini API rate limit exceeded. Please review manually.

What to do next

  1. Manual Review: Please proceed with manual code review
  2. Retry: A review can be triggered by the repo maintainer commenting 'review'
  3. Support: If this error persists, please contact support

🤖 This is an automated error message from the PR review system.

💬 Need help? Open an issue or contact support.

@automaton365-sys
Copy link
Author

Updated tests per review:

  • Mocked db.select().from().where() count-query chain used by the optimized route
  • Switched assertions to applicationCount
  • Aligned nested user fields to avatarUrl

Validation run:
JWT_PUBLIC_KEY=test npx vitest run src/__tests__/bounty_detail.test.ts
Passed (3/3).

@devasign-app
Copy link

devasign-app bot commented Mar 3, 2026

🔄 Follow-Up AI Code Review

Status: Ready to Merge
Confidence: 100%


🟢 Updated Merge Score: 95/100

🟢 ███████████████████░ 95%

Recommendation: ✅ This PR looks great and is ready for merge!

📋 Previous Review Summary

The PR successfully enriches the bounty detail endpoint and adds good test coverage. However, there is a critical performance issue in how the application count is calculated that must be addressed before merging. A minor code redundancy was also found.

Excellent work addressing the previous feedback. The critical performance issue with the application count has been resolved effectively by using a direct database count query. The code has also been refactored to be much cleaner and more maintainable. The PR is in great shape. I've added one minor, non-blocking suggestion to parallelize the database queries for a small performance gain.

💡 Code Suggestions (1)

🔵 Low Priority (1)

  1. packages/api/src/routes/bounties.ts (Line 131)
    ⚡ The two database queries to fetch the bounty details and the application count are currently executed sequentially. They can be run in parallel using Promise.all to slightly improve the endpoint's response time, especially under high database latency.

💭 Reasoning: Running independent database queries in parallel reduces the total wait time to the duration of the longest query, rather than the sum of both queries' durations. This makes the endpoint more resilient to database load and slightly faster.

Suggested Code:

    const [bounty, [{ count: applicationCount }]] = await Promise.all([
        db.query.bounties.findFirst({
            where: eq(bounties.id, id),
            with: {
                creator: {
                    columns: {
                        username: true,
                        avatarUrl: true,
                    },
                },
                assignee: {
                    columns: {
                        id: true,
                        username: true,
                        avatarUrl: true,
                    },
                },
            },
        }),
        db.select({ count: count() }).from(applications).where(eq(applications.bountyId, id)),
    ]);

    if (!bounty) {
        return c.json({ error: 'Bounty not found' }, 404);
    }

    return c.json({
        ...bounty,
        applicationCount,
    });
📊 Review Metadata
  • Processing Time: 174s
  • Analysis Date: 3/3/2026, 9:08:34 PM
  • Review Type: Follow-Up (triggered by new push)

🤖 This is a follow-up review generated after new commits were pushed to the PR.

💬 Questions? Open an issue or contact support.

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 GET /bounties/:id — bounty detail

1 participant