API hosting
The API backs the admin panel, the Android app, and any integration you write. It is optional: with it down, watches still run.
Running it
Section titled “Running it”pnpm serveOr as a container — the repository includes a Dockerfile:
docker build -t watcher .docker run -d --name watcher --env-file .env -p 3000:3000 watcherGET /health is the health-check endpoint. Secrets come from the environment;
never bake them into an image.
Required settings
Section titled “Required settings”-
Everything the executor needs — the model key and the database URI.
-
AUTH_JWT_SECRET, at least 32 characters. The API refuses to start without it rather than serving unauthenticated. -
WEB_ORIGIN— the panel’s origin, so a browser may call the API cross-origin. Comma-separate several. With none set, no CORS headers are sent at all. -
SCHEDULER_ENABLED=falseif a scheduled CI job already runs your watches.
Choosing a host
Section titled “Choosing a host”Any platform that runs a container works. What matters:
| Requirement | Why |
|---|---|
| Outbound internet | Model providers, the sites being watched, alert channels |
| Environment secrets | Everything sensitive arrives that way |
| HTTPS | The panel and app expect it |
| Persistent database elsewhere | The container itself is stateless |
Suspend-when-idle hosting is fine, with one caveat below.
Cold starts
Section titled “Cold starts”The Android app already accounts for this with a warm-up probe and extended retries on the first call.
Stateless by design
Section titled “Stateless by design”The container keeps nothing that matters:
- All persistent state is in the database.
- Key cooldowns are per process and self-heal after a restart.
- Rate-limiter windows reset on restart.
So you can redeploy at any moment. The only cost of a restart mid-run is that the run is lost and repeated next cycle.
Shutdown
Section titled “Shutdown”On SIGTERM or SIGINT the service stops the scheduler, drains in-flight HTTP
requests, flushes buffered usage metering, closes the database connection and
exits.
Scaling
Section titled “Scaling”Watcher is a single-process design. Run one instance with the scheduler
enabled. You may run additional instances with SCHEDULER_ENABLED=false to serve
API traffic, since API requests are stateless — but two schedulers against one
database is not a supported topology.
Verifying a deployment
Section titled “Verifying a deployment”curl -s https://<your-host>/health # {"status":"ok"}curl -s https://<your-host>/config/status # booleans for each integrationThen sign in from the panel and open a watch’s run history — that exercises auth, the database and the read path in one go.