Caldera Labs

Orbital Outlook – Automated Launch Briefings for Slack

Engineering TeamVersion 1.0.0Completed
DenoSlackLaunch LibraryLLM SummariesCron Jobs

Overview

Orbital Outlook is a Deno-based background service that watches upcoming launches, enriches each mission with trusted news or web context, and posts a single daily briefing to our  #outer-space Slack channel. The service runs on Vercel's Deno runtime, stores launch snapshots plus Slack metadata in Neon Postgres, and leans on OpenAI for web search and conversational summarization.

Under the hood we follow a layered approach: domain models describe launches, summaries, and Slack blocks; infrastructure adapters talk to Launch Library 2, Spaceflight News, OpenAI, Slack, and Postgres; and orchestration pipelines compose everything into the hourly cache refresh and the daily publishing run.

Every digest opens with NASA's Astronomy Picture of the Day, dropping the image URL and a trimmed GPT caption ahead of the launch stack so Space Nerds get fresh art alongside the schedule.

The Daily Slack Rhythm

Every morning the bot announces whether launches are scheduled for the requested date and, when nothing is on the pad, automatically rolls the copy forward to the next window. The entry stays pinned so folks can quickly see schedules, vehicle details, and any scrub notices. Same-day launches remain in view after liftoff so the hourly refresh can append the final status once web-search snippets report a confirmed outcome.

Sample Orbital Outlook Slack post showing highlights and launch schedule

Data Pipeline

The hourly pipeline wires together Launch Library 2, Spaceflight News, OpenAI web search, and our persistence layer. Everything is wrapped in a resilient HTTP client that understands retries, conditional requests, and caching headers.

Launch intake

`LaunchService` pulls detailed manifests from Launch Library 2, preserving provider metadata, launch windows, and pad data. ETags are stored in Postgres so we skip unchanged feeds.

News + web context

Spaceflight News lookups and OpenAI web-search queries run in parallel pools, trimming each launch to three high-confidence tidbits for the prompt.

Snapshot cache

Every processed launch plus the rendered summary is written to `daily_launches` and `launch_summaries`, providing a historical record and a fast reuse path for the daily run.

Idempotent orchestration

Summaries are hashed (`computeSummaryHash`) before persisting. If nothing changed, we simply reuse the cached payload and skip writes, which keeps cron executions cheap.

Enrichment & Summaries

`SummaryService.prepareDailySummary` filters launches for the requested timezone, auto-labels the intro (today, tomorrow, or a friendly date), and falls forward when a day is empty. Each launch section carries mission background, provider notes, and formatted schedules so the LLM prompt only has to polish tone—not invent facts. The intro also embeds the APOD image link plus a succinct caption so every Slack post pairs the mission rundown with NASA's featured photo of the day.

  • • Astronomy Picture of the Day metadata is cached per run so the HD image + caption stay consistent across the hourly refresh and daily publish.
  • • Spaceflight news + search results feed a Launch Status Monitor that spots scrubs, failures, or confirmed liftoffs and surfaces those inside the metadata block, including post-launch updates when fresh coverage lands within the first hour after liftoff.
  • • Prompt payloads include the full enriched launch array plus audience/tone hints, and the same payload is stored with the cache for replay or debugging.

Slack Delivery & Pin Management

The notification gateway wraps the Slack Web API for posting, updating, fetching channel history, and reconciling pins. We only post when the digest changes, otherwise the pipeline exits early to avoid rate limits.

Create or update

If a message already exists for the day we update it in place; otherwise we create and immediately persist the timestamp + permalink so future runs know where to operate.

Pin reconciliation

`reconcilePins` guarantees exactly one pinned summary per channel by unpinning anything stale before pinning the latest.

Slack-aware metadata

Launch summaries track the Slack channel, timestamps, and hash inside Postgres, which lets `/daily` skip re-posting even if the cron fires multiple times.

Architecture & Ops Posture

The service exposes `/api/healthz`, `/api/hourly`, and `/api/daily` through an Oak server with per-request correlation IDs. Config is type-safe and validated on boot so missing env vars fail fast.

Dependency container

We register clients (Launch Library, Spaceflight News, Slack, OpenAI, Postgres) and repositories once, then lazily resolve them within handlers. Swapping adapters for testing stays easy.

Vercel deployment

Cron jobs hit `/api/hourly` every hour and `/api/daily` shortly after midnight UTC. Secrets live in Vercel, and Neon's schema auto-initialises when the service boots.

Observability

Structured JSON logging captures request IDs, latency, cache hits, and upstream errors—enough to wire alerts for repeated failures or missing daily posts.

Secrets & env matrix

Environment docs outline the Slack token, OpenAI keys, Neon URL and tuning flags so staging, preview, and production stay in lockstep.