Introduce getRedisConnection('cache' | 'queue') so ops can point BullMQ at
a separate Redis instance from the cache/throttler/ws-adapter without a
code change. Falls back to REDIS_HOST/PORT/PASSWORD when REDIS_QUEUE_*
vars are unset, so dev and single-instance deploys are unchanged.
- New helper + describeRedisTopology() (safe summary, never leaks password)
- BullModule.forRoot now uses the queue connection
- .env.example documents optional REDIS_QUEUE_HOST/PORT/PASSWORD
- 6 unit tests cover defaults, fallback, precedence, shared/split topology,
and password leak prevention
Refs: GOO-175
Co-Authored-By: Paperclip <noreply@paperclip.ing>
242 lines
9.4 KiB
Plaintext
242 lines
9.4 KiB
Plaintext
# =============================================================================
|
|
# GoodGo Platform — Environment Variables
|
|
# Copy this file to .env and update values for your local environment
|
|
# =============================================================================
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# PostgreSQL + PostGIS
|
|
# -----------------------------------------------------------------------------
|
|
DB_HOST=localhost
|
|
DB_PORT=5432
|
|
DB_NAME=goodgo
|
|
DB_USER=goodgo
|
|
DB_PASSWORD=CHANGE_ME
|
|
DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?schema=public
|
|
|
|
# Direct connection (bypasses PgBouncer — used for migrations/introspection)
|
|
DATABASE_URL_DIRECT=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?schema=public
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# PgBouncer (Connection Pooling — production only)
|
|
# -----------------------------------------------------------------------------
|
|
PGBOUNCER_POOL_SIZE=20
|
|
PGBOUNCER_MAX_CLIENT_CONN=200
|
|
PGBOUNCER_ADMIN_PASSWORD=CHANGE_ME
|
|
PGBOUNCER_STATS_PASSWORD=CHANGE_ME
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Redis
|
|
# -----------------------------------------------------------------------------
|
|
REDIS_HOST=localhost
|
|
REDIS_PORT=6379
|
|
REDIS_PASSWORD=CHANGE_ME_IN_PRODUCTION
|
|
REDIS_URL=redis://:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Redis — Queue (BullMQ)
|
|
#
|
|
# RFC-004 Phase 3: the async backbone (BullMQ) can point at a Redis instance
|
|
# separate from cache / throttler / websocket to keep hot cache traffic from
|
|
# starving queue operations. If unset, queue traffic falls back to the cache
|
|
# REDIS_* vars above (single-instance dev and small deployments keep working
|
|
# unchanged).
|
|
# -----------------------------------------------------------------------------
|
|
# REDIS_QUEUE_HOST=
|
|
# REDIS_QUEUE_PORT=
|
|
# REDIS_QUEUE_PASSWORD=
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Typesense
|
|
# -----------------------------------------------------------------------------
|
|
TYPESENSE_HOST=localhost
|
|
TYPESENSE_PORT=8108
|
|
TYPESENSE_PROTOCOL=http
|
|
TYPESENSE_API_KEY=CHANGE_ME
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# MinIO (S3-compatible Object Storage)
|
|
# -----------------------------------------------------------------------------
|
|
MINIO_ENDPOINT=localhost
|
|
MINIO_API_PORT=9000
|
|
MINIO_PORT=9000
|
|
MINIO_CONSOLE_PORT=9001
|
|
MINIO_ACCESS_KEY=CHANGE_ME
|
|
MINIO_SECRET_KEY=CHANGE_ME
|
|
MINIO_BUCKET=goodgo-media
|
|
MINIO_USE_SSL=false
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# NestJS API
|
|
# -----------------------------------------------------------------------------
|
|
API_PORT=3000
|
|
PORT=3001
|
|
NODE_ENV=development
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# CORS — comma-separated allowed origins (REQUIRED in production)
|
|
# -----------------------------------------------------------------------------
|
|
CORS_ORIGINS=http://localhost:3000,http://localhost:3001
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# JWT / Auth (REQUIRED — app will not start without these)
|
|
#
|
|
# SECURITY: Generate strong, random secrets (min 32 characters).
|
|
# openssl rand -base64 48
|
|
#
|
|
# Do NOT use placeholder values like "CHANGE_ME" — the app will reject them.
|
|
# Each secret must be unique and kept out of version control.
|
|
# -----------------------------------------------------------------------------
|
|
JWT_SECRET=<generate with: openssl rand -base64 48>
|
|
JWT_EXPIRES_IN=15m
|
|
JWT_REFRESH_SECRET=<generate with: openssl rand -base64 48>
|
|
JWT_REFRESH_EXPIRES_IN=7d
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# OAuth Providers
|
|
# -----------------------------------------------------------------------------
|
|
GOOGLE_CLIENT_ID=
|
|
GOOGLE_CLIENT_SECRET=
|
|
GOOGLE_CALLBACK_URL=http://localhost:3001/auth/google/callback
|
|
|
|
ZALO_APP_ID=
|
|
ZALO_APP_SECRET=
|
|
ZALO_CALLBACK_URL=http://localhost:3001/auth/zalo/callback
|
|
|
|
FRONTEND_URL=http://localhost:3000
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Next.js Web
|
|
# -----------------------------------------------------------------------------
|
|
NEXT_PUBLIC_API_URL=http://localhost:3000
|
|
WEB_PORT=3001
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# AI Service (Python/FastAPI)
|
|
# -----------------------------------------------------------------------------
|
|
AI_SERVICE_PORT=8000
|
|
AI_SERVICE_URL=http://localhost:8000
|
|
CLAUDE_API_KEY=
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Mapbox
|
|
# -----------------------------------------------------------------------------
|
|
NEXT_PUBLIC_MAPBOX_TOKEN=
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Payment Gateways (VNPay, MoMo, ZaloPay)
|
|
# Leave empty if not using payment features.
|
|
#
|
|
# IMPORTANT: The values below default to SANDBOX endpoints. When deploying
|
|
# with NODE_ENV=production, swap each *_BASE_URL / *_ENDPOINT to the
|
|
# production URL and set *_TMN_CODE / *_PARTNER_CODE / *_APP_ID / secret
|
|
# values to live merchant credentials issued by the gateway. See
|
|
# docs/payment-go-live-checklist.md for the full cutover procedure.
|
|
# The API logs a startup warning if production mode is detected with
|
|
# sandbox-looking credentials.
|
|
# -----------------------------------------------------------------------------
|
|
|
|
# VNPay — sandbox by default
|
|
# Production: VNPAY_BASE_URL=https://pay.vnpay.vn/vpcpay.html
|
|
# Production: VNPAY_API_URL=https://merchant.vnpay.vn/merchant_webapi/api/transaction
|
|
VNPAY_TMN_CODE=
|
|
VNPAY_HASH_SECRET=
|
|
VNPAY_BASE_URL=https://sandbox.vnpayment.vn/paymentv2/vpcpay.html
|
|
VNPAY_API_URL=https://sandbox.vnpayment.vn/merchant_webapi/api/transaction
|
|
|
|
# MoMo — sandbox by default
|
|
# Production: MOMO_ENDPOINT=https://payment.momo.vn/v2/gateway/api
|
|
MOMO_PARTNER_CODE=
|
|
MOMO_ACCESS_KEY=
|
|
MOMO_SECRET_KEY=
|
|
MOMO_ENDPOINT=https://test-payment.momo.vn/v2/gateway/api
|
|
|
|
# ZaloPay — sandbox by default
|
|
# Production: ZALOPAY_ENDPOINT=https://openapi.zalopay.vn/v2
|
|
ZALOPAY_APP_ID=
|
|
ZALOPAY_KEY1=
|
|
ZALOPAY_KEY2=
|
|
ZALOPAY_ENDPOINT=https://sb-openapi.zalopay.vn/v2
|
|
|
|
# Backend base URL used to construct IPN (server-to-server) callback URLs for
|
|
# MoMo (ipnUrl) and ZaloPay (callback_url). Must point to the API server, NOT
|
|
# the frontend. Example: https://api.goodgo.vn
|
|
# Individual gateway callback paths are appended automatically:
|
|
# MoMo → {PAYMENT_CALLBACK_BASE_URL}/api/v1/payments/callback/momo
|
|
# ZaloPay → {PAYMENT_CALLBACK_BASE_URL}/api/v1/payments/callback/zalopay
|
|
PAYMENT_CALLBACK_BASE_URL=https://api.goodgo.vn
|
|
|
|
BANK_TRANSFER_ACCOUNT_NUMBER=
|
|
BANK_TRANSFER_BANK_NAME=
|
|
BANK_TRANSFER_ACCOUNT_HOLDER=
|
|
BANK_TRANSFER_WEBHOOK_SECRET=
|
|
BANK_TRANSFER_INSTRUCTIONS_URL=https://goodgo.vn/thanh-toan/chuyen-khoan
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Email / SMTP
|
|
# -----------------------------------------------------------------------------
|
|
SMTP_HOST=localhost
|
|
SMTP_PORT=1025
|
|
SMTP_USER=
|
|
SMTP_PASS=
|
|
SMTP_FROM=noreply@goodgo.vn
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Stringee SMS (Vietnamese SMS provider — OTP & notifications)
|
|
# -----------------------------------------------------------------------------
|
|
STRINGEE_API_KEY=
|
|
STRINGEE_BRANDNAME=GoodGo
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Firebase Cloud Messaging (optional)
|
|
# -----------------------------------------------------------------------------
|
|
FIREBASE_SERVICE_ACCOUNT=
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Zalo OA Notifications (ZNS — Zalo Notification Service)
|
|
# Obtain from Zalo OA Manager: https://oa.zalo.me/manage
|
|
# -----------------------------------------------------------------------------
|
|
ZALO_OA_ID=
|
|
ZALO_OA_ACCESS_TOKEN=
|
|
|
|
# ZNS Template IDs (registered in Zalo OA Manager console)
|
|
ZALO_ZNS_TEMPLATE_INQUIRY=
|
|
ZALO_ZNS_TEMPLATE_PAYMENT=
|
|
ZALO_ZNS_TEMPLATE_LISTING_APPROVED=
|
|
ZALO_ZNS_TEMPLATE_LISTING_REJECTED=
|
|
ZALO_ZNS_TEMPLATE_LISTING_SOLD=
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Sentry Error Tracking
|
|
# -----------------------------------------------------------------------------
|
|
SENTRY_DSN=
|
|
NEXT_PUBLIC_SENTRY_DSN=
|
|
SENTRY_AUTH_TOKEN=
|
|
SENTRY_ORG=
|
|
SENTRY_PROJECT=
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# KYC Field Encryption (REQUIRED in production)
|
|
#
|
|
# AES-256-GCM key for encrypting sensitive KYC data at rest.
|
|
# Must be exactly 64 hex characters (32 bytes).
|
|
# openssl rand -hex 32
|
|
# -----------------------------------------------------------------------------
|
|
KYC_ENCRYPTION_KEY=<generate with: openssl rand -hex 32>
|
|
KYC_ENCRYPTION_KEY_VERSION=1
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Logging
|
|
# -----------------------------------------------------------------------------
|
|
LOG_LEVEL=info
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Monitoring & Alerting
|
|
# -----------------------------------------------------------------------------
|
|
GRAFANA_ADMIN_USER=admin
|
|
GRAFANA_ADMIN_PASSWORD=CHANGE_ME
|
|
GRAFANA_PORT=3002
|
|
GRAFANA_ROOT_URL=http://localhost:3002
|
|
|
|
# Slack webhook for alert notifications (Alertmanager + CI/CD)
|
|
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/CHANGE_ME
|