Ritzy One • Installation & Licensing Runbook — Internal

New Server Installation & Licensing

The complete order of operations for standing up Ritzy One on a new server and licensing it — from the application install (which brings PostgreSQL with it), through creating the first company, to activating the licence with a single code. Written for Ritzy staff performing an installation; it is not a customer document.

Applies to build license-activation-2026-07-26 and later  |  Internal / vendor tooling

1Before you start

Gather these before touching the server. Stopping half-way to hunt for one of them is the usual cause of a long install.

What you need to hand

ItemWhy
Both deploy bundles — RitzyOne-deploy.zip and (first time only) RitzyLicence-deploy.zipBuilt on the dev machine to C:\Projects\ by package-deploy.ps1 and packages\license-server\package.cmd.
Administrator access on the serverEvery installer writes services and firewall rules.
Internet access from the server or the EDB PostgreSQL 18 installer (Windows x64) copied overThe installer downloads PostgreSQL 18 (about 400 MB) when it is not installed; offline, pass -PgInstaller <file>.
The customer's seat count and purchased modulesNeeded to mint the licence.
Today's support passwordGates first-run setup and every DBA Console action. It is date-derived and recomputed daily — not stored anywhere.
The company code (1–5 chars, A–Z/0–9), name, financial year and the administrator login to createEntered in the first-run wizard.
Node is handled for you
The installer requires Node 18 or newer and will silently install v20.18.0 LTS if Node is absent. Pass -SkipNodeInstall to manage it yourself.
Order matters — License Server first
If this customer will be licensed (rather than left unenforced), the License Server must be running and reachable before you activate the customer install, because activation calls it. Doing Part A first also means the customer's activation code is ready when you get to Part E.

2Choose the topology

The License Server is vendor infrastructure. It holds the RSA private signing key and must never be installed on a customer's box.

ModelWhere the License Server runsWhen to use it
Hosted / SaaS (normal)One Ritzy-controlled server on the internet, https://lic2.ritzy.net, shared by every customer. A new install uses it by defaultDefault. Gives you live suspend/revoke and automatic renewal delivery.
On-prem, connectedSame shared Ritzy server; the customer's site reaches it outbound over HTTPSCustomer hosts the ERP but has internet access. Same benefits as SaaS.
Air-gappedNot reachableNo heartbeat, no activation code. Use the manual key path in §9; the licence then only ends at expiry.
All-in-one (lab/demo only)Same box as Ritzy One, on http://localhost:4100Testing. Never for a real customer — it puts the signing key on their hardware.
The private key is the crown jewels
data\license-private.pem on the License Server signs every licence Ritzy has ever issued. If it leaks, anyone can mint licences. If it is lost, every issued licence stops verifying and every customer must be re-keyed. Back it up, and keep it off customer servers.

3Part A — The Ritzy License Server once, ever

Skip this entire section if your License Server is already running — you only build it once and then share it across all customers. Jump to §4.

