To execute this example, install Node.js and Docker. The local workflow below starts MongoDB and Mailpit for you in Docker.
- Node.js 26+
- Latest Docker engine
The backend now uses the built-in Temporal API available in Node.js 26. Keep Temporal usage inside business-logic helpers and convert back to native Date values at MongoDB or other library boundaries.
There are two Docker compose paths.
Local Docker stack (Mailpit included, no real SMTP needed)
make dev-composeThis builds the image and starts Mongo, the app in development mode, and Mailpit for SMTP capture. Open http://localhost:8025 to inspect captured mail. No SMTP credentials are required.
Production Docker stack (real SMTP required)
Ensure SMTP_HOST, SMTP_PORT, SMTP_SECURE, SMTP_USER, and SMTP_PASS are set in .env, then:
docker compose -f docker-compose.yml upor the makefile alias:
make upThe app boots in production mode and fails fast at startup if SMTP is not configured. That behavior is intentional.
-
Install Dependencies:
npm install
-
Create the local env file:
make init-envmake init-env creates .env with local-safe defaults and generates secrets when openssl is available. If .env already exists, the target leaves it unchanged.
-
Adjust
.envif needed:Leave
SMTP_HOST,SMTP_PORT,SMTP_SECURE,SMTP_USER, andSMTP_PASSunset to use local Mailpit by default. Review or rotate the generated secrets before reusing the environment elsewhere. -
Start the local stack:
make dev
This starts MongoDB on
localhost:27017, Mailpit SMTP onlocalhost:1025, and the Mailpit inbox UI onhttp://localhost:8025. -
Inspect captured email in Mailpit:
Open
http://localhost:8025and trigger flows such as password reset. Development defaults to Mailpit unless you set real SMTP credentials in.env. -
Run Tests:
make test
make test starts the managed local test runtime, including Docker-backed test dependencies, managed runtime state, and cleanup.
Use the raw CI-oriented runner only when the test dependencies are already available outside the managed wrapper:
make test-cimake test-ci and npm run test:ci are intentionally plain, CI-style entrypoints. They do not boot MongoDB or other test dependencies for you.
-
Stop the local containers when finished:
make dev-stop
For short manual delivery checks, add the SMTP settings below to .env and rerun make dev:
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-smtp-user
SMTP_PASS=your-smtp-passwordOutside development and test, the app now fails fast during boot if SMTP is not configured.
-
Show the canonical local command surface:
make
-
Create
.envonce for local development:make init-env
-
Start the local Docker app stack with Mailpit:
make dev-compose
-
Start local MongoDB + Mailpit + app:**
make dev
-
Stop local MongoDB + Mailpit:
make dev-stop
-
Inspect managed runtime state:
make runtime-status
-
Clean managed runtime state and owned processes:
make runtime-cleanup
-
Run database migrations with
.envloaded:make migrate
-
Run tests:
make test -
Run the raw CI-style Node suite when test dependencies are already running:
make test-ci
-
Run lint:
make lint
-
Emit machine-readable managed runtime status:
make runtime-status-json
make runtime-statusandnpm run runtime:statusshow human-readable managed runtime status and keep exit code0for inspection.make runtime-status-jsonandnpm run runtime:status -- --jsonemit machine-readable JSON without ANSI styling.make runtime-cleanupandnpm run runtime:cleanupclean backend-owned runtime state and owned stale processes.- Cleanup first attempts a graceful stop, waits for the process to exit, and then escalates to forced termination if the process remains alive.
- If cleanup still cannot remove all runtime state, the cleanup command exits with code
1and prints a manual-recovery message instead of pretending the machine is clean.
- Managed runtimes record ownership in the system temp directory instead of inside the repository.
- Automatic stale-state recovery only happens after the recorded runtime has been inactive for the stale-state TTL, which defaults to 15 minutes.
- If a recorded runtime is too recent for automatic recovery, startup fails fast and asks you to wait for the TTL window or run explicit cleanup.
- Explicit cleanup bypasses the stale-state TTL so operators can recover immediately.
- Human-oriented Node-managed surfaces such as
make dev,make test,make runtime-status, and the managed local Node test reporter use semantic color when the output stream is interactive. - Set
NO_COLORto disable ANSI styling. SetFORCE_COLOR=1to force ANSI styling on Node-managed human output even for non-TTY streams. - JSON status output remains plain text JSON.
make helpis plain text by design so the make entrypoint stays thin and predictable.- Focused wrapper tests intentionally use quiet output sinks so they can validate lifecycle semantics without leaking fake operator banners into the suite output.