# Signal Trade stock mirror for Node.js

Copy your dealership's stock and active branches to a local SQLite database. The mirror reads Signal; it does not publish a website or write changes back.

## Start

1. Use Node.js **22.13 or newer** ([built-in SQLite requirements](https://nodejs.org/api/sqlite.html)). Save `signal-trade-stock-sync.mjs` and `signal-trade-sqlite-example.mjs` together.
2. Set `SIGNAL_TRADE_API_KEY` privately on the server to your stock-read key.
3. Run `node signal-trade-sqlite-example.mjs` and read its result.

The default database is `signal-trade-stock.db`. Set `SIGNAL_TRADE_SQLITE_PATH` for another path. Set `SIGNAL_TRADE_BASE_URL` only when deliberately using another approved server. Keep the key and database on trusted storage. The key is never saved in the database.

## Keep it current

Run the same command again to fetch changes. Each invocation runs once. Arrange its schedule in your receiving system and allow for the API's hourly limits. The mirror performs a complete reconciliation at least daily when invoked, pruning missing rows only after the complete load and catch-up succeed.

| Command option | Use |
| --- | --- |
| `--status` | Inspect saved local sync information without contacting Signal. |
| `--reconcile` | Refresh the complete inventory now. |
| `--rebind` | Deliberately rebuild the same dealership's copy after a key or permission change, or upgrade an old unbound mirror. |

Add an option after the filename, for example `node signal-trade-sqlite-example.mjs --reconcile`.

## Recovery

The mirror checks the key's dealership and exact permission before reading and again before committing. Another business or server needs a separate database. A changed key or scope requires `--rebind`; a successful rebuild removes older finance fields from the current mirror when the new key cannot read them. Your own backups and other exports need their own retention handling.

Vehicles, branches and the checkpoint commit together. Failed reads, denied access, malformed responses, local failures and interrupted runs keep the previous complete dataset. Retry the command after resolving the reported problem. One writer is allowed at a time; readers can retain the last committed copy while a sync runs.

The stock feed identifies affected records; the client then fetches their current state. An existing record is kept even after an earlier deletion and recreation. A missing record is deleted during a poll only when that poll also contains a validated deletion notice for it. Other missing records stop the poll; use `--reconcile` after checking access to recover from a history gap. A vehicle whose stage is `removed` is still an existing record.

The Node.js and Python stock mirrors share the same database format. This is a reference receiver, not evidence that an external dealer system has been integrated. Test your receiving system's mapping and complete dealer workflow before relying on it.
