new-site/infra/ansible/roles/app/templates/app.env.j2
justin a04ecf7df3 chore(email): decommission SMTP2GO references — local MTA only
SMTP2GO is no longer used: Listmonk relays through the local Postfix MTA
(172.18.0.1:25 from the Docker network), which DKIM-signs and delivers
direct-to-recipient-MX; transactional mail goes through Carbonio. Verified
zero smtp2go in any live container env + postfix has no external relayhost.

Removed the stale references so a rebuild/new dev can't re-introduce it:
- api/src/config.ts: SMTP_HOST default mail.smtp2go.com -> co.carrierone.com
- scripts/workers/crypto_payment_worker.py: same default fix
- infra/ansible all.yml: listmonk_smtp_* now 172.18.0.1:25, no auth (+comment)
- app.env.j2 / email.ts / crm.md / go-live-todo.md / architecture.svg: docs
2026-06-17 22:46:59 -05:00

168 lines
10 KiB
Django/Jinja

# {{ ansible_managed }}
# Performance West — API + Workers environment variables
# Deployed to {{ project_dir }}/.env by Ansible (ansible-playbook site.yml)
# DO NOT edit this file directly on the server — edit the j2 template and re-run.
NODE_ENV=production
PORT={{ api_port }}
# ── Database (PostgreSQL) ─────────────────────────────────────────────────────
DATABASE_URL=postgresql://{{ pg_user }}:{{ pg_password }}@api-postgres:5432/{{ pg_database }}
DB_PASSWORD={{ pg_password }}
# ── Auth ──────────────────────────────────────────────────────────────────────
ADMIN_JWT_SECRET={{ vault_admin_jwt_secret }}
PW_INTERNAL_API_KEY={{ vault_pw_internal_api_key }}
WEBHOOK_SECRET={{ vault_webhook_secret }}
# ── ERPNext (CRM — source of truth) ──────────────────────────────────────────
ERPNEXT_URL=http://erpnext:8080
ERPNEXT_SITE_NAME={{ domain }}
ERPNEXT_API_KEY={{ vault_erpnext_api_key }}
ERPNEXT_API_SECRET={{ vault_erpnext_api_secret }}
ERPNEXT_DB_PASSWORD={{ erpnext_db_password }}
# ── MinIO (document storage) ─────────────────────────────────────────────────
MINIO_ENDPOINT=minio
MINIO_PORT=9000
MINIO_ACCESS_KEY={{ minio_access_key }}
MINIO_SECRET_KEY={{ minio_secret_key }}
MINIO_BUCKET={{ minio_bucket }}
# ── Stripe ───────────────────────────────────────────────────────────────────
STRIPE_SECRET_KEY={{ vault_stripe_secret_key }}
STRIPE_PUBLISHABLE_KEY={{ vault_stripe_publishable_key }}
STRIPE_WEBHOOK_SECRET={{ vault_stripe_webhook_secret }}
STRIPE_IDENTITY_WEBHOOK_SECRET={{ vault_stripe_identity_webhook_secret }}
# Test keys — used only when NODE_ENV != production
STRIPE_TEST_SECRET_KEY={{ vault_stripe_test_secret_key | default('') }}
STRIPE_TEST_WEBHOOK_SECRET={{ vault_stripe_test_webhook_secret | default('') }}
STRIPE_TEST_IDENTITY_WEBHOOK_SECRET={{ vault_stripe_test_identity_webhook_secret | default('') }}
# ── PayPal ───────────────────────────────────────────────────────────────────
PAYPAL_CLIENT_ID={{ vault_paypal_client_id | default('') }}
PAYPAL_CLIENT_SECRET={{ vault_paypal_client_secret | default('') }}
PAYPAL_API_URL=https://api-m.paypal.com
# ── SHKeeper (crypto payments) ────────────────────────────────────────────────
SHKEEPER_URL=http://127.0.0.1:5000
SHKEEPER_PUBLIC_URL=https://{{ shkeeper_admin_domain }}
SHKEEPER_API_KEY={{ vault_shkeeper_api_key | default('') }}
# ── Workers ───────────────────────────────────────────────────────────────────
WORKER_URL=http://workers:8090
# ── Transactional email — Carbonio (co.carrierone.com) ───────────────────────
# All transactional mail: order confirmations, worker notifications, ERPNext alerts.
# Listmonk mass-mail relays through the local Postfix MTA — configured separately in the Listmonk admin UI.
SMTP_HOST={{ smtp_host }}
SMTP_PORT={{ smtp_port }}
SMTP_USER={{ smtp_user }}
SMTP_PASS={{ smtp_pass }}
SMTP_FROM={{ smtp_from }}
ADMIN_EMAIL={{ smtp_admin_email }}
# ── Listmonk (email marketing) ────────────────────────────────────────────────
LISTMONK_URL=http://listmonk:9000
LISTMONK_ADMIN_USER={{ listmonk_admin_user }}
LISTMONK_ADMIN_PASSWORD={{ listmonk_admin_password }}
LISTMONK_USER={{ listmonk_admin_user }}
LISTMONK_PASS={{ listmonk_admin_password }}
LISTMONK_PASSWORD={{ listmonk_admin_password }}
# Source campaign IDs cloned by the daily trucking campaign builder. Create/fetch
# them with: python3 scripts/create_deficiency_source_campaigns.py
CAMPAIGN_FOR_HIRE_ID={{ trucking_campaign_for_hire_id | default('') }}
CAMPAIGN_IRP_IFTA_ID={{ trucking_campaign_irp_ifta_id | default('') }}
CAMPAIGN_INTRASTATE_ID={{ trucking_campaign_intrastate_id | default('') }}
CAMPAIGN_WEIGHT_TAX_ID={{ trucking_campaign_weight_tax_id | default('') }}
CAMPAIGN_EMISSIONS_ID={{ trucking_campaign_emissions_id | default('') }}
CAMPAIGN_HAZMAT_ID={{ trucking_campaign_hazmat_id | default('') }}
# ── Umami analytics ──────────────────────────────────────────────────────────
UMAMI_DB_PASSWORD={{ umami_db_password }}
UMAMI_APP_SECRET={{ umami_app_secret }}
# ── Anytime Mailbox (IMAP for OTP auto-fetch) ─────────────────────────────────
ANYTIME_MAILBOX_IMAP_HOST={{ smtp_host }}
ANYTIME_MAILBOX_IMAP_PORT=993
ANYTIME_MAILBOX_IMAP_SSL=true
ANYTIME_MAILBOX_IMAP_USER={{ vault_anytime_mailbox_imap_user | default(smtp_user) }}
ANYTIME_MAILBOX_IMAP_PASS={{ vault_anytime_mailbox_imap_pass | default(smtp_pass) }}
ANYTIME_MAILBOX_IMAP_FOLDER=INBOX
ANYTIME_MAILBOX_OTP_SENDER_HINT=anytimemailbox
ANYTIME_MAILBOX_OTP_TIMEOUT_SECONDS=180
ANYTIME_MAILBOX_OTP_POLL_SECONDS=6
ANYTIME_MAILBOX_SIGNUP_EMAIL={{ vault_anytime_mailbox_signup_email | default('filings@performancewest.net') }}
ANYTIME_MAILBOX_SIGNUP_PHONE={{ vault_anytime_mailbox_signup_phone | default('+16025550123') }}
ANYTIME_MAILBOX_DEFAULT_PASSWORD={{ vault_anytime_mailbox_default_password | default('') }}
# ── Relay (ACH / card routing) ────────────────────────────────────────────────
RELAY_IMAP_HOST={{ vault_relay_imap_host | default('') }}
RELAY_IMAP_PORT={{ vault_relay_imap_port | default('993') }}
RELAY_IMAP_USER={{ vault_relay_imap_user | default('') }}
RELAY_IMAP_PASS={{ vault_relay_imap_pass | default('') }}
RELAY_IMAP_FOLDER={{ vault_relay_imap_folder | default('INBOX') }}
RELAY_FILING_CARD_ID={{ vault_relay_filing_card_id | default('') }}
CRYPTO_FILING_CARD_ID={{ vault_crypto_filing_card_id | default('') }}
# ── IRP filings mailbox (state apportioned-fee invoice replies) ──────────────
# Dedicated mailbox the IRP submission Reply-To points at; the irp-invoice-poller
# cron scans it for state fee invoices and bills customers the exact amount.
# Leave the IMAP_USER blank to fall back to OPS_IMAP_* and filter by the
# [PW-IRP ...] subject tag.
IRP_FILINGS_IMAP_HOST={{ vault_irp_filings_imap_host | default(smtp_host) }}
IRP_FILINGS_IMAP_PORT={{ vault_irp_filings_imap_port | default('993') }}
IRP_FILINGS_IMAP_USER={{ vault_irp_filings_imap_user | default('') }}
IRP_FILINGS_IMAP_PASS={{ vault_irp_filings_imap_pass | default('') }}
IRP_FILINGS_IMAP_FOLDER={{ vault_irp_filings_imap_folder | default('INBOX') }}
IRP_FILINGS_FROM={{ vault_irp_filings_from | default('filings@performancewest.net') }}
IRP_SC_EMAIL={{ vault_irp_sc_email | default('MCS@scdmv.net') }}
# Intrastate operating-authority (PSC/PUC) submission emails per base state.
# Leave blank until the exact agency submission address is confirmed — the
# worker then creates a manual todo instead of emailing a guessed address.
ISA_SC_EMAIL={{ vault_isa_sc_email | default('') }}
ISA_GA_EMAIL={{ vault_isa_ga_email | default('') }}
ISA_TX_EMAIL={{ vault_isa_tx_email | default('') }}
# SC PSC MyDMS / E-File portal credentials (non-attorney "Service" filer
# registered under Performance West). Used by the SC intrastate Playwright
# filer to log in and eFile authority applications. Secret lives only in the
# server .env (never committed); blank default here.
ISA_SC_DMS_USER={{ vault_isa_sc_dms_user | default('') }}
ISA_SC_DMS_PASS={{ vault_isa_sc_dms_pass | default('') }}
# ── Porkbun (.ca domain registration) ────────────────────────────────────────
PORKBUN_API_KEY={{ vault_porkbun_api_key | default('') }}
PORKBUN_SECRET_KEY={{ vault_porkbun_secret_key | default('') }}
# ── Flowroute (Canadian DID provisioning) ────────────────────────────────────
FLOWROUTE_ACCESS_KEY={{ vault_flowroute_access_key | default('') }}
FLOWROUTE_SECRET_KEY={{ vault_flowroute_secret_key | default('') }}
# ── HestiaCP (hosting provisioner) ───────────────────────────────────────────
HESTIA_URL={{ vault_hestia_url | default('https://cp.carrierone.com:8083') }}
HESTIA_USER={{ vault_hestia_user | default('admin') }}
HESTIA_PASS={{ vault_hestia_pass | default('') }}
# ── Residential proxy (healthcare NPPES/PECOS automation) ────────────────────
# CMS healthcare portals (NPPES, PECOS, I&A) block datacenter IPs, so the
# Playwright healthcare flows egress through a residential SOCKS proxy
# (host hg409y7ez04.sn.mynetname.net, username "performancewest").
#
# Chromium can't use an *authenticated* SOCKS5 proxy, so the docker-compose
# "proxy-relay" (gost) listens unauthenticated and forwards to the
# authenticated upstream below. Workers point Playwright at the relay.
#
# HEALTHCARE_PROXY_UPSTREAM_URL = authenticated upstream consumed by the relay.
# Password may contain URL-special chars; store it PERCENT-ENCODED here
# (e.g. '#' -> '%23'): socks5://performancewest:<pw%23enc>@host:11080
# HEALTHCARE_PROXY_URL = address Playwright/workers use (the relay, no auth).
HEALTHCARE_PROXY_UPSTREAM_URL={{ vault_healthcare_proxy_upstream_url | default('') }}
HEALTHCARE_PROXY_URL={{ healthcare_proxy_url | default('socks5://proxy-relay:11080') }}
UNDETECTED_PROXY_URL={{ undetected_proxy_url | default('socks5://proxy-relay:11080') }}
# ── Application URLs ──────────────────────────────────────────────────────────
DOMAIN=https://{{ domain }}
SITE_URL=https://{{ domain }}
API_URL=https://{{ api_domain }}
PORTAL_URL=https://{{ portal_domain }}