Upgrading Chart Engine
The fixed order an upgrade has to run in — stop, unpack, rebuild the bundle, rebuild the frontend, start — and how to prove the site is actually serving the new build.
Chart Engine has no tables, no routes, no seeders and no cron jobs, so an upgrade
touches nothing you have to migrate. What it has instead is the sharpest ordering
constraint in the product: the app loads a built bundle, and the frontend
build compiles that bundle into .next at build time. Do the same four steps in
the wrong order and you get an install that is fully updated on disk, reports the
new version in the admin panel, and serves the previous chart to every trader.
That is the failure this page exists to prevent. Everything else about a Chart Engine upgrade is uneventful.
The Install v… button on the product page extracts the ZIP over the project
root and writes the new number into the extension row for product 61364182.
It does not rebuild anything and it does not restart anything. The running
Next.js server keeps serving the build it loaded at boot.
So the version badge in Extension Manager is evidence of what was unpacked, not of what the browser is running. Until the frontend is rebuilt and the platform restarted, the two disagree.
The order, and why each step is where it is
| # | Step | What breaks if it runs later |
|---|---|---|
| 1 | pnpm stop |
Files are replaced under a running server, which has to be restarted afterwards anyway — and pnpm stop proves the ports are actually free before anything is written |
| 2 | Unpack the release | The frontend build reads the addon off the filesystem while it loads its config — files that land afterwards were not in the build |
| 3 | pnpm build:chart-engine |
The bundle is rebuilt into dist/, which .next has already been compiled against — the new code sits on disk and in nothing the browser loads |
| 4 | pnpm build:frontend |
Nothing about the new addon reaches .next at all |
| 5 | pnpm start |
Started earlier, the site serves the pre-upgrade build until it is restarted again |
frontend/next.config.js resolves Chart Engine while it is loading. It checks
for components/(ext)/chart-engine/index.tsx or dist/index.js, bakes
NEXT_PUBLIC_HAS_CHART_ENGINE into the client bundle as a literal "true" or
"false", and aliases every import of @/lib/stubs/chart-engine-stub onto the
package. The package's package.json points main, module, types and its
exports map at ./dist/index.js.
Everything in that sentence is decided once, during pnpm build:frontend.
Rebuilding the addon afterwards produces a correct dist/index.js that no page
loads until the frontend is built again.
The upgrade
-
Back up first. Nothing in a Chart Engine release touches the database, but the extractor writes over the project root and the release also carries core files. Take the usual set — the MySQL dump from
/admin/system/database/backup, plus your own copies of.env,frontend/public/uploads/andlic/. See Updating. -
Download the release. Open Admin → Extension Manager (
/admin/system/extension, permissionaccess.extension), pick Chart Engine, and press Install v… on the product page at/admin/system/extension/61364182. Four keys are involved and they are not interchangeable.access.extensionopens the route.view.extensiongates the product listing both screens are built from, and without it the product page does not render a permission error — it renders Extension not found, because the list it looks Chart Engine up in came back empty. Check for updates and Install v… both call routes gated oncreate.license, and the enable/disable switch onedit.extension. Grant all four, or none.From a shell instead,
pnpm update-alldownloads every pending release across the whole install and finalises once. -
Stop the platform.
pnpm stopThis removes the
backend,frontendandcronPM2 apps and puts the maintenance server on their ports. -
Rebuild the addon bundle. A release ships
dist/pre-built, so this is required only when you have customised the addon's own source — but running it is the cheapest way to guarantee the bundle matches the source that was just unpacked.pnpm build:chart-engine -
Rebuild the frontend.
pnpm build:frontend -
Bring it back up.
pnpm start
Or let the update chain do it
pnpm updator is pnpm stop, then dependencies, then the schema migration boot,
then the seeders, then pnpm build:frontend, then pnpm start — in that order,
with each link stopping the chain if it fails. Because the release has already
put the addon's dist/ on disk by then, the frontend build sees the new bundle
and the ordering above is satisfied without you thinking about it.
Two things it does not do:
- It does not run
pnpm build:chart-engine. It does not need to for a stock release, which ships the bundle built. If you have customised the source, run that command yourself betweenpnpm stopand the chain, or run it and thenpnpm build:frontendafterwards. - It does nothing for files you extracted by hand after the fact. A manual unpack done after a frontend build has none of the ordering guarantees the chain provides.
What pnpm build:chart-engine actually runs
cd frontend/components/(ext)/chart-engine && npm install && npm run buildNote the package manager. The addon is not a pnpm workspace project —
pnpm-workspace.yaml lists frontend, backend and e2e, and nothing else. It
keeps its own package-lock.json and its own node_modules directory inside the
frontend tree, holding its build toolchain (tsup, typescript, rimraf). A
root pnpm install never installs any of it; only that npm install does.
Two consequences worth knowing before you need them:
- The first run on a fresh box needs the npm registry. On an air-gapped or
firewalled server with no
node_modulesinside the addon directory, the command fails atnpm installand you are dependent on thedist/the release shipped. That is a working state, not a broken one — it is what most installs run. npm run buildclearsdist/before it writes. The tsup config setsclean: true, so a build that fails part-way can leave the package with no entry point at all. Do not run the frontend build untildist/index.jsis back.
A successful run produces three files:
| File | What it is |
|---|---|
dist/index.js |
The bundle. This is the package entry point and the only thing the app loads |
dist/index.d.ts |
The type definitions, which is what turns a misspelled prop in a custom integration into a build error |
dist/.build-manifest.json |
A record of the build — builtAt, sourceCount, and the sha256 of every source file it was built from |
Proving you are on the new build
-
Check the bundle on disk, with its timestamp:
ls -l frontend/components/\(ext\)/chart-engine/dist/index.jsThe parentheses are part of the path and have to be escaped in a POSIX shell.
-
Read the build manifest, if the release shipped one.
builtAtis an ISO timestamp of when that bundle was produced, which is a better answer than a file mtime — an extraction or a fresh checkout restamps every file at once.head -3 frontend/components/\(ext\)/chart-engine/dist/.build-manifest.json -
Hard reload a trading page you have switched over — ::kbd[Ctrl+Shift+R] — and confirm the chart's own toolbar is there: timeframes, chart-type picker, and buttons for indicators, alerts, replay, heatmap and fullscreen.
-
Check the browser console. This line means the build did not see the addon and the page fell back:
[ChartSwitcher] Chart Engine addon not installed. Falling back to TradingView.The fix is a frontend rebuild, not a setting.
-
Confirm both settings still read Chart Engine.
binarySettings.display.chartTypeon/admin/finance/binary/settingsandspotChartEngineon/admin/trading/settings. They live in the database and an upgrade does not touch them — but a licence that lapsed during the window does. See below.
Where the version numbers come from
The product page at /admin/system/extension/61364182 shows two figures that can
legitimately disagree, plus a third list from somewhere else again.
| Shown as | Source | Caveat |
|---|---|---|
| Current version | The version column of the extension row for 61364182. Written by the download route when it finished extracting |
Says what was unpacked, not what was built or restarted |
| Latest version | The licence service's answer to the update check | The batch check behind the product list is cached for 10 minutes; the detail page's Check for updates button asks again |
| Recent releases | The published release catalogue, fetched from the documentation site | A separate service. The installed build is often not in this list at all |
Updates are offered one version at a time: after a successful download the panel re-checks and offers the next one.
If the licence service is unreachable, the check is answered with the same
"latest version" wording as a genuine up-to-date result, and a missing licence
file answers No purchase code found under the same heading. Read the message
line, not the heading.
Clear out what the release deleted
An update is extracted over the install. Files a release changed are overwritten and files it added appear, but files it removed are still sitting there — nothing in the pipeline deletes anything.
pnpm build:frontend runs scripts/clean-stale-files.mjs as its first step, so
in the normal chain this happens for you. To look before it acts:
pnpm clean:stale --check # preview only, changes nothing
pnpm clean:stale # deleteInside the addon directory the case that matters is a leftover module that
shadows a directory beside it — a foo.ts left over next to the foo/ folder
that replaced it. Module resolution prefers the file, so tsup would bundle last
version's code and the resulting dist/index.js would be a hybrid of two
releases. The script's shadow pass walks the whole of frontend/ (skipping
node_modules, .next, .git, .turbo, coverage, public, messages and
uploads), so it reaches inside the addon and removes exactly that.
What it does not remove is an orphan leftover that shadows nothing: the script's
explicit retired-paths list names no Chart Engine files today. Those are inert
for the running site — tsup only bundles what index.tsx reaches — but they do
mean the package directory accumulates files from past releases.
When the script reports Kept N stale path(s): still imported on this install,
it is telling you that something on disk still imports a module this release
removed — which means that importer is an old copy the extraction did not
replace. Re-extract the release over the install and run it again rather than
deleting by hand.
The licence, after a version bump
Licence files in lic/ are not shipped in a release package, so an upgrade
leaves them untouched and there is nothing to re-enter. Opening
/admin/system/extension/61364182 calls the verify route on load
(POST /api/admin/system/license/verify, permission create.license) — if the
page renders the licensed product view with the version card, the licence is
good.
Reactivation is only needed when the machine fingerprint changed, which is a server move rather than an upgrade — see Moving an install.
The licenseHeartbeat scheduled job runs every six hours. A revoked or
expired result for product 61364182 is handled by writing configuration, not
by raising a banner: binarySettings.display.chartType goes back to
TRADINGVIEW, spotChartEngine goes back to TRADINGVIEW, and the settings
cache is cleared so every process picks it up at once.
There is no notification and no audit entry naming the licence. If your charts are TradingView again after an upgrade and the build checks above all pass, the cause is the licence — and reactivating it does not restore your choice. Set both settings again. Administering Chart Engine has the detail.
What survives on the user side
All of it. Chart Engine stores nothing on the server, so there is nothing to migrate and nothing to back up. Every piece of a trader's arrangement lives in that browser's local storage, keyed by name rather than by build:
| Key | Holds | Lifetime |
|---|---|---|
binary-chart-state |
Per-symbol timeframe, zoom, chart type and expiry minutes | Discarded 24 hours after it was last saved |
binary-chart-indicators |
The indicator list — global to the browser, not per market | Discarded 30 days after it was last saved |
binary-chart-drawings-<SYMBOL> |
Drawings, one key per market | No expiry |
binary-chart-favorite-indicators |
Favourited indicators | No expiry |
chart-templates |
Saved templates | No expiry |
One upgrade-visible exception, and it is deliberate. Stored indicators carry a
paletteVersion; when it is older than the current one the chart drops the
colour keys as it loads them — the color on every style sub-object, and every
parameter whose name ends in color, colour or colors — so an indicator
picks up the themed palette instead of a hex value frozen at the moment it was
added. Periods, sources, thresholds and line widths are kept.
Colours are not, and that includes the ones a trader picked by hand. The saved
shape is id, type, params, style, isVisible and placement — nothing
in it records where a value came from, so a custom colour is indistinguishable
from a frozen palette one and goes with it. A trader reporting "my indicators
changed colour after the update" is seeing that, once, and it does not recur —
but any colour they had set deliberately has to be set again.
When it goes wrong
The download bumped the extension row and rebuilt nothing. Run
pnpm build:frontend and pnpm restart, then hard reload. This is by far the
most common report on this page.
The frontend was built before the files landed — or built while dist/index.js
was missing, which a failed pnpm build:chart-engine will leave you with, since
tsup clears the directory before it writes. Confirm dist/index.js exists, then
rebuild the frontend.
The addon installs its own toolchain from the npm registry and is not covered by
the workspace install. Check outbound access to the registry. If you cannot get
one, skip the step: a stock release ships dist/ already built, and only a
customised source tree needs rebuilding.
A leftover from a previous version. pnpm clean:stale --check shows it,
pnpm clean:stale removes it, then rebuild. See the stale-files section above,
and the same entry in Updating.
Then it is not the upgrade. An empty chart with a Retry button is a data problem — wrong market type, or a market with no candles — and belongs in Troubleshooting.
Related
- Install and enable — the first install, the two settings, and removal
- Updating — the core update chain, link by link
- Licences and activation — the
.licfiles, the heartbeat and the fingerprint - Integration — how the addon is resolved at build time, for a customised install
- Troubleshooting — symptom-first diagnosis once the build is right