3.1 Install

  1. Copy RitzyLicence-deploy.zip to the vendor server and unzip it to a permanent folder, e.g. C:\RitzyLicence. Do not run it from a temp folder — the licence database, its backups and the keys are created in data\ beside it. The licence database is Firebird: install the Firebird server (3, 4 or 5) on this machine first.
  2. Open a Command Prompt as Administrator in that folder and run:
    install.cmd
  3. Answer the prompts:
    PromptDefaultWhat to enter
    HTTP port4100Keep 4100 unless it clashes. Must match your reverse proxy.
    Bootstrap admin usernameadminYour vendor console login.
    Password / Confirm password—A strong password. It is hashed on first boot; never leave it as changeme.
    Public base URLhttps://lic2.ritzy.netThe externally reachable URL. Accept the default on the live server; use http://localhost:<port> only for a local test. Used for PayPal returns and given to installs as the heartbeat URL.
    Allowed console origin(s)the public URLSame HTTPS URL. Comma-separate if more than one.
    Enable PayPal payments?NoN unless you are taking card payments now; you can enable it later in .env.
    Enquiry intake keyblank (intake off)The shared key the website sends with each quotation request. Type generate for a random one (it is printed — copy it into the website's ritzy-config.php), or leave blank to keep the intake off.
    Intake posts accepted per minute30Asked only when a key is set. Keep 30.
    Is this server proxied by Cloudflare?YesY for lic2.ritzy.net. The client address is then read from CF-Connecting-IP, only for requests from Cloudflare's edge.

The installer generates ADMIN_JWT_SECRET automatically, installs dependencies, registers and starts the Windows service ritzy-license (through NSSM, like Ritzy One's ritzy-api), opens the firewall port and runs a health check. Run install.cmd and deploy.cmd as Administrator.

Starts at boot with nobody signed in
The service has delayed auto-start (Firebird is up first), restarts the app if it stops, and logs to logs\service.log / logs\service-error.log. Older installs ran the License Server under PM2 with a boot hook that only fired when the installing user signed in, so after an unattended restart it stayed down while Ritzy One came up. On such a server run deploy.cmd as Administrator, as the same Windows user that installed it: it removes the PM2 ritzy-license process and moves the app to the service.
Updating later
Do not uninstall. Extract the new zip into a new folder beside it, then right-click update.cmd there and choose Run as administrator. It finds the folder the service runs from, replaces the compiled files, keeps data\ and .env, and restarts the service. Ritzy One has its own update.cmd that works the same way.

3.2 First login — do all four

Browse to the console (the installer prints the URL) and sign in with the bootstrap admin.

  1. Change the password — minimum 6 characters. Editing BOOTSTRAP_ADMIN_PASSWORD in .env afterwards does nothing; it is only read when the database is empty.
  2. Enable two-factor in Settings.
  3. Settings → Licence signing key → Generate new key pair. The private key is shown once — copy it into your password manager now. Until this is done the console cannot sign anything (canSign=false).
  4. Back up the data\ folder (see §12).
Do not rotate the key pair casually
Generating a new pair replaces the old one. Every licence already issued and verified against the old public key stops verifying, and every install must be re-trusted and re-keyed. Rotate only for a fresh setup or a deliberate, planned migration.

3.3 Put it behind HTTPS (any internet-facing server)

Customers post their licence tokens to this server, so it must not be plain HTTP in production. A ready nginx config ships in the bundle as nginx.sample.conf:

  1. Replace licenses.example.com in three places (the two server_name lines and the certificate paths).
  2. Install it to /etc/nginx/sites-available/ritzy-license.conf, symlink into sites-enabled.
  3. sudo certbot --nginx -d licence.yourdomain, then sudo nginx -t && sudo systemctl reload nginx.
  4. Set PUBLIC_BASE_URL and CORS_ORIGIN in .env to the HTTPS URL and restart: Restart-Service ritzy-license (elevated PowerShell).

It proxies to http://127.0.0.1:4100. On Windows, mirror the same thing with IIS ARR + URL Rewrite.

Never rewrite the webhook body
Do not apply sub_filter or any body rewriting to /api/webhooks/*. PayPal's signature is computed over the raw body; altering it makes every webhook fail verification.

3.4 Confirm it is healthy

healthcheck.cmd https://licence.yourdomain

Exit code 0 = healthy. It prints the running version and canSign, and checks the Windows service ritzy-license is running. With no argument it tests http://localhost:4100. It is a drop-in for a Windows Scheduled Task.

4Part B — Prepare the customer server

4.1 PostgreSQL 18

Ritzy One keeps every company in one PostgreSQL database, kept apart by Row-Level Security. Nothing has to be installed beforehand: install.ps1 installs PostgreSQL 18 with the EDB installer in silent mode (server and command-line tools only), puts its data folder under the base folder (<RITZY_ROOT>\PostgreSQL\18\data), sets the postgresql-x64-18 service to start automatically, generates two passwords and writes them into packages\api\.env as PG_URL (the postgres superuser) and PG_APP_URL (ritzy_app). On its first start the app creates the database, the schema and the ritzy_app login itself.

PostgreSQL already on the server
A PostgreSQL 18 that is already installed is reused. The installer then needs its postgres password once — it asks, or pass -PgSuperPassword on an unattended run. An older PostgreSQL (17 or before) is not reused and 18 is not installed beside it: the installer stops and lists what it found. Uninstall it if nothing in it is needed, or move its data to 18 first (dump and restore, or pg_upgrade; see DEPLOYMENT.md, Upgrading from PostgreSQL 17), then run the installer again.
Customer coming from Ritzy 8 / Firebird
Their companies are in .FDB files, which the server no longer reads. Convert them into PostgreSQL before running the first-run wizard: npm run pg:convert from a RitzyWeb source checkout on a machine with Firebird (DEPLOYMENT.md, Moving Firebird data into PostgreSQL). The installer warns when it finds DB_*.FDB files in <RITZY_ROOT>\Data and PostgreSQL has no company yet.

4.2 Understand RITZY_ROOT before you install

Getting this wrong is the single most common installation mistake. RITZY_ROOT is the base folder — not the Ritzy folder inside it. Default C:\Ritzy Solutions:

PathHolds
<RITZY_ROOT>\Ritzy\SystemInstall-wide state kept outside the database (licence revocations, billing) and the nightly backup script
<RITZY_ROOT>\PostgreSQL\18\dataThe PostgreSQL data folder — every company
<RITZY_ROOT>\BackupsDBA Console backups, and Backups\PostgreSQL for the nightly pg_dump

So for the default, RITZY_ROOT=C:\Ritzy Solutions — never C:\Ritzy Solutions\Ritzy.

4.3 Ports

The installer opens these inbound TCP rules. Confirm nothing else is using them:

PortUsed by
80Dashboard (nginx)
3001API
8081Track Shipment PWA
8082Customer Statement / Dues PWA

5Part C — Install Ritzy One

  1. Extract RitzyOne-deploy.zip to the install folder, e.g. C:\RitzyOne.
  2. Open PowerShell as Administrator in that folder and run:
    powershell -ExecutionPolicy Bypass -File install.ps1
  3. Answer the prompts as they come:
    PromptAnswer
    Enter the Ritzy base folder pathThe RITZY_ROOT base folder — see §4.2. Only asked if it can't be auto-detected.
    Password of the PostgreSQL superuser 'postgres'Only asked when PostgreSQL 18 was already installed. A new install generates it.
    Overwrite existing nginx.conf?Y on a new server

What it sets up

An existing .env is never touched
If packages\api\.env already exists the installer keeps it. It only adds PG_URL / PG_APP_URL when they are missing and comments out old FB_* lines; a PG_URL already there (even one pointing at another server) is used as it is. When re-installing over an old build, check that file yourself for anything new.
Updating an existing server later
For application-only updates use install-app.ps1 instead — it installs, builds and restarts, with no prompts and no .env changes; the app applies any database upgrades itself when it starts. The usual update is simply: extract the new zip over the folder, then pm2 restart ritzy-api.

Confirm the API is live and running the build you expect:

curl http://localhost:3001/api/version

6Part D — Create the first company

On a server with no companies yet, the login page replaces the sign-in form with a Set up Ritzy button.

  1. Browse to http://<server>/ and click Set up Ritzy.
  2. Enter today's support password when prompted.
  3. Complete the wizard:
    FieldNotes
    Company code1–5 characters, A–Z and 0–9 only. Identifies the company in the database and cannot be changed later.
    Company nameStored upper-case.
    Base currencyDrives the tax/registration caption (AUD→ABN, BHD→CR.No., SAR→VAT No., AED→TRN).
    Financial yearStart/end month and year. Must span 1–24 periods; one PERIODS row is created per month.
    Administrator loginThe customer-facing admin account. DBA is reserved and will be rejected — use ADMIN.
  4. Click Create Company. It adds the company to the database and seeds it: financial year, periods, numbering, starter charges and user groups.
  5. The wizard's last page is Activation. Paste the activation code here and click Activate — it does exactly what Part E below describes, so a server set up this way is licensed before you ever sign in. Leave it blank and click Finish to license later from the DBA Console.
Change the built-in DBA password before hand-over
Every new company is seeded with a fixed internal DBA support account (password t@11b0y) so the DBA Console is reachable immediately. It is the same on every install. Sign in as DBA, go to Tools → Change Password, and set a unique one before the server leaves your hands. Never give DBA credentials to the customer — they use ADMIN.
Additional companies
First-run setup self-locks once one company exists. Add any further companies from DBA Console → Companies. Licences are billed per company database: a company added to an install that holds an older installation-wide licence inherits it, but a company-bound licence is never copied — the new company needs its own subscription. Every new company is reported to the License Server (https://lic2.ritzy.net unless another URL is set): with its contact details (email, telephone, city, country, base currency, modules, server name), under the licence's customer when the install is licensed (re-created from those details if that customer is no longer on file), or under a customer the License Server creates from them when it is not. The creation log says which. Saving Settings → Company later sends the details again, so the License Server's copy stays current.

7Part E — Licence the installation one code

Licensing is now a single field. You mint a short code on the License Server and the DBA pastes it into the install.

Already done it in the wizard?
The New Company wizard's last page takes the same code and performs the same steps. If you activated there, skip to §7.3 Confirm.
Create customer→ Create subscription→ New activation code→ Paste & Activate→ Licensed

7.1 On the License Server (vendor)

  1. Customers → New customer. The Customer code you set here is the stable id embedded in every token and used by billing and revocation — choose it carefully, e.g. ACME.
  2. Open the customer → Create subscription: seats, add-on modules, cycle, amount, start date, grace days. Saving mints the signed token automatically.
    Seats
    Seats are concurrent devices (browsers), pooled globally. The Customer Statement PWA is exempt, and the DBA account is seat-exempt so support can always get in. Avoid 1-seat tokens outside a lab — they lock ordinary users to a single browser.
  3. In the Activation code card, click New activation code:
    FieldGuidance
    Times it can be used1 for a single install. Use 0 (unlimited) only when a customer is rebuilding servers, and revoke it afterwards.
    ExpiresDefault 30 days. Leave empty for no expiry.
    NoteInternal, e.g. “emailed to their IT on 26 Jul”.
    The code is shown once in a dialog and copied to your clipboard. It looks like RTZY-4K7M-9XQP-2WDF.
  4. Send the customer the code. That is all they need — no key file, no public key, no PEM.

7.2 On the customer install

Any administrator can also do this without the DBA Console or the support password: click Activate beside the licence message at the top of the screen and paste the code (after the trial ends an administrator's sign-in opens straight onto an Activate Ritzy screen). That path uses the License Server the install is already configured for. The DBA Console route below is the one to use when the server URL has to be set.

  1. Sign in as DBA and open Tools → DBA Console → Licensing.
  2. Enter today's support password in the header.
  3. Paste the code into Activate this installation and click Activate. It activates against https://lic2.ritzy.net unless the install was pointed at another License Server; only when the URL was deliberately cleared does a second field appear for it (it is remembered afterwards).

That one action does all of this:

  1. Fetches and trusts the vendor's public key.
  2. Pulls the customer's current signed licence and verifies it against that key.
  3. Saves the heartbeat URL so renewals, suspensions and revocations flow automatically from now on.
  4. Installs each company's own licence against that company — billing is per company database (Company ID + Company Code), so every subscribed company gets the key billed for it. A company Ritzy has no subscription for stays unlicensed; ask Ritzy to add it.
  5. Switches enforcement on.

7.3 Confirm

Hard-reload the browser (the badge caches per page load). The header badge should read a green Licensed; hover it for plan, seats and expiry. The Licence on <company> card shows the customer, seats, modules and validity.

Activation codes are bearer credentials
Anyone holding the code can pull that customer's licence. That is why they are single-use by default, can expire, and can be revoked from the customer's page at any time — every redemption is logged with its IP. Send them like a password, and revoke unlimited-use codes once the install is done.

8Hand-over checklist

Walk this before you call the installation done.

9Offline / air-gapped installs

When the install genuinely cannot reach the License Server, use the manual path under Advanced / offline setup on the Licensing tab. The order matters here — this is exactly what the activation code exists to avoid getting wrong.

  1. On the License Server: Settings → Copy public key, and issue the customer a key (the customer's Issue stand-alone key, or the subscription's Download .lic).
  2. On the install: Advanced / offline setup → Trusted public key → paste the PEM → Save pasted key. Do this first.
  3. Install a key by hand → paste the token or upload the .lic. A key names its company and installs into that company's database only; issue one per company.
  4. Switch Enforcement on.
If you forget step 2
Installing a key before trusting the vendor's key used to fail flatly. It now auto-trusts: if the key doesn't verify and the install knows which License Server to ask, it fetches that server's public key and retries once, telling you the trust changed. It can only do that when it has a server URL, which an air-gapped install won't — hence the manual order above.

An air-gapped licence cannot be suspended or renewed remotely — it simply ends at validTo plus grace. Re-key by repeating step 3 with a fresh .lic.

10Settings reference

Customer install — packages\api\.env

Path gotcha
The API loads packages\api\.env, i.e. C:\RitzyOne\packages\api\.env — not a .env in the deploy root. Editing the wrong one is a classic hour-waster. Any change here needs pm2 restart ritzy-api.
VariableDefaultPurpose
RITZY_ROOTC:/Ritzy SolutionsBase folder — see §4.2
PG_URLgeneratedThe postgres superuser: the app makes the database ready from it on every start. Also read by the nightly backup
PG_APP_URLgeneratedThe ritzy_app login every request uses (Row-Level Security applies to it)
JWT_SECRETgeneratedMandatory. Changing it signs everyone out
PORT3001API port
LICENSING_ENABLEDunsetLeave unset so the console toggle works. Setting it to true or false pins enforcement and makes the toggle read-only
LICENSE_HEARTBEAT_URLunsetLeave unset — the install defaults to https://lic2.ritzy.net and Activate saves the server it used. An env value pins it and disables the UI field
LICENSE_PUBLIC_KEY[_FILE]unsetLeave unset — Activate stores the trusted key. An env value pins it
LICENSE_HEARTBEAT_INTERVAL_MIN60Heartbeat period, minimum 5
LICENSE_SIGNING_KEY[_FILE]—Issuer only. Never set this on a customer install.
ANTHROPIC_API_KEYemptyOptional — enables the AI features (Paste Enquiry, CRM)

License Server — .env

VariableDefaultPurpose
PORT4100Serves both API and console
ADMIN_JWT_SECRETgenerated by installerMandatory. If unset, every restart signs all admins out
BOOTSTRAP_ADMIN_USER / _PASSWORDadmin / changemeSeeds the first admin — only on an empty database. Use reset-admin.cmd afterwards
PUBLIC_BASE_URLhttps://lic2.ritzy.netHanded to installs as the heartbeat URL; base for PayPal returns
CORS_ORIGINhttp://localhost:5180Must list the console's real URL
LICENSE_SIGNING_KEY_FILE./data/license-private.pemWritten by Generate key pair
LICENSE_BILLING_ENABLEDfalseSet true for the daily auto-renew and dunning sweep
PAYMENT_GATEWAY, PAYPAL_*noneOptional online payments
ENQUIRY_INTAKE_KEYemptyShared key for website enquiries (X-Enquiry-Key). Empty = intake off, the endpoint answers 404
ENQUIRY_INTAKE_PER_MINUTE30Intake posts accepted per minute from one address
BEHIND_CLOUDFLAREtrueRead the client address from CF-Connecting-IP (Cloudflare edge ranges only)

11Troubleshooting

“This key could not be verified” when installing a key

The token's signature doesn't match the public key this install trusts. Compare fingerprints — curl https://<license-server>/api/license/public-key against the one on the Licensing tab. If they differ, re-trust the key (or just use an activation code, which does it for you). If they match, the token was signed before a key-pair rotation — re-issue the customer's key.

“Subscription starts on <today>” and login is blocked

A timezone bug in builds before license-tz-validity-2026-07-26: date-only bounds were compared against UTC midnight, so anywhere ahead of UTC (Australia, the Gulf) a licence starting today read as not-yet-valid all morning. Check /api/version and upgrade.

“That activation code is not valid”

Deliberately uniform — it means unknown, expired, revoked or already used. Open the customer on the License Server and read the code's real status in the Activation code table, then issue a new one. (Single-use codes are the default, so a second attempt on the same code always fails.)

“No licence has been issued for this account yet”

The code is valid but the customer has neither a subscription nor an issued key. Create the subscription first, then activate.

“Too many activation attempts” (HTTP 429)

Brute-force throttling, 10 attempts per minute per IP. Wait a minute.

A renewed subscription isn't picked up

Renewals arrive on the hourly heartbeat, and on login when a licence would otherwise block. Check that the install has a heartbeat URL and enforcement on. If the subscription was renewed on the server but the install is offline, it stays on its old token until it can reach the server again.

Locked out of the License Server console

reset-admin.cmd                          :: list admins
reset-admin.cmd admin "NewPassw0rd"      :: reset a password
reset-admin.cmd admin "NewPassw0rd" --clear-2fa

It works with the service running.

Users can't log in — “maximum number of users”

The seat cap comes from the token when a licence is present. Raise seats on the subscription and save (it re-mints and delivers automatically), or clear stale sessions in DBA Console. DBA is always seat-exempt.

A module is missing from the menu

Usually it simply isn't in the token: edit the subscription, add the module, save — the new entitlement is delivered on the next heartbeat with no database change. The gated add-ons are Liner (LN), Marine (MA), Warehousing (WH), Inland Transport (TR), Shipchandling (SC), Payroll (E) and CRM (CR); Cargo (SP) and Accounts (AC) are core and always available.

If the licence already grants it and it still doesn't appear
The company database predates July 2026. Older builds installed only Accounts, Cargo and Payroll into VISION, and the side menu joins VISION before the licence filter runs — so the add-on can never show, whatever the token says. Run the module migrations once against that database from DBA Console → Upgrade: 008, 009, 010, 017, 018, 019, 020, 021, 022, 023, 026. They are idempotent, and they also grant the package rights, so sign out and back in afterwards. The give-away symptom is Payroll showing while every other add-on is missing — Payroll is the one gated module the old schema seeded by default.

The Cargo module still says “Shipping”

The module name lives in VISION.MODULENAME and older databases seeded it as “Shipping”. Run 027_cargo_module_rename.sql from the Upgrade tab. (The product itself remains Ritzy Shipping; only the freight-forwarding module is called Cargo, to distinguish it from Liner, Marine and Inland Transport. “Shipping Line” stays as-is — that is the ocean carrier, not the module.)

The app looks stale after an update

Hard-reload the browser. A cached bundle regularly masquerades as a bug.

12Backup & routine ops

Back up on the License Server

The licence database backs itself up: a gbak backup runs daily into data\backups\ (the newest 14 kept), and Settings → Database backup in the console backs up now, downloads, uploads and restores. A restore checks the backup first and takes a backup of the current database before replacing it, so it can be undone. Copy the .fbk files off the machine as well, with the rest of the data\ folder and .env:

FileWhy it matters
data\license-private.pemIrreplaceable. Lose it and every licence ever issued stops verifying
data\backups\*.fbkCustomers, subscriptions, invoices, activation codes, audit trail — the gbak backups of data\LICENSE.FDB (copy the backups, not the live database file)
data\license-public.pemDerivable from the private key, but back it up anyway
.envADMIN_JWT_SECRET and gateway credentials

Back up on the customer server

The nightly dumps in <RITZY_ROOT>\Backups\PostgreSQL\ (restore with pg_restore --clean --if-exists -U postgres -d ritzy <file>), plus <RITZY_ROOT>\Ritzy\System\ and packages\api\.env. The licence itself needs no special backup — re-activating restores it.

Everyday commands

pm2 status                     :: what is running
pm2 restart ritzy-api          :: after an .env change or update
pm2 logs ritzy-api --lines 100 :: recent API log
Restart-Service ritzy-license  :: License Server (vendor box, elevated PowerShell)
healthcheck.cmd                :: License Server health, exit 0 = OK

Updating an existing customer server

  1. Extract the new RitzyOne-deploy.zip over the install folder.
  2. pm2 restart ritzy-api.
  3. Confirm /api/version shows the new build, and hard-reload the browser.

13Start over (wipe test data)

To repeat an installation test from a clean slate. Neither uninstaller deletes data by default, so the steps below are what actually clears it.

Test machines only
Both procedures are permanent; the only way back is a backup. Never run them on lic2.ritzy.net or a customer server. Deleting the License Server's private signing key makes every licence ever issued unverifiable, and every customer install would need a new public key and new licences.

13.1 Customer server (Ritzy One)

Every company lives in one PostgreSQL database (default name ritzy). Dropping it and restarting the app gives an empty install at the first-run company setup (§6). uninstall.ps1 does not touch the database.

  1. Stop the app: pm2 stop ritzy-api (or net stop ritzy-api where it runs as a Windows service).
  2. Find the postgres password in PG_URL in packages\api\.env (postgres://postgres:<password>@localhost:5432/ritzy), then drop the database — use the name from PG_URL if it isn't ritzy:
    "C:\Program Files\PostgreSQL\18\bin\psql.exe" -h localhost -U postgres -d postgres -c "DROP DATABASE ritzy WITH (FORCE);"
    WITH (FORCE) closes any connections still open.
  3. Start the app again: pm2 start ritzy-api (or net start ritzy-api). On start it uses PG_URL to create a new empty database, the schema and the ritzy_app login.

Keep packages\api\.env — it holds the PostgreSQL logins the app needs to rebuild the database. Optional extras:

To also clearDo this
Nightly database dumpsDelete <RITZY_ROOT>\Backups\PostgreSQL\
DBA console backupsDelete the files in <RITZY_ROOT>\Backups\
Old Firebird companiesDB_*.FDB files in <RITZY_ROOT>\Data are not affected by the drop, and the installer will offer to convert them again. Move them away if the test should start with none
The whole installAfter the steps above, run uninstall.ps1 as Administrator: it removes the services, firewall rules and the install folder (including .env, so note PG_URL first if you will reconnect to the same PostgreSQL server). It stops only ritzy-api and node processes running from the install folder, and leaves the PM2 daemon up while it runs anything else, so a License Server on the same machine keeps running

13.2 License Server

From the License Server folder, in a Command Prompt as Administrator:

uninstall.cmd -Yes -PurgeData

This removes the Windows service ritzy-license (and any PM2 process or boot hook an older install left), the firewall rule, and deletes .env and the whole data\ folder: the licence database (LICENSE.FDB, and an old license.db if present), data\backups\ and the signing key pair. Run uninstall.cmd without flags to be asked about each step instead (data is kept unless you say yes).

Then run install.cmd again (§3). The first start creates an empty licence database and the bootstrap admin, and you generate a new key pair in Settings.