Console commands
Console commands
Section titled “Console commands”Audience: backend, devops
Status: implemented (CAP + Orchestrator shell)
Owns: backend
Depends on: CI/CD, System architecture, Backend stack ADR
CAP and Orchestrator expose a console CLI for one-off deploy tasks and manual VPS repairs. The pattern mirrors the existing seed runners (src/seed/cli.ts → dist/seed/cli.js) but stays separate — seeds populate reference/demo data; console commands run idempotent backfills and repairs.
When commands run
Section titled “When commands run”| Trigger | Where | Notes |
|---|---|---|
| Deploy activate | VPS activate.sh |
After prisma migrate deploy, before optional seed and before the current symlink flip |
| Manual SSH | Release dir on VPS | Same compiled entrypoint as activate |
| Local dev | pnpm console … |
Runs via tsx src/console/cli.ts against local .env |
Commands are not invoked from HTTP app boot (main.ts / PM2). Running on every process restart would race in cluster mode and repeat work unpredictably.
Activate sequence (Prisma apps)
Section titled “Activate sequence (Prisma apps)”flowchart LR Migrate["prisma migrate deploy"] DeployCmd["node dist/console/cli.js --deploy"] Seed["node dist/seed/cli.js optional"] Symlink["symlink current + PM2"] Migrate --> DeployCmd --> Seed --> SymlinkImplementation: monorepo infra/deploy/activate.sh. If dist/console/cli.js is missing (older artifact), activate logs a skip and continues.
Failure policy: any command error or non-zero exit fails the release — same as migrate and seed. The current symlink is not flipped and PM2 is not reloaded.
Per-app layout
Section titled “Per-app layout”Each Prisma app that ships console code owns a thin duplicate under src/console/ (no shared @elimi/console package yet):
| File | Purpose |
|---|---|
types.ts |
Command, CommandContext, exit codes |
deploy-commands.ts |
Checked-in deploy list (DEPLOY_COMMANDS const array) |
resolve-deploy-commands.ts |
Merge file list + process.env.DEPLOY_COMMANDS (comma-separated, trimmed, deduped) |
kernel.ts |
Registry, argv parsing, Prisma lifecycle |
cli.ts |
Entry: node dist/console/cli.js |
commands/*.command.ts |
Domain commands (CAP only today) |
Compiled output is included in the release tarball via existing tsc + pack.sh — no pack changes required.
CLI behaviour
Section titled “CLI behaviour”node dist/console/cli.js # usage + listnode dist/console/cli.js list # registered commandsnode dist/console/cli.js <name> [--dry-run]node dist/console/cli.js --deploy [--dry-run]--deployruns the merged deploy list in order.- Empty merged list → no-op, exit 0 (Orchestrator default until commands are added).
--dry-runis supported per command where implemented; deploy passes the flag through.
Local equivalent:
pnpm --filter @elimi/cap console listpnpm --filter @elimi/cap console repair:organisation-centres --dry-runpnpm --filter @elimi/orchestrator console listDeploy list (hybrid)
Section titled “Deploy list (hybrid)”Two sources, merged and deduped:
- Checked in:
apps/<app>/src/console/deploy-commands.ts - Optional env:
DEPLOY_COMMANDS=repair:organisation-centres,custom:onceinshared/.env
Use the file for release-tagged backfills the team reviews in PR. Use env for environment-specific overrides without rebuilding (still merged with the file list).
CAP commands (current)
Section titled “CAP commands (current)”| Command | Purpose |
|---|---|
repair:organisation-centres |
Provision Centre + CentreStaff (SUPER_ADMIN) for completed organisation onboarding rows that never received founder staff |
Logic:
- Find
OnboardingRecordwherepersona = CENTRE,variant = organisation,status = COMPLETED, and noCentreStaffwithrole = SUPER_ADMINfor thatcapUserId. - Per user (transaction): call
provisionCentreFromOrganisationOnboarding— same helper used on live org submit and re-submit repair in onboarding service. - Per-user errors (e.g. registration number collision) log and rethrow — fail-release.
Deploy list for the organisation-centres backfill release: deploy-commands.ts includes repair:organisation-centres. Clear to [] in a follow-up PR after staging/production verification.
Alternative before deploy: affected users can re-submit via POST /onboarding/centre/submit (repair path in onboarding service).
Orchestrator shell
Section titled “Orchestrator shell”Orchestrator ships the same console framework. DEPLOY_COMMANDS stays empty by
default (activate --deploy is a no-op until you add deploy entries).
Manual: mail:test — send a one-off probe via the configured
EMAIL_PROVIDER / EMAIL_FROM (same adapters as auth OTP mail).
pnpm --filter @elimi/orchestrator console listpnpm --filter @elimi/orchestrator console mail:test --to=you@yahoo.com --dry-runpnpm --filter @elimi/orchestrator console mail:test --to=you@yahoo.comWith EMAIL_PROVIDER=console, send logs locally (no network). With smtp /
resend, the provider must accept the message — that does not guarantee
Yahoo inbox delivery (check spam + provider logs). Not on --deploy.
HTTP (temporary): POST /v1/dev/mail-test with header X-Mail-Test-Key —
requires MAIL_TEST_HTTP_ENABLED=true and MAIL_TEST_HTTP_KEY in env. Disabled → 404.
Set MAIL_TEST_HTTP_ENABLED=false when finished.
VPS examples
Section titled “VPS examples”cd ~/elimi-ecosystem/cap_staging/currentset -a && source ../shared/.env && set +a
node dist/console/cli.js listnode dist/console/cli.js repair:organisation-centres --dry-runnode dist/console/cli.js --deployOptional env in shared/.env:
# Merged with deploy-commands.ts (deduped)DEPLOY_COMMANDS=repair:organisation-centresSeeds vs console
Section titled “Seeds vs console”| Seeds | Console | |
|---|---|---|
| Purpose | Reference data, demo orgs, platform admin bootstrap | One-off repairs and backfills |
| Trigger | RUN_SEEDS=true on activate |
Always --deploy step when CLI exists |
| Entry | dist/seed/cli.js |
dist/console/cli.js |
| Local | pnpm prisma:seed / per-module seed scripts |
pnpm console … |
Runbook detail: monorepo infra/deploy/README.md, apps/cap/README.md, apps/orchestrator/README.md.
Adding a new command
Section titled “Adding a new command”- Add
src/console/commands/<name>.command.tsimplementingCommand. - Register in
kernel.tscommandsarray. - Add unit tests under
test/unit/(mock Prisma). - For deploy-time execution: add the name to
deploy-commands.tsor setDEPLOY_COMMANDSon the VPS — prefer clearing one-off entries after the backfill ships. - Document behaviour here and in the relevant product/backend module page if user-visible.
Out of scope (later)
Section titled “Out of scope (later)”- Moving seed runners under
console seed … - Shared
@elimi/consolenpm package - Running commands on HTTP boot
- LMS / WorkMasters console (add when those apps ship Prisma + activate)
See also
Section titled “See also”- CI/CD — artifact activate pipeline
- CAP backend overview — CAP module context
- Orchestrator backend — OL module context
- Centres module — organisation onboarding + centre provisioning