Back to tools

N3X Flow

A self-hosted client portal for project stages, acceptance, consolidated feedback rounds, scope changes and decision history.

SELF-HOSTED PROJECT OPSv0.1.0

Delivery completed. Decisions documented.

N3X Flow turns scattered email and chat threads into a premium Project Room: the client always sees the next action, the team controls scope, and every comment, acceptance and commercial decision stays with the right stage.

Data on your server · single-use email links · encrypted SMTP · no application telemetry

Managed hosting by N3X

Want to use it without maintaining the server?

N3X can deploy and maintain this application, from initial setup and SSL to updates, monitoring and backups.

Ask about N3X hosting

A process that protects the relationship and margin

Five acceptance gates

Discovery, direction, design, development and launch each carry their own state, deadline and unambiguous acceptance history.

Consolidated feedback rounds

Up to three shared responses per stage instead of an endless stream of conflicting messages.

One decision maker

Reviewers may add items, but only the designated decision maker accepts stages and additional cost.

Scope-change control

Defects, questions and scope changes stay distinct, while each change order includes price, timing, validity and a decision.

Five-business-day reviews

The worker tracks review windows and records precisely whether a stage was accepted explicitly or deemed accepted after the deadline.

Email-link sign-in

Clients do not create passwords. Tokens are hashed, single-use, valid for 15 minutes and consumed only after confirmation.

Append-only history

The audit trail records actor, time, project, event and context for material decisions.

Phone-ready PWA

Install with a dedicated icon, iOS support, bottom navigation and a safe offline screen that never stores project content.

DOCKER COMPOSE

A private, white-label-ready stack

One configuration starts the portal, worker and PostgreSQL. The owner configures agency branding and SMTP in the authenticated panel, keeping secrets out of Compose.

N3X Flow Web — Project Rooms, roles, acceptance, feedback and settings
N3X Flow Worker — deadlines, offer expiry and email delivery
PostgreSQL 17 — projects, decisions and append-only audit history
Your reverse proxy — HTTPS and a custom domain such as portal.example.com

DOCKER CONFIGURATOR

Compose tailored to your agency

Set the domain, bind address, port and image version. The configurator prepares a ready-to-use Docker Compose file and startup commands without manually managing secrets.

The domain must point to your reverse proxy. Do not include https:// or a path.

0.0.0.0 provides LAN and proxy access. Use 127.0.0.1 when the reverse proxy runs on the same host.

The application port available to your reverse proxy. The default is 8792.

Keep latest for the newest release or pin a specific version.

Configure branding and SMTP after sign-in. After startup, open http://SERVER_IP:8792 and create the owner account immediately. Then configure the public HTTPS URL and SMTP. Create consistent backups of postgres_data and runtime_secrets.
Public address
https://flow.example.com
First-run address
http://DOCKER_SERVER_IP:8792
Reverse proxy target
http://DOCKER_SERVER_IP:8792
Health check
http://127.0.0.1:8792/api/health

Ready-to-use docker-compose.yml

name: n3xflow

x-app-environment: &app-environment
  N3XFLOW_DATABASE_PASSWORD_FILE: /run/n3xflow/database_password
  N3XFLOW_TRUST_PROXY_HOPS: ${N3XFLOW_TRUST_PROXY_HOPS:-0}
  N3XFLOW_DEV_MAGIC_LINKS: ${N3XFLOW_DEV_MAGIC_LINKS:-0}
  N3XFLOW_UPLOADS_DIR: /var/lib/n3xflow/uploads
  TZ: Europe/Warsaw

x-app-security: &app-security
  read_only: true
  security_opt:
    - no-new-privileges:true
  cap_drop:
    - ALL
  tmpfs:
    - /tmp:size=64m,mode=1777
    - /app/.next/cache:size=128m,mode=0700,uid=1001,gid=1001

