feat(#2): Implement PostgreSQL 17 + pgvector database schema
Establishes multi-tenant database layer with vector similarity search for AI-powered memory features. Includes Docker infrastructure, Prisma ORM integration, NestJS services, and shared types across the monorepo. Key changes: - Docker: PostgreSQL 17 + pgvector v0.7.4, Valkey cache - Schema: 8 models (User, Workspace, Task, Event, Project, ActivityLog, MemoryEmbedding) with RLS preparation - NestJS: PrismaModule, DatabaseModule, EmbeddingsService - Shared: Type-safe enums, constants, and database types Fixes #2 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
13
apps/api/src/prisma/prisma.module.ts
Normal file
13
apps/api/src/prisma/prisma.module.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Global, Module } from "@nestjs/common";
|
||||
import { PrismaService } from "./prisma.service";
|
||||
|
||||
/**
|
||||
* Global Prisma module providing database access throughout the application
|
||||
* Marked as @Global() so PrismaService is available in all modules without importing
|
||||
*/
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [PrismaService],
|
||||
exports: [PrismaService],
|
||||
})
|
||||
export class PrismaModule {}
|
||||
95
apps/api/src/prisma/prisma.service.ts
Normal file
95
apps/api/src/prisma/prisma.service.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import {
|
||||
Injectable,
|
||||
Logger,
|
||||
OnModuleDestroy,
|
||||
OnModuleInit,
|
||||
} from "@nestjs/common";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
/**
|
||||
* Prisma service that manages database connection lifecycle
|
||||
* Extends PrismaClient to provide connection management and health checks
|
||||
*/
|
||||
@Injectable()
|
||||
export class PrismaService
|
||||
extends PrismaClient
|
||||
implements OnModuleInit, OnModuleDestroy
|
||||
{
|
||||
private readonly logger = new Logger(PrismaService.name);
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
log:
|
||||
process.env.NODE_ENV === "development"
|
||||
? ["query", "info", "warn", "error"]
|
||||
: ["error"],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to database when NestJS module initializes
|
||||
*/
|
||||
async onModuleInit() {
|
||||
try {
|
||||
await this.$connect();
|
||||
this.logger.log("Database connection established");
|
||||
} catch (error) {
|
||||
this.logger.error("Failed to connect to database", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from database when NestJS module is destroyed
|
||||
*/
|
||||
async onModuleDestroy() {
|
||||
await this.$disconnect();
|
||||
this.logger.log("Database connection closed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Health check for database connectivity
|
||||
* @returns true if database is accessible, false otherwise
|
||||
*/
|
||||
async isHealthy(): Promise<boolean> {
|
||||
try {
|
||||
await this.$queryRaw`SELECT 1`;
|
||||
return true;
|
||||
} catch (error) {
|
||||
this.logger.error("Database health check failed", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get database connection info for debugging
|
||||
* @returns Connection status and basic info
|
||||
*/
|
||||
async getConnectionInfo(): Promise<{
|
||||
connected: boolean;
|
||||
database?: string;
|
||||
version?: string;
|
||||
}> {
|
||||
try {
|
||||
const result = await this.$queryRaw<
|
||||
Array<{ current_database: string; version: string }>
|
||||
>`
|
||||
SELECT current_database(), version()
|
||||
`;
|
||||
|
||||
if (result && result.length > 0 && result[0]) {
|
||||
const dbVersion = result[0].version?.split(" ")[0];
|
||||
return {
|
||||
connected: true,
|
||||
database: result[0].current_database,
|
||||
...(dbVersion && { version: dbVersion }),
|
||||
};
|
||||
}
|
||||
|
||||
return { connected: false };
|
||||
} catch (error) {
|
||||
this.logger.error("Failed to get connection info", error);
|
||||
return { connected: false };
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user