westfarn 433308d615
Deploy Beta / unit-tests (push) Successful in 4s
Deploy Beta / docker (push) Successful in 10s
Deploy Beta / deploy-beta (push) Successful in 1m3s
Serve /api/ on piha.lc / beta.piha.li (#8)
## Summary
- Serve `/api/` on `piha.lc` / `beta.piha.li` (Bearer still required).
- Drop `shortener.aimloperations.com` / `shortener-beta.aimloperations.com` from env examples and caller docs.
- `/admin/` stays 404 on the public host.

Closes #7.

## Test plan
- [ ] `POST https://beta.piha.li/api/links/` with valid Bearer → 201
- [ ] Same without Bearer → 401
- [ ] `GET https://beta.piha.li/<code>` still 302
- [ ] `/admin/` on beta.piha.li → 404
- [ ] Unit tests: `cd site && uv run python manage.py test`

Reviewed-on: #8
2026-08-30 17:27:40 -07:00

url_shortening_service

Django 6 URL shortener. monica_site (and other trusted callers) mint links over Bearer auth on the same public host phones use. SMS recipients hit GET /<code> on piha.lc (prod) / beta.piha.li (beta) and get a 302 to the long HTTPS URL.

This service is standalone. Do not fold it into monica_site.

Two surfaces

Who Path Auth Host
Phone / public internet GET /<code> none SHORT_DOMAIN (piha.lc / beta.piha.li)
Anyone GET / none landing page on that same host
monica_site /api/links/ Authorization: Bearer name:secret same host

/api/ is on the public internet. It is not open: every /api/ request needs a named Bearer token. No token / wrong token → 401. No tokens configured → 503. GET /<code> never requires a token.

/admin/ is 404 on the public host (localhost only). GET /debug/ is a mint form when DEBUG=true and never on the public short host.

Local run

cp .env.example .env
# SHORTENER_API_TOKENS=monica:dev-only-token is already set
docker compose up --build

Or without Docker:

uv sync
cp .env.example .env
cd site && uv run python manage.py migrate
uv run python manage.py runserver
# optional local admin:
# uv run python manage.py createsuperuser
# then http://127.0.0.1:8005/admin/  (compose) or :8000 (runserver)

Tests (SQLite, no network):

cd site && uv run python manage.py test

CI / deploy (Gitea)

Same split as monica_site:

Workflow When What
CI pull request → master unit tests
Deploy Beta push / merge to master unit tests → compose tests → deploy beta
Deploy Prod Actions → Run workflow (button) unit tests → compose tests → deploy prod

Deploy calls server-infra/scripts/deploy.sh --app url_shortening_service. Needs server-infra#22 first.

Use case

  1. Your site POSTs to this service with a Bearer token and a long HTTPS URL.
  2. Response 201 includes short_url built from PUBLIC_SHORT_URL.
  3. A person on the public internet opens that short URL.
  4. This service 302s them to the long URL and increments click_count.

Mint (same host / localhost):

curl -sS -X POST http://127.0.0.1:8005/api/links/ \
  -H "Authorization: Bearer monica:dev-only-token" \
  -H "Content-Type: application/json" \
  -d '{"target_url":"https://mkdrealtor.com/","title":"test"}'

Follow (no token — this is the public path):

curl -sSI http://127.0.0.1:8005/<code>

Expect HTTP/1.1 302 Found and Location: https://mkdrealtor.com/.

Caller integration (onboard + /api/links/): API.md.

Caller contract (monica_site, other repo)

SHORTENER_BASE_URL=https://piha.lc
SHORTENER_API_TOKEN=monica:<same-secret-as-SHORTENER_API_TOKENS>
POST /api/links/
Authorization: Bearer monica:<secret>
Content-Type: application/json

{"target_url":"https://mkdrealtor.com/listings/oak-st?utm_source=monica&utm_medium=sms","title":"Oak St","external_ref":"campaign-uuid"}

target_url must be https and its host must match SHORT_ALLOWED_HOSTS (exact or suffix, e.g. mkdrealtor.com). Same target_url + external_ref + still-active link returns 200 with the existing row instead of a new code.

Do not put the Bearer token on GET /<code>.

Environment

See .env.example and .env.prod.example. Prod secrets live in ~/Documents/secrets/url_shortening_service/ on the control node.

Generate tokens and peppers with:

python -c "import secrets; print(secrets.token_urlsafe(32))"

Never reuse DJANGO_SECRET_KEY as an API token. Never put the token in the short URL, logs, or git.

Deploy notes

One NPM host, container WEB_PORT (default 8005 prod / 8015 beta):

  1. SHORT_DOMAIN (piha.lc prod / beta.piha.li beta) — / landing, GET /[a-z0-9]{4,8}, and /api/ (Bearer). Django 404s /admin/ and /debug/ on this host. Add it to DJANGO_ALLOWED_HOSTS, SHORT_PUBLIC_HOSTS, and SHORT_API_HOSTS.
S
Description
No description provided
Readme
302 KiB
Languages
Python 65.7%
CSS 21.7%
HTML 10.7%
Shell 1.3%
Dockerfile 0.6%