Skip to content

feat: implement GET /submissions/mine and GET /submissions/:id endpoints (#27, #28)#101

Open
chengfei-gh wants to merge 1 commit intodevasignhq:mainfrom
chengfei-gh:feat/submissions-endpoints
Open

feat: implement GET /submissions/mine and GET /submissions/:id endpoints (#27, #28)#101
chengfei-gh wants to merge 1 commit intodevasignhq:mainfrom
chengfei-gh:feat/submissions-endpoints

Conversation

@chengfei-gh
Copy link

Summary

Implements two new authenticated API endpoints for the submissions system:

GET /api/submissions/mine

  • Returns paginated list of authenticated user's submissions
  • Includes bounty title, status, PR URL, and creation date
  • Supports limit and offset query parameters (default: limit=10, max=100)

GET /api/submissions/:id

  • Returns full submission details including review status
  • Includes rejection reason (if any) and associated dispute info
  • Enforces ownership: only the submission creator can view details
  • Returns 403 if user doesn't own the submission

Implementation Details

  • Route module: packages/api/src/routes/submissions.ts — clean Hono router following existing patterns
  • Tests: packages/api/src/__tests__/submissions.test.ts — comprehensive tests covering happy path, pagination, auth, 403/404 cases
  • Registration: Updated packages/api/src/app.ts to mount submissions router at /api/submissions

Testing

Run with: cd packages/api && npm test

Closes

Payment

Solana Wallet: CZkLs4m55JBffoowGUtyfqb5GrymUVxgr9kMTrXKfbJV

Closes devasignhq#27
Closes devasignhq#28

Implements two new authenticated API endpoints:

## GET /api/submissions/mine
- Returns paginated list of authenticated user's submissions
- Includes bounty title, status, PR URL, and creation date
- Supports cursor-style limit/offset pagination

## GET /api/submissions/:id
- Returns full submission details including review status
- Includes rejection reason (if any) and associated dispute info
- Enforces ownership: only the submission creator can view details

## Files added/changed:
- packages/api/src/routes/submissions.ts (new route module)
- packages/api/src/__tests__/submissions.test.ts (comprehensive tests)
- packages/api/src/app.ts (register submissions route)

Solana Wallet: CZkLs4m55JBffoowGUtyfqb5GrymUVxgr9kMTrXKfbJV
@devasign-app
Copy link

devasign-app bot commented Mar 18, 2026

Merge Score: 88/100

🟢 ██████████████████░░ 88%

The PR successfully implements the required submission endpoints with excellent test coverage and proper authorization checks. A few minor improvements are suggested: handling potential NaN values in pagination parameters, optimizing database queries by running them concurrently, and ensuring consistency with user ID properties.

Code Suggestions (4)

Medium Priority (1)

  1. packages/api/src/routes/submissions.ts (Line 20)
    Handle potential NaN values when parsing pagination query parameters.

Reasoning: If a user provides a non-numeric string for limit or offset (e.g., ?limit=abc), parseInt will return NaN. Math.min(NaN, 100) results in NaN, which will cause the database query to fail or throw an error. Adding an isNaN check prevents this. Alternatively, consider using @hono/zod-validator for robust validation as seen in other routes.

Suggested Code:

    const query = c.req.query();
    const parsedLimit = parseInt(query.limit || '10', 10);
    const parsedOffset = parseInt(query.offset || '0', 10);
    const limit = isNaN(parsedLimit) ? 10 : Math.min(parsedLimit, 100);
    const offset = isNaN(parsedOffset) ? 0 : Math.max(parsedOffset, 0);

Low Priority (3)

  1. packages/api/src/routes/submissions.ts (Line 82)
    Fetch the bounty and related disputes concurrently.

Reasoning: The queries for bounty and relatedDisputes do not depend on each other. Running them concurrently using Promise.all reduces the overall response time by saving one database roundtrip.

Suggested Code:

    // Fetch associated bounty info and disputes concurrently
    const [bounty, relatedDisputes] = await Promise.all([
        db.query.bounties.findFirst({
            where: eq(bounties.id, submission.bountyId),
        }),
        db.query.disputes.findMany({
            where: eq(disputes.submissionId, id),
            orderBy: [desc(disputes.createdAt)],
        })
    ]);
  1. packages/api/src/routes/submissions.ts (Line 36)
    Use user.id as a fallback or primary identifier to maintain consistency with other routes.

Reasoning: In other routes (e.g., tasks.ts), user.id is used to identify the user (eq(bounties.assigneeId, user.id)). Depending on how the JWT middleware populates the user object, relying solely on user.sub might lead to inconsistencies. Using user.id || user.sub is safer.

Suggested Code:

        .where(eq(submissions.developerId, user.id || user.sub))
  1. packages/api/src/routes/submissions.ts (Line 5)
    Remove unused and import from drizzle-orm.

Reasoning: Keeping imports clean improves code readability and maintainability.

Suggested Code:

import { eq, desc } from 'drizzle-orm';
📊 Review Metadata
  • Processing Time: 62s
  • Analysis Date: 3/18/2026, 6:33:57 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.

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 /submissions/:id — submission detail Implement GET /submissions/mine — submission history

1 participant