services:
  bootstrap:
    image: alpine:3.22
    restart: "no"
    command:
      - /bin/sh
      - -ec
      - |
        umask 077
        if [ ! -s /run/n3xflow/database_password ]; then
          od -An -N32 -tx1 /dev/urandom | tr -d ' \n' > /run/n3xflow/database_password
        fi
        if [ ! -s /run/n3xflow/settings_key ]; then
          od -An -N32 -tx1 /dev/urandom | tr -d ' \n' > /run/n3xflow/settings_key
        fi
        chmod 0444 /run/n3xflow/database_password /run/n3xflow/settings_key
    volumes:
      - runtime_secrets:/run/n3xflow
    networks:
      - backend
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL

  web:
    image: ghcr.io/nexitpl/n3xflow:latest
    pull_policy: always
    restart: unless-stopped
    depends_on:
      bootstrap:
        condition: service_completed_successfully
      postgres:
        condition: service_healthy
    environment: *app-environment
    volumes:
      - runtime_secrets:/run/n3xflow:ro
      - uploads_data:/var/lib/n3xflow/uploads
    ports:
      # Keep behind a firewall until the owner account exists; publish through HTTPS.
      - "0.0.0.0:8792:3000"
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3000/api/health"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 30s
    networks:
      - frontend
      - backend
    <<: *app-security

  worker:
    image: ghcr.io/nexitpl/n3xflow:latest
    pull_policy: always
    restart: unless-stopped
    depends_on:
      bootstrap:
        condition: service_completed_successfully
      postgres:
        condition: service_healthy
      web:
        condition: service_healthy
    environment: *app-environment
    volumes:
      - runtime_secrets:/run/n3xflow:ro
    command: ["node", "dist/worker.cjs"]
    networks:
      - backend
    <<: *app-security

  postgres:
    image: postgres:17-alpine
    restart: unless-stopped
    depends_on:
      bootstrap:
        condition: service_completed_successfully
    environment:
      POSTGRES_DB: n3xflow
      POSTGRES_USER: n3xflow
      POSTGRES_PASSWORD_FILE: /run/n3xflow/database_password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - runtime_secrets:/run/n3xflow:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n3xflow -d n3xflow"]
      interval: 5s
      timeout: 5s
      retries: 12
    networks:
      - backend

networks:
  frontend:
  backend:
    internal: true

volumes:
  postgres_data:
  runtime_secrets:
  uploads_data:

Start and health check

mkdir -p n3xflow
cd n3xflow
# Save the copied configuration as docker-compose.yml
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:8792/api/health

Changelog

    • ReleaseFirst self-hosted release: a web panel, deadline and notification worker, and PostgreSQL deployed with Docker Compose.
    • NewFive-stage Project Rooms with a designated decision maker, five-business-day reviews and up to three consolidated feedback rounds.
    • NewFeedback classification as defect, scope change or question, plus change-order cards with price, timing and an explicit client decision.
    • NewSingle-use email links, encrypted SMTP settings, project roles and an append-only log of material events.
    • NewAn installable PWA with a dedicated icon, iOS support, mobile bottom navigation and a safe offline screen that never stores project content.
A decision trail, not a signature substitute. N3X Flow supports documentary-form records and project coordination. It does not replace a handwritten or qualified electronic signature when a specific act, such as many copyright assignments, requires that form.

USER GUIDE

N3XFlow user guide

Installation, getting started, settings and troubleshooting.

N3XFlow

N3XFlow is a client collaboration portal for project stages, feedback, approvals, scope changes and decision history.

Requirements and installation

You need a server with Docker Compose, a browser, an HTTPS domain and SMTP for messages and sign-in links. PostgreSQL is included.

  1. Download docker-compose.yml into a dedicated directory.
  2. Run these commands in that directory:
docker compose up -d
docker compose ps
  1. Open http://SERVER_IP:8792 from a trusted network and create the owner account.
  2. Configure the public HTTPS URL and SMTP in Settings. Point your reverse proxy at port 8792, preserving Host and X-Forwarded-Proto.

Restrict access with a firewall until the owner exists. With one trusted proxy, you can set N3XFLOW_TRUST_PROXY_HOPS=1; the application should not be accessible by bypassing that proxy.

Work on a project

Create a project and assign the team, client decision maker and reviewers. Work through its stages, collect consolidated feedback, agree on scope changes and record decisions.

The built-in Guide explains responsibilities, deadlines, feedback rounds, attachments and approval rules in Polish and English. Use it alongside the project's agreements.

Email notifications go to the opposite project side. Client messages include a single-use sign-in link valid for 15 minutes.

Attachments and mobile

Images and short videos are available to authenticated project participants. Uploads are limited to 30 MB per form; the reverse proxy should allow at least 32 MB.

Install the portal on your home screen as a PWA. Project content requires a server connection and is not cached for offline work.

Backups and updates

Take consistent backups of postgres_data, uploads_data and runtime_secrets. Losing the settings key makes saved SMTP credentials unrecoverable.

Before updating, review release notes and Compose changes. After backing up:

docker compose pull
docker compose up -d
docker compose ps

When upgrading an older installation without attachment support, update Compose too and retain the named uploads_data volume.

Troubleshooting

For missing email, check SMTP settings and docker compose logs --tail=100 worker. Expired links require a fresh sign-in link. For failed uploads, check file size and the proxy limit. Approval records do not replace a special signature form required by a contract.