Compare commits

..

2 Commits

Author SHA1 Message Date
mineseo-kim ca9413e665 fix(db): honor DATABASE_URL schema for pg Pool and PrismaPg
node-postgres ignores Prisma's ?schema= query param, so connections
defaulted to public. Parse the schema from the URL, set search_path on
the pool, and pass schema to PrismaPg (see prisma/prisma#28611).

Made-with: Cursor
2026-04-09 09:45:10 +09:00
mineseo-kim f317be9eab fix(logging): clarify LOG_DIR creation and bootstrap errors
- Wrap mkdir in ensureLogDir with stderr message on failure.

- Trim LOG_DIR; note in .env.example that the directory is created at startup.

Made-with: Cursor
2026-04-09 09:38:59 +09:00
3 changed files with 41 additions and 6 deletions

View File

@ -9,5 +9,5 @@ DATABASE_URL="postgresql://kord:password@localhost:5432/kord_db?schema=public"
# Logging (log4js — file only under LOG_DIR, no console appender) # Logging (log4js — file only under LOG_DIR, no console appender)
# Levels: trace, debug, info, warn, error, fatal # Levels: trace, debug, info, warn, error, fatal
LOG_LEVEL=info LOG_LEVEL=info
# Daily log files; keep 7 rotated days (see logger.ts) # Daily log files; keep 7 rotated days (see logger.ts). Directory is created at startup if missing.
LOG_DIR=logs LOG_DIR=logs

View File

@ -1,11 +1,36 @@
import type { PoolConfig } from 'pg';
import { Pool } from 'pg'; import { Pool } from 'pg';
import { PrismaPg } from '@prisma/adapter-pg'; import { PrismaPg } from '@prisma/adapter-pg';
import { PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client';
import { env } from '../config/env';
import { logger } from '../utils/logger'; import { logger } from '../utils/logger';
// Prisma 7 requires a driver adapter for direct database connections. /**
const pool = new Pool({ connectionString: process.env.DATABASE_URL }); * `?schema=` in DATABASE_URL is a Prisma URL extension. node-postgres does not apply it,
const adapter = new PrismaPg(pool); * so connections default to `search_path=public`. PrismaPg also needs an explicit schema
* option in some setups (see prisma/prisma#28611).
*/
function createPgPoolConfig(connectionString: string): { poolConfig: PoolConfig; prismaSchema?: string } {
if (!connectionString) {
return { poolConfig: { connectionString: '' } };
}
try {
const url = new URL(connectionString);
const schema = url.searchParams.get('schema')?.trim();
const poolConfig: PoolConfig = { connectionString };
if (schema) {
const escaped = schema.replace(/"/g, '""');
poolConfig.options = `-c search_path="${escaped}"`;
}
return { poolConfig, prismaSchema: schema || undefined };
} catch {
return { poolConfig: { connectionString } };
}
}
const { poolConfig, prismaSchema } = createPgPoolConfig(env.DATABASE_URL);
const pool = new Pool(poolConfig);
const adapter = prismaSchema ? new PrismaPg(pool, { schema: prismaSchema }) : new PrismaPg(pool);
export const prisma = new PrismaClient({ export const prisma = new PrismaClient({
adapter, adapter,

View File

@ -14,10 +14,20 @@ function resolveLogLevel(): LogLevel {
return (LOG_LEVELS as readonly string[]).includes(raw) ? (raw as LogLevel) : 'info'; return (LOG_LEVELS as readonly string[]).includes(raw) ? (raw as LogLevel) : 'info';
} }
const logDir = resolve(process.env.LOG_DIR || 'logs'); function ensureLogDir(dir: string): void {
try {
mkdirSync(dir, { recursive: true });
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
process.stderr.write(`[kord] Failed to create LOG_DIR "${dir}": ${msg}\n`);
throw err;
}
}
const logDir = resolve((process.env.LOG_DIR || 'logs').trim());
const level = resolveLogLevel(); const level = resolveLogLevel();
mkdirSync(logDir, { recursive: true }); ensureLogDir(logDir);
log4js.configure({ log4js.configure({
appenders: { appenders: {