Port campaign tracked-link UX and piha.li shortener integration from monica_site into this template so new client sites get both without copying by hand.
Reference implementation: ai_ml_operations/monica_site (issue to be linked after create; includes composer UTM panel + POST /api/links/ client).
Template split: email_sms (email/SMS composer) and directmail (postcard QR). Shared helper should live where both flags can use it (core or a small shared module) — do not duplicate mint logic.
Configured shortener mints piha.li / beta.piha.li URLs into SMS + QR
Feature-flag off → no shortener calls, no extra nav
Tests for UTM shape, mint (mocked HTTP), and unconfigured fallback
Env examples document caller + operator secrets
Port campaign tracked-link UX and piha.li shortener integration from monica_site into this template so new client sites get both without copying by hand.
Reference implementation: [ai_ml_operations/monica_site](https://git.aimloperations.com/ai_ml_operations/monica_site) (issue to be linked after create; includes composer UTM panel + `POST /api/links/` client).
Template split: `email_sms` (email/SMS composer) and `directmail` (postcard QR). Shared helper should live where both flags can use it (core or a small shared module) — do not duplicate mint logic.
## 1. Auto UTM tracked links (composer + report)
Same contract as Monica:
- `utm_source` = client brand slug (not hardcoded `monica`; derive from site/branding)
- `utm_medium` = `email` | `sms` | `postcard`
- `utm_campaign` = hyphenated campaign name
- Email: insert/refresh HTML `<a>` as the name is typed / on save
- SMS: insert/refresh a plain-text URL (preview may linkify; the stored body stays text)
- Postcard: QR of the tracked URL for copy/download into the PCM designer
- Campaign report page shows the same panel
## 2. URL shortener
Call [url_shortening_service](https://git.aimloperations.com/ai_ml_operations/url_shortening_service) ([API.md](https://git.aimloperations.com/ai_ml_operations/url_shortening_service/src/branch/master/API.md)).
- `POST /api/links/` on the **API host** (`SHORTENER_BASE_URL`), never `piha.li` / `beta.piha.li`
- Auth: `Authorization: Bearer <name>:<secret>` (`SHORTENER_API_TOKEN`)
- UTM query on `target_url` before mint; `external_ref` = campaign UUID
- Live composer: portal JSON endpoint (login + CSRF). Browser must not call the shortener (no CORS).
- Unconfigured env → long UTM URL, compose still works
- `target_url` must be `https` and host must be on the shortener allowlist (`SHORT_ALLOWED_HOSTS` on that service)
## 3. Env / secrets to document in `.env.example` + `.env.prod.example`
```
SHORTENER_BASE_URL=https://shortener.aimloperations.com
SHORTENER_API_TOKEN=<caller-name>:<secret>
```
Beta: `https://shortener-beta.aimloperations.com` + a distinct token.
Operator side (shortener secret files, not this repo):
```
SHORTENER_API_TOKENS=<caller-name>:<secret>
SHORT_ALLOWED_HOSTS=<client-domain>,aimloperations.com
```
Public short hosts: `piha.li` (prod), `beta.piha.li` (beta).
`scripts/bootstrap-client.sh` / `validate-env.sh`: require these when `FEATURE_EMAIL_SMS` or `FEATURE_DIRECT_MAIL` is on in beta/prod.
## Acceptance
- [ ] Email/SMS/postcard composers auto-build UTM links (brand-specific `utm_source`)
- [ ] Configured shortener mints `piha.li` / `beta.piha.li` URLs into SMS + QR
- [ ] Feature-flag off → no shortener calls, no extra nav
- [ ] Tests for UTM shape, mint (mocked HTTP), and unconfigured fallback
- [ ] Env examples document caller + operator secrets
That ticket covers auto UTM in the campaign composer plus minting short links via POST /api/links/ on the shortener API host. Copy that behavior into email_sms + directmail (shared mint client).
Monica implementation (source of truth for this port): https://git.aimloperations.com/ai_ml_operations/monica_site/issues/9
That ticket covers auto UTM in the campaign composer plus minting short links via `POST /api/links/` on the shortener API host. Copy that behavior into `email_sms` + `directmail` (shared mint client).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Port campaign tracked-link UX and piha.li shortener integration from monica_site into this template so new client sites get both without copying by hand.
Reference implementation: ai_ml_operations/monica_site (issue to be linked after create; includes composer UTM panel +
POST /api/links/client).Template split:
email_sms(email/SMS composer) anddirectmail(postcard QR). Shared helper should live where both flags can use it (core or a small shared module) — do not duplicate mint logic.1. Auto UTM tracked links (composer + report)
Same contract as Monica:
utm_source= client brand slug (not hardcodedmonica; derive from site/branding)utm_medium=email|sms|postcardutm_campaign= hyphenated campaign name<a>as the name is typed / on save2. URL shortener
Call url_shortening_service (API.md).
POST /api/links/on the API host (SHORTENER_BASE_URL), neverpiha.li/beta.piha.liAuthorization: Bearer <name>:<secret>(SHORTENER_API_TOKEN)target_urlbefore mint;external_ref= campaign UUIDtarget_urlmust behttpsand host must be on the shortener allowlist (SHORT_ALLOWED_HOSTSon that service)3. Env / secrets to document in
.env.example+.env.prod.exampleBeta:
https://shortener-beta.aimloperations.com+ a distinct token.Operator side (shortener secret files, not this repo):
Public short hosts:
piha.li(prod),beta.piha.li(beta).scripts/bootstrap-client.sh/validate-env.sh: require these whenFEATURE_EMAIL_SMSorFEATURE_DIRECT_MAILis on in beta/prod.Acceptance
utm_source)piha.li/beta.piha.liURLs into SMS + QRMonica implementation (source of truth for this port): ai_ml_operations/monica_site#9
That ticket covers auto UTM in the campaign composer plus minting short links via
POST /api/links/on the shortener API host. Copy that behavior intoemail_sms+directmail(shared mint client).