Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
266 lines
13 KiB
YAML
266 lines
13 KiB
YAML
services:
|
||
api:
|
||
build:
|
||
context: .
|
||
dockerfile: Dockerfile
|
||
args:
|
||
- VITE_FARO_ENABLED=${VITE_FARO_ENABLED:-false}
|
||
- VITE_FARO_COLLECTOR_URL=${VITE_FARO_COLLECTOR_URL:-}
|
||
- VITE_POSTHOG_KEY=${VITE_POSTHOG_KEY:-}
|
||
- VITE_META_PIXEL_ID=${VITE_META_PIXEL_ID:-}
|
||
- VITE_CHATWOOT_BASE_URL=${VITE_CHATWOOT_BASE_URL:-}
|
||
- VITE_CHATWOOT_WEBSITE_TOKEN=${VITE_CHATWOOT_WEBSITE_TOKEN:-}
|
||
# Sentry browser SDK — gated on DSN presence (unset = skip init).
|
||
# VITE_* args must be build-time; runtime env won't reach the bundle.
|
||
- VITE_SENTRY_DSN=${VITE_SENTRY_DSN:-}
|
||
- VITE_SENTRY_ENVIRONMENT=${VITE_SENTRY_ENVIRONMENT:-production}
|
||
- VITE_SENTRY_RELEASE=${VITE_SENTRY_RELEASE:-}
|
||
- VITE_GOOGLE_ADS_ID=${VITE_GOOGLE_ADS_ID:-}
|
||
- VITE_GOOGLE_ADS_SIGNUP_LABEL=${VITE_GOOGLE_ADS_SIGNUP_LABEL:-}
|
||
environment:
|
||
- NODE_ENV=production
|
||
- PORT=4000
|
||
- DATABASE_URL=${DATABASE_URL}
|
||
- REDIS_HOST=sase-redis
|
||
- REDIS_PORT=6379
|
||
- REDIS_PASSWORD=${REDIS_PASSWORD}
|
||
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
|
||
- BETTER_AUTH_URL=${BETTER_AUTH_URL}
|
||
# Süper Panel ↔ Sase.tr internal admin token (X-Internal-Token header)
|
||
- INTERNAL_API_TOKEN=${INTERNAL_API_TOKEN:-}
|
||
- INTERNAL_IMPERSONATION_SECRET=${INTERNAL_IMPERSONATION_SECRET:-}
|
||
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID:-}
|
||
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET:-}
|
||
- MINIO_ENDPOINT=http://minio-global:9000
|
||
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
|
||
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
|
||
- MINIO_BUCKET_NAME=${MINIO_BUCKET_NAME:-sase-schemas}
|
||
- MINIO_PUBLIC_URL=${MINIO_PUBLIC_URL}
|
||
- MINIO_USE_SSL=false
|
||
- CORS_ORIGIN=${CORS_ORIGIN}
|
||
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY:-}
|
||
- STRIPE_PUBLISHABLE_KEY=${STRIPE_PUBLISHABLE_KEY:-}
|
||
- PL24_BASE_URL=${PL24_BASE_URL:-https://www.partslink24.com}
|
||
- PL24_COMPANY_CODE=${PL24_COMPANY_CODE:-}
|
||
- PL24_USERNAME=${PL24_USERNAME:-}
|
||
- PL24_PASSWORD=${PL24_PASSWORD:-}
|
||
- PL24_COMPANY_CODE_2=${PL24_COMPANY_CODE_2:-}
|
||
- PL24_USERNAME_2=${PL24_USERNAME_2:-}
|
||
- PL24_PASSWORD_2=${PL24_PASSWORD_2:-}
|
||
- PL24_PROXY_DE=${PL24_PROXY_DE:-}
|
||
- EMEX_USERNAME=${EMEX_USERNAME:-}
|
||
- EMEX_PASSWORD=${EMEX_PASSWORD:-}
|
||
- EMEX_USE_PROXY=${EMEX_USE_PROXY:-false}
|
||
- EMEX_PROXY_HOST=${EMEX_PROXY_HOST:-74.81.81.81}
|
||
- EMEX_PROXY_USER=${EMEX_PROXY_USER:-1726bbe361918676d44e}
|
||
- EMEX_PROXY_PASS=${EMEX_PROXY_PASS:-f11c7b6128cc86c6}
|
||
- PCAT_USE_PROXY=${PCAT_USE_PROXY:-true}
|
||
- PCAT_PROXY_HOST=${PCAT_PROXY_HOST:-gw.dataimpulse.com}
|
||
- PCAT_PROXY_USER=${PCAT_PROXY_USER:-}
|
||
- PCAT_PROXY_PASS=${PCAT_PROXY_PASS:-}
|
||
# Vinpin ePER VIN-decode fallback (flag-gated, off by default)
|
||
- VINPIN_ENABLED=${VINPIN_ENABLED:-false}
|
||
- VINPIN_URL=${VINPIN_URL:-https://login.tr.vinpin.online}
|
||
- VINPIN_USER=${VINPIN_USER:-}
|
||
- VINPIN_PASS=${VINPIN_PASS:-}
|
||
- POSTAL_API_URL=${POSTAL_API_URL:-}
|
||
- POSTAL_API_KEY=${POSTAL_API_KEY:-}
|
||
- POSTAL_FROM_ADDRESS=${POSTAL_FROM_ADDRESS:-noreply@sase.tr}
|
||
- POSTAL_FROM_NAME=${POSTAL_FROM_NAME:-Sase.tr}
|
||
# Novu lifecycle e-mail automation (Tailscale-only; sends via Postal)
|
||
- NOVU_API_URL=${NOVU_API_URL:-https://api.bildirim.semih.ai}
|
||
- NOVU_API_KEY=${NOVU_API_KEY:-}
|
||
- APP_PUBLIC_URL=${APP_PUBLIC_URL:-https://sase.tr}
|
||
- MAILTRACK_SECRET=${MAILTRACK_SECRET:-}
|
||
# PostHog server-side analytics (payments, subscription lifecycle, $revenue).
|
||
# Empty key → PostHogService no-ops (server-side analytics disabled).
|
||
- POSTHOG_API_KEY=${POSTHOG_API_KEY:-}
|
||
# Personal/secure key → LOCAL feature-flag evaluation (source kill switches,
|
||
# guarded decode rollout, remote config). Empty → flags fail open (inert).
|
||
- POSTHOG_PERSONAL_API_KEY=${POSTHOG_PERSONAL_API_KEY:-}
|
||
# "false" on non-prod → evaluate flags but DON'T emit analytics to prod project.
|
||
- POSTHOG_CAPTURE_ENABLED=${POSTHOG_CAPTURE_ENABLED:-}
|
||
- POSTHOG_HOST=${POSTHOG_HOST:-https://eu.i.posthog.com}
|
||
# Meta Conversions API — server-side signup tracking. Empty → CAPI no-ops.
|
||
- META_CAPI_PIXEL_ID=${META_CAPI_PIXEL_ID:-}
|
||
- META_CAPI_ACCESS_TOKEN=${META_CAPI_ACCESS_TOKEN:-}
|
||
- META_CAPI_TEST_EVENT_CODE=${META_CAPI_TEST_EVENT_CODE:-}
|
||
- OTEL_ENABLED=${OTEL_ENABLED:-false}
|
||
- OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-}
|
||
- OTEL_EXPORTER_OTLP_HEADERS=${OTEL_EXPORTER_OTLP_HEADERS:-}
|
||
- OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-sase-api}
|
||
- OTEL_TRACE_SAMPLE_RATE=${OTEL_TRACE_SAMPLE_RATE:-1.0}
|
||
- ML_PREDICTION_ENABLED=${ML_PREDICTION_ENABLED:-false}
|
||
# Chatwoot live-chat widget — HMAC secret for verified user identity
|
||
- CHATWOOT_HMAC_TOKEN=${CHATWOOT_HMAC_TOKEN:-}
|
||
# Local catalog-dump lookup (CategoriesService → PcatSourceDb / EmexSourceDb).
|
||
# Defaults off; when CATALOG_SOURCE_DB_ENABLED=true + URLs set, parts fetches
|
||
# hit the dump first and only fall through to live upstream on miss.
|
||
- CATALOG_SOURCE_DB_ENABLED=${CATALOG_SOURCE_DB_ENABLED:-false}
|
||
- PCAT_SOURCE_DB_URL=${PCAT_SOURCE_DB_URL:-}
|
||
- EMEX_SOURCE_DB_URL=${EMEX_SOURCE_DB_URL:-}
|
||
# Per-source kill switches. pcat default off (dump doesn't cover TR vehicles).
|
||
- EMEX_SOURCE_DB_ENABLED=${EMEX_SOURCE_DB_ENABLED:-true}
|
||
- PCAT_SOURCE_DB_ENABLED=${PCAT_SOURCE_DB_ENABLED:-false}
|
||
# Per-catalog parts-lookup allowlist (comma-separated). Empty → all
|
||
# fetchCategoryParts calls return null. See sase-emex-source-db-safety
|
||
# memory: catalog-wide bridge had 7-114x noise; only add a catalog once
|
||
# its per-vehicle bridge is wired & OEM-verified.
|
||
- EMEX_SOURCE_DB_ALLOWED_CATALOGS=${EMEX_SOURCE_DB_ALLOWED_CATALOGS:-}
|
||
# P snapshot lookup (db `td`) backing the OEM detail page. Off until
|
||
# both vars are set in Coolify; see sase-prod-db-api-access memory.
|
||
- P_DB_ENABLED=${P_DB_ENABLED:-false}
|
||
- P_DB_URL=${P_DB_URL:-}
|
||
# Tedarikçi fiyat geçmişi (takip MySQL, Tailscale 100.82.193.79). Boş →
|
||
# part-prices uçları matched:false döner, UI fiyat bölümü çizmez.
|
||
- SUPPLIER_PRICE_DB_ENABLED=${SUPPLIER_PRICE_DB_ENABLED:-false}
|
||
- SUPPLIER_PRICE_DB_URL=${SUPPLIER_PRICE_DB_URL:-}
|
||
# Central Directus CMS (Süper Panel project on Coolify). Prod and staging
|
||
# point at the SAME instance so blog content is shared across envs.
|
||
# Internal docker-network URL — both stacks join the `coolify` network.
|
||
- DIRECTUS_URL=${DIRECTUS_URL:-}
|
||
- DIRECTUS_TOKEN=${DIRECTUS_TOKEN:-}
|
||
- DIRECTUS_PROJECT=${DIRECTUS_PROJECT:-sase}
|
||
# Bearer token for POST /blog/posts/internal (Süper Panel n8n pipeline)
|
||
- BLOG_AUTOMATION_TOKEN=${BLOG_AUTOMATION_TOKEN:-}
|
||
# Catalog prefetch / backfill tuning (in-process worker lives in THIS api
|
||
# container, not worker.js). All empty → compiled-in defaults; set in Coolify
|
||
# to ramp without a code change. PL24 rate stays conservative unless rotating
|
||
# residential proxies are confirmed (upstream ban risk). See
|
||
# sase-coolify-compose-env-injection + sase-catalog-backfill memories.
|
||
- CATALOG_BACKFILL_ENABLED=${CATALOG_BACKFILL_ENABLED:-}
|
||
- PREFETCH_CONCURRENCY=${PREFETCH_CONCURRENCY:-}
|
||
- PREFETCH_RATE_MAX=${PREFETCH_RATE_MAX:-}
|
||
- PREFETCH_MAX_DEPTH=${PREFETCH_MAX_DEPTH:-}
|
||
- PREFETCH_RATE_PL24=${PREFETCH_RATE_PL24:-}
|
||
- PREFETCH_RATE_EMEX=${PREFETCH_RATE_EMEX:-}
|
||
- PREFETCH_RATE_PCAT=${PREFETCH_RATE_PCAT:-}
|
||
- PREFETCH_PCAT_DELAY_MS=${PREFETCH_PCAT_DELAY_MS:-}
|
||
- PREFETCH_PL24_START=${PREFETCH_PL24_START:-}
|
||
- PREFETCH_PL24_END=${PREFETCH_PL24_END:-}
|
||
- PREFETCH_NORESULT_MAX=${PREFETCH_NORESULT_MAX:-}
|
||
- PREFETCH_NORESULT_TTL_DAYS=${PREFETCH_NORESULT_TTL_DAYS:-}
|
||
- PREFETCH_COMPLETE_TTL_DAYS=${PREFETCH_COMPLETE_TTL_DAYS:-}
|
||
depends_on:
|
||
sase-redis:
|
||
condition: service_healthy
|
||
healthcheck:
|
||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:4000/api/health"]
|
||
interval: 15s
|
||
timeout: 5s
|
||
retries: 5
|
||
start_period: 30s
|
||
labels:
|
||
- "traefik.docker.network=coolify"
|
||
expose:
|
||
- "4000"
|
||
networks:
|
||
- default
|
||
- coolify
|
||
|
||
worker:
|
||
build:
|
||
context: .
|
||
dockerfile: Dockerfile
|
||
command: ["node", "--enable-source-maps", "apps/api/dist/worker.js"]
|
||
environment:
|
||
- NODE_ENV=production
|
||
- DATABASE_URL=${DATABASE_URL}
|
||
- REDIS_HOST=sase-redis
|
||
- REDIS_PORT=6379
|
||
- REDIS_PASSWORD=${REDIS_PASSWORD}
|
||
- MINIO_ENDPOINT=http://minio-global:9000
|
||
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
|
||
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
|
||
- MINIO_BUCKET_NAME=${MINIO_BUCKET_NAME:-sase-schemas}
|
||
- MINIO_PUBLIC_URL=${MINIO_PUBLIC_URL}
|
||
- MINIO_USE_SSL=false
|
||
- PL24_BASE_URL=${PL24_BASE_URL:-https://www.partslink24.com}
|
||
- PL24_COMPANY_CODE=${PL24_COMPANY_CODE:-}
|
||
- PL24_USERNAME=${PL24_USERNAME:-}
|
||
- PL24_PASSWORD=${PL24_PASSWORD:-}
|
||
- PL24_COMPANY_CODE_2=${PL24_COMPANY_CODE_2:-}
|
||
- PL24_USERNAME_2=${PL24_USERNAME_2:-}
|
||
- PL24_PASSWORD_2=${PL24_PASSWORD_2:-}
|
||
- PL24_PROXY_DE=${PL24_PROXY_DE:-}
|
||
- EMEX_USERNAME=${EMEX_USERNAME:-}
|
||
- EMEX_PASSWORD=${EMEX_PASSWORD:-}
|
||
- EMEX_USE_PROXY=${EMEX_USE_PROXY:-false}
|
||
- EMEX_PROXY_HOST=${EMEX_PROXY_HOST:-74.81.81.81}
|
||
- EMEX_PROXY_USER=${EMEX_PROXY_USER:-1726bbe361918676d44e}
|
||
- EMEX_PROXY_PASS=${EMEX_PROXY_PASS:-f11c7b6128cc86c6}
|
||
- PCAT_USE_PROXY=${PCAT_USE_PROXY:-true}
|
||
- PCAT_PROXY_HOST=${PCAT_PROXY_HOST:-gw.dataimpulse.com}
|
||
- PCAT_PROXY_USER=${PCAT_PROXY_USER:-}
|
||
- PCAT_PROXY_PASS=${PCAT_PROXY_PASS:-}
|
||
# Vinpin ePER VIN-decode fallback (worker drives the headless browser)
|
||
- VINPIN_ENABLED=${VINPIN_ENABLED:-false}
|
||
- VINPIN_URL=${VINPIN_URL:-https://login.tr.vinpin.online}
|
||
- VINPIN_USER=${VINPIN_USER:-}
|
||
- VINPIN_PASS=${VINPIN_PASS:-}
|
||
# Novu lifecycle e-mail automation — the worker fires trial-ending + win-back
|
||
- NOVU_API_URL=${NOVU_API_URL:-https://api.bildirim.semih.ai}
|
||
- NOVU_API_KEY=${NOVU_API_KEY:-}
|
||
- APP_PUBLIC_URL=${APP_PUBLIC_URL:-https://sase.tr}
|
||
- MAILTRACK_SECRET=${MAILTRACK_SECRET:-}
|
||
# PostHog server-side analytics (payments, subscription lifecycle, $revenue).
|
||
# Empty key → PostHogService no-ops (server-side analytics disabled).
|
||
- POSTHOG_API_KEY=${POSTHOG_API_KEY:-}
|
||
# Personal/secure key → LOCAL feature-flag evaluation (source kill switches,
|
||
# guarded decode rollout, remote config). Empty → flags fail open (inert).
|
||
- POSTHOG_PERSONAL_API_KEY=${POSTHOG_PERSONAL_API_KEY:-}
|
||
# "false" on non-prod → evaluate flags but DON'T emit analytics to prod project.
|
||
- POSTHOG_CAPTURE_ENABLED=${POSTHOG_CAPTURE_ENABLED:-}
|
||
- POSTHOG_HOST=${POSTHOG_HOST:-https://eu.i.posthog.com}
|
||
# Meta Conversions API — server-side signup tracking. Empty → CAPI no-ops.
|
||
- META_CAPI_PIXEL_ID=${META_CAPI_PIXEL_ID:-}
|
||
- META_CAPI_ACCESS_TOKEN=${META_CAPI_ACCESS_TOKEN:-}
|
||
- META_CAPI_TEST_EVENT_CODE=${META_CAPI_TEST_EVENT_CODE:-}
|
||
- OTEL_ENABLED=${OTEL_ENABLED:-false}
|
||
- OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-}
|
||
- OTEL_EXPORTER_OTLP_HEADERS=${OTEL_EXPORTER_OTLP_HEADERS:-}
|
||
- OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-sase-worker}
|
||
- OTEL_TRACE_SAMPLE_RATE=${OTEL_TRACE_SAMPLE_RATE:-1.0}
|
||
# Local catalog-dump lookup (worker drives prefetch which uses CategoriesService).
|
||
- CATALOG_SOURCE_DB_ENABLED=${CATALOG_SOURCE_DB_ENABLED:-false}
|
||
- PCAT_SOURCE_DB_URL=${PCAT_SOURCE_DB_URL:-}
|
||
- EMEX_SOURCE_DB_URL=${EMEX_SOURCE_DB_URL:-}
|
||
# Per-source kill switches. pcat default off (dump doesn't cover TR vehicles).
|
||
- EMEX_SOURCE_DB_ENABLED=${EMEX_SOURCE_DB_ENABLED:-true}
|
||
- PCAT_SOURCE_DB_ENABLED=${PCAT_SOURCE_DB_ENABLED:-false}
|
||
# Per-catalog parts-lookup allowlist (comma-separated). Empty → all
|
||
# fetchCategoryParts calls return null. See sase-emex-source-db-safety
|
||
# memory: catalog-wide bridge had 7-114x noise; only add a catalog once
|
||
# its per-vehicle bridge is wired & OEM-verified.
|
||
- EMEX_SOURCE_DB_ALLOWED_CATALOGS=${EMEX_SOURCE_DB_ALLOWED_CATALOGS:-}
|
||
# Tedarikçi fiyat tazeleme cron'u (19:30 İstanbul) bu env'lerle çalışır;
|
||
# boşsa processor sessiz no-op.
|
||
- SUPPLIER_PRICE_DB_ENABLED=${SUPPLIER_PRICE_DB_ENABLED:-false}
|
||
- SUPPLIER_PRICE_DB_URL=${SUPPLIER_PRICE_DB_URL:-}
|
||
depends_on:
|
||
sase-redis:
|
||
condition: service_healthy
|
||
networks:
|
||
- default
|
||
- coolify
|
||
|
||
sase-redis:
|
||
image: redis:7.4-alpine
|
||
command: redis-server --requirepass ${REDIS_PASSWORD}
|
||
volumes:
|
||
- redis_data:/data
|
||
healthcheck:
|
||
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 5
|
||
networks:
|
||
- default
|
||
|
||
volumes:
|
||
redis_data:
|
||
|
||
networks:
|
||
coolify:
|
||
external: true
|