# Pathrule Pattern: Express.js Production APIs (1.0.0)
# ::pathrule:package:express-js

### [RULE] Build the middleware pipeline in one visible order  (path: /src/http)
<!-- scope: folder | priority: high | strict -->

Express behavior is order-dependent. A middleware mounted after a route cannot protect or observe that route, and an error handler mounted too early never sees failures from later handlers.

- Create one application composition module that registers correlation context and security headers before body parsing, authentication before protected routes, and error middleware last.
- Set body size limits per content type and route. Do not accept framework defaults for uploads or JSON bodies that can consume process memory before validation runs.
- Keep a final not-found handler after all routers, then mount the four-argument error handler after that. Do not mix 404 generation into domain controllers.
- Test ordering with a representative protected route, malformed body, unknown route, and thrown error so a refactor cannot silently move a boundary.

See /src/middleware for the adjacent decision or procedure that completes this constraint.

---

### [RULE] Treat forwarded headers as trusted input only from known proxies  (path: /src/http)
<!-- scope: folder | priority: high | strict -->

Express can derive `req.ip`, `req.protocol`, and secure-cookie behavior from forwarding headers, but those headers are attacker-controlled unless every direct connection arrives through a proxy you trust.

- Configure `trust proxy` to the known hop count, subnet, or verification function for the deployment topology; do not enable a blanket boolean without proving the direct path is unreachable.
- Ensure the last trusted proxy overwrites incoming forwarding headers instead of appending attacker-supplied values it received from the public internet.
- Use the derived client IP for diagnostics and abuse controls only after this topology is tested from every ingress path, including health checks and internal calls.
- Keep canonical host and public origin in configuration for redirects and absolute URLs rather than reconstructing security-sensitive destinations from request headers.

See /src/http for the adjacent decision or procedure that completes this constraint.

---

### [RULE] Finish each request exactly once  (path: /src/http)
<!-- scope: folder | priority: high | strict -->

A handler that sends a response and continues can trigger side effects twice or throw after headers are committed. Asynchronous failures must reach one error boundary instead of producing unhandled rejections or partial responses.

- Return the response or return immediately after `res.send`, `res.json`, `res.end`, or a redirect. Do not let execution fall through into another write or mutation.
- Use promise-aware handlers and ensure every rejected operation reaches `next` or the framework error path. Never start an unawaited promise that can reject after the request completes.
- Translate known domain errors to HTTP in one error middleware. Controllers should throw typed failures, not duplicate status-code tables across routes.
- When headers are already sent, delegate to Express's final handling path instead of attempting a second JSON error response on a streaming or partially written request.

See /src/domain for the adjacent decision or procedure that completes this constraint.

---

### [MEMORY] Controllers adapt HTTP while services own business transitions  (path: /src/domain)

Express makes it convenient to place everything in a route callback, but that couples validation, authorization, persistence, and response formatting to one mutable request object. The separation worth preserving is transport adaptation versus domain transition.

- Parse and validate params, query, headers, and body at the controller boundary, then pass a typed command into a service.
- Perform authorization on the resolved resource and actor, not merely on a route name. A service should receive enough identity context to enforce the invariant again.
- Return domain values or typed failures from services. Controllers choose status codes and response envelopes without teaching the domain about Express.
- Open transactions in the service layer around the complete state transition; do not hold them open while streaming a response or calling an unrelated remote service.

See /src/http for the rule or workflow that puts this decision into practice.

---

### [MEMORY] Graceful shutdown is part of request correctness  (path: /src/http)

A container signal is not permission to exit immediately. Express sits on a Node HTTP server whose active requests and keep-alive sockets must be given time to finish, while background intake must stop before dependencies are closed.

- Handle the platform termination signal once and mark the instance unready before beginning shutdown so new traffic is routed elsewhere.
- Close the HTTP server to stop accepting new connections, track active work, and wait for ordinary requests to finish within a configured deadline.
- Stop queue consumers and schedulers before closing database or cache pools; otherwise an in-flight job can begin after its dependency has disappeared.
- Force termination only after the deadline and record which resources remained active. A silent forced exit hides the capacity or cancellation bug that caused it.

See /src/http for the rule or workflow that puts this decision into practice.

---

### [SKILL] review-express-production-boundaries  (path: /)

---
name: review-express-production-boundaries
description: Review an Express service after route, middleware, ingress, or lifecycle changes.
---

# Review Express Production Boundaries

Run this procedure when the affected surface changes, before the result is promoted to production. Record evidence for every step instead of accepting a plausible-looking result.

- [ ] Enumerate middleware in execution order for one public, one protected, and one failing route; verify every intended boundary runs.
- [ ] Send oversized and malformed bodies for each parser and confirm rejection occurs before allocation-heavy business logic.
- [ ] Probe forwarded host, protocol, and client IP headers through both trusted ingress and a direct connection; confirm untrusted values are ignored.
- [ ] Force a rejected asynchronous operation before and after headers are sent and verify exactly one error path records the failure.
- [ ] Start a slow request, trigger termination, and prove readiness drops, new intake stops, active work drains, and the deadline is observable.

## Exit criteria

The change is complete only when the expected behavior, failure behavior, and rollback path have all been exercised with representative data. Preserve the evidence with the change so the next operator can repeat the same checks.
