diff --git a/.env.example b/.env.example index 0da2ffe..74acf4d 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,12 @@ DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/postgres +# Cloud SQL Auth Proxy (Unix socket) — set these instead of DATABASE_URL on Cloud Run. +# INSTANCE_UNIX_SOCKET=/cloudsql/PROJECT:REGION:INSTANCE +# DB_USER=your_db_user +# DB_PASSWORD=**** +# DB_NAME=your_db_name +# DB_USE_UNIX_SOCKET=true # set to "false" to force DATABASE_URL even when INSTANCE_UNIX_SOCKET is set + # `openssl rand -hex 32` NEXTAUTH_SECRET=**** diff --git a/apphosting.yaml b/apphosting.yaml index 5260942..ec5f4dc 100644 --- a/apphosting.yaml +++ b/apphosting.yaml @@ -59,3 +59,22 @@ env: availability: - BUILD - RUNTIME + + # Cloud SQL Auth Proxy (Unix socket) connection. + # Set INSTANCE_UNIX_SOCKET to enable; set DB_USE_UNIX_SOCKET=false to force DATABASE_URL fallback. + - variable: INSTANCE_UNIX_SOCKET + value: /cloudsql/f3data:us-central1:f3data + availability: + - RUNTIME + - variable: DB_USER + value: app_codex + availability: + - RUNTIME + - variable: DB_PASSWORD + secret: client-database-password + availability: + - RUNTIME + - variable: DB_NAME + value: f3_prod + availability: + - RUNTIME diff --git a/src/lib/db.ts b/src/lib/db.ts index 0000f63..a9918e4 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -4,11 +4,44 @@ import { Pool, type PoolClient } from "pg"; let pool: Pool | null = null; function initializePool(): Pool { + const instanceUnixSocket = process.env.INSTANCE_UNIX_SOCKET; // e.g. /cloudsql/PROJECT:REGION:INSTANCE + const useUnixSocket = + instanceUnixSocket && process.env.DB_USE_UNIX_SOCKET !== "false"; + + if (useUnixSocket) { + const dbUser = process.env.DB_USER; + const dbPassword = process.env.DB_PASSWORD; + const dbName = process.env.DB_NAME; + + if (!dbUser || !dbName) { + throw new Error( + "INSTANCE_UNIX_SOCKET is set but DB_USER and/or DB_NAME are missing.", + ); + } + + const newPool = new Pool({ + user: dbUser, + password: dbPassword, + database: dbName, + host: instanceUnixSocket, + }); + + newPool.on("error", (err) => { + console.error("Unexpected error on idle PostgreSQL client:", err); + }); + + console.log("✅ PostgreSQL pool initialized via Cloud SQL Unix socket."); + return newPool; + } + + // Fallback: direct TCP connection via DATABASE_URL const connectionString = process.env.DATABASE_URL; if (!connectionString) { console.error("❌ CRITICAL: DATABASE_URL is not set in the environment."); - throw new Error("DATABASE_URL is missing. Cannot connect to the database."); + throw new Error( + "Neither INSTANCE_UNIX_SOCKET nor DATABASE_URL is configured. Cannot connect to the database.", + ); } const isProduction = process.env.NODE_ENV === "production"; @@ -23,6 +56,7 @@ function initializePool(): Pool { console.error("Unexpected error on idle PostgreSQL client:", err); }); + console.log("✅ PostgreSQL pool initialized via DATABASE_URL (TCP)."); return newPool; }