diff --git a/apps/backend/package-lock.json b/apps/backend/package-lock.json index 64f44440..832b4eee 100644 --- a/apps/backend/package-lock.json +++ b/apps/backend/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "@devcard/backend", "version": "1.0.0", + "hasInstallScript": true, "dependencies": { "@devcard/shared": "file:../../packages/shared", "@fastify/cookie": "^11.0.0", diff --git a/apps/backend/package.json b/apps/backend/package.json index 995ce916..d71b0777 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -15,6 +15,7 @@ "db:deploy": "prisma migrate deploy", "db:seed": "tsx prisma/seed.ts", "db:studio": "prisma studio", + "postinstall": "prisma generate", "typecheck": "tsc --noEmit" }, "dependencies": { diff --git a/apps/backend/src/__tests__/app.test.ts b/apps/backend/src/__tests__/app.test.ts index 648d98a6..92b5ce48 100644 --- a/apps/backend/src/__tests__/app.test.ts +++ b/apps/backend/src/__tests__/app.test.ts @@ -1,8 +1,11 @@ -process.env.NODE_ENV = 'test'; +import { describe, it, expect, vi } from 'vitest'; -import { describe, it, expect } from 'vitest'; import { buildApp } from '../app'; +process.env.NODE_ENV = 'test'; +process.env.JWT_SECRET ||= 'test-jwt-secret'; +process.env.ENCRYPTION_KEY ||= 'test-encryption-key'; + describe('GET /health', () => { it('should return status ok', async () => { const app = await buildApp(); @@ -15,6 +18,22 @@ describe('GET /health', () => { expect(res.statusCode).toBe(200); expect(JSON.parse(res.body)).toEqual({ status: 'ok' }); + await app.close(); + }); +}); + +describe('request logging hook', () => { + it('logs method and url for each request', async () => { + const app = await buildApp(); + const spy = vi.spyOn(app.log, 'info'); + + await app.inject({ method: 'GET', url: '/health' }); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ method: 'GET', url: '/health' }), + 'incoming request', + ); + await app.close(); }); }); \ No newline at end of file diff --git a/apps/backend/src/app.ts b/apps/backend/src/app.ts index 06b87205..be0b27e9 100644 --- a/apps/backend/src/app.ts +++ b/apps/backend/src/app.ts @@ -7,7 +7,6 @@ import helmet from '@fastify/helmet'; import jwt from '@fastify/jwt'; import multipart from '@fastify/multipart'; import rateLimit from '@fastify/rate-limit'; -import fastifyStatic from '@fastify/static'; import Fastify, {type FastifyInstance} from 'fastify'; import { prismaPlugin } from './plugins/prisma.js'; @@ -21,8 +20,8 @@ import { followRoutes } from './routes/follow.js'; import { nfcRoutes } from './routes/nfc.js'; import { profileRoutes } from './routes/profiles.js'; import { publicRoutes } from './routes/public.js'; -import { validateEnv } from './utils/validateEnv.js'; import { teamRoutes } from './routes/team.js'; +import { validateEnv } from './utils/validateEnv.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -42,6 +41,12 @@ export async function buildApp():Promise { }, }); + // Log method + path for every incoming request. + app.addHook('onRequest', (request, _reply, done) => { + app.log.info({ method: request.method, url: request.url }, 'incoming request'); + done(); + }); + // ─── Core Plugins ─── await app.register(cors, { origin: process.env.PUBLIC_APP_URL || 'http://localhost:5173', @@ -92,8 +97,8 @@ export async function buildApp():Promise { try { // Ensure the verified payload is assigned to `request.user` like the original plugin. const payload = await request.jwtVerify(); - if (payload) request.user = payload; - } catch (error) { + if (payload) { request.user = payload; } + } catch (_error) { reply.status(401).send({ error: 'Unauthorized' }); } });