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:
Jason Woltje
2026-01-28 16:06:34 -06:00
parent 355cf2124b
commit 99afde4f99
26 changed files with 1844 additions and 64 deletions

View 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 {}

View 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 };
}
}
}