Run the Node application and PostgreSQL.
This repository supports a plain Node.js + Express process backed by PostgreSQL. It does not include a Dockerfile or Compose definition, so this guide installs the checked-out application with npm and runs it as a managed Node process. Use Node.js 20 or newer and a reachable PostgreSQL database.
- Keep the source release and
package-lock.jsontogether so the dependency tree is reproducible. - Provision PostgreSQL before first start and allow the application host to connect to it.
- The app does not load
.envfiles itself. Inject settings through your service manager or deployment environment.
Prepare once online, then install offline.
-
Obtain a source release that includes
package.jsonandpackage-lock.json. -
On a network-connected staging host with the same operating system, architecture, and Node runtime platform as the target, populate a release-local npm cache:
npm ci --cache .npm-cache
-
Transfer the complete release and its
.npm-cachedirectory into the restricted environment. The cache must contain every package referenced bypackage-lock.json. -
In the release directory on the restricted host, install from that cache:
npm ci --offline --cache .npm-cache
-
Configure the process environment, including
DATABASE_URL. Use a service manager or deployment configuration; this app does not read a local.envfile. -
Apply the database schema before routing traffic:
npm run migrate
-
Start the server:
npm start
-
From a host that can reach the service, verify the health endpoint:
curl -fsS http://127.0.0.1:3000/health
Separate startup settings from optional features.
Only DATABASE_URL is required for the server to start. The rest of these settings enable authentication, integrations, outbound services, or hosted features.
| Setting | When to set it |
|---|---|
DATABASE_URL | Required at startup. PostgreSQL connection string used by the app and migration runner. |
PORT | Optional. HTTP port; defaults to 3000. |
NODE_ENV | Set to production for deployment. Authentication cookies are marked secure unless the value is development. |
JWT_SECRET | Set an explicit high-entropy secret for session signing. The current code falls back to DATABASE_URL, but that is not a suitable production secret. |
APP_URL | Set to the local public origin when enabling magic-link email, so generated links return to this installation. |
OPENAI_API_KEY | Optional for LLM workflow steps. Without a key, the runner uses a heuristic fallback. |
OPENAI_BASE_URL | Optional LLM endpoint override. Defaults to https://api.openai.com/v1; point it at an approved reachable OpenAI-compatible endpoint, including an internal service. |
SLACK_WEBHOOK_URL | Optional. Enables Slack notifications when the configured webhook endpoint is reachable. |
POSTMARK_API_KEY | Optional for direct Postmark email features. Requires access to Postmark's API. |
POSTMARK_FROM | Not currently read from the environment in this repository. The magic-link sender currently uses hello@polsia.app. |
POLSIA_API_KEY | Optional for email sent through the Polsia proxy and for hosted billing. Those proxy calls require access to polsia.com. |
STRIPE_SECRET_KEY, STRIPE_TEAM_PRICE_ID, STRIPE_BUSINESS_PRICE_ID, STRIPE_WEBHOOK_SECRET | Hosted billing settings. Checkout uses the Polsia billing proxy and requires POLSIA_API_KEY plus network access; billing is not part of a fully air-gapped baseline. |
S1_WEBHOOK_SECRET | Conditional inbound SentinelOne webhook authentication. Configure it when authenticating incoming SentinelOne events. |
POSTMARK_WEBHOOK_SECRET | Conditional inbound Postmark webhook authentication. Configure it when authenticating incoming Postmark events. |
POSTMARK_API_KEY; proxy-backed sends use POLSIA_API_KEY. Both require network access to their respective services and are not available in a fully air-gapped baseline.
Keep durable state in PostgreSQL.
PostgreSQL stores application records and the _migrations migration history. Give the database durable storage, back it up on an operator-defined schedule, and test a restore. Run npm run migrate successfully before sending traffic to a new release.
- The connection pool is configured in
db/index.js. It disables SSL whenDATABASE_URLcontainslocalhost; other database URLs use SSL with certificate verification disabled. GET /healthchecks that PostgreSQL can query the migratedtriggerstable. A healthy response confirms database connectivity and that this table exists.- Keep application instances replaceable. Do not use an instance filesystem as the database or as durable application state.
Enable only integrations with reachable services.
Offline npm installation covers the Node dependencies; it does not make external integrations local. LLM calls, Slack, Postmark, Stripe billing through https://polsia.com, SentinelOne, and workflow enrichment or integration endpoints need their configured services to be reachable. In a restricted network, use approved internal endpoints where supported or leave those capabilities disabled.
OPENAI_BASE_URLcan point LLM steps at an internal OpenAI-compatible service. Without an API key, LLM steps use the runner's heuristic fallback.SLACK_WEBHOOK_URLcan target an approved reachable webhook endpoint. Workflow HTTP steps and other integrations must likewise be configured for services available from the deployment network.- Postmark email and the Polsia email and billing proxies use public services and are not part of a fully air-gapped baseline.
/js/pixel.js loads Meta Pixel. This guide omits both requests; other application pages need a separate egress review.
Confirm the installation before handoff.
npm run migratecompletes successfully against the intended PostgreSQL database.GET /healthreturns a healthy response after migrations.GET /docs/on-premloads and is linked from the documentation index.- A sample workflow completes using only the services configured and reachable from this installation.
A Node.js process, PostgreSQL, an offline npm cache, and a controlled service environment are enough to install and operate the repository's local baseline. Add network-dependent capabilities only when their endpoints are available to your deployment.