feat(api): integrate Prisma client with /db/health endpoint

- Add @ketopath/db and fastify-plugin to apps/api
- prismaPlugin decorates the Fastify instance with prisma and disconnects
  on app close, with FastifyInstance type augmented in src/types/fastify.d.ts
- DATABASE_URL is now required by env validation
- New module modules/db with GET /db/health running SELECT 1 via Prisma
- dev script switched to tsx --env-file=.env for env loading

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
lucianoandClaude Opus 4.7 committed 2026-04-29 12:38:04 +02:00
1 parent d309d06970
commit 72d47da453
8 files changed
+40 -3

No files matched your search

+4
View File
@@ -5,7 +5,9 @@ import sensible from '@fastify/sensible';
import Fastify, { type FastifyInstance } from 'fastify';
import { env } from './config/env.js';
import { dbRoutes } from './modules/db/db.routes.js';
import { healthRoutes } from './modules/health/health.routes.js';
import { prismaPlugin } from './plugins/prisma.js';
export async function buildApp(): Promise<FastifyInstance> {
const app = Fastify({
@@ -33,8 +35,10 @@ export async function buildApp(): Promise<FastifyInstance> {
timeWindow: '1 minute',
});
await app.register(sensible);
await app.register(prismaPlugin);
await app.register(healthRoutes);
await app.register(dbRoutes);
return app;
}
+1
View File
@@ -14,6 +14,7 @@ const envSchema = z.object({
.map((origin) => origin.trim())
.filter(Boolean),
),
DATABASE_URL: z.string().url(),
});
export type Env = z.infer<typeof envSchema>;
+13
View File
@@ -0,0 +1,13 @@
import type { FastifyPluginAsync } from 'fastify';
export const dbRoutes: FastifyPluginAsync = async (fastify) => {
fastify.get('/db/health', async (_request, reply) => {
try {
await fastify.prisma.$queryRaw`SELECT 1`;
return { status: 'ok', database: 'reachable' };
} catch (err) {
fastify.log.error({ err }, 'database health check failed');
return reply.code(503).send({ status: 'error', database: 'unreachable' });
}
});
};
+11
View File
@@ -0,0 +1,11 @@
import { prisma } from '@ketopath/db';
import fp from 'fastify-plugin';
export const prismaPlugin = fp(async (app) => {
await prisma.$connect();
app.decorate('prisma', prisma);
app.addHook('onClose', async () => {
await prisma.$disconnect();
});
});
+7
View File
@@ -0,0 +1,7 @@
import type { prisma } from '@ketopath/db';
declare module 'fastify' {
interface FastifyInstance {
prisma: typeof prisma;
}
}