From c49952bc4630b6b70b0264c32e1fc60a60d9bb37 Mon Sep 17 00:00:00 2001 From: Ramon Guilherme <13917322+ram0ng1@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:23:22 +0000 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20identidade=20visual=20uniforme=20(R?= =?UTF-8?q?EADME,=20labels=20como=20c=C3=B3digo,=20=C3=ADcone,=20LICENSE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit README reescrito em tom direto, sem travessões e sem listas superlotadas, com a régua de badges padronizada da família (CI, Packagist, downloads, Flarum 2.x, licença e doação, todos flat-square). Labels passam a ser declarados em .github/labels.json e aplicados pelo workflow labels-sync.yml, idênticos em todos os repositórios. O icon.svg ganha width/height explícitos na raiz para renderizar fora do GitHub (indexadores de extensão como o Flarum). Entra o arquivo LICENSE (MIT) que o composer.json declarava mas não existia no repositório. --- .github/labels.json | 13 ++ .github/workflows/labels-sync.yml | 60 ++++++++ LICENSE | 21 +++ README.md | 221 ++++++++---------------------- icon.svg | 2 +- 5 files changed, 155 insertions(+), 162 deletions(-) create mode 100644 .github/labels.json create mode 100644 .github/workflows/labels-sync.yml create mode 100644 LICENSE diff --git a/.github/labels.json b/.github/labels.json new file mode 100644 index 0000000..193f56a --- /dev/null +++ b/.github/labels.json @@ -0,0 +1,13 @@ +[ + { "name": "BC", "color": "b60205", "description": "Mudança que quebra compatibilidade (major)" }, + { "name": "seguranca", "color": "d93f0b", "description": "Correção ou reforço de segurança" }, + { "name": "melhoria", "color": "0e8a16", "description": "Nova funcionalidade ou aprimoramento (minor)" }, + { "name": "correcao", "color": "d73a4a", "description": "Correção de erro (patch)" }, + { "name": "performance", "color": "fbca04", "description": "Otimização de desempenho" }, + { "name": "documentacao", "color": "0075ca", "description": "Documentação, README e exemplos" }, + { "name": "refatoracao", "color": "c5def5", "description": "Refatoração sem mudança de comportamento" }, + { "name": "dependencias", "color": "0366d6", "description": "Atualização de dependências (composer, npm, actions)" }, + { "name": "traducao", "color": "5319e7", "description": "Traduções e arquivos de locale" }, + { "name": "manutencao", "color": "bfd4f2", "description": "Manutenção de rotina, CI e infraestrutura" }, + { "name": "pular changelog", "color": "ededed", "description": "Excluído do changelog da release" } +] diff --git a/.github/workflows/labels-sync.yml b/.github/workflows/labels-sync.yml new file mode 100644 index 0000000..0631445 --- /dev/null +++ b/.github/workflows/labels-sync.yml @@ -0,0 +1,60 @@ +name: Sincronizar Labels + +# Mantém os labels do repositório idênticos ao manifesto .github/labels.json +# (mesmo nome, cor e descrição em todos os repositórios da família). Labels +# fora do manifesto são REMOVIDOS para o conjunto ficar uniforme. +on: + push: + branches: + - main + paths: + - '.github/labels.json' + - '.github/workflows/labels-sync.yml' + workflow_dispatch: + +# §35.13 C1 — default-deny. +permissions: {} + +concurrency: + group: labels-${{ github.ref }} + cancel-in-progress: true + +jobs: + sync: + name: Aplicar manifesto de labels + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Harden runner + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Sincronizar labels com o manifesto + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const fs = require('fs'); + const desired = JSON.parse(fs.readFileSync('.github/labels.json', 'utf8')); + const { owner, repo } = context.repo; + const current = await github.paginate(github.rest.issues.listLabelsForRepo, { owner, repo, per_page: 100 }); + const byName = new Map(current.map(l => [l.name.toLowerCase(), l])); + for (const want of desired) { + const have = byName.get(want.name.toLowerCase()); + byName.delete(want.name.toLowerCase()); + if (!have) { + await github.rest.issues.createLabel({ owner, repo, name: want.name, color: want.color, description: want.description }); + core.info(`criado: ${want.name}`); + } else if (have.color !== want.color || (have.description || '') !== want.description || have.name !== want.name) { + await github.rest.issues.updateLabel({ owner, repo, name: have.name, new_name: want.name, color: want.color, description: want.description }); + core.info(`atualizado: ${want.name}`); + } + } + for (const [, extra] of byName) { + await github.rest.issues.deleteLabel({ owner, repo, name: extra.name }); + core.info(`removido: ${extra.name}`); + } diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d2e289b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Ramon Guilherme + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 7bca83e..0646580 100644 --- a/README.md +++ b/README.md @@ -1,161 +1,60 @@ -# 📦 Backup & Migration — Portable Backups for Flarum - -![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square) [![Latest Stable Version](https://img.shields.io/packagist/v/ramon/backup.svg?style=flat-square)](https://packagist.org/packages/ramon/backup) [![Total Downloads](https://img.shields.io/packagist/dt/ramon/backup.svg?style=flat-square)](https://packagist.org/packages/ramon/backup) [![GitHub Release](https://img.shields.io/github/v/release/ram0ng1/backup?style=flat-square&label=release&color=success)](https://github.com/ram0ng1/backup/releases/latest) [![Donate](https://img.shields.io/badge/donate-stripe-%236772E5?style=flat-square)](https://donate.stripe.com/fZe5o66nebkf39S28a) - -**A complete backup, export and import system for Flarum 2.x** - -### About the Project - -**Backup & Migration** is a full-featured backup and migration extension I've been -building for Flarum, inspired by *All-in-One WP Migration* but written from -scratch with a Flarum-native format. It bundles your forum into a single -portable `.flarum` file — database, uploads, storage, and any installed -extensions (workbench *or* vendor) — and restores it on the same install or a -different one with one click. - -It started from my own need to migrate forums between hosts without the manual -mysqldump-and-zip dance, and grew into a complete suite covering encryption, -cross-server transfer, per-extension picking, and automatic URL rewriting. - ---- - -### ✨ Highlights - -- **Single portable `.flarum` file** — custom streaming format (not `.wpress`, - not zip), forward-only so multi-GB backups never need to fit in memory -- **Pick what to bundle** — database, `public/assets`, `storage`, and individual - extensions, with a tag on each row showing whether it lives in `workbench/` - or in `vendor/` (composer-managed) -- **`composer.json` + `composer.lock` travel along** — vendor extensions stay - reproducible on the destination -- **Resumable, chunked progress** on both export and import (~4 MB per HTTP - request), with live progress bars and an upload `%` indicator -- **Command-line export & import** — run a full backup or restore from - `php flarum backup:export` / `backup:import`, with no `max_execution_time` - or `memory_limit` worries and no browser tab to keep open; ideal for large - forums, cron jobs and scripted server-to-server transfer -- **Optional asymmetric encryption** — libsodium hybrid scheme: sealed-box - wraps a per-archive XChaCha20-Poly1305 stream key. Public key in the database, - private key only in `config.php` -- **Cross-server transfer** — encrypt to a foreign public key, paste the - matching private key at import time -- **Automatic URL rewriting** — the source URL is recorded in the archive - header and rewritten across `settings`, `posts.content` and - `posts.parsed_content` when restoring on a different host -- **Selectable restore** — per-section and per-extension checkboxes populated - from the archive's manifest -- **Foreign-key-safe restore** — disables FK checks per tick so DDL referencing - not-yet-created tables succeeds without ordering dance -- **Smart pruning** while scanning (`node_modules`, `.git`, `.idea`, nested - `vendor/`…) so workbench scans stay seconds-fast -- **Dedicated "you've been logged out" screen** when a DB restore replaces the - admin's session - ---- - -### 🛠️ Technologies - -- **PHP 8.1+** — resumable export / import jobs, libsodium crypto, MySQL dumper -- **TypeScript + Mithril** — admin panel UI -- **LESS** — styling (theme-aware via Flarum's CSS variables) -- **libsodium** — sealed-box + secretstream chunked encryption - ---- - -### Installation - -```sh -composer require ramon/backup -php flarum migrate -php flarum cache:clear -``` - -Then enable **Backup & Migration** under the *Extensions* page in the admin -panel. - ---- - -### 🖥️ Command-line interface (CLI) - -Export and import are also available as console commands. A CLI run has no HTTP -request timeout, no `memory_limit` pressure from a web worker, and doesn't -depend on keeping a browser tab open — so the CLI is the most reliable way to -back up or migrate **large** forums, and the natural fit for cron jobs and -scripted server-to-server transfer. Under the hood it drives the exact same -engine as the admin panel, simply looped to completion in a single process. - -#### Export — `backup:export` - -```sh -# Database only, same engine as the source -php flarum backup:export --db - -# Full backup: database + assets + storage + every extension -php flarum backup:export --all - -# Database, retargeted to a different engine (cross-engine migration) -php flarum backup:export --db --target=postgres - -# Pick specific extensions and also copy the finished archive elsewhere -php flarum backup:export --db --extensions=ramon/verified,fof/byobu -o /backups/forum.flarum - -# Encrypt to a public key (e.g. preparing a transfer to another server) -php flarum backup:export --all --encrypt --public-key="BASE64_PUBLIC_KEY" -``` - -Options: `--db/--no-db` (default on), `--assets`, `--storage`, -`--extensions[=LIST]` (omit the value for **all** installed extensions), -`--all`, `--target=mysql|mariadb|postgres|sqlite` (defaults to the source -engine), `--encrypt`, `--public-key=…`, `-o, --output=PATH`. - -#### Import — `backup:import` - -```sh -# Restore everything in an archive (replaces current data) -php flarum backup:import /backups/forum.flarum --yes - -# Restore only the database -php flarum backup:import /backups/forum.flarum --yes --db --no-assets --no-storage - -# Decrypt an encrypted archive with the matching private key -php flarum backup:import /backups/forum.flarum --yes --private-key="BASE64_PRIVATE_KEY" -``` - -> ⚠️ A restore **replaces** the destination database and files, so -> `backup:import` refuses to run without the explicit `--yes` flag. - -Options: `-y, --yes` (**required**), `--private-key=…`, `--db/--no-db`, -`--assets/--no-assets`, `--storage/--no-storage`, `--extensions[=LIST]`. With no -selection flags, the entire archive is restored. - -A typical server-to-server migration: - -```sh -# On the OLD server -php flarum backup:export --all --target=postgres -o /tmp/forum.flarum - -# copy /tmp/forum.flarum to the NEW server, then there: -php flarum backup:import /tmp/forum.flarum --yes -``` - ---- - -### Links - -- **GitHub:** [github.com/ram0ng1/backup](https://github.com/ram0ng1/backup) -- **Packagist:** [packagist.org/packages/ramon/backup](https://packagist.org/packages/ramon/backup) -- **Issues:** [github.com/ram0ng1/backup/issues](https://github.com/ram0ng1/backup/issues) -- **Donate:** [Stripe](https://donate.stripe.com/fZe5o66nebkf39S28a) - ---- - -### License - -[MIT](LICENSE) - ---- - -**Built with ❤️ by [Ramon Guilherme](https://ramonguilherme.com.br)** - -*A personal project focused on making it easier to back up, move and restore -Flarum communities — without leaving the admin panel.* +

+ Backup & Migration +

+ +

Backup & Migration

+ +

+ CI + Packagist + Downloads + Flarum + License + Donate +

+ +

Full backups and one click migration for Flarum 2.

+ +Backup & Migration packs your whole forum into a single portable `.flarum` file: database, uploads, storage and extensions. Restore it on the same install or on a brand new server and keep going. + +I wrote it after one too many rounds of the mysqldump and zip dance while moving forums between hosts. It ended up becoming something close to what All-in-One WP Migration is for WordPress, just built natively for Flarum. + +## What it does + +- Exports everything into one streaming `.flarum` file, so multi GB forums never need to fit in memory +- Lets you pick what goes in: database, assets, storage and individual extensions +- Restores with per section and per extension checkboxes, resumable in chunks +- Migrates between database engines: export from MySQL, restore on PostgreSQL, MariaDB or SQLite +- Rewrites the forum URL automatically when restoring on a different host +- Encrypts archives with libsodium when you ask it to, including transfers to another server's public key +- Ships `composer.json` and `composer.lock` inside the archive, so vendor extensions stay reproducible + +## Installation + +```sh +composer require ramon/backup +php flarum migrate +php flarum cache:clear +``` + +Then enable Backup & Migration on the Extensions page of the admin panel. + +## Command line + +The same engine runs as console commands, with no HTTP timeout and no browser tab to babysit. Best route for large forums and cron jobs. + +```sh +php flarum backup:export --all # everything +php flarum backup:export --db --target=postgres # database only, retargeted to another engine +php flarum backup:import /backups/forum.flarum --yes +``` + +A restore replaces the destination data, so `backup:import` refuses to run without `--yes`. Use `--help` on either command for the full list of flags. + +## About encryption + +Encrypted archives use a libsodium sealed box wrapping a per archive stream key. The public key lives in the database, the private key only in `config.php`. Keep that private key safe: without it an encrypted archive cannot be opened. + +## License + +[MIT](LICENSE). Found a bug or have an idea? [Open an issue](https://github.com/ram0ng1/backup/issues). diff --git a/icon.svg b/icon.svg index 28ac552..41be67f 100644 --- a/icon.svg +++ b/icon.svg @@ -1,4 +1,4 @@ - + Green Core backup (primary) From 1e0dd177d480637d1aea8a789631330d13037bf4 Mon Sep 17 00:00:00 2001 From: Ramon Guilherme <13917322+ram0ng1@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:23:22 +0000 Subject: [PATCH 2/3] =?UTF-8?q?docs:=20fixa=20o=20=C3=ADcone=20em=20150x15?= =?UTF-8?q?0=20mantendo=20o=20viewBox?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- icon.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icon.svg b/icon.svg index 41be67f..d40505b 100644 --- a/icon.svg +++ b/icon.svg @@ -1,4 +1,4 @@ - + Green Core backup (primary) From 40784cef5641688a420202fd8b99a79315002867 Mon Sep 17 00:00:00 2001 From: Ramon Guilherme <13917322+ram0ng1@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:23:23 +0000 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20uniformiza=20a=20descri=C3=A7=C3=A3?= =?UTF-8?q?o=20do=20composer.json=20com=20a=20tagline=20da=20fam=C3=ADlia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4876233..ea9d910 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "ramon/backup", - "description": "All-in-one backup, export and import for Flarum, with optional asymmetric encryption.", + "description": "Full backups and one click migration for Flarum 2", "keywords": [ "flarum", "backup",