Skip to content

Feat/nfc payload endpoint#189

Open
Midoriya-w wants to merge 8 commits into
Dev-Card:mainfrom
Midoriya-w:feat/nfc-payload-endpoint
Open

Feat/nfc payload endpoint#189
Midoriya-w wants to merge 8 commits into
Dev-Card:mainfrom
Midoriya-w:feat/nfc-payload-endpoint

Conversation

@Midoriya-w
Copy link
Copy Markdown

Closes #35

Changes:

  • Added apps/backend/src/routes/nfc.ts with:
    • GET /api/nfc/payload returns NDEF URI payload for user's default DevCard URL
    • GET /api/nfc/payload?card= returns card-specific URL with ownership validation
    • Returns 403 if cardId doesn't belong to authenticated user
    • Returns 404 if user or card not found
  • Registered route in apps/backend/src/app.ts at prefix /api/nfc
  • Follows existing Fastify route pattern with preHandler: app.authenticate

@ShantKhatri ShantKhatri requested a review from Harxhit May 20, 2026 09:31
@Harxhit Harxhit added the gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking. label May 20, 2026
Comment thread apps/backend/src/routes/nfc.ts Outdated

let username: string;

// Get username from user profile
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Error handling around the DB logic should be improved here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Wrapped the user fetch in try/catch with request.log.error logging and returns 500 with a clear error message if DB fails.

