Files
monica_site/.env.prod.example
T
westfarn 2b3f10e784
Deploy Beta / unit-tests (push) Successful in 21s
Deploy Beta / docker (push) Successful in 26s
Deploy Beta / deploy-beta (push) Successful in 5m20s
Mint campaign UTM links through the piha.li shortener (#10)
## 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
2026-08-30 13:24:40 -07:00

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