# Deploying Three things must be true before the system is useful, and the third is the one the previous version got wrong. ## 1. Compose service ```yaml news: image: git.rcjohnstone.com/connor/news:latest restart: unless-stopped networks: [internal] environment: - TZ=America/Louisville - NEWS_DB=/data/news.db - NEWS_CONFIG_DIR=/config # ntfy. The topic must differ from news_triage's during the parallel run. - NTFY_URL=${NTFY_URL} - NTFY_TOPIC=news2 - NTFY_USER=${NTFY_USER} - NTFY_PASS=${NTFY_PASS} # REQUIRED for feedback buttons -- see section 3. - NEWS_API_BASE_URL=https://news2.rcjohnstone.com - NEWS_FEEDBACK_SECRET=${NEWS_FEEDBACK_SECRET} # One LLM call per day, for the digest prose only. - NEWS_LITELLM_KEY=${NEWS_LITELLM_KEY} volumes: - ./data/news2:/data - ./config/news2:/config:ro healthcheck: # NOT curl. The v0.2 image shipped no curl, so its healthcheck failed # forever while the service was fine and `podman ps` lied for four days. test: ["CMD", "python", "-c", "import urllib.request;urllib.request.urlopen('http://localhost:3000/healthz')"] interval: 60s timeout: 5s retries: 3 start_period: 20s ``` Remember that a bind-mounted config change needs `sudo podman restart news`; `podman-compose up -d` will not restart a container when only a mounted file changed. An **environment** change does need the full `up -d`. ## 2. Caddy vhost ``` news2.rcjohnstone.com { reverse_proxy news:3000 } ``` ## 3. Why the feedback buttons need all of this ntfy executes an action button's HTTP request **from the phone**, not from the server. So a container-local address can never work, and this is exactly how the previous version failed: `NEWS_API_BASE_URL` was unset, the buttons were dropped behind a single boot WARN, and nobody noticed for a week. The result was 32 feedback labels in total -- for a system whose entire premise is learning from feedback. Because the endpoint is therefore public, every button carries an HMAC signed over `(cluster_id, kind)`. A leaked URL authorises one vote on one story rather than acting as a bearer token for the whole model. Generate the secret once: ```sh openssl rand -hex 32 # -> NEWS_FEEDBACK_SECRET in ~/.env ``` `news notify` prints a loud warning and omits the buttons if either `NEWS_API_BASE_URL` or `NEWS_FEEDBACK_SECRET` is missing, rather than shipping inert buttons. ## 4. Scheduling Two timers, or one loop inside the container: ``` */15 * * * * news poll && news notify 45 8 * * * news digest ``` ## 5. Running in parallel with news_triage Use a different ntfy topic and a different vhost, and leave `news_triage` running. Compare a week of both before retiring it.