Operational scripts
Operational scripts are one-off backend CLIs underapps/backend/src/scripts/. They backfill data, reconcile provider state, or run targeted migrations that do not belong in Sequelize schema migrations or seeds.
Schema changes and baseline seed data still go through Migrations & Seeds (make migrate-up, make seed-up). Operational scripts are for work that is environment-specific, replayable, or too risky to fold into a migration file.
How to run
Local development
With the stack up, run from the host against thebackend container:
ARGS= wrapper, no -- separator after an npm script name.
Production (Railway)
Operational scripts compile with the normal backend build (tsc → apps/backend/dist/scripts/). On the built image, run compiled JS only:
webapp and consumer. See Railway for how the production image is built and deployed — this page does not prescribe Railway UI steps beyond that context.
Always run
--help and a --dryRun pass before mutating production data.How to create a script
1. Add a thin CLI file
Createapps/backend/src/scripts/<name>.ts and wire it through operationalScriptEntrypoint:
2. Put domain logic elsewhere
Keep the script file thin. Business logic belongs inapps/backend/src/utilities/ or the relevant tool module (e.g. apps/backend/src/tools/paymentProcessor/stripe/).
3. Build output
The backendtsc build emits apps/backend/dist/scripts/<name>.js. No extra package.json script entry is required.
Shared flags (via the wrapper)
Journals default to
operational-journals/<scriptName>/ under the process cwd. Only non-dry-run forward runs persist them.
Best practices
- Run
--helpfirst — every script must implement it through the wrapper. - Dry-run locally (
--dryRun) before any production forward run. - For mutating forwards: set
supportsRevert: true, append journal entries during the run, and implementrevertwith a domain journal helper. - Design for idempotency when replay or partial failure is likely.
Avoid
- Per-script entries in
apps/backend/package.json— use the run contract above instead. - Documenting or relying on
ts-nodein production. maketargets that pass script flags throughARGS='…'.- Calling Stripe or other vendor SDKs outside tool implementation trees.
- Confusing these with
make migrate-up/make seed-up— those are Sequelize schema/seed runners, not operational one-offs.
What’s next?
- Migrations & Seeds — schema migrations and baseline seeds.
- Railway — production image, deploy flow, and one-off commands on the built image.
- Billing architecture — catalog IDs and product/price shape (context for catalog migration scripts).
