Production is in demo mode and taking no money — restore real payments #190

Closed
opened 2026-08-26 08:38:36 -05:00 by bermudalamb · 0 comments
Owner

Production is currently taking no money. The whole cart and checkout flow works end to end and every order placed is a pretend one.

This is deliberate and temporary. On 2026-08-25 the cutover to the committed docker-compose.prod.yml could not complete: DEMO_MODE=false makes the three PayPal secrets required, they were not available, and the container crash-looped refusing to start. Demo mode is the interim the compose file's own header sanctions for exactly that situation.

It is also, in that header's words, "a quiet disaster if it is left on". Hence this issue.

To restore

  1. Get the live PayPal credentials — client id and secret from the developer dashboard's live app, webhook id from the webhook entry for PUBLIC_URL/webhooks/paypal. The webhook id is readable rather than only recreatable, so a lost one does not mean a new one.
  2. Set PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET and PAYPAL_WEBHOOK_ID as stack variables in Portainer, with real values. Declaring them empty is identical to not declaring them — isPresent rejects a blank string deliberately.
  3. Set DEMO_MODE=false in docker-compose.prod.yml and remove the banner comment above it. It is hardcoded, so this is a commit and not a stack variable — see below.
  4. Change demoMode back to 'false' for the production entry in backend/tests/unit/composeEnvironment.test.ts and drop the comment explaining the interim. The suite fails until this matches the compose file, which is the point.
  5. Redeploy, and confirm the boot log has no [config] refusing to start block.
  6. Place one real order and confirm it reaches PayPal.

Two things worth keeping after this closes

A DEMO_MODE stack variable does nothing. The compose line is hardcoded rather than ${DEMO_MODE}, and Portainer substitutes stack variables into the file rather than handing them to the container — so there is nothing for it to substitute into and the file's value wins silently. That hardcoding is correct and should stay: the single value deciding whether the shop takes money should not be flippable from a web UI without a commit anybody can read. The failure mode is what is unkind, and the line now documents it.

The compose guard is what makes this safe to leave open. composeEnvironment.test.ts asserts the production file's DEMO_MODE matches the expectation recorded beside it, so the file and the test cannot disagree in either direction without CI failing. That is what stops this being switched back quietly, and equally what stops it being forgotten — the assertion reads 'true' today and someone has to look at it.

Related: the cutover runbook gained the crash-loop diagnosis this produced (#175).

**Production is currently taking no money.** The whole cart and checkout flow works end to end and every order placed is a pretend one. This is deliberate and temporary. On 2026-08-25 the cutover to the committed `docker-compose.prod.yml` could not complete: `DEMO_MODE=false` makes the three PayPal secrets required, they were not available, and the container crash-looped refusing to start. Demo mode is the interim the compose file's own header sanctions for exactly that situation. It is also, in that header's words, "a quiet disaster if it is left on". Hence this issue. ## To restore 1. Get the live PayPal credentials — client id and secret from the developer dashboard's live app, webhook id from the webhook entry for `PUBLIC_URL/webhooks/paypal`. The webhook id is readable rather than only recreatable, so a lost one does not mean a new one. 2. Set `PAYPAL_CLIENT_ID`, `PAYPAL_CLIENT_SECRET` and `PAYPAL_WEBHOOK_ID` as stack variables in Portainer, with real values. Declaring them empty is identical to not declaring them — `isPresent` rejects a blank string deliberately. 3. Set `DEMO_MODE=false` in `docker-compose.prod.yml` and remove the banner comment above it. It is hardcoded, so this is a commit and not a stack variable — see below. 4. Change `demoMode` back to `'false'` for the production entry in `backend/tests/unit/composeEnvironment.test.ts` and drop the comment explaining the interim. The suite fails until this matches the compose file, which is the point. 5. Redeploy, and confirm the boot log has no `[config] refusing to start` block. 6. Place one real order and confirm it reaches PayPal. ## Two things worth keeping after this closes **A `DEMO_MODE` stack variable does nothing.** The compose line is hardcoded rather than `${DEMO_MODE}`, and Portainer substitutes stack variables *into* the file rather than handing them to the container — so there is nothing for it to substitute into and the file's value wins silently. That hardcoding is correct and should stay: the single value deciding whether the shop takes money should not be flippable from a web UI without a commit anybody can read. The failure mode is what is unkind, and the line now documents it. **The compose guard is what makes this safe to leave open.** `composeEnvironment.test.ts` asserts the production file's `DEMO_MODE` matches the expectation recorded beside it, so the file and the test cannot disagree in either direction without CI failing. That is what stops this being switched back quietly, and equally what stops it being forgotten — the assertion reads `'true'` today and someone has to look at it. Related: the cutover runbook gained the crash-loop diagnosis this produced (#175).
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bermudalamb/redefined-designs#190