mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
Addresses two seventh-round review findings on PR #3157. 1. Cross-directory imports + current Railway build root (todo 230). The consolidated digest cron imports from ../api, ../shared, and (transitively via scripts/lib/brief-compose.mjs) ../server/_shared. The running digest-notifications Railway service builds from the scripts/ root — those parent paths are outside the deploy tree and would 500 on next rebuild with ERR_MODULE_NOT_FOUND. New Dockerfile.digest-notifications (repo-root build context) COPYs exactly the modules the cron needs: scripts/ contents, scripts/lib/, shared/brief-envelope.*, shared/brief-filter.*, server/_shared/brief-render.*, api/_upstash-json.js, api/_seed-envelope.js. Tight list to keep the watch surface small. Pattern matches the retired Dockerfile.seed-brief-composer + the existing Dockerfile.relay. 2. Silent compose failures (todo 231). composeBriefsForRun logged counters but never exited non-zero. An Upstash outage or missing signing secret silently dropped every brief write while Railway showed the cron green. The retired standalone composer exited 1 on structural failures; that observability was lost in the consolidation. Changed the compose fn to return {briefByUser, composeSuccess, composeFailed}. Main captures the counters, runs the full digest send loop first (compose-layer breakage must NEVER block user- visible digest delivery), then calls shouldExitNonZero at the very end. Exit-on-failure gives ops the Railway-red signal without touching send behaviour. Also: a total read failure of news:insights:v1 (catch branch) now counts as 1 compose failure so the gate trips on insights- key infra breakage, not just per-user write failures. Tests unchanged (98/98). Typecheck + node --check clean. Biome complexity ticks 63→65 — same pre-existing bucket, already tolerated by CI; no new blocker. PRE-MERGE Railway work still pending: set BRIEF_URL_SIGNING_SECRET + WORLDMONITOR_PUBLIC_BASE_URL on the digest-notifications service, AND switch its dockerfilePath to /Dockerfile.digest-notifications before merging. Without the dockerfilePath switch, the next rebuild fails.
57 lines
2.6 KiB
Docker
57 lines
2.6 KiB
Docker
# =============================================================================
|
|
# Digest notifications cron (consolidated: digest + brief compose + channel send)
|
|
# =============================================================================
|
|
# Runs scripts/seed-digest-notifications.mjs as a Railway cron (every 30 min).
|
|
# The script now also owns the brief envelope write path — per-user
|
|
# brief:{userId}:{issueDate} keys are produced here, and every channel
|
|
# dispatch (email/telegram/slack/discord) gets a signed magazine URL CTA.
|
|
#
|
|
# Historical context: before 2026-04-18 this service built from the
|
|
# scripts/ root with plain `npm ci`. The consolidation PR introduced
|
|
# cross-directory imports (shared/*, server/_shared/*, api/*) so the
|
|
# service now needs repo-root as build context with the specific
|
|
# modules COPY'd in. The retired seed-brief-composer Dockerfile had
|
|
# the same pattern.
|
|
#
|
|
# Required env (Railway service vars):
|
|
# UPSTASH_REDIS_REST_URL
|
|
# UPSTASH_REDIS_REST_TOKEN
|
|
# CONVEX_URL (or CONVEX_SITE_URL)
|
|
# RELAY_SHARED_SECRET
|
|
# RESEND_API_KEY
|
|
# TELEGRAM_BOT_TOKEN
|
|
# BRIEF_URL_SIGNING_SECRET (brief compose disabled without this)
|
|
# WORLDMONITOR_PUBLIC_BASE_URL (defaults to https://worldmonitor.app)
|
|
# Optional:
|
|
# DIGEST_CRON_ENABLED=0 (kill switch for the whole cron)
|
|
# BRIEF_COMPOSE_ENABLED=0 (kill switch for just brief compose)
|
|
# AI_DIGEST_ENABLED=0 (kill switch for AI summary LLM call)
|
|
# =============================================================================
|
|
|
|
FROM node:22-alpine
|
|
|
|
WORKDIR /app
|
|
|
|
# Install scripts/ runtime dependencies (resend, convex, etc.).
|
|
COPY scripts/package.json scripts/package-lock.json ./scripts/
|
|
RUN npm ci --prefix scripts --omit=dev
|
|
|
|
# Digest cron + shared script helpers it imports via createRequire.
|
|
COPY scripts/seed-digest-notifications.mjs ./scripts/
|
|
COPY scripts/_digest-markdown.mjs ./scripts/
|
|
COPY scripts/lib/ ./scripts/lib/
|
|
|
|
# Brief envelope contract + filter + renderer assertion. These live
|
|
# under shared/ and server/_shared/ in the repo and are imported from
|
|
# scripts/lib/brief-compose.mjs. Keep this COPY list tight — adding
|
|
# unrelated shared/* files expands the rebuild watch surface.
|
|
COPY shared/brief-envelope.js shared/brief-envelope.d.ts ./shared/
|
|
COPY shared/brief-filter.js shared/brief-filter.d.ts ./shared/
|
|
COPY server/_shared/brief-render.js server/_shared/brief-render.d.ts ./server/_shared/
|
|
|
|
# Upstash REST helper (brief compose uses redisPipeline + readRawJson).
|
|
COPY api/_upstash-json.js ./api/
|
|
COPY api/_seed-envelope.js ./api/
|
|
|
|
CMD ["node", "scripts/seed-digest-notifications.mjs"]
|