Comment thread apps/backend/src/routes/nfc.ts Outdated
// GET /api/nfc/payload?card=<cardId> — returns payload for a specific card
app.get('/payload', async (request: FastifyRequest<{ Querystring: { card?: string } }>, reply: FastifyReply) => {
const userId = (request.user as any).id;
const { card: cardId } = request.query;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could we validate the query params with Zod here it can be more robust.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added a Zod schema nfcQuerySchema with safeParse to validate query params returns 400 with flattened error details if invalid.

Comment thread apps/backend/src/routes/nfc.ts Outdated

if (cardId) {
// Validate card belongs to authenticated user
const card = await app.prisma.card.findUnique({
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could error handling can be improved here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Wrapped card fetch in its own try/catch returns 404 if card not found, 403 if ownership mismatch, and 500 with request.log.error logging if DB fails.

Comment thread apps/backend/src/routes/nfc.ts Outdated
});
}

return reply.send({
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Typed response schema is missing here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Adding a typed response interface now will push the fix shortly!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please add typed response here.

Comment thread apps/backend/src/routes/nfc.ts Outdated

return reply.send({
type: 'URI',
payload: `https://devcard.dev/${username}`,
Copy link
Copy Markdown
Collaborator

@Harxhit Harxhit May 20, 2026

Choose a reason for hiding this comment

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

Typed response schema missing here?

@Harxhit
Copy link
Copy Markdown
Collaborator

Harxhit commented May 20, 2026

@Midoriya-w Your PR have merge conflicts.

@Midoriya-w
Copy link
Copy Markdown
Author

Good catch! Adding a typed response interface now.

@Midoriya-w
Copy link
Copy Markdown
Author

Hey @Harxhit! Resolved the merge conflicts in app.ts kept both nfcRoutes and eventRoutes registrations. Also addressed all review comments. Could you re-review when you get a chance?

@Midoriya-w Midoriya-w requested a review from Harxhit May 20, 2026 10:48
@Midoriya-w
Copy link
Copy Markdown
Author

Added NfcPayloadResponse type and updated both reply.send calls to reply.send() for full type safety.

Comment thread apps/backend/src/routes/cards.ts Outdated
@@ -1,4 +1,4 @@
import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
Dimport type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Dimport?

Copy link
Copy Markdown
Author

@Midoriya-w Midoriya-w May 20, 2026

Choose a reason for hiding this comment

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

Fixed, removed the accidental D from the import statement.

@Harxhit
Copy link
Copy Markdown
Collaborator

Harxhit commented May 20, 2026

@Midoriya-w Could you please add proofs for test in the PR descriptions.

@Midoriya-w
Copy link
Copy Markdown
Author

Test Evidence

"Endpoint: GET /api/nfc/payload"

  • Returns { type: 'URI', payload: 'https://devcard.dev/<username>' } for authenticated user

"Endpoint: GET /api/nfc/payload?card="

  • Returns card-specific URL if card belongs to user
  • Returns 403 if card belongs to different user
  • Returns 404 if card not found
  • Returns 400 if cardId is not a valid UUID (Zod validation)
  • Returns 500 with logged error if DB fails

@Harxhit
Copy link
Copy Markdown
Collaborator

Harxhit commented May 20, 2026

Test Evidence

"Endpoint: GET /api/nfc/payload"

* Returns `{ type: 'URI', payload: 'https://devcard.dev/<username>' }` for authenticated user

"Endpoint: GET /api/nfc/payload?card="

* Returns card-specific URL if card belongs to user

* Returns 403 if card belongs to different user

* Returns 404 if card not found

* Returns 400 if cardId is not a valid UUID (Zod validation)

* Returns 500 with logged error if DB fails

packages/shared/src/tests/cards.test.ts Add proofs for these in the PR description.

@Midoriya-w
Copy link
Copy Markdown
Author

Hey @Harxhit! Here are the test proofs from packages/shared/src/tests/cards.test.ts:
validateCardPlatforms tests (7 cases):

-passes with valid platforms

  • fails with empty array
  • fails with unknown platform
  • fails with duplicate platforms
  • passes with exactly 10 platforms
  • fails with more than 10 platforms
  • ails with all invalid platforms

diffCardPlatforms tests (3 cases):

  • correctly identifies added, removed, unchanged
  • handles empty old card
  • handles identical cards

All 10 test cases cover the acceptance criteria edge cases

@Harxhit
Copy link
Copy Markdown
Collaborator

Harxhit commented May 20, 2026

Hey @Harxhit! Here are the test proofs from packages/shared/src/tests/cards.test.ts:
validateCardPlatforms tests (7 cases):

-passes with valid platforms

  • fails with empty array
  • fails with unknown platform
  • fails with duplicate platforms
  • passes with exactly 10 platforms
  • fails with more than 10 platforms
  • ails with all invalid platforms

diffCardPlatforms tests (3 cases):

  • correctly identifies added, removed, unchanged
  • handles empty old card
  • handles identical cards

All 10 test cases cover the acceptance criteria edge cases

Please attach terminal screenshots to the description

@Midoriya-w
Copy link
Copy Markdown
Author

Test Evidence

Shared Package Tests

All shared package tests pass successfully.

  • src/platforms.test.ts 9 tests passed
  • src/__tests__/cards.test.ts 10 tests passed
  • Total: 19 tests passed
Screenshot 2026-05-20 193310

@Midoriya-w
Copy link
Copy Markdown
Author

Added terminal screenshots to the PR description as requested. All shared package tests are passing successfully.

Comment thread apps/backend/src/routes/nfc.ts Outdated
where: { id: userId },
select: { username: true },
});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Catch position should be here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Refactored the code to narrow the try/catch scope as suggested. Thanks for the review!

const card = await app.prisma.card.findUnique({
where: { id: cardId },
select: { userId: true },
});
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Catch position should be here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Updated this section as well to keep the try/catch scoped only around the database call. Thanks for catching that.

@Midoriya-w Midoriya-w requested a review from Harxhit May 21, 2026 04:06
@Midoriya-w
Copy link
Copy Markdown
Author

Hey @ShantKhatri! Harxhit has reviewed and confirmed the changes look good. Could you do the final PA review when you get a chance?

@Harxhit
Copy link
Copy Markdown
Collaborator

Harxhit commented May 21, 2026

@ShantKhatri Looks good to me your final review please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

backend: implement NFC tag payload generation endpoint

2 participants