# Changelog All notable changes to this project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [1.4.0] - 2026-09-28 Every country's flag, on every platform. On PasarGuard, the applications and the announcement link the operator already configured in the panel. Live figures on PasarGuard and Rebecca, as on 3X-UI. And on a fresh PasarGuard or Rebecca install, the panel's own name and support link are offered instead of being typed again. Row stays the default design, and nothing changes for an existing install except what is listed below. ### Added - **Every country's flag, on every platform.** A node's flag used to be drawn by the reader's own emoji font, and Windows has none with flags, so Chromium-based browsers there — most desktop readers — printed the two letters (`TR`, `DE`) instead; only six countries were drawn another way. The page now carries the Twemoji flags as a small colour font and uses it for the flag badge alone, so all 258 flags draw the same on Windows, Android, iOS, macOS and Linux, in Chromium, Safari and Firefox. It covers flag emoji and ISO codes alike (`🇹🇷 Istanbul`, `TR | Ankara`, `GB-LON-1`). `UK` now draws the British flag (no emoji set draws a `UK` pair), and `XK` (Kosovo) is recognised. The font is a 64-units-per-em subset of Twemoji Country Flags — visually identical at badge size and a third smaller — rebuilt reproducibly by `tools/subset-flag-font.sh`; the artwork is CC-BY 4.0 (`src/fonts/TWEMOJI-LICENSE.txt`). - **PasarGuard: the operator's own applications.** When the operator has listed applications in PasarGuard (Settings → Subscription → Applications), the Connect card shows those instead of the built-in list: one tab for each platform the list covers (Android, iOS, Windows, macOS, Linux, Android TV, Apple TV), the recommended application first, the operator's description in the reader's language, and a download link. Import uses the link PasarGuard built for this subscriber — completed with the page's own address when PasarGuard has no subscription URL prefix and gives only a path — and for a device-bound subscription PasarGuard has already left out the applications that do not apply. With no list configured, the page keeps its built-in catalogue. The icons the panel names are never loaded, because the page makes no request to another site. - **PasarGuard: the announcement's own link.** An announcement with an address set in the panel (`announce_url`) gains an *Open link* under its text. - **Live figures on PasarGuard and Rebecca.** Usage, expiry and online status now refresh while the page is open on every panel. Both panels serve them at `//info` in their own format; the page reads that format and stops, leaving the figures it has, if a panel ever answers with anything else. - **The panel's own name and support link, offered at install.** PasarGuard and Rebecca already hold a subscription title and a support URL. A fresh install on either reads them (read-only) and asks *Use them for this page?*. In a script, `RT_PANEL_BRANDING=1` takes them and `RT_PANEL_BRANDING=0` never offers them; `RT_SERVICE_NAME` and `RT_SUPPORT_URL` always win. On an existing install, **Reconfigure → Use PasarGuard's (Rebecca's) name and support link** in the manager, or `RT_PANEL_BRANDING=1 row-template config`, does the same. The panels' defaults (`Subscription`, `https://t.me/`) are never offered, nor a PasarGuard title that still carries a per-subscriber placeholder such as `{USERNAME}`; every value passes the same checks a typed one does. ### Fixed - **A panel's default support link no longer replaces yours.** Rebecca's support URL defaults to the bare `https://t.me/`, and a support link from the panel outranks the one configured in Row-Template, so on a default Rebecca every page's *Contact support* went to Telegram's front page. The bare default now counts as no link, on Rebecca and PasarGuard alike. - **Rolling back after the update keeps your design.** The backup a pre-1.4.0 updater takes of the page it replaces is written after the new designs are installed, so it matches none of them and names no design; a rollback to it restored Row instead of the design you had. The rollback now takes the design that backup's own saved settings record, and restores it from the installed designs. ### Changed - **The page is larger, and paints as early as before.** 1.4.0 adds 81,052 bytes to every design, 68,748 of them the flag font (the largest design is now 285,757 bytes); the size ceiling is 280 KiB (was 200 KiB). The font is placed after the page's markup, not in its head, so the first paint does not wait for it: measured on a 4× slower CPU and a 1.6 Mbit/s link, first paint is unchanged or earlier, and the page finishes loading about 0.4 s later on that link (about 0.1 s on 4G). Script time is unchanged. - **Tabs wrap.** With more than four platforms in a panel's list, the tab strip wraps onto a second line in every design instead of shortening the labels. ### Known limitations - The panel-branding offer reads SQLite databases only; with MySQL, MariaDB or PostgreSQL the installer simply asks as before. - PasarGuard's application icons are not shown (see above), and the page does not state a device limit; the panel's own filtering of the application list is what a device-bound subscription gets. - PasarGuard's page title (`subTitle`) and Clash templates are still not produced, and Rebecca on MySQL/MariaDB still needs its one setting entered in the dashboard. - Rebecca's Docker image is still the 0.0.x Python edition, which cannot render this page, and is refused before anything is changed. Use Rebecca 1.x from its binary installer (`rebecca-binary.sh`). ### Development - **Every built script is compiled by the suite.** The runtime modules are concatenated into one scope for the page, so two modules declaring the same name are fine as modules and a syntax error as a page. `tests/artifact-scripts .test.mjs` compiles every script of every design on every panel, and refuses a top-level name declared twice. - **The flag font is tested from its bytes.** `tests/flag-font.test.mjs` reads the committed WOFF2 with Node's own Brotli and proves that every code the page can emit has a colour glyph, and where the face sits in every page. - **Browser validation in three engines.** The PasarGuard and Rebecca pages, rendered by the panels' real engines, and the 3X-UI pages from the fixture renderer, were checked in Chromium, WebKit and Firefox: every flag drawn as a flag, the panel's applications and platforms, the announcement link, live refresh repainting, Persian right-to-left, no request to another host. - `tools/rebaseline.mjs` re-pins the seventeen artifact locks to the current build and prints what moved, for a deliberate change to the shared runtime. ### Upgrading - From **1.1.0, 1.2.0 or 1.3.x**, on any panel: run `row-template update`. Your design, branding and panel wiring are kept; the new page is in place at once. - To take PasarGuard's or Rebecca's own name and support link on an existing install: `row-template` → **Reconfigure** → the last item, or `RT_PANEL_BRANDING=1 row-template config`. - Rolling back after the update returns the page and the recorded version, not the manager, as before; only the two newest backups are kept. ## [1.3.1] - 2026-09-27 A hotfix release: everything fixed after v1.3.0 was published, packaged as one small upgrade. The PasarGuard and Rebecca pages now name themselves after the subscriber instead of the generic word "Subscription", a node name that carries an ISO 3166-1 alpha-2 code now draws that country's flag, and the release validation is reproducible and fully green on Linux. No installer adapter changes behaviour, and nothing changes for an existing 3X-UI install. ### Fixed - **PasarGuard: the page no longer titles itself "Subscription".** PasarGuard's page context carries the subscriber (`user.username`) and the admin's own columns, but **not** the panel-wide subscription settings, so the template had nothing to read and every page fell back to the generic word. The page is now named by the admin's configured profile title when there is one, and by the subscriber otherwise — the order PasarGuard itself resolves a title in. A profile title that still carries a PasarGuard format placeholder (`{DATA_LIMIT}`, `{EXPIRE_DATE}`, `{USERNAME}`, …) is refused rather than printed literally, because the page cannot resolve those variables and a literal placeholder is worse than the subscriber's own name. The subscriber's address (`user.ip`) is still never read. - **Rebecca: the page no longer titles itself "Subscription" either.** Rebecca's page context carries **no profile title at all**: the panel-wide `subscription_profile_title` is written into the `/info` `profile-title` **header** (`subscriptionHeaders`) and the page render path (`renderSubscriptionHTML` → `renderSubscriptionPageTemplate`) never passes it, so the title the adapter reads from that header is invisible to the page. The one identity the page does receive is `user.username`, so that now names the page — the same fallback PasarGuard takes when no profile title is configured. A value with no word in it at all (absent, empty, whitespace-only) is not a name and the page keeps its generic fallback; the value is never rewritten. No `{` guard is needed here, unlike PasarGuard: Rebecca never runs a title through `str.format_map`. The subscriber's token and address are still never read, and nothing changes for an existing 3X-UI or PasarGuard install. - **Country flags: a node name that carries an ISO alpha-2 code now gets that country's flag.** `TR | Istanbul`, `RU-01`, `GB-LON-1`, `FI-01`, `DE` and the rest previously found no regional-indicator pair and fell to the monogram (`T-I`, `R-U`, `G-B`, `F-I`) — which on any platform reads as the code, which is why the badge appeared to show `TR`/`RU`/`GB`/`FI` instead of a flag. A two-letter token is read as a country only when it is uppercase, stands alone between non-letters, and names a real country in the **same 258-code registry the emoji path already uses**; `LON` out of `GB-LON-1`, `USA`, `A1B`, `ZZ-01` and lowercase English words (`no`, `it`, `us`, `in`) are all still refused. An explicit flag emoji still wins over a code in the same name, and the displayed name is never rewritten. Country *names* and *city names* — `Turkey - Istanbul`, `Türkiye`, `Turkiye`, `Finland Helsinki` — still draw the monogram: a name table does not fit the frozen artifact budget, and guessing from an ambiguous name is worse than a monogram. All 15 artifacts were re-baselined (+179 B each; `pulsenova` is 204,705 B with 95 B of headroom). ### Documentation - `docs/design/PGCLOCK-AUDIT.md` — a read-only audit of the third-party PGClock template as a secondary reference. It confirms `user.username` as the exposed subscriber identity, has no service-name, support-URL or flag logic, and is unlicensed, so nothing was derived from it and `PROVENANCE.md` is unchanged. - `docs/design/PASARGUARD-ADAPTER-AUDIT.md` §8 — the page context is not the `/info` payload: the headers carry the values the panel *resolved*, the page context carries the admin's own columns and nothing else. - `docs/design/REBECCA-ADAPTER-AUDIT.md` §2 — the same distinction for Rebecca, stated against `subscriptionHeaders` and `subscriptionTemplateContext`: the page context carries no profile title at all, so the page's title and the adapter's header-derived `title` field can legitimately differ. - `docs/design/FLAG-RENDERER-AUDIT.md` §17 — the alpha-2 path is an **input** extension; the return shape, `CODES` and every fallback are unchanged. ### Development - **The release validation now runs on Linux, in CI.** The repository's only workflow was `Docs`, which builds the documentation site and never ran the suite — so a green check on a pull request said nothing about whether the page still rendered. `.github/workflows/release-validation.yml` runs the four release commands (`npm test`, `npm run verify`, `npm run lint:sh`, `npm run build:panels`) on `ubuntu-latest`, installing the three tools the suite needs and a Node runtime does not provide: **Go** (the fixture renderer and the pongo2 harness), **Python 3 with Jinja2** (the PasarGuard harness) and **ShellCheck**. Each command reports its own result even when an earlier one fails, because the point of the job is the four results. - **The panel life-cycle tests are offline, and no longer validate a published release.** Both installer panel suites built a two-design payload while the release registry names seventeen, so `rt_complete_install` always judged the install short of what its own version ships and downloaded the release pinned to that version — the published v1.3.0 tarball. On a host with network the download succeeded, the template store was rebuilt from that release, and `verify` then compared it against the working tree: `FAIL canonical artifact does not match the selected template (row)`. The payload is now the complete release, so the download is never reached, and `curl` and `wget` are denied in every fake host and record the attempt, so a regression fails the suite loudly instead of quietly reaching the internet. - **`sqlite: false` now means sqlite3 is *unavailable*, not merely unimplemented.** The adapters gate on `command -v sqlite3`, and `ubuntu-latest` ships a real one, so the manual-activation test read `outcome=auto` where it expected `manual`. Every directory holding a sqlite3 is now removed from the child's `PATH`, replaced by a mirror of itself so nothing else on the host stops resolving; a new test plants a real-looking sqlite3 and proves it cannot reach the child. - **The release validation is reproducible and fully green.** With both leaks closed, the four release commands pass on `ubuntu-latest` — `npm test` with no failures, `npm run verify` all checks passed, `npm run lint:sh` 12 scripts clean, `npm run build:panels` 51 shells — and the result no longer depends on whether the host has network or happens to ship a `sqlite3`. ## [1.3.0] - 2026-09-26 Row-Template now installs on **PasarGuard** and **Rebecca** as well as 3X-UI, and ships two more designs. A minor release: nothing changes for an existing 3X-UI install except what is listed below, and Row stays the default design. It also carries every fix prepared for 1.2.1, which was not released on its own. ### Added - **PasarGuard support.** PasarGuard is supported from this release: detect, install, activate, verify, back up, restore and uninstall, on the official Docker install and on a source install (`pasarguard.service`). The page is placed at `/var/lib/pasarguard/templates/row-template/index.html` (or inside your own `CUSTOM_TEMPLATES_DIRECTORY`) and selected by one marked block appended to `/opt/pasarguard/.env`; a running panel is restarted once. None of your own `.env` lines is edited, and uninstall returns the file to its exact previous bytes. `row-template verify` also reports the two panel settings that still take precedence over the page: an admin's own `sub_template`, and `disable_sub_template`. - **Rebecca support.** Rebecca 1.x — the Go edition, which Rebecca publishes for its binary install — is supported from this release, with the same seven operations. The page is placed at `/var/lib/rebecca/templates/row-template/index.html` (or inside your own custom templates directory) and selected in the newest `subscription_settings` row, which Rebecca reads on every request — so nothing is ever restarted. Activation is automatic with the default SQLite database and `sqlite3`; with MySQL/MariaDB the page is still placed and the installer prints the two values to enter in the dashboard. `NULL`, empty and a set templates directory are each restored exactly. - **Panel detection and choice.** The installer finds the panel on the server and installs for it (`/etc/3x-ui/sub_templates/row-template` for 3X-UI, `/etc/row-template` for PasarGuard and Rebecca). A panel counts only when two independent signals agree; a half-installed panel is refused, not guessed at. On a server with more than one panel it asks, or reads `RT_PANEL=3xui|pasarguard|rebecca` in a script. - **Transactional activation on PasarGuard and Rebecca.** The panel's state is snapshotted, changed and verified; if any step fails it is restored exactly, and the installer says so — and shows the real cause. - **Two new designs: Meter and Notebook.** Meter is a calm instrument dashboard of rounded cards with a segmented traffic meter; Notebook is a page from a dotted notebook, hand-inked. Both were contributed by the project's author, ported onto the shared runtime, and held to the same contract as the other fifteen — seventeen designs in all, on every panel. - **Every design, for every panel.** Each release now carries a PasarGuard (Jinja2) and a Rebecca (pongo2) page for every design, under `shells/`, checksum-verified like the 3X-UI pages. ### Fixed - **Rolling back to a backup taken under 1.1.0 works.** 1.2.x refused it with "backup artifact matches no installed template". A backup that names its design is restored as that design; one whose page is none of this release's designs (1.1.0's) is restored as this release's Row, so `verify`, design switching and updates keep working afterwards. - **A successful rollback is reported as a success.** The transaction engine checked, after restoring the panel, that the panel was still pointing at Row-Template's directory — which is exactly the state a correct rollback has just undone. Every rollback therefore ended in "the rollback failed" even when the panel had been restored perfectly. The engine no longer asks that question: the restore verifies itself. Each panel adapter now re-reads the panel's own setting after restoring and confirms it matches the value it recorded before changing anything, and a restore that does not land is reported as a failed rollback with the real cause. A regression test pins this: the engine must never re-run the forward check after a restore. - **The manual PasarGuard instructions are complete.** When activation cannot be done automatically, the installer printed only `SUBSCRIPTION_PAGE_TEMPLATE` and told you to edit `.env` — but the page had not been copied anywhere the panel could read. It now prints both the copy and the two `.env` values (`CUSTOM_TEMPLATES_DIRECTORY` and `SUBSCRIPTION_PAGE_TEMPLATE`), and says to keep your own templates directory if you already have one. - **A rollback right after a change undoes that change.** Backup names have one-second resolution, and two backups made in the same second — a design switch followed at once by `row-template rollback --auto`, which snapshots the current state first — shared one directory. The newer snapshot overwrote the older one, so the rollback re-applied the state it was meant to undo. A backup now waits for the next second rather than reuse a name. - **The live check after `config`, `update` and `rollback` runs on 3X-UI.** It always said "skipped (no test URL available without sqlite3)", even with `sqlite3` installed, because those commands had not located the panel database. And the check made right after activation no longer warns "could not reach the subscription endpoint" while 3X-UI is still restarting. - **A page change that cannot reach PasarGuard or Rebecca changes nothing.** Regenerating the page (a rebrand, a design switch, an update) replaced `sub.html` before copying it into the panel; if that copy failed, `sub.html` was left newer than the page the panel serves. It is now put back, and on a first activation, where there was no `sub.html` before, none is left behind. - **A valid page is never refused under load.** The structural check before every install, update and design switch read the page through `head | grep -q`. On a busy server `grep -q` could stop reading before `head` finished writing, and the shell then reported the match as a failure — "generated template does not begin with " for a perfectly valid page, about once in 150 checks. Every such check is now written so that it cannot be cut short. - All fixes prepared for 1.2.1 (below): one `row-template update` is enough to move from 1.1.0, misplaced designs are moved back, branding works on an install the 1.1.0 updater left incomplete, and `verify` names missing and damaged designs. ### Security - **Every value is escaped on every panel.** PasarGuard renders pages with a non-sandboxed Jinja2 whose autoescaping is off. Every PasarGuard and Rebecca page therefore wraps its body in an explicit autoescape block, and is tested with the panels' real engines against hostile usernames, notes, links and malformed data. - **Branding can never open a template tag.** `{` and `}` in your service name, support link or logo are written as `{` and `}`, so no branding value can start a Jinja2 or pongo2 expression. - **Panel secrets stay where they are.** PasarGuard's `.env` and Rebecca's database URL are read only for the keys the installer needs, never printed, and never copied into a backup. A MySQL/MariaDB password is never asked for or read. - **Backups record their panel** and are never restored onto another one. ### Changed - `row-template version` shows the panel it serves; on 3X-UI it still shows the minimum-supported and detected versions. - `row-template uninstall` returns each panel to the page it had before Row-Template, and leaves a page you chose afterwards alone. - **A scripted fresh install on a server with more than one supported panel needs `RT_PANEL`.** 1.2 installed for 3X-UI there because it was the only panel it supported; 1.3.0 does not guess which panel you meant, and stops with a message naming `RT_PANEL=3xui|pasarguard|rebecca`. An interactive install asks instead. Re-running the installer on an existing install, and `row-template update`, keep the install's own panel and are unaffected. - The `on_hold` state on PasarGuard and Rebecca is shown as active: with its "starts on first connection" duration on PasarGuard, and with an unknown expiry on Rebecca, which does not give the page that duration (`docs/design/PANEL-ON-HOLD-DECISION.md`). ### Known limitations - On PasarGuard and Rebecca the page shows the values as of when it was opened; live refresh (`?format=info`) is 3X-UI only, because both panels serve live status on a path suffix. - PasarGuard's page title (`subTitle`) and Clash templates are not produced. - Rebecca on MySQL/MariaDB needs its one setting entered in the dashboard. - Rebecca's Docker image (`rebeccapanel/rebecca` on Docker Hub) is still the 0.0.x Python edition, which cannot render this page. The installer identifies it and refuses before changing anything; Rebecca's own `rebecca migrate-binary` moves a Docker install to 1.x. ### Documentation - The compatibility page, installation, configuration and troubleshooting cover all three panels, in English, Persian and Arabic; the READMEs in all five languages describe PasarGuard and Rebecca as supported. - `docs/design/PASARGUARD-INSTALLER-AUDIT.md` and `docs/design/REBECCA-INSTALLER-AUDIT.md` record, from each panel's source, what activation is and how the installer follows it. ### Development - The test suite renders the PasarGuard and Rebecca pages with the real engines, and needs Python 3 with Jinja2 as well as Go; a missing engine is a failure, never a skip. - `tools/make-release.sh` writes checksums in the text form on every platform. ### Upgrading - From **1.2.0** or **1.1.0** on 3X-UI: run `row-template update`. From 1.1.0, the next `row-template`, `row-template config` or `row-template verify` completes the install. Your design, branding and panel wiring are kept. - On **PasarGuard** or **Rebecca**: run the installer. Earlier releases did not install on these panels. Rebecca must be 1.x (its binary install); a Docker Rebecca is 0.0.x and is refused until it is moved to 1.x. - **Rolling back after the update.** `row-template update` backs up the version it replaces, and `row-template rollback --to ` returns to its page and branding. A rollback restores the page and the recorded version, not the manager itself: `row-template` stays 1.3.0 and reports the version it rolled back to, and the next `row-template update` returns to 1.3.0. Only the two newest backups are kept, so the pre-update backup is replaced after two further changes (a design switch, an update or a rollback each make one). ## [1.2.1] - Unreleased (shipped in 1.3.0) Fixes the update from 1.1.0, which could leave the manager with no designs to choose from. 3X-UI (>= 3.6.0) stays the only supported panel. ### Fixed - **One `row-template update` is enough to move from 1.1.0.** 1.1.0's own updater installs the new version but copies only four files, so in 1.2.0 the designs were missing until a second update, and **Reconfigure branding → Template** said "No templates are installed". Now the first time you open `row-template`, or run `row-template config` or `row-template verify` as root, after the update, it downloads the rest of the same release — every design and the remaining installer files, checksum-verified — before doing anything else. It downloads the version you have installed, never a newer one, and changes nothing else: the live page, branding, selected design and backups stay as they are. If the release cannot be reached, it says so and tries again the next time the manager opens. - **Designs found outside their folder are moved back.** The designs belong in `dist/templates/`. A copy at the install root's `templates/` — where a copied or extracted release leaves it — is now moved into place automatically by `install`, `update` and `verify`. Each design is checked against its own checksum first; one that fails is reported and left where it is, and files Row-Template does not recognise are never removed. - **Changing branding works on an install the 1.1.0 updater left incomplete.** `row-template config` and the manager's branding editors refused with "the template selection could not be reconciled" until a second update; they now complete the install first. - **`row-template verify` names missing and damaged designs.** A design that fails its checksum is reported by name as a failure; missing designs are a warning that names them. It previously reported a failing store without saying which design, and did not report missing ones at all. ### Changed - `row-template verify` is no longer strictly read-only. Run as root, it first repairs the template store — moving misplaced designs back into place and downloading any the installed version is missing, from that same release — and then checks it. It makes no other change, and none at all when run without root. ### Documentation - The compatibility page lists, per panel, what the installer can do today: detection, install, activation, verification, and backup and rollback. For PasarGuard and Rebecca the answer is none of them — only the page shells are built and packaged — so both stay **research targets, not supported panels**. A test checks every README and compatibility page against the installer. ### Known issues - Rolling back from 1.2.x to a backup taken under 1.1.0 fails with "backup artifact matches no installed template": 1.1.0's page is not one of the current release's designs. The rollback stops before changing anything, so the running page stays as it was. Rolling back to a backup taken under 1.2.x is not affected. ### Upgrading - From **1.1.0**: run `row-template update`. The next `row-template`, `row-template config` or `row-template verify` completes the install. - From **1.2.0**: run `row-template update`. This also completes a 1.2.0 install that the 1.1.0 updater left without its designs. ## [1.2.0] - 2026-09-24 Turns Row-Template from one page into a collection of designs. A minor release: Row stays the default design, and 3X-UI (>= 3.6.0) stays the only supported panel. ### Added - **Fifteen designs.** Row plus Editorial, Canvas, Prism, Terminal, Pulse, Brutal, Arcade, Sketch, Signature, Saffron, Pulse Nova, Prism Nova, Terminal Nova, and Arcade Nova. Every design is built from the same runtime and translations, so status, Connect, QR codes, the Configuration Explorer, and the five languages behave the same in each. - **Choosing a design.** A fresh interactive install shows a design chooser (Enter keeps Row). `RT_TEMPLATE=` picks one for a scripted install, and the manager's **Reconfigure branding → Template** changes it later. Updates keep the selected design. - **Checksummed designs.** Each design ships in the release with its own SHA-256 checksum. `row-template verify` checks every installed design against its checksum and confirms the live page is the selected design. - **Painted country flags.** The flags of Germany, France, the Netherlands, Japan, Sweden, and the United States are drawn with CSS, so they appear on Windows in Chromium-based browsers, which otherwise show the two letters (`DE`) instead of a flag. Other countries keep the platform's flag emoji. - **Documentation site** in English, Persian, and Arabic: installation, configuration, a template gallery with real previews, branding, security, compatibility, a developer reference, and troubleshooting. - **Panel shells for research.** The release carries each design's page shell for every panel in the registry under `shells/`: 3X-UI, PasarGuard (Jinja2) and Rebecca (pongo2). The installer does not place these files. PasarGuard and Rebecca are research targets, not supported panels, and there are no installation instructions for them. ### Changed - **Panel database detection fails closed.** Row-Template previously used the first `x-ui.db` it found. It now uses the first database file that exists — the one `XUI_DB_FOLDER` names, then the default locations in order — and only if it is a real SQLite database. If that file is not, it is refused with a warning instead of silently moving on to another, possibly stale, database; activation then falls back to the manual instructions. - **Live refresh accepts only its own data.** The status refresh now checks that a response carries the page's own fields before using it. An unexpected response stops the refresh and leaves the server-rendered figures in place, instead of repainting the page with wrong values. - The country-code table is stored as a bitmap, saving about 800 bytes in every page. ### Internal - Groundwork for installing on more than one panel: a normalized data contract, build-time adapters for 3X-UI, PasarGuard and Rebecca, a frozen panel interface, a transaction engine, a 3X-UI panel adapter, and a format-2 backup snapshot. No `row-template` command calls any of it yet; backups and rollback still use the 1.1.0 format. - The release ships the management library's companion files (`lib/transaction.sh` and `panels/`), and install and update put them next to the library. A payload whose library is present without them is refused before anything changes. ### Development - `npm test` first renders every design's fixture pages (`npm run fixtures:all`), so a fresh clone can run the suite; it needs Go 1.22 or newer. - `npm run lint:sh` runs ShellCheck over every shell script. - The test harness runs on Linux and on Windows with Git Bash. - `tools/make-release.sh` is executable, as its usage line documents. - Design records moved from the repository root to [`docs/design/`](docs/design/README.md), with an index. ### Compatibility - Requires 3X-UI (MHSanaei) **>= 3.6.0**. - **Updating from 1.1.0 takes two runs of `row-template update`.** The first is carried out by 1.1.0's own updater: it installs the new version — the page updates and your branding is kept — but copies only the library and the command, so only Row is available. The second, carried out by 1.2.0, installs every design and the remaining installer files. `row-template verify` reports whether the second run is still needed. (Fixed in 1.2.1, which needs one run.) ## [1.1.0] - 2026-08-30 Evolves the subscriber page into a connection and configuration hub. A minor, backward-compatible release: the v1.0.0 experience (status, Copy subscription, QR, and per-app Connect actions) is unchanged and extended. ### Added - **Configuration Explorer.** A new "Configurations" section that lists each usable server on its own row — a country flag or monogram badge, the configuration name, and a protocol label — with per-configuration **View** (local QR code and copy) and **Copy** actions. When the list is long it gains a search box; exact-duplicate links are collapsed and malformed links are isolated rather than shown. - **Protocol awareness** for VLESS, VMess, Trojan, Shadowsocks, Hysteria/Hysteria2, WireGuard, AmneziaWG, and Telegram MTProto, presented as proper-noun labels. - **Restrained country badges** derived only from a valid ISO country code in a configuration's own label; a monogram is shown when there is no valid flag — the badge is never empty, and the country is never inferred from a host or IP. ### Improved - Individual configurations are secret-aware: links stay masked until you open **View**, are never written to the console, and QR codes render locally with no external QR, geolocation, or telemetry requests. - Configuration names and labels are always inserted as text, never as markup, keeping the page safe against hostile link fragments; links are isolated for correct left-to-right display within right-to-left interfaces. - Broader automated coverage: client-side URI parsing and classification, flag mapping, and explorer rendering, filtering, and XSS safety, plus expanded Go rendering fixtures (30 cases, including real WireGuard, AmneziaWG, MTProto, and Hysteria links, flags, bidirectional text, and large lists). - The build size gate now warns at 185 KiB and fails only at 200 KiB (previously a hard failure at 185 KiB), matching the artifact's real budget while keeping a firm upper bound. ### Security - The served page still makes no third-party requests. The Configuration Explorer adds no network calls, no external QR or geolocation lookups, and no telemetry, and it never logs subscriber links or identifiers. ### Compatibility - Requires 3X-UI (MHSanaei) **>= 3.6.0**; validated against stock 3.7.0. - Updating from v1.0.0 preserves your branding and configuration and keeps a restorable backup for rollback. ## [1.0.0] - 2026-08-30 First stable release. ### Added - Self-contained custom subscription page for 3X-UI panels — a single HTML artifact with all CSS, JavaScript, fonts, and the QR generator inlined. No third-party CDNs and no external network requests from the served page. - White-label branding: configurable service name, support link, and logo, all stored as data and injected safely (never executed). - Five interface languages: English, فارسی, العربية, Русский, and 简体中文, with right-to-left support. - One-command installer with a mandatory SHA-256 integrity check on every download (no skip path), safe archive extraction, and atomic activation. - `row-template` manager with an interactive menu and direct commands: `config`, `update`, `rollback`, `verify`, `version`, `uninstall`, and `help`. - Update checking against the public stable release channel, with graceful handling when the network or release source is unavailable. - Backup and rollback: the previously installed version is snapshotted before an update and can be restored without losing branding configuration. ### Compatibility - Requires 3X-UI (MHSanaei) **>= 3.6.0**; validated against stock 3.7.0. - Recommended operating system: Ubuntu 24.04 LTS (x86_64). [1.3.1]: https://github.com/iitzSeriZdev/Row-Template/compare/v1.3.0...v1.3.1 [1.3.0]: https://github.com/iitzSeriZdev/Row-Template/releases/tag/v1.3.0 [1.2.1]: https://github.com/iitzSeriZdev/Row-Template/compare/v1.2.0...v1.3.0 [1.2.0]: https://github.com/iitzSeriZdev/Row-Template/releases/tag/v1.2.0 [1.1.0]: https://github.com/iitzSeriZdev/Row-Template/releases/tag/v1.1.0 [1.0.0]: https://github.com/iitzSeriZdev/Row-Template/releases/tag/v1.0.0