Ctrl K
ComunidadGuías…

CHANGELOG.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# 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
  `/<token>/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 <!doctype html>" 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 <that backup>` 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=<id>` 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