Closes #13.
monica_site
Django 6 marketing platform for Monica Dhillon / MKDRealtor.com — public site, realtor portal, multi-channel outreach (email + SMS via SMTP2GO, postcards via PCM Integrations), and social scheduling (Facebook / Instagram / LinkedIn) with Ollama-assisted drafting.
Stack
- Django 6 +
uv - Postgres (prod/beta); SQLite locally when
DATABASE_URLunset - dj-queue (Django Tasks backend, Postgres queue, no Redis/Celery)
- Docker; deploy via
server-infraAnsible pipeline
Environments
| Env | Domain | Port (host) | Gate |
|---|---|---|---|
| prod | mkdrealtor.com |
8004 | SITE_UNDER_CONSTRUCTION=true (holding page) |
| beta | monica-preview.aimloperations.com |
8014 | full app (SITE_UNDER_CONSTRUCTION=false) |
Local development
uv sync
cd site
uv run python manage.py migrate
uv run python manage.py runserver
# optional: docker compose up # web + postgres + worker (hot reload)
Docker compose mounts ./site into the container and runs Django runserver when
DJANGO_ENV=dev (the default). The worker service polls dispatch_due every 15s so
scheduled campaigns and social posts fire without a manual command. Edit Python/templates
→ auto-reload; no image rebuild.
Rebuild only when Dockerfile, entrypoint scripts, or deps (pyproject.toml, uv.lock) change:
docker compose up --build
Local secrets (SMTP2GO, etc.)
Copy .env.example → .env (gitignored). Compose reads .env for email vars.
cp .env.example .env
# fill EMAIL_HOST_USER / EMAIL_HOST_PASSWORD
# for real delivery (not console logs):
# EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
docker compose up
Without EMAIL_BACKEND=…smtp…, mail prints to the web container logs (console backend).
SMTP2GO delivery webhooks
See site/messaging/README.md for SMTP2GO email/SMS webhooks
and PCM Integrations postcard designer + webhook setup (Bearer auth, events).
Prod compose (docker-compose.prod.yml) still uses gunicorn with baked-in image code.
Secret env files (control node)
Create on the deploy host:
~/Documents/secrets/monica_site/monica_site_prod.env
~/Documents/secrets/monica_site/monica_site_beta.env
Templates: .env.prod.example (full var list). Validate with:
./scripts/validate-env.sh ~/Documents/secrets/monica_site/monica_site_prod.env
Campaign UTM short links (piha.li) need both sides:
| File | Vars |
|---|---|
monica_site_prod.env |
SHORTENER_BASE_URL=https://piha.lc · SHORTENER_API_TOKEN=monica:<secret> |
monica_site_beta.env |
SHORTENER_BASE_URL=https://beta.piha.li · distinct SHORTENER_API_TOKEN |
url_shortening_service_prod.env |
SHORTENER_API_TOKENS=monica:<same-secret> · SHORT_ALLOWED_HOSTS includes mkdrealtor.com · PUBLIC_SHORT_URL=https://piha.lc |
url_shortening_service_beta.env |
matching beta token · PUBLIC_SHORT_URL=https://beta.piha.li |
Generate the secret with python -c "import secrets; print(secrets.token_urlsafe(32))". Do not put it in git. Mint and redirects share the short host; Bearer is required on /api/.
Deploy
CI on merge to main → tests → server-infra/scripts/deploy.sh --app monica_site --env prod --ref <sha>.
Start the dj-queue worker on exactly one host:
docker compose -f docker-compose.prod.yml --profile worker up -d
Apps
public · accounts · dashboard · leads · contacts · analytics · messaging · social
Social AI drafts: POST /portal/social/api/generate/ → Ollama at OLLAMA_BASE_URL (default http://10.0.0.128:11434).
See docs/monica-site-design.md for architecture.