## Summary Closes #9. - Campaign composer auto-inserts a tracked homepage link (`utm_source=monica`, `utm_medium` = channel, `utm_campaign` = slug of the name) for email, SMS, and postcard QR — no manual UTM paste. - When `SHORTENER_BASE_URL` + `SHORTENER_API_TOKEN` are set, the app mints that long HTTPS URL via `POST /api/links/` on the shortener **API host** and puts the returned `piha.li` / `beta.piha.li` short URL in SMS, email hrefs, and QR codes. Empty env (local) falls back to the long UTM URL. - Live composer resolves shorts through a portal JSON endpoint (login + CSRF). Browser never calls the shortener. ## Secrets (control node, not git) **monica_site** (`~/Documents/secrets/monica_site/`): ``` # prod SHORTENER_BASE_URL=https://shortener.aimloperations.com SHORTENER_API_TOKEN=monica:<secret> # beta SHORTENER_BASE_URL=https://shortener-beta.aimloperations.com SHORTENER_API_TOKEN=monica:<beta-secret> ``` **url_shortening_service** (same secret, named token): ``` SHORTENER_API_TOKENS=monica:<secret> SHORT_ALLOWED_HOSTS=mkdrealtor.com,aimloperations.com ``` Prod public short host: `piha.li`. Beta: `beta.piha.li`. Generate with `python -c "import secrets; print(secrets.token_urlsafe(32))"`. Template port: westfarn/web_django_template#3 ## Test plan - [ ] `cd site && uv run python manage.py test messaging.tests.CampaignUtmLinkTests` - [ ] Composer: type a campaign name — email gets an HTML link, SMS gets a URL, postcard shows a QR - [ ] With shortener env set: SMS/QR show `piha.li` (or `beta.piha.li`); without it, long UTM URL still works - [ ] Copy/download QR into postcard designer - [ ] Secret files have `SHORTENER_*` on both caller and operator sides before beta/prod deploy Reviewed-on: #10
135 lines
5.4 KiB
Bash
135 lines
5.4 KiB
Bash
# Secret env files for server-infra deploy.
|
|
# Copy to the control node (never commit):
|
|
# ~/Documents/secrets/monica_site/monica_site_prod.env
|
|
# ~/Documents/secrets/monica_site/monica_site_beta.env
|
|
#
|
|
# server-infra pushes these to /opt/apps/env/monica_site_<env>.env on each host.
|
|
#
|
|
# Docker Compose: if a secret contains $ (e.g. in DATABASE_URL password), escape each
|
|
# $ as $$ or compose will treat $word as a variable.
|
|
|
|
# =============================================================================
|
|
# PROD — mkdrealtor.com (holding page until launch)
|
|
# =============================================================================
|
|
DJANGO_ENV=prod
|
|
DJANGO_DEBUG=false
|
|
DJANGO_SECRET_KEY=replace-with-a-long-random-secret
|
|
DJANGO_ALLOWED_HOSTS=mkdrealtor.com,www.mkdrealtor.com
|
|
# Optional override; when unset, https:// origins are derived from DJANGO_ALLOWED_HOSTS.
|
|
# DJANGO_CSRF_TRUSTED_ORIGINS=https://mkdrealtor.com,https://www.mkdrealtor.com
|
|
|
|
# Holding page gate — keep true on prod until go-live; beta should be false.
|
|
SITE_UNDER_CONSTRUCTION=true
|
|
|
|
SITE_NAME=Monica Dhillon
|
|
SITE_TAGLINE=MKDRealtor.com · EXIT Realty Redefined
|
|
PUBLIC_SITE_URL=https://mkdrealtor.com
|
|
# Inbox From. Docker Compose .env: do NOT use "Name" <addr> (breaks parse).
|
|
# Prefer bare address (SITE_NAME auto-wrapped) OR one quoted string:
|
|
# DEFAULT_FROM_EMAIL=notifications-beta@mkdrealtor.com
|
|
# DEFAULT_FROM_EMAIL="Monica Dhillon <notifications-beta@mkdrealtor.com>"
|
|
DEFAULT_FROM_EMAIL=noreply@mkdrealtor.com
|
|
CONTACT_PHONE=
|
|
CONTACT_EMAIL=
|
|
CONTACT_SERVICE_AREA=Serving Greater Metro Area
|
|
CREDIT_NAME=AI ML Operations, LLC
|
|
CREDIT_URL=https://aimloperations.com
|
|
|
|
# Shared external Postgres (10.0.0.230)
|
|
DATABASE_URL=postgres://westfarn:replace-db-password@10.0.0.230:5432/monica_site
|
|
|
|
# Host port on adama/roslin/ai-server-4080 (must match server-infra host_apps)
|
|
WEB_PORT=8004
|
|
|
|
# reCAPTCHA v3
|
|
RECAPTCHA_PUBLIC_KEY=replace-me
|
|
RECAPTCHA_PRIVATE_KEY=replace-me
|
|
|
|
# SMTP2GO email — HOST_USER is SMTP auth only; From uses DEFAULT_FROM_EMAIL
|
|
EMAIL_HOST=mail.smtp2go.com
|
|
EMAIL_HOST_USER=replace-me
|
|
EMAIL_HOST_PASSWORD=replace-me
|
|
EMAIL_PORT=2525
|
|
EMAIL_USE_TLS=true
|
|
|
|
# SMTP2GO SMS
|
|
SMTP2GO_SMS_API_KEY=replace-me
|
|
# Email + SMS event webhook auth. SMTP2GO Authorization header = Bearer + this value.
|
|
SMTP2GO_WEBHOOK_SECRET=replace-me
|
|
|
|
# Postcards — PCM Integrations (key+secret → POST /auth/login → Bearer token)
|
|
POSTCARD_PROVIDER=pcm
|
|
PCM_API_KEY=replace-me
|
|
PCM_API_SECRET=replace-me
|
|
# PCM_CHILD_REF_NBR=
|
|
# One signature secret per PCM webhook subscription (comma-separated).
|
|
PCM_WEBHOOK_SECRETS=replace-me,replace-me-2
|
|
# PCM_WEBHOOK_SECRET=replace-me # optional single-secret alias
|
|
|
|
# JSON return address for postcard orders (quote so compose keeps commas)
|
|
PCM_RETURN_ADDRESS='{"firstName":"Monica","lastName":"Dhillon","address":"replace-me","city":"replace-me","state":"IL","zipCode":"replace-me"}'
|
|
# LOB_API_KEY= # only if POSTCARD_PROVIDER=lob
|
|
# CLICK2MAIL_API_KEY=
|
|
# POSTGRID_API_KEY=
|
|
|
|
# Social (native OAuth)
|
|
# LinkedIn Client ID/Secret: Portal → Social accounts (not env).
|
|
# LinkedIn Auth redirect (prod): https://YOUR_DOMAIN/portal/social/accounts/linkedin/callback/
|
|
META_APP_ID=
|
|
META_APP_SECRET=
|
|
# Must be a real Fernet key (44 chars). Generate:
|
|
# python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
|
# Do NOT use a placeholder — invalid keys break LinkedIn/Meta token save.
|
|
SOCIAL_TOKEN_ENCRYPTION_KEY=
|
|
|
|
# Ollama for social drafting (reachable from app hosts)
|
|
OLLAMA_BASE_URL=http://10.0.0.128:11434
|
|
OLLAMA_MODEL=llama3.2
|
|
OLLAMA_TIMEOUT_SECONDS=120
|
|
|
|
# URL shortener — mint short links for campaign SMS / email / postcard QR.
|
|
# POST /api/links/ on the API host. Recipients hit https://piha.li/<code>.
|
|
# Token must match SHORTENER_API_TOKENS on url_shortening_service (name:secret).
|
|
# Generate: python -c "import secrets; print(secrets.token_urlsafe(32))"
|
|
SHORTENER_BASE_URL=https://shortener.aimloperations.com
|
|
SHORTENER_API_TOKEN=monica:replace-me
|
|
|
|
# Nominatim address suggest (server-side proxy only; not called from browser)
|
|
NOMINATIM_BASE_URL=http://10.0.0.128:8089
|
|
NOMINATIM_TIMEOUT_SECONDS=8
|
|
NOMINATIM_COUNTRY_CODES=us
|
|
# NOMINATIM_API_KEY=
|
|
|
|
# Tianji analytics (pageviews + events)
|
|
TIANJI_ENABLED=true
|
|
TIANJI_TRACKER_URL=https://tianji.aimloperations.com/tracker.js
|
|
TIANJI_WEBSITE_ID=cmshzhxdf6gee10qzkzrfn9iw
|
|
|
|
GUNICORN_WORKERS=2
|
|
GUNICORN_BIND=0.0.0.0:8000
|
|
|
|
# =============================================================================
|
|
# BETA overrides — monica-preview.aimloperations.com (full app)
|
|
# File: monica_site_beta.env
|
|
# =============================================================================
|
|
# DJANGO_ENV=beta
|
|
# DJANGO_DEBUG=false
|
|
# DJANGO_SECRET_KEY=replace-with-a-different-beta-secret
|
|
# DJANGO_ALLOWED_HOSTS=monica-preview.aimloperations.com
|
|
# SITE_UNDER_CONSTRUCTION=false
|
|
# PUBLIC_SITE_URL=https://monica-preview.aimloperations.com
|
|
# DATABASE_URL=postgres://westfarn:replace-db-password@10.0.0.230:5432/monica_site_beta
|
|
# WEB_PORT=8014
|
|
# RECAPTCHA_PUBLIC_KEY=replace-me
|
|
# RECAPTCHA_PRIVATE_KEY=replace-me
|
|
# EMAIL_HOST_USER=replace-me
|
|
# EMAIL_HOST_PASSWORD=replace-me
|
|
# SMTP2GO_SMS_API_KEY=replace-me
|
|
# LOB_API_KEY=replace-me
|
|
# SOCIAL_TOKEN_ENCRYPTION_KEY= # real Fernet.generate_key() output, not a placeholder
|
|
# OLLAMA_BASE_URL=http://10.0.0.128:11434
|
|
# NOMINATIM_BASE_URL=http://10.0.0.128:8089
|
|
# NOMINATIM_COUNTRY_CODES=us
|
|
# SHORTENER_BASE_URL=https://shortener-beta.aimloperations.com
|
|
# SHORTENER_API_TOKEN=monica:replace-with-a-different-token
|