Document how the live feed reaches production

Production shows yahoo with a ten minute delay because LIVE_SOURCE=schwab lives
in .env, which is gitignored and so has never been deployed. Nothing in the repo
can carry it, and that is deliberate — but it means the switch is invisible
until someone looks at the status line and wonders.

Written down: the three Coolify variables, the token file that has to land on
the persistent volume, and two things easy to get wrong. The local token needs
no new login because it was minted against the production callback and Schwab
binds tokens to the app rather than the machine. And the dev stream has to stop
first, because one refresh token means one streaming connection and the two
installs will fight over it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Chris Amow 2026-08-11 00:28:15 -05:00
parent decd069ec8
commit 3dfd44aa02

View file

@ -134,6 +134,50 @@ curl -X POST -H "Authorization: Bearer $(cat ~/.coolify-token)" \
``` ```
## Putting the live feed on production
Production runs the default `LIVE_SOURCE=yahoo` and therefore shows "yahoo" with
a ~10 minute delay. `LIVE_SOURCE=schwab` and the credentials live in `.env`,
which is gitignored — so the switch has never crossed the deploy boundary. It
cannot: nothing in the repo carries it.
Four things are needed, and all of them are set on the VPS rather than here.
**1. Environment, in Coolify:**
```
LIVE_SOURCE=schwab
SCHWAB_API_KEY=... # same values as the local .env
SCHWAB_APP_SECRET=...
```
`SCHWAB_CALLBACK_URL` already defaults to `https://chart.amow.com/api/qt`, which
is what the Schwab app is registered with. Do not change it — a registered
callback edit can send the app back through approval.
**2. The OAuth token, at `data/.schwab_token.json` on the persistent volume.**
No new login is required: the local token was minted against the production
callback, and Schwab tokens are bound to the app rather than the machine. Copy
the file's contents into that path on the volume. If the path is not persistent,
the next deploy erases it and production falls silently back to Yahoo.
**3. Stop the dev stream first.** One refresh token means one Schwab streaming
connection. Dev and production both streaming will fight for it — see the risk
register on duplicate connections. Set `LIVE_SOURCE=yahoo` in the local `.env`,
or stop the local stack, before production goes live.
**4. Plan for expiry.** The Schwab refresh token lasts about seven days. When it
lapses, production drops back to Yahoo and needs a fresh token by the same
route: run the flow locally, paste the callback URL from `/api/qt` into the
waiting prompt, then copy the new token onto the volume.
Verify from anywhere:
```bash
curl -s -H "X-Chart-Token: $TOKEN" https://chart.amow.com/api/status
# want: "source":"schwab","delay_minutes":0
```
## Access token ## Access token
`CHART_AUTH_TOKEN` guards everything under `/api` plus the `/ws` stream. Leave `CHART_AUTH_TOKEN` guards everything under `/api` plus the `/ws` stream. Leave