From aab05e0cb34ffff814eed296f03b20fe3fdc7ac6 Mon Sep 17 00:00:00 2001 From: Aman Sayyad <153252172+mramansayyad@users.noreply.github.com> Date: Sat, 23 May 2026 18:57:34 +0530 Subject: [PATCH 1/6] fix(backend): automatically handle default card reassignment on card deletion --- apps/backend/src/__tests__/cards.test.ts | 83 ++++++++++++++++++++++++ apps/backend/src/routes/cards.ts | 20 ++++++ 2 files changed, 103 insertions(+) create mode 100644 apps/backend/src/__tests__/cards.test.ts diff --git a/apps/backend/src/__tests__/cards.test.ts b/apps/backend/src/__tests__/cards.test.ts new file mode 100644 index 00000000..e2d2ff4e --- /dev/null +++ b/apps/backend/src/__tests__/cards.test.ts @@ -0,0 +1,83 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import Fastify from 'fastify'; +import { cardRoutes } from '../routes/cards.js'; +import type { PrismaClient } from '@prisma/client'; + +const mockPrisma = { + card: { + findFirst: vi.fn(), + count: vi.fn(), + update: vi.fn(), + delete: vi.fn(), + create: vi.fn(), + findMany: vi.fn(), + updateMany: vi.fn(), + }, + cardLink: { + deleteMany: vi.fn(), + createMany: vi.fn(), + } +} as unknown as PrismaClient; + +async function buildApp() { + const app = Fastify(); + app.decorate('prisma', mockPrisma); + app.decorate('authenticate', async (request: any) => { + request.user = { id: 'user-123' }; + }); + app.register(cardRoutes, { prefix: '/api/cards' }); + await app.ready(); + return app; +} + +describe('DELETE /api/cards/:id', () => { + beforeEach(() => vi.clearAllMocks()); + + it('should return 404 if card is not found', async () => { + (mockPrisma.card.findFirst as any).mockResolvedValue(null); + const app = await buildApp(); + const res = await app.inject({ method: 'DELETE', url: '/api/cards/card-1' }); + expect(res.statusCode).toBe(404); + expect(res.json().error).toBe('Card not found'); + }); + + it('should return 400 if trying to delete the last remaining card', async () => { + (mockPrisma.card.findFirst as any).mockResolvedValue({ id: 'card-1', isDefault: true, userId: 'user-123' }); + (mockPrisma.card.count as any).mockResolvedValue(1); + const app = await buildApp(); + const res = await app.inject({ method: 'DELETE', url: '/api/cards/card-1' }); + expect(res.statusCode).toBe(400); + expect(res.json().error).toBe('Cannot delete the last remaining card. A user must have at least one card.'); + }); + + it('should successfully delete a non-default card without reassigning', async () => { + (mockPrisma.card.findFirst as any).mockResolvedValue({ id: 'card-1', isDefault: false, userId: 'user-123' }); + (mockPrisma.card.count as any).mockResolvedValue(2); + (mockPrisma.card.delete as any).mockResolvedValue({ id: 'card-1' }); + const app = await buildApp(); + const res = await app.inject({ method: 'DELETE', url: '/api/cards/card-1' }); + expect(res.statusCode).toBe(204); + expect(mockPrisma.card.update).not.toHaveBeenCalled(); + expect(mockPrisma.card.delete).toHaveBeenCalledWith({ where: { id: 'card-1' } }); + }); + + it('should reassign default to oldest remaining card if deleting the default card', async () => { + (mockPrisma.card.findFirst as any) + .mockResolvedValueOnce({ id: 'card-1', isDefault: true, userId: 'user-123' }) // first findFirst for existing + .mockResolvedValueOnce({ id: 'card-2', isDefault: false, userId: 'user-123' }); // second findFirst for oldest remaining + + (mockPrisma.card.count as any).mockResolvedValue(2); + (mockPrisma.card.update as any).mockResolvedValue({ id: 'card-2', isDefault: true }); + (mockPrisma.card.delete as any).mockResolvedValue({ id: 'card-1' }); + + const app = await buildApp(); + const res = await app.inject({ method: 'DELETE', url: '/api/cards/card-1' }); + + expect(res.statusCode).toBe(204); + expect(mockPrisma.card.update).toHaveBeenCalledWith({ + where: { id: 'card-2' }, + data: { isDefault: true }, + }); + expect(mockPrisma.card.delete).toHaveBeenCalledWith({ where: { id: 'card-1' } }); + }); +}); diff --git a/apps/backend/src/routes/cards.ts b/apps/backend/src/routes/cards.ts index 6927a73a..80a8f3c7 100644 --- a/apps/backend/src/routes/cards.ts +++ b/apps/backend/src/routes/cards.ts @@ -142,6 +142,26 @@ export async function cardRoutes(app: FastifyInstance): Promise { return; } + const userCardCount = await app.prisma.card.count({ where: { userId } }); + if (userCardCount <= 1) { + reply.status(400).send({ error: 'Cannot delete the last remaining card. A user must have at least one card.' }); + return; + } + + if (existing.isDefault) { + const oldestRemainingCard = await app.prisma.card.findFirst({ + where: { userId, id: { not: id } }, + orderBy: { createdAt: 'asc' }, + }); + + if (oldestRemainingCard) { + await app.prisma.card.update({ + where: { id: oldestRemainingCard.id }, + data: { isDefault: true }, + }); + } + } + await app.prisma.card.delete({ where: { id } }); reply.status(204).send(); }); From 3819b031d15b264bd302f3191fdb389225e2fc51 Mon Sep 17 00:00:00 2001 From: Aman Sayyad <153252172+mramansayyad@users.noreply.github.com> Date: Sat, 23 May 2026 23:02:05 +0530 Subject: [PATCH 2/6] feat(backend): add limit to card list query --- apps/backend/src/routes/cards.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/backend/src/routes/cards.ts b/apps/backend/src/routes/cards.ts index 80a8f3c7..63b34701 100644 --- a/apps/backend/src/routes/cards.ts +++ b/apps/backend/src/routes/cards.ts @@ -12,6 +12,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { const cards = await app.prisma.card.findMany({ where: { userId }, + take: 50, include: { cardLinks: { include: { platformLink: true }, From bde923af49a968e69f6ac65c4278b62ae7c57791 Mon Sep 17 00:00:00 2001 From: Aman Sayyad <153252172+mramansayyad@users.noreply.github.com> Date: Sat, 23 May 2026 23:07:13 +0530 Subject: [PATCH 3/6] refactor(backend): add try-catch and typed responses per review --- apps/backend/src/routes/cards.ts | 287 +++++++++++++++++-------------- 1 file changed, 157 insertions(+), 130 deletions(-) diff --git a/apps/backend/src/routes/cards.ts b/apps/backend/src/routes/cards.ts index 63b34701..9e72711b 100644 --- a/apps/backend/src/routes/cards.ts +++ b/apps/backend/src/routes/cards.ts @@ -1,4 +1,5 @@ import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; +import type { Card } from '@devcard/shared'; import { createCardSchema, updateCardSchema } from '../utils/validators.js'; @@ -7,32 +8,37 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── List Cards ─── - app.get('/', async (request: FastifyRequest): Promise => { + app.get('/', async (request: FastifyRequest, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; - const cards = await app.prisma.card.findMany({ - where: { userId }, - take: 50, - include: { - cardLinks: { - include: { platformLink: true }, - orderBy: { displayOrder: 'asc' }, + try { + const cards = await app.prisma.card.findMany({ + where: { userId }, + take: 50, + include: { + cardLinks: { + include: { platformLink: true }, + orderBy: { displayOrder: 'asc' }, + }, }, - }, - orderBy: { createdAt: 'asc' }, - }); - - return cards.map((card) => ({ - id: card.id, - title: card.title, - isDefault: card.isDefault, - links: card.cardLinks.map((cl) => cl.platformLink), - })); + orderBy: { createdAt: 'asc' }, + }); + + return cards.map((card) => ({ + id: card.id, + title: card.title, + isDefault: card.isDefault, + links: card.cardLinks.map((cl) => cl.platformLink) as any, + })); + } catch (error) { + request.log.error(error); + return reply.status(500).send({ error: 'Internal Server Error' }); + } }); // ─── Create Card ─── - app.post('/', async (request: FastifyRequest, reply: FastifyReply): Promise => { + app.post('/', async (request: FastifyRequest, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const parsed = createCardSchema.safeParse(request.body); @@ -40,92 +46,103 @@ export async function cardRoutes(app: FastifyInstance): Promise { return reply.status(400).send({ error: 'Validation failed', details: parsed.error.flatten() }); } - const cardCount = await app.prisma.card.count({ where: { userId } }); - - const card = await app.prisma.card.create({ - data: { - userId, - title: parsed.data.title, - isDefault: cardCount === 0, - cardLinks: { - create: parsed.data.linkIds.map((linkId, index) => ({ - platformLinkId: linkId, - displayOrder: index, - })), + try { + const cardCount = await app.prisma.card.count({ where: { userId } }); + + const card = await app.prisma.card.create({ + data: { + userId, + title: parsed.data.title, + isDefault: cardCount === 0, + cardLinks: { + create: parsed.data.linkIds.map((linkId, index) => ({ + platformLinkId: linkId, + displayOrder: index, + })), + }, }, - }, - include: { - cardLinks: { - include: { platformLink: true }, - orderBy: { displayOrder: 'asc' }, + include: { + cardLinks: { + include: { platformLink: true }, + orderBy: { displayOrder: 'asc' }, + }, }, - }, - }); - - return reply.status(201).send({ - id: card.id, - title: card.title, - isDefault: card.isDefault, - links: card.cardLinks.map((cl) => cl.platformLink), - }); + }); + + return reply.status(201).send({ + id: card.id, + title: card.title, + isDefault: card.isDefault, + links: card.cardLinks.map((cl) => cl.platformLink) as any, + }); + } catch (error) { + request.log.error(error); + return reply.status(500).send({ error: 'Internal Server Error' }); + } }); // ─── Update Card ─── - app.put('/:id', async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { + app.put('/:id', async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; - const existing = await app.prisma.card.findFirst({ - where: { id, userId }, - }); + try { + const existing = await app.prisma.card.findFirst({ + where: { id, userId }, + }); - if (!existing) { - return reply.status(404).send({ error: 'Card not found' }); - } + if (!existing) { + return reply.status(404).send({ error: 'Card not found' }); + } - const parsed = updateCardSchema.safeParse(request.body); - if (!parsed.success) { - return reply.status(400).send({ error: 'Validation failed', details: parsed.error.flatten() }); - } + const parsed = updateCardSchema.safeParse(request.body); + if (!parsed.success) { + return reply.status(400).send({ error: 'Validation failed', details: parsed.error.flatten() }); + } - if (parsed.data.title) { - await app.prisma.card.update({ + if (parsed.data.title) { + await app.prisma.card.update({ + where: { id }, + data: { title: parsed.data.title }, + }); + } + + if (parsed.data.linkIds) { + await app.prisma.cardLink.deleteMany({ where: { cardId: id } }); + + // Add new links + await app.prisma.cardLink.createMany({ + data: parsed.data.linkIds.map((linkId, index) => ({ + cardId: id, + platformLinkId: linkId, + displayOrder: index, + })), + }); + } + + const updated = await app.prisma.card.findUnique({ where: { id }, - data: { title: parsed.data.title }, + include: { + cardLinks: { + include: { platformLink: true }, + orderBy: { displayOrder: 'asc' }, + }, + }, }); - } - if (parsed.data.linkIds) { - await app.prisma.cardLink.deleteMany({ where: { cardId: id } }); - - - // Add new links - await app.prisma.cardLink.createMany({ - data: parsed.data.linkIds.map((linkId, index) => ({ - cardId: id, - platformLinkId: linkId, - displayOrder: index, - })), - }); + const response: Card = { + id: updated!.id, + title: updated!.title, + isDefault: updated!.isDefault, + links: updated!.cardLinks.map((cl) => cl.platformLink) as any, + }; + + return response; + } catch (error) { + request.log.error(error); + return reply.status(500).send({ error: 'Internal Server Error' }); } - - const updated = await app.prisma.card.findUnique({ - where: { id }, - include: { - cardLinks: { - include: { platformLink: true }, - orderBy: { displayOrder: 'asc' }, - }, - }, - }); - - return { - id: updated!.id, - title: updated!.title, - isDefault: updated!.isDefault, - links: updated!.cardLinks.map((cl) => cl.platformLink), - }; }); // ─── Delete Card ─── @@ -134,63 +151,73 @@ export async function cardRoutes(app: FastifyInstance): Promise { const userId = (request.user as { id: string }).id; const { id } = request.params; - const existing = await app.prisma.card.findFirst({ - where: { id, userId }, - }); - - if (!existing) { - reply.status(404).send({ error: 'Card not found' }); - return; - } + try { + const existing = await app.prisma.card.findFirst({ + where: { id, userId }, + }); - const userCardCount = await app.prisma.card.count({ where: { userId } }); - if (userCardCount <= 1) { - reply.status(400).send({ error: 'Cannot delete the last remaining card. A user must have at least one card.' }); - return; - } + if (!existing) { + reply.status(404).send({ error: 'Card not found' }); + return; + } - if (existing.isDefault) { - const oldestRemainingCard = await app.prisma.card.findFirst({ - where: { userId, id: { not: id } }, - orderBy: { createdAt: 'asc' }, - }); + const userCardCount = await app.prisma.card.count({ where: { userId } }); + if (userCardCount <= 1) { + reply.status(400).send({ error: 'Cannot delete the last remaining card. A user must have at least one card.' }); + return; + } - if (oldestRemainingCard) { - await app.prisma.card.update({ - where: { id: oldestRemainingCard.id }, - data: { isDefault: true }, + if (existing.isDefault) { + const oldestRemainingCard = await app.prisma.card.findFirst({ + where: { userId, id: { not: id } }, + orderBy: { createdAt: 'asc' }, }); + + if (oldestRemainingCard) { + await app.prisma.card.update({ + where: { id: oldestRemainingCard.id }, + data: { isDefault: true }, + }); + } } - } - await app.prisma.card.delete({ where: { id } }); - reply.status(204).send(); + await app.prisma.card.delete({ where: { id } }); + reply.status(204).send(); + } catch (error) { + request.log.error(error); + reply.status(500).send({ error: 'Internal Server Error' }); + } }); // ─── Set Default Card ─── - app.put('/:id/default', async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { + app.put('/:id/default', async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; - const existing = await app.prisma.card.findFirst({ - where: { id, userId }, - }); + try { + const existing = await app.prisma.card.findFirst({ + where: { id, userId }, + }); - if (!existing) { - return reply.status(404).send({ error: 'Card not found' }); - } + if (!existing) { + return reply.status(404).send({ error: 'Card not found' }); + } - await app.prisma.card.updateMany({ - where: { userId }, - data: { isDefault: false }, - }); + await app.prisma.card.updateMany({ + where: { userId }, + data: { isDefault: false }, + }); - await app.prisma.card.update({ - where: { id }, - data: { isDefault: true }, - }); + await app.prisma.card.update({ + where: { id }, + data: { isDefault: true }, + }); - return { message: 'Default card updated' }; + return { message: 'Default card updated' }; + } catch (error) { + request.log.error(error); + return reply.status(500).send({ error: 'Internal Server Error' }); + } }); } \ No newline at end of file From 3b77203bcd026be74e193edbb2a628ad986c47e2 Mon Sep 17 00:00:00 2001 From: Aman Sayyad <153252172+mramansayyad@users.noreply.github.com> Date: Sat, 23 May 2026 23:48:24 +0530 Subject: [PATCH 4/6] feat(backend): add Fastify request schemas for card routes --- apps/backend/src/routes/cards.ts | 62 +++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/apps/backend/src/routes/cards.ts b/apps/backend/src/routes/cards.ts index 0f27e519..ce9f6d8a 100644 --- a/apps/backend/src/routes/cards.ts +++ b/apps/backend/src/routes/cards.ts @@ -38,7 +38,21 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Create Card ─── - app.post('/', async (request: FastifyRequest, reply: FastifyReply): Promise => { + app.post('/', { + schema: { + body: { + type: 'object', + required: ['title', 'linkIds'], + properties: { + title: { type: 'string', minLength: 1, maxLength: 100 }, + linkIds: { + type: 'array', + items: { type: 'string', format: 'uuid' } + } + } + } + } + }, async (request: FastifyRequest, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const parsed = createCardSchema.safeParse(request.body); @@ -82,7 +96,27 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Update Card ─── - app.put('/:id', async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { + app.put('/:id', { + schema: { + params: { + type: 'object', + required: ['id'], + properties: { + id: { type: 'string' } + } + }, + body: { + type: 'object', + properties: { + title: { type: 'string', minLength: 1, maxLength: 100 }, + linkIds: { + type: 'array', + items: { type: 'string', format: 'uuid' } + } + } + } + } + }, async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; @@ -157,7 +191,17 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Delete Card ─── - app.delete('/:id', async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { + app.delete('/:id', { + schema: { + params: { + type: 'object', + required: ['id'], + properties: { + id: { type: 'string' } + } + } + } + }, async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; @@ -200,7 +244,17 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Set Default Card ─── - app.put('/:id/default', async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { + app.put('/:id/default', { + schema: { + params: { + type: 'object', + required: ['id'], + properties: { + id: { type: 'string' } + } + } + } + }, async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; From 28ea4154de14d37ccf009ccbce78b5bcc44ba9f1 Mon Sep 17 00:00:00 2001 From: Aman Sayyad <153252172+mramansayyad@users.noreply.github.com> Date: Sat, 23 May 2026 23:57:57 +0530 Subject: [PATCH 5/6] feat(backend): use Fastify typed request schema generics for card routes --- apps/backend/src/routes/cards.ts | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/backend/src/routes/cards.ts b/apps/backend/src/routes/cards.ts index ce9f6d8a..68287c16 100644 --- a/apps/backend/src/routes/cards.ts +++ b/apps/backend/src/routes/cards.ts @@ -4,6 +4,20 @@ import type { Card } from '@devcard/shared'; import { createCardSchema, updateCardSchema } from '../utils/validators.js'; import { handleDbError } from '../utils/error.util.js'; +interface CreateCardBody { + title: string; + linkIds: string[]; +} + +interface UpdateCardBody { + title?: string; + linkIds?: string[]; +} + +interface CardParams { + id: string; +} + export async function cardRoutes(app: FastifyInstance): Promise { app.addHook('preHandler', app.authenticate); @@ -52,7 +66,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { } } } - }, async (request: FastifyRequest, reply: FastifyReply): Promise => { + }, async (request: FastifyRequest<{ Body: CreateCardBody }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const parsed = createCardSchema.safeParse(request.body); @@ -116,7 +130,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { } } } - }, async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { + }, async (request: FastifyRequest<{ Params: CardParams; Body: UpdateCardBody }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; @@ -201,7 +215,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { } } } - }, async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { + }, async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; @@ -254,7 +268,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { } } } - }, async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply): Promise => { + }, async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; From 3abfe08d0ee1909d250f12f9262007fb5641faca Mon Sep 17 00:00:00 2001 From: Aman Sayyad <153252172+mramansayyad@users.noreply.github.com> Date: Sun, 24 May 2026 00:01:43 +0530 Subject: [PATCH 6/6] feat(backend): remove manual JSON request schemas, keeping Fastify generic typing --- apps/backend/src/routes/cards.ts | 62 +++----------------------------- 1 file changed, 4 insertions(+), 58 deletions(-) diff --git a/apps/backend/src/routes/cards.ts b/apps/backend/src/routes/cards.ts index 68287c16..04ca1436 100644 --- a/apps/backend/src/routes/cards.ts +++ b/apps/backend/src/routes/cards.ts @@ -52,21 +52,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Create Card ─── - app.post('/', { - schema: { - body: { - type: 'object', - required: ['title', 'linkIds'], - properties: { - title: { type: 'string', minLength: 1, maxLength: 100 }, - linkIds: { - type: 'array', - items: { type: 'string', format: 'uuid' } - } - } - } - } - }, async (request: FastifyRequest<{ Body: CreateCardBody }>, reply: FastifyReply): Promise => { + app.post('/', async (request: FastifyRequest<{ Body: CreateCardBody }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const parsed = createCardSchema.safeParse(request.body); @@ -110,27 +96,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Update Card ─── - app.put('/:id', { - schema: { - params: { - type: 'object', - required: ['id'], - properties: { - id: { type: 'string' } - } - }, - body: { - type: 'object', - properties: { - title: { type: 'string', minLength: 1, maxLength: 100 }, - linkIds: { - type: 'array', - items: { type: 'string', format: 'uuid' } - } - } - } - } - }, async (request: FastifyRequest<{ Params: CardParams; Body: UpdateCardBody }>, reply: FastifyReply): Promise => { + app.put('/:id', async (request: FastifyRequest<{ Params: CardParams; Body: UpdateCardBody }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; @@ -205,17 +171,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Delete Card ─── - app.delete('/:id', { - schema: { - params: { - type: 'object', - required: ['id'], - properties: { - id: { type: 'string' } - } - } - } - }, async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise => { + app.delete('/:id', async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; @@ -258,17 +214,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Set Default Card ─── - app.put('/:id/default', { - schema: { - params: { - type: 'object', - required: ['id'], - properties: { - id: { type: 'string' } - } - } - } - }, async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise => { + app.put('/:id/default', async